diff options
| author | Manfred Spraul <manfred@colorfullife.com> | 2018-08-22 01:01:21 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-22 13:52:51 -0400 |
| commit | 615c999cd8a07b7c3c93bbdee89ef705d2ce52e1 (patch) | |
| tree | 9a61d371b17498dead9ff9136ebd25402bab82fa | |
| parent | 5cb366bb3a746f6b06ea086b322e21e345401c9d (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.c | 19 | ||||
| -rw-r--r-- | ipc/sem.c | 18 | ||||
| -rw-r--r-- | ipc/shm.c | 19 |
3 files changed, 41 insertions, 15 deletions
| @@ -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); | ||
| 556 | out_unlock: | 565 | out_unlock: |
| 557 | rcu_read_unlock(); | 566 | rcu_read_unlock(); |
| 558 | return err; | 567 | return err; |
| @@ -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 | |||
| 1282 | out_unlock: | 1290 | out_unlock: |
| 1283 | rcu_read_unlock(); | 1291 | rcu_read_unlock(); |
| 1284 | return err; | 1292 | return err; |
| @@ -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); | ||
| 1031 | out_unlock: | 1040 | out_unlock: |
| 1032 | rcu_read_unlock(); | 1041 | rcu_read_unlock(); |
| 1033 | return err; | 1042 | return err; |
