Skip to content

Commit

Permalink
ipc: compute kern_ipc_perm.id under the ipc lock
Browse files Browse the repository at this point in the history
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
[email protected]: syzbot found an
issue with kern_ipc_perm.seq

Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Manfred Spraul <[email protected]>
Reviewed-by: Davidlohr Bueso <[email protected]>
Cc: Dmitry Vyukov <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Davidlohr Bueso <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Michael Kerrisk <[email protected]>
Cc: Michal Hocko <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
manfred-colorfu authored and torvalds committed Aug 22, 2018
1 parent 5cb366b commit 615c999
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 15 deletions.
19 changes: 14 additions & 5 deletions ipc/msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,6 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
int cmd, struct msqid64_ds *p)
{
struct msg_queue *msq;
int id = 0;
int err;

memset(p, 0, sizeof(*p));
Expand All @@ -504,7 +503,6 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
err = PTR_ERR(msq);
goto out_unlock;
}
id = msq->q_perm.id;
} else { /* IPC_STAT */
msq = msq_obtain_object_check(ns, msqid);
if (IS_ERR(msq)) {
Expand Down Expand Up @@ -549,10 +547,21 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
p->msg_lspid = pid_vnr(msq->q_lspid);
p->msg_lrpid = pid_vnr(msq->q_lrpid);

ipc_unlock_object(&msq->q_perm);
rcu_read_unlock();
return id;
if (cmd == IPC_STAT) {
/*
* As defined in SUS:
* Return 0 on success
*/
err = 0;
} else {
/*
* MSG_STAT and MSG_STAT_ANY (both Linux specific)
* Return the full id, including the sequence number
*/
err = msq->q_perm.id;
}

ipc_unlock_object(&msq->q_perm);
out_unlock:
rcu_read_unlock();
return err;
Expand Down
18 changes: 13 additions & 5 deletions ipc/sem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,6 @@ static int semctl_stat(struct ipc_namespace *ns, int semid,
{
struct sem_array *sma;
time64_t semotime;
int id = 0;
int err;

memset(semid64, 0, sizeof(*semid64));
Expand All @@ -1235,7 +1234,6 @@ static int semctl_stat(struct ipc_namespace *ns, int semid,
err = PTR_ERR(sma);
goto out_unlock;
}
id = sma->sem_perm.id;
} else { /* IPC_STAT */
sma = sem_obtain_object_check(ns, semid);
if (IS_ERR(sma)) {
Expand Down Expand Up @@ -1275,10 +1273,20 @@ static int semctl_stat(struct ipc_namespace *ns, int semid,
#endif
semid64->sem_nsems = sma->sem_nsems;

if (cmd == IPC_STAT) {
/*
* As defined in SUS:
* Return 0 on success
*/
err = 0;
} else {
/*
* SEM_STAT and SEM_STAT_ANY (both Linux specific)
* Return the full id, including the sequence number
*/
err = sma->sem_perm.id;
}
ipc_unlock_object(&sma->sem_perm);
rcu_read_unlock();
return id;

out_unlock:
rcu_read_unlock();
return err;
Expand Down
19 changes: 14 additions & 5 deletions ipc/shm.c
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,6 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
int cmd, struct shmid64_ds *tbuf)
{
struct shmid_kernel *shp;
int id = 0;
int err;

memset(tbuf, 0, sizeof(*tbuf));
Expand All @@ -974,7 +973,6 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
err = PTR_ERR(shp);
goto out_unlock;
}
id = shp->shm_perm.id;
} else { /* IPC_STAT */
shp = shm_obtain_object_check(ns, shmid);
if (IS_ERR(shp)) {
Expand Down Expand Up @@ -1024,10 +1022,21 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
tbuf->shm_lpid = pid_vnr(shp->shm_lprid);
tbuf->shm_nattch = shp->shm_nattch;

ipc_unlock_object(&shp->shm_perm);
rcu_read_unlock();
return id;
if (cmd == IPC_STAT) {
/*
* As defined in SUS:
* Return 0 on success
*/
err = 0;
} else {
/*
* SHM_STAT and SHM_STAT_ANY (both Linux specific)
* Return the full id, including the sequence number
*/
err = shp->shm_perm.id;
}

ipc_unlock_object(&shp->shm_perm);
out_unlock:
rcu_read_unlock();
return err;
Expand Down

0 comments on commit 615c999

Please sign in to comment.