Skip to content

Commit 87ad4b0

Browse files
Philippe Mikoyantorvalds
Philippe Mikoyan
authored andcommitted
ipc: fix ipc data structures inconsistency
As described in the title, this patch fixes <ipc>id_ds inconsistency when <ipc>ctl_stat executes concurrently with some ds-changing function, e.g. shmat, msgsnd or whatever. For instance, if shmctl(IPC_STAT) is running concurrently with shmat, following data structure can be returned: {... shm_lpid = 0, shm_nattch = 1, ...} Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Philippe Mikoyan <[email protected]> Reviewed-by: Davidlohr Bueso <[email protected]> Cc: Al Viro <[email protected]> Cc: Manfred Spraul <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent bac7a1f commit 87ad4b0

File tree

4 files changed

+43
-12
lines changed

4 files changed

+43
-12
lines changed

ipc/msg.c

+14-6
Original file line numberDiff line numberDiff line change
@@ -476,9 +476,9 @@ static int msgctl_info(struct ipc_namespace *ns, int msqid,
476476
static int msgctl_stat(struct ipc_namespace *ns, int msqid,
477477
int cmd, struct msqid64_ds *p)
478478
{
479-
int err;
480479
struct msg_queue *msq;
481-
int success_return;
480+
int id = 0;
481+
int err;
482482

483483
memset(p, 0, sizeof(*p));
484484

@@ -489,14 +489,13 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
489489
err = PTR_ERR(msq);
490490
goto out_unlock;
491491
}
492-
success_return = msq->q_perm.id;
492+
id = msq->q_perm.id;
493493
} else {
494494
msq = msq_obtain_object_check(ns, msqid);
495495
if (IS_ERR(msq)) {
496496
err = PTR_ERR(msq);
497497
goto out_unlock;
498498
}
499-
success_return = 0;
500499
}
501500

502501
err = -EACCES;
@@ -507,6 +506,14 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
507506
if (err)
508507
goto out_unlock;
509508

509+
ipc_lock_object(&msq->q_perm);
510+
511+
if (!ipc_valid_object(&msq->q_perm)) {
512+
ipc_unlock_object(&msq->q_perm);
513+
err = -EIDRM;
514+
goto out_unlock;
515+
}
516+
510517
kernel_to_ipc64_perm(&msq->q_perm, &p->msg_perm);
511518
p->msg_stime = msq->q_stime;
512519
p->msg_rtime = msq->q_rtime;
@@ -516,9 +523,10 @@ static int msgctl_stat(struct ipc_namespace *ns, int msqid,
516523
p->msg_qbytes = msq->q_qbytes;
517524
p->msg_lspid = msq->q_lspid;
518525
p->msg_lrpid = msq->q_lrpid;
519-
rcu_read_unlock();
520526

521-
return success_return;
527+
ipc_unlock_object(&msq->q_perm);
528+
rcu_read_unlock();
529+
return id;
522530

523531
out_unlock:
524532
rcu_read_unlock();

ipc/sem.c

+10
Original file line numberDiff line numberDiff line change
@@ -1213,10 +1213,20 @@ static int semctl_stat(struct ipc_namespace *ns, int semid,
12131213
if (err)
12141214
goto out_unlock;
12151215

1216+
ipc_lock_object(&sma->sem_perm);
1217+
1218+
if (!ipc_valid_object(&sma->sem_perm)) {
1219+
ipc_unlock_object(&sma->sem_perm);
1220+
err = -EIDRM;
1221+
goto out_unlock;
1222+
}
1223+
12161224
kernel_to_ipc64_perm(&sma->sem_perm, &semid64->sem_perm);
12171225
semid64->sem_otime = get_semotime(sma);
12181226
semid64->sem_ctime = sma->sem_ctime;
12191227
semid64->sem_nsems = sma->sem_nsems;
1228+
1229+
ipc_unlock_object(&sma->sem_perm);
12201230
rcu_read_unlock();
12211231
return id;
12221232

ipc/shm.c

+15-5
Original file line numberDiff line numberDiff line change
@@ -909,24 +909,25 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
909909
int cmd, struct shmid64_ds *tbuf)
910910
{
911911
struct shmid_kernel *shp;
912-
int result;
912+
int id = 0;
913913
int err;
914914

915+
memset(tbuf, 0, sizeof(*tbuf));
916+
915917
rcu_read_lock();
916918
if (cmd == SHM_STAT) {
917919
shp = shm_obtain_object(ns, shmid);
918920
if (IS_ERR(shp)) {
919921
err = PTR_ERR(shp);
920922
goto out_unlock;
921923
}
922-
result = shp->shm_perm.id;
924+
id = shp->shm_perm.id;
923925
} else {
924926
shp = shm_obtain_object_check(ns, shmid);
925927
if (IS_ERR(shp)) {
926928
err = PTR_ERR(shp);
927929
goto out_unlock;
928930
}
929-
result = 0;
930931
}
931932

932933
err = -EACCES;
@@ -937,7 +938,14 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
937938
if (err)
938939
goto out_unlock;
939940

940-
memset(tbuf, 0, sizeof(*tbuf));
941+
ipc_lock_object(&shp->shm_perm);
942+
943+
if (!ipc_valid_object(&shp->shm_perm)) {
944+
ipc_unlock_object(&shp->shm_perm);
945+
err = -EIDRM;
946+
goto out_unlock;
947+
}
948+
941949
kernel_to_ipc64_perm(&shp->shm_perm, &tbuf->shm_perm);
942950
tbuf->shm_segsz = shp->shm_segsz;
943951
tbuf->shm_atime = shp->shm_atim;
@@ -946,8 +954,10 @@ static int shmctl_stat(struct ipc_namespace *ns, int shmid,
946954
tbuf->shm_cpid = shp->shm_cprid;
947955
tbuf->shm_lpid = shp->shm_lprid;
948956
tbuf->shm_nattch = shp->shm_nattch;
957+
958+
ipc_unlock_object(&shp->shm_perm);
949959
rcu_read_unlock();
950-
return result;
960+
return id;
951961

952962
out_unlock:
953963
rcu_read_unlock();

ipc/util.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,12 @@
2323
* tree.
2424
* - perform initial checks (capabilities, auditing and permission,
2525
* etc).
26-
* - perform read-only operations, such as STAT, INFO commands.
26+
* - perform read-only operations, such as INFO command, that
27+
* do not demand atomicity
2728
* acquire the ipc lock (kern_ipc_perm.lock) through
2829
* ipc_lock_object()
30+
* - perform read-only operations that demand atomicity,
31+
* such as STAT command.
2932
* - perform data updates, such as SET, RMID commands and
3033
* mechanism-specific operations (semop/semtimedop,
3134
* msgsnd/msgrcv, shmat/shmdt).

0 commit comments

Comments
 (0)