aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-09-30 12:48:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-30 12:48:40 -0400
commitb9a532277938798b53178d5a66af6e2915cb27cf (patch)
tree61938755aa03a1fcde29b3fcea8b29ef962af58f /ipc
parent3225031fbeb1e32b269a82eccd815128267a4bfe (diff)
Initialize msg/shm IPC objects before doing ipc_addid()
As reported by Dmitry Vyukov, we really shouldn't do ipc_addid() before having initialized the IPC object state. Yes, we initialize the IPC object in a locked state, but with all the lockless RCU lookup work, that IPC object lock no longer means that the state cannot be seen. We already did this for the IPC semaphore code (see commit e8577d1f0329: "ipc/sem.c: fully initialize sem_array before making it visible") but we clearly forgot about msg and shm. Reported-by: Dmitry Vyukov <dvyukov@google.com> Cc: Manfred Spraul <manfred@colorfullife.com> Cc: Davidlohr Bueso <dbueso@suse.de> Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/msg.c14
-rw-r--r--ipc/shm.c13
-rw-r--r--ipc/util.c8
3 files changed, 18 insertions, 17 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 66c4f567eb73..1471db9a7e61 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -137,13 +137,6 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
137 return retval; 137 return retval;
138 } 138 }
139 139
140 /* ipc_addid() locks msq upon success. */
141 id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
142 if (id < 0) {
143 ipc_rcu_putref(msq, msg_rcu_free);
144 return id;
145 }
146
147 msq->q_stime = msq->q_rtime = 0; 140 msq->q_stime = msq->q_rtime = 0;
148 msq->q_ctime = get_seconds(); 141 msq->q_ctime = get_seconds();
149 msq->q_cbytes = msq->q_qnum = 0; 142 msq->q_cbytes = msq->q_qnum = 0;
@@ -153,6 +146,13 @@ static int newque(struct ipc_namespace *ns, struct ipc_params *params)
153 INIT_LIST_HEAD(&msq->q_receivers); 146 INIT_LIST_HEAD(&msq->q_receivers);
154 INIT_LIST_HEAD(&msq->q_senders); 147 INIT_LIST_HEAD(&msq->q_senders);
155 148
149 /* ipc_addid() locks msq upon success. */
150 id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
151 if (id < 0) {
152 ipc_rcu_putref(msq, msg_rcu_free);
153 return id;
154 }
155
156 ipc_unlock_object(&msq->q_perm); 156 ipc_unlock_object(&msq->q_perm);
157 rcu_read_unlock(); 157 rcu_read_unlock();
158 158
diff --git a/ipc/shm.c b/ipc/shm.c
index 222131e8e38f..41787276e141 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -551,12 +551,6 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
551 if (IS_ERR(file)) 551 if (IS_ERR(file))
552 goto no_file; 552 goto no_file;
553 553
554 id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
555 if (id < 0) {
556 error = id;
557 goto no_id;
558 }
559
560 shp->shm_cprid = task_tgid_vnr(current); 554 shp->shm_cprid = task_tgid_vnr(current);
561 shp->shm_lprid = 0; 555 shp->shm_lprid = 0;
562 shp->shm_atim = shp->shm_dtim = 0; 556 shp->shm_atim = shp->shm_dtim = 0;
@@ -565,6 +559,13 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
565 shp->shm_nattch = 0; 559 shp->shm_nattch = 0;
566 shp->shm_file = file; 560 shp->shm_file = file;
567 shp->shm_creator = current; 561 shp->shm_creator = current;
562
563 id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
564 if (id < 0) {
565 error = id;
566 goto no_id;
567 }
568
568 list_add(&shp->shm_clist, &current->sysvshm.shm_clist); 569 list_add(&shp->shm_clist, &current->sysvshm.shm_clist);
569 570
570 /* 571 /*
diff --git a/ipc/util.c b/ipc/util.c
index be4230020a1f..0f401d94b7c6 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -237,6 +237,10 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
237 rcu_read_lock(); 237 rcu_read_lock();
238 spin_lock(&new->lock); 238 spin_lock(&new->lock);
239 239
240 current_euid_egid(&euid, &egid);
241 new->cuid = new->uid = euid;
242 new->gid = new->cgid = egid;
243
240 id = idr_alloc(&ids->ipcs_idr, new, 244 id = idr_alloc(&ids->ipcs_idr, new,
241 (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0, 245 (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0,
242 GFP_NOWAIT); 246 GFP_NOWAIT);
@@ -249,10 +253,6 @@ int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
249 253
250 ids->in_use++; 254 ids->in_use++;
251 255
252 current_euid_egid(&euid, &egid);
253 new->cuid = new->uid = euid;
254 new->gid = new->cgid = egid;
255
256 if (next_id < 0) { 256 if (next_id < 0) {
257 new->seq = ids->seq++; 257 new->seq = ids->seq++;
258 if (ids->seq > IPCID_SEQ_MAX) 258 if (ids->seq > IPCID_SEQ_MAX)