| From: "Eric W. Biederman" <ebiederm@xmission.com> |
| Date: Fri, 23 Mar 2018 00:22:05 -0500 |
| Subject: ipc/util: Helpers for making the sysvipc operations pid namespace |
| aware |
| |
| commit 03f1fc09180b345582889a344b012d069b3a6dbe upstream. |
| |
| Capture the pid namespace when /proc/sysvipc/msg /proc/sysvipc/shm |
| and /proc/sysvipc/sem are opened, and make it available through |
| the new helper ipc_seq_pid_ns. |
| |
| This makes it possible to report the pids in these files in the |
| pid namespace of the opener of the files. |
| |
| Implement ipc_update_pid. A simple impline helper that will only update |
| a struct pid pointer if the new value does not equal the old value. This |
| removes the need for wordy code sequences like: |
| |
| old = object->pid; |
| object->pid = new; |
| put_pid(old); |
| |
| and |
| |
| old = object->pid; |
| if (old != new) { |
| object->pid = new; |
| put_pid(old); |
| } |
| |
| Allowing the following to be written instead: |
| |
| ipc_update_pid(&object->pid, new); |
| |
| Which is easier to read and ensures that the pid reference count is |
| not touched the old and the new values are the same. Not touching |
| the reference count in this case is important to help avoid issues |
| like af_unix experienced, where multiple threads of the same |
| process managed to bounce the struct pid between cpu cache lines, |
| but updating the pids reference count. |
| |
| Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> |
| [bwh: Backported to 3.16: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| ipc/util.c | 9 +++++++++ |
| ipc/util.h | 11 +++++++++++ |
| 2 files changed, 20 insertions(+) |
| |
| --- a/ipc/util.c |
| +++ b/ipc/util.c |
| @@ -777,9 +777,16 @@ int ipc_parse_version(int *cmd) |
| #ifdef CONFIG_PROC_FS |
| struct ipc_proc_iter { |
| struct ipc_namespace *ns; |
| + struct pid_namespace *pid_ns; |
| struct ipc_proc_iface *iface; |
| }; |
| |
| +struct pid_namespace *ipc_seq_pid_ns(struct seq_file *s) |
| +{ |
| + struct ipc_proc_iter *iter = s->private; |
| + return iter->pid_ns; |
| +} |
| + |
| /* |
| * This routine locks the ipc structure found at least at position pos. |
| */ |
| @@ -914,6 +921,7 @@ static int sysvipc_proc_open(struct inod |
| |
| iter->iface = PDE_DATA(inode); |
| iter->ns = get_ipc_ns(current->nsproxy->ipc_ns); |
| + iter->pid_ns = get_pid_ns(task_active_pid_ns(current)); |
| out: |
| return ret; |
| } |
| @@ -923,6 +931,7 @@ static int sysvipc_proc_release(struct i |
| struct seq_file *seq = file->private_data; |
| struct ipc_proc_iter *iter = seq->private; |
| put_ipc_ns(iter->ns); |
| + put_pid_ns(iter->pid_ns); |
| return seq_release_private(inode, file); |
| } |
| |
| --- a/ipc/util.h |
| +++ b/ipc/util.h |
| @@ -20,6 +20,7 @@ void msg_init(void); |
| void shm_init(void); |
| |
| struct ipc_namespace; |
| +struct pid_namespace; |
| |
| #ifdef CONFIG_POSIX_MQUEUE |
| extern void mq_clear_sbinfo(struct ipc_namespace *ns); |
| @@ -90,6 +91,7 @@ void ipc_init_ids(struct ipc_ids *); |
| #ifdef CONFIG_PROC_FS |
| void __init ipc_init_proc_interface(const char *path, const char *header, |
| int ids, int (*show)(struct seq_file *, void *)); |
| +struct pid_namespace *ipc_seq_pid_ns(struct seq_file *); |
| #else |
| #define ipc_init_proc_interface(path, header, ids, show) do {} while (0) |
| #endif |
| @@ -141,6 +143,15 @@ struct kern_ipc_perm *ipcctl_pre_down_no |
| struct ipc_ids *ids, int id, int cmd, |
| struct ipc64_perm *perm, int extra_perm); |
| |
| +static inline void ipc_update_pid(struct pid **pos, struct pid *pid) |
| +{ |
| + struct pid *old = *pos; |
| + if (old != pid) { |
| + *pos = get_pid(pid); |
| + put_pid(old); |
| + } |
| +} |
| + |
| #ifndef CONFIG_ARCH_WANT_IPC_PARSE_VERSION |
| /* On IA-64, we always use the "64-bit version" of the IPC structures. */ |
| # define ipc_parse_version(cmd) IPC_64 |