aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2018-03-23 01:42:21 -0400
committerEric W. Biederman <ebiederm@xmission.com>2018-03-27 16:53:41 -0400
commit39a4940eaa185910bb802ca9829c12268fd2c855 (patch)
treefdc9b438417ca1b272303d3a724212be26979d27
parent98f929b1bd4d0b7c7a77d0d9776d1b924db2e454 (diff)
ipc/msg: Fix msgctl(..., IPC_STAT, ...) between pid namespaces
Today msg_lspid and msg_lrpid are remembered in the pid namespace of the creator and the processes that last send or received a sysvipc message. If you have processes in multiple pid namespaces that is just wrong. The process ids reported will not make the least bit of sense. This fix is slightly more susceptible to a performance problem than the related fix for System V shared memory. By definition the pids are updated by msgsnd and msgrcv, the fast path of System V message queues. The only concern over the previous implementation is the incrementing and decrementing of the pid reference count. As that is the only difference and multiple updates by of the task_tgid by threads in the same process have been shown in af_unix sockets to create a cache line ping-pong between cpus of the same processor. In this case I don't expect cache lines holding pid reference counts to ping pong between cpus. As senders and receivers update different pids there is a natural separation there. Further if multiple threads of the same process either send or receive messages the pid will be updated to the same value and ipc_update_pid will avoid the reference count update. Which means in the common case I expect msg_lspid and msg_lrpid to remain constant, and reference counts not to be updated when messages are sent. In rare cases it may be possible to trigger the issue which was observed for af_unix sockets, but it will require multiple processes with multiple threads to be either sending or receiving messages. It just does not feel likely that anyone would do that in practice. This change updates msgctl(..., IPC_STAT, ...) to return msg_lspid and msg_lrpid in the pid namespace of the process calling stat. This change also updates cat /proc/sysvipc/msg to return print msg_lspid and msg_lrpid in the pid namespace of the process that opened the proc file. Fixes: b488893a390e ("pid namespaces: changes to show virtual ids to user") Reviewed-by: Nagarathnam Muthusamy <nagarathnam.muthusamy@oracle.com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r--ipc/msg.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index af5a963306c4..825ad585a6ff 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -52,8 +52,8 @@ struct msg_queue {
52 unsigned long q_cbytes; /* current number of bytes on queue */ 52 unsigned long q_cbytes; /* current number of bytes on queue */
53 unsigned long q_qnum; /* number of messages in queue */ 53 unsigned long q_qnum; /* number of messages in queue */
54 unsigned long q_qbytes; /* max number of bytes on queue */ 54 unsigned long q_qbytes; /* max number of bytes on queue */
55 pid_t q_lspid; /* pid of last msgsnd */ 55 struct pid *q_lspid; /* pid of last msgsnd */
56 pid_t q_lrpid; /* last receive pid */ 56 struct pid *q_lrpid; /* last receive pid */
57 57
58 struct list_head q_messages; 58 struct list_head q_messages;
59 struct list_head q_receivers; 59 struct list_head q_receivers;
@@ -154,7 +154,7 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
154 msq->q_ctime = ktime_get_real_seconds(); 154 msq->q_ctime = ktime_get_real_seconds();
155 msq->q_cbytes = msq->q_qnum = 0; 155 msq->q_cbytes = msq->q_qnum = 0;
156 msq->q_qbytes = ns->msg_ctlmnb; 156 msq->q_qbytes = ns->msg_ctlmnb;
157 msq->q_lspid = msq->q_lrpid = 0; 157 msq->q_lspid = msq->q_lrpid = NULL;
158 INIT_LIST_HEAD(&msq->q_messages); 158 INIT_LIST_HEAD(&msq->q_messages);
159 INIT_LIST_HEAD(&msq->q_receivers); 159 INIT_LIST_HEAD(&msq->q_receivers);
160 INIT_LIST_HEAD(&msq->q_senders); 160 INIT_LIST_HEAD(&msq->q_senders);
@@ -267,6 +267,8 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
267 free_msg(msg); 267 free_msg(msg);
268 } 268 }
269 atomic_sub(msq->q_cbytes, &ns->msg_bytes); 269 atomic_sub(msq->q_cbytes, &ns->msg_bytes);
270 ipc_update_pid(&msq->q_lspid, NULL);
271 ipc_update_pid(&msq->q_lrpid, NULL);
270 ipc_rcu_putref(&msq->q_perm, msg_rcu_free); 272 ipc_rcu_putref(&msq->q_perm, msg_rcu_free);
271} 273}
272 274
@@ -536,8 +538,8 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
536 p->msg_cbytes = msq->q_cbytes; 538 p->msg_cbytes = msq->q_cbytes;
537 p->msg_qnum = msq->q_qnum; 539 p->msg_qnum = msq->q_qnum;
538 p->msg_qbytes = msq->q_qbytes; 540 p->msg_qbytes = msq->q_qbytes;
539 p->msg_lspid = msq->q_lspid; 541 p->msg_lspid = pid_vnr(msq->q_lspid);
540 p->msg_lrpid = msq->q_lrpid; 542 p->msg_lrpid = pid_vnr(msq->q_lrpid);
541 543
542 ipc_unlock_object(&msq->q_perm); 544 ipc_unlock_object(&msq->q_perm);
543 rcu_read_unlock(); 545 rcu_read_unlock();
@@ -741,7 +743,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg,
741 wake_q_add(wake_q, msr->r_tsk); 743 wake_q_add(wake_q, msr->r_tsk);
742 WRITE_ONCE(msr->r_msg, ERR_PTR(-E2BIG)); 744 WRITE_ONCE(msr->r_msg, ERR_PTR(-E2BIG));
743 } else { 745 } else {
744 msq->q_lrpid = task_pid_vnr(msr->r_tsk); 746 ipc_update_pid(&msq->q_lrpid, task_pid(msr->r_tsk));
745 msq->q_rtime = get_seconds(); 747 msq->q_rtime = get_seconds();
746 748
747 wake_q_add(wake_q, msr->r_tsk); 749 wake_q_add(wake_q, msr->r_tsk);
@@ -842,7 +844,7 @@ static long do_msgsnd(int msqid, long mtype, void __user *mtext,
842 844
843 } 845 }
844 846
845 msq->q_lspid = task_tgid_vnr(current); 847 ipc_update_pid(&msq->q_lspid, task_tgid(current));
846 msq->q_stime = get_seconds(); 848 msq->q_stime = get_seconds();
847 849
848 if (!pipelined_send(msq, msg, &wake_q)) { 850 if (!pipelined_send(msq, msg, &wake_q)) {
@@ -1060,7 +1062,7 @@ static long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, in
1060 list_del(&msg->m_list); 1062 list_del(&msg->m_list);
1061 msq->q_qnum--; 1063 msq->q_qnum--;
1062 msq->q_rtime = get_seconds(); 1064 msq->q_rtime = get_seconds();
1063 msq->q_lrpid = task_tgid_vnr(current); 1065 ipc_update_pid(&msq->q_lrpid, task_tgid(current));
1064 msq->q_cbytes -= msg->m_ts; 1066 msq->q_cbytes -= msg->m_ts;
1065 atomic_sub(msg->m_ts, &ns->msg_bytes); 1067 atomic_sub(msg->m_ts, &ns->msg_bytes);
1066 atomic_dec(&ns->msg_hdrs); 1068 atomic_dec(&ns->msg_hdrs);
@@ -1202,6 +1204,7 @@ void msg_exit_ns(struct ipc_namespace *ns)
1202#ifdef CONFIG_PROC_FS 1204#ifdef CONFIG_PROC_FS
1203static int sysvipc_msg_proc_show(struct seq_file *s, void *it) 1205static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
1204{ 1206{
1207 struct pid_namespace *pid_ns = ipc_seq_pid_ns(s);
1205 struct user_namespace *user_ns = seq_user_ns(s); 1208 struct user_namespace *user_ns = seq_user_ns(s);
1206 struct kern_ipc_perm *ipcp = it; 1209 struct kern_ipc_perm *ipcp = it;
1207 struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm); 1210 struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
@@ -1213,8 +1216,8 @@ static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
1213 msq->q_perm.mode, 1216 msq->q_perm.mode,
1214 msq->q_cbytes, 1217 msq->q_cbytes,
1215 msq->q_qnum, 1218 msq->q_qnum,
1216 msq->q_lspid, 1219 pid_nr_ns(msq->q_lspid, pid_ns),
1217 msq->q_lrpid, 1220 pid_nr_ns(msq->q_lrpid, pid_ns),
1218 from_kuid_munged(user_ns, msq->q_perm.uid), 1221 from_kuid_munged(user_ns, msq->q_perm.uid),
1219 from_kgid_munged(user_ns, msq->q_perm.gid), 1222 from_kgid_munged(user_ns, msq->q_perm.gid),
1220 from_kuid_munged(user_ns, msq->q_perm.cuid), 1223 from_kuid_munged(user_ns, msq->q_perm.cuid),