|
11 | 11 | #include <linux/proc_fs.h>
|
12 | 12 | #include <linux/proc_ns.h>
|
13 | 13 | #include <linux/pseudo_fs.h>
|
| 14 | +#include <linux/ptrace.h> |
14 | 15 | #include <linux/seq_file.h>
|
15 | 16 | #include <uapi/linux/pidfd.h>
|
| 17 | +#include <linux/ipc_namespace.h> |
| 18 | +#include <linux/time_namespace.h> |
| 19 | +#include <linux/utsname.h> |
| 20 | +#include <net/net_namespace.h> |
16 | 21 |
|
17 | 22 | #include "internal.h"
|
| 23 | +#include "mount.h" |
18 | 24 |
|
19 | 25 | #ifdef CONFIG_PROC_FS
|
20 | 26 | /**
|
@@ -108,11 +114,95 @@ static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts)
|
108 | 114 | return poll_flags;
|
109 | 115 | }
|
110 | 116 |
|
| 117 | +static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 118 | +{ |
| 119 | + struct task_struct *task __free(put_task) = NULL; |
| 120 | + struct nsproxy *nsp __free(put_nsproxy) = NULL; |
| 121 | + struct pid *pid = pidfd_pid(file); |
| 122 | + struct ns_common *ns_common; |
| 123 | + |
| 124 | + if (arg) |
| 125 | + return -EINVAL; |
| 126 | + |
| 127 | + task = get_pid_task(pid, PIDTYPE_PID); |
| 128 | + if (!task) |
| 129 | + return -ESRCH; |
| 130 | + |
| 131 | + scoped_guard(task_lock, task) { |
| 132 | + nsp = task->nsproxy; |
| 133 | + if (nsp) |
| 134 | + get_nsproxy(nsp); |
| 135 | + } |
| 136 | + if (!nsp) |
| 137 | + return -ESRCH; /* just pretend it didn't exist */ |
| 138 | + |
| 139 | + /* |
| 140 | + * We're trying to open a file descriptor to the namespace so perform a |
| 141 | + * filesystem cred ptrace check. Also, we mirror nsfs behavior. |
| 142 | + */ |
| 143 | + if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) |
| 144 | + return -EACCES; |
| 145 | + |
| 146 | + switch (cmd) { |
| 147 | + /* Namespaces that hang of nsproxy. */ |
| 148 | + case PIDFD_GET_CGROUP_NAMESPACE: |
| 149 | + get_cgroup_ns(nsp->cgroup_ns); |
| 150 | + ns_common = to_ns_common(nsp->cgroup_ns); |
| 151 | + break; |
| 152 | + case PIDFD_GET_IPC_NAMESPACE: |
| 153 | + get_ipc_ns(nsp->ipc_ns); |
| 154 | + ns_common = to_ns_common(nsp->ipc_ns); |
| 155 | + break; |
| 156 | + case PIDFD_GET_MNT_NAMESPACE: |
| 157 | + get_mnt_ns(nsp->mnt_ns); |
| 158 | + ns_common = to_ns_common(nsp->mnt_ns); |
| 159 | + break; |
| 160 | + case PIDFD_GET_NET_NAMESPACE: |
| 161 | + ns_common = to_ns_common(nsp->net_ns); |
| 162 | + get_net_ns(ns_common); |
| 163 | + break; |
| 164 | + case PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE: |
| 165 | + get_pid_ns(nsp->pid_ns_for_children); |
| 166 | + ns_common = to_ns_common(nsp->pid_ns_for_children); |
| 167 | + break; |
| 168 | + case PIDFD_GET_TIME_NAMESPACE: |
| 169 | + get_time_ns(nsp->time_ns); |
| 170 | + ns_common = to_ns_common(nsp->time_ns); |
| 171 | + break; |
| 172 | + case PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE: |
| 173 | + get_time_ns(nsp->time_ns_for_children); |
| 174 | + ns_common = to_ns_common(nsp->time_ns_for_children); |
| 175 | + break; |
| 176 | + case PIDFD_GET_UTS_NAMESPACE: |
| 177 | + get_uts_ns(nsp->uts_ns); |
| 178 | + ns_common = to_ns_common(nsp->uts_ns); |
| 179 | + break; |
| 180 | + /* Namespaces that don't hang of nsproxy. */ |
| 181 | + case PIDFD_GET_USER_NAMESPACE: |
| 182 | + rcu_read_lock(); |
| 183 | + ns_common = to_ns_common(get_user_ns(task_cred_xxx(task, user_ns))); |
| 184 | + rcu_read_unlock(); |
| 185 | + break; |
| 186 | + case PIDFD_GET_PID_NAMESPACE: |
| 187 | + rcu_read_lock(); |
| 188 | + ns_common = to_ns_common(get_pid_ns(task_active_pid_ns(task))); |
| 189 | + rcu_read_unlock(); |
| 190 | + break; |
| 191 | + default: |
| 192 | + return -ENOIOCTLCMD; |
| 193 | + } |
| 194 | + |
| 195 | + /* open_namespace() unconditionally consumes the reference */ |
| 196 | + return open_namespace(ns_common); |
| 197 | +} |
| 198 | + |
111 | 199 | static const struct file_operations pidfs_file_operations = {
|
112 | 200 | .poll = pidfd_poll,
|
113 | 201 | #ifdef CONFIG_PROC_FS
|
114 | 202 | .show_fdinfo = pidfd_show_fdinfo,
|
115 | 203 | #endif
|
| 204 | + .unlocked_ioctl = pidfd_ioctl, |
| 205 | + .compat_ioctl = compat_ptr_ioctl, |
116 | 206 | };
|
117 | 207 |
|
118 | 208 | struct pid *pidfd_pid(const struct file *file)
|
|
0 commit comments