294b766
From b9a532277938798b53178d5a66af6e2915cb27cf Mon Sep 17 00:00:00 2001
294b766
From: Linus Torvalds <torvalds@linux-foundation.org>
294b766
Date: Wed, 30 Sep 2015 12:48:40 -0400
294b766
Subject: [PATCH] Initialize msg/shm IPC objects before doing ipc_addid()
294b766
294b766
As reported by Dmitry Vyukov, we really shouldn't do ipc_addid() before
294b766
having initialized the IPC object state.  Yes, we initialize the IPC
294b766
object in a locked state, but with all the lockless RCU lookup work,
294b766
that IPC object lock no longer means that the state cannot be seen.
294b766
294b766
We already did this for the IPC semaphore code (see commit e8577d1f0329:
294b766
"ipc/sem.c: fully initialize sem_array before making it visible") but we
294b766
clearly forgot about msg and shm.
294b766
294b766
Reported-by: Dmitry Vyukov <dvyukov@google.com>
294b766
Cc: Manfred Spraul <manfred@colorfullife.com>
294b766
Cc: Davidlohr Bueso <dbueso@suse.de>
294b766
Cc: stable@vger.kernel.org
294b766
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
294b766
---
294b766
 ipc/msg.c  | 14 +++++++-------
294b766
 ipc/shm.c  | 13 +++++++------
294b766
 ipc/util.c |  8 ++++----
294b766
 3 files changed, 18 insertions(+), 17 deletions(-)
294b766
294b766
diff --git a/ipc/msg.c b/ipc/msg.c
294b766
index 66c4f567eb73..1471db9a7e61 100644
294b766
--- a/ipc/msg.c
294b766
+++ b/ipc/msg.c
294b766
@@ -137,13 +137,6 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
294b766
 		return retval;
294b766
 	}
294b766
 
294b766
-	/* ipc_addid() locks msq upon success. */
294b766
-	id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
294b766
-	if (id < 0) {
294b766
-		ipc_rcu_putref(msq, msg_rcu_free);
294b766
-		return id;
294b766
-	}
294b766
-
294b766
 	msq->q_stime = msq->q_rtime = 0;
294b766
 	msq->q_ctime = get_seconds();
294b766
 	msq->q_cbytes = msq->q_qnum = 0;
294b766
@@ -153,6 +146,13 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
294b766
 	INIT_LIST_HEAD(&msq->q_receivers);
294b766
 	INIT_LIST_HEAD(&msq->q_senders);
294b766
 
294b766
+	/* ipc_addid() locks msq upon success. */
294b766
+	id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
294b766
+	if (id < 0) {
294b766
+		ipc_rcu_putref(msq, msg_rcu_free);
294b766
+		return id;
294b766
+	}
294b766
+
294b766
 	ipc_unlock_object(&msq->q_perm);
294b766
 	rcu_read_unlock();
294b766
 
294b766
diff --git a/ipc/shm.c b/ipc/shm.c
294b766
index 222131e8e38f..41787276e141 100644
294b766
--- a/ipc/shm.c
294b766
+++ b/ipc/shm.c
294b766
@@ -551,12 +551,6 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
294b766
 	if (IS_ERR(file))
294b766
 		goto no_file;
294b766
 
294b766
-	id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
294b766
-	if (id < 0) {
294b766
-		error = id;
294b766
-		goto no_id;
294b766
-	}
294b766
-
294b766
 	shp->shm_cprid = task_tgid_vnr(current);
294b766
 	shp->shm_lprid = 0;
294b766
 	shp->shm_atim = shp->shm_dtim = 0;
294b766
@@ -565,6 +559,13 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
294b766
 	shp->shm_nattch = 0;
294b766
 	shp->shm_file = file;
294b766
 	shp->shm_creator = current;
294b766
+
294b766
+	id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
294b766
+	if (id < 0) {
294b766
+		error = id;
294b766
+		goto no_id;
294b766
+	}
294b766
+
294b766
 	list_add(&shp->shm_clist, &current->sysvshm.shm_clist);
294b766
 
294b766
 	/*
294b766
diff --git a/ipc/util.c b/ipc/util.c
294b766
index be4230020a1f..0f401d94b7c6 100644
294b766
--- a/ipc/util.c
294b766
+++ b/ipc/util.c
294b766
@@ -237,6 +237,10 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
294b766
 	rcu_read_lock();
294b766
 	spin_lock(&new->lock);
294b766
 
294b766
+	current_euid_egid(&euid, &egid);
294b766
+	new->cuid = new->uid = euid;
294b766
+	new->gid = new->cgid = egid;
294b766
+
294b766
 	id = idr_alloc(&ids->ipcs_idr, new,
294b766
 		       (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0,
294b766
 		       GFP_NOWAIT);
294b766
@@ -249,10 +253,6 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
294b766
 
294b766
 	ids->in_use++;
294b766
 
294b766
-	current_euid_egid(&euid, &egid);
294b766
-	new->cuid = new->uid = euid;
294b766
-	new->gid = new->cgid = egid;
294b766
-
294b766
 	if (next_id < 0) {
294b766
 		new->seq = ids->seq++;
294b766
 		if (ids->seq > IPCID_SEQ_MAX)
294b766
-- 
294b766
2.4.3
294b766