History

pidfs: allow retrieval of namespace file descriptors

For users that hold a reference to a pidfd procfs might not even be available nor is it desirable to parse through procfs just for the sake of getting namespace file descriptors for a process. Make it possible to directly retrieve namespace file descriptors from a pidfd. Pidfds already can be used with setns() to change a set of namespaces atomically.

Christian Brauner committed 2 years ago

Commit 5b08bd41 parent 460695a2 files · +104 −0Browse files

Unified · Split

2 files
  1. fs/pidfs.c +90 −0
  2. include/uapi/linux/pidfd.h +14 −0
fs/pidfs.c+90−0
@@ -11,10 +11,16 @@ · 10 unmodified lines
11#include <linux/proc_fs.h>11#include <linux/proc_fs.h>
12#include <linux/proc_ns.h>12#include <linux/proc_ns.h>
13#include <linux/pseudo_fs.h>13#include <linux/pseudo_fs.h>
14#include <linux/ptrace.h>
14#include <linux/seq_file.h>15#include <linux/seq_file.h>
15#include <uapi/linux/pidfd.h>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#include "internal.h"22#include "internal.h"
23#include "mount.h"
18 24
19#ifdef CONFIG_PROC_FS25#ifdef CONFIG_PROC_FS
20/**26/**
@@ -108,11 +114,95 @@ static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts) · 87 unmodified lines
108 return poll_flags;114 return poll_flags;
109}115}
110 116
117static 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
111static const struct file_operations pidfs_file_operations = {199static const struct file_operations pidfs_file_operations = {
112 .poll = pidfd_poll,200 .poll = pidfd_poll,
113#ifdef CONFIG_PROC_FS201#ifdef CONFIG_PROC_FS
114 .show_fdinfo = pidfd_show_fdinfo,202 .show_fdinfo = pidfd_show_fdinfo,
115#endif203#endif
204 .unlocked_ioctl = pidfd_ioctl,
205 .compat_ioctl = compat_ptr_ioctl,
116};206};
117 207
118struct pid *pidfd_pid(const struct file *file)208struct pid *pidfd_pid(const struct file *file)
include/uapi/linux/pidfd.h+14−0
@@ -5,6 +5,7 @@ · 4 unmodified lines
5 5
6#include <linux/types.h>6#include <linux/types.h>
7#include <linux/fcntl.h>7#include <linux/fcntl.h>
8#include <linux/ioctl.h>
8 9
9/* Flags for pidfd_open(). */10/* Flags for pidfd_open(). */
10#define PIDFD_NONBLOCK O_NONBLOCK11#define PIDFD_NONBLOCK O_NONBLOCK
@@ -15,4 +16,17 @@ · 4 unmodified lines
15#define PIDFD_SIGNAL_THREAD_GROUP (1UL << 1)16#define PIDFD_SIGNAL_THREAD_GROUP (1UL << 1)
16#define PIDFD_SIGNAL_PROCESS_GROUP (1UL << 2)17#define PIDFD_SIGNAL_PROCESS_GROUP (1UL << 2)
17 18
19#define PIDFS_IOCTL_MAGIC 0xFF
20
21#define PIDFD_GET_CGROUP_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 1)
22#define PIDFD_GET_IPC_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 2)
23#define PIDFD_GET_MNT_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 3)
24#define PIDFD_GET_NET_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 4)
25#define PIDFD_GET_PID_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 5)
26#define PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 6)
27#define PIDFD_GET_TIME_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 7)
28#define PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 8)
29#define PIDFD_GET_USER_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 9)
30#define PIDFD_GET_UTS_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 10)
31
18#endif /* _UAPI_LINUX_PIDFD_H */32#endif /* _UAPI_LINUX_PIDFD_H */