aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManfred Spraul <manfred@colorfullife.com>2018-08-22 01:01:21 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-22 13:52:51 -0400
commit615c999cd8a07b7c3c93bbdee89ef705d2ce52e1 (patch)
tree9a61d371b17498dead9ff9136ebd25402bab82fa
parent5cb366bb3a746f6b06ea086b322e21e345401c9d (diff)
ipc: compute kern_ipc_perm.id under the ipc lock
ipc_addid() initializes kern_ipc_perm.id after having called ipc_idr_alloc(). Thus a parallel semctl() or msgctl() that uses e.g. MSG_STAT may use this unitialized value as the return code. The patch moves all accesses to kern_ipc_perm.id under the spin_lock(). The issues is related to the finding of syzbot+2827ef6b3385deb07eaf@syzkaller.appspotmail.com: syzbot found an issue with kern_ipc_perm.seq Link: http://lkml.kernel.org/r/20180712185241.4017-2-manfred@colorfullife.com Signed-off-by: Manfred Spraul <manfred@colorfullife.com> Reviewed-by: Davidlohr Bueso <dbueso@suse.de> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Kees Cook <keescook@chromium.org> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: Michael Kerrisk <mtk.manpages@gmail.com> Cc: Michal Hocko <mhocko@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--ipc/msg.c19
-rw-r--r--ipc/sem.c18
-rw-r--r--ipc/shm.c19
3 files changed, 41 insertions, 15 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 203281198079..7cb89a9b24e2 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -492,7 +492,6 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
492 int cmd, struct msqid64_ds *p) 492 int cmd, struct msqid64_ds *p)
493{ 493{
494 struct msg_queue *msq; 494 struct msg_queue *msq;
495 int id = 0;
496 int err; 495 int err;
497 496
498 memset(p, 0, sizeof(*p)); 497 memset(p, 0, sizeof(*p));
@@ -504,7 +503,6 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
504 err = PTR_ERR(msq); 503 err = PTR_ERR(msq);
505 goto out_unlock; 504 goto out_unlock;
506 } 505 }
507 id = msq->q_perm.id;
508 } else { /* IPC_STAT */ 506 } else { /* IPC_STAT */
509 msq = msq_obtain_object_check(ns, msqid); 507 msq = msq_obtain_object_check(ns, msqid);
510 if (IS_ERR(msq)) { 508 if (IS_ERR(msq)) {
@@ -549,10 +547,21 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
549 p->msg_lspid = pid_vnr(msq->q_lspid); 547 p->msg_lspid = pid_vnr(msq->q_lspid);
550 p->msg_lrpid = pid_vnr(msq->q_lrpid); 548 p->msg_lrpid = pid_vnr(msq->q_lrpid);
551 549
552 ipc_unlock_object(&msq->q_perm); 550 if (cmd == IPC_STAT) {
553 rcu_read_unlock(); 551 /*
554 return id; 552 * As defined in SUS:
553 * Return 0 on success
554 */
555 err = 0;
556 } else {
557 /*
558 * MSG_STAT and MSG_STAT_ANY (both Linux specific)
559 * Return the full id, including the sequence number
560 */
561 err = msq->q_perm.id;
562 }
555 563
564 ipc_unlock_object(&msq->q_perm);
556out_unlock: 565out_unlock:
557 rcu_read_unlock(); 566 rcu_read_unlock();
558 return err; 567 return err;
diff --git a/ipc/sem.c b/ipc/sem.c
index 00ef2f743a62..18e50f464f76 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1223,7 +1223,6 @@ static int semctl_stat(struct ipc_namespace *ns, int semid,
1223{ 1223{
1224 struct sem_array *sma; 1224 struct sem_array *sma;
1225 time64_t semotime; 1225 time64_t semotime;
1226 int id = 0;
1227 int err; 1226 int err;
1228 1227
1229 memset(semid64, 0, sizeof(*semid64)); 1228 memset(semid64, 0, sizeof(*semid64));
@@ -1235,7 +1234,6 @@ static int semctl_stat(struct ipc_namespace *ns, int semid,
1235 err = PTR_ERR(sma); 1234 err = PTR_ERR(sma);
1236 goto out_unlock; 1235 goto out_unlock;
1237 } 1236 }
1238 id = sma->sem_perm.id;
1239 } else { /* IPC_STAT */ 1237 } else { /* IPC_STAT */
1240 sma = sem_obtain_object_check(ns, semid); 1238 sma = sem_obtain_object_check(ns, semid);
1241 if (IS_ERR(sma)) { 1239 if (IS_ERR(sma)) {
@@ -1275,10 +1273,20 @@ static int semctl_stat(struct ipc_namespace *ns, int semid,
1275#endif 1273#endif
1276 semid64->sem_nsems = sma->sem_nsems; 1274 semid64->sem_nsems = sma->sem_nsems;
1277 1275
1276 if (cmd == IPC_STAT) {
1277 /*
1278 * As defined in SUS:
1279 * Return 0 on success
1280 */
1281 err = 0;
1282 } else {
1283 /*
1284 * SEM_STAT and SEM_STAT_ANY (both Linux specific)
1285 * Return the full id, including the sequence number
1286 */
1287 err = sma->sem_perm.id;
1288 }
1278 ipc_unlock_object(&sma->sem_perm); 1289 ipc_unlock_object(&sma->sem_perm);
1279 rcu_read_unlock();
1280 return id;
1281
1282out_unlock: 1290out_unlock:
1283 rcu_read_unlock(); 1291 rcu_read_unlock();
1284 return err; 1292 return err;
diff --git a/ipc/shm.c b/ipc/shm.c
index b204feb38274..b3b089315d3b 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -962,7 +962,6 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
962 int cmd, struct shmid64_ds *tbuf) 962 int cmd, struct shmid64_ds *tbuf)
963{ 963{
964 struct shmid_kernel *shp; 964 struct shmid_kernel *shp;
965 int id = 0;
966 int err; 965 int err;
967 966
968 memset(tbuf, 0, sizeof(*tbuf)); 967 memset(tbuf, 0, sizeof(*tbuf));
@@ -974,7 +973,6 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
974 err = PTR_ERR(shp); 973 err = PTR_ERR(shp);
975 goto out_unlock; 974 goto out_unlock;
976 } 975 }
977 id = shp->shm_perm.id;
978 } else { /* IPC_STAT */ 976 } else { /* IPC_STAT */
979 shp = shm_obtain_object_check(ns, shmid); 977 shp = shm_obtain_object_check(ns, shmid);
980 if (IS_ERR(shp)) { 978 if (IS_ERR(shp)) {
@@ -1024,10 +1022,21 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
1024 tbuf->shm_lpid = pid_vnr(shp->shm_lprid); 1022 tbuf->shm_lpid = pid_vnr(shp->shm_lprid);
1025 tbuf->shm_nattch = shp->shm_nattch; 1023 tbuf->shm_nattch = shp->shm_nattch;
1026 1024
1027 ipc_unlock_object(&shp->shm_perm); 1025 if (cmd == IPC_STAT) {
1028 rcu_read_unlock(); 1026 /*
1029 return id; 1027 * As defined in SUS:
1028 * Return 0 on success
1029 */
1030 err = 0;
1031 } else {
1032 /*
1033 * SHM_STAT and SHM_STAT_ANY (both Linux specific)
1034 * Return the full id, including the sequence number
1035 */
1036 err = shp->shm_perm.id;
1037 }
1030 1038
1039 ipc_unlock_object(&shp->shm_perm);
1031out_unlock: 1040out_unlock:
1032 rcu_read_unlock(); 1041 rcu_read_unlock();
1033 return err; 1042 return err;