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