From 87ad4b0d853e8a65d6002f4e7bd3dce4ae3a52da Mon Sep 17 00:00:00 2001 From: Philippe Mikoyan Date: Tue, 6 Feb 2018 15:40:49 -0800 Subject: ipc: fix ipc data structures inconsistency As described in the title, this patch fixes id_ds inconsistency when ctl_stat executes concurrently with some ds-changing function, e.g. shmat, msgsnd or whatever. For instance, if shmctl(IPC_STAT) is running concurrently with shmat, following data structure can be returned: {... shm_lpid = 0, shm_nattch = 1, ...} Link: http://lkml.kernel.org/r/20171202153456.6514-1-philippe.mikoyan@skat.systems Signed-off-by: Philippe Mikoyan Reviewed-by: Davidlohr Bueso Cc: Al Viro Cc: Manfred Spraul Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/msg.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'ipc/msg.c') diff --git a/ipc/msg.c b/ipc/msg.c index 1bbc029d2b17..0dcc6699dc53 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -476,9 +476,9 @@ static int msgctl_info(struct ipc_namespace *ns, int msqid, static int msgctl_stat(struct ipc_namespace *ns, int msqid, int cmd, struct msqid64_ds *p) { - int err; struct msg_queue *msq; - int success_return; + int id = 0; + int err; memset(p, 0, sizeof(*p)); @@ -489,14 +489,13 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid, err = PTR_ERR(msq); goto out_unlock; } - success_return = msq->q_perm.id; + id = msq->q_perm.id; } else { msq = msq_obtain_object_check(ns, msqid); if (IS_ERR(msq)) { err = PTR_ERR(msq); goto out_unlock; } - success_return = 0; } err = -EACCES; @@ -507,6 +506,14 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid, if (err) goto out_unlock; + ipc_lock_object(&msq->q_perm); + + if (!ipc_valid_object(&msq->q_perm)) { + ipc_unlock_object(&msq->q_perm); + err = -EIDRM; + goto out_unlock; + } + kernel_to_ipc64_perm(&msq->q_perm, &p->msg_perm); p->msg_stime = msq->q_stime; p->msg_rtime = msq->q_rtime; @@ -516,9 +523,10 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid, p->msg_qbytes = msq->q_qbytes; p->msg_lspid = msq->q_lspid; p->msg_lrpid = msq->q_lrpid; - rcu_read_unlock(); - return success_return; + ipc_unlock_object(&msq->q_perm); + rcu_read_unlock(); + return id; out_unlock: rcu_read_unlock(); -- cgit v1.2.3