aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ipc/msg.c24
-rw-r--r--ipc/sem.c27
-rw-r--r--ipc/shm.c23
-rw-r--r--ipc/util.c21
4 files changed, 56 insertions, 39 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 7a3d6aab369d..f62fa5eed847 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -407,31 +407,38 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
407 return -EFAULT; 407 return -EFAULT;
408 } 408 }
409 409
410 down_write(&msg_ids(ns).rw_mutex);
411 rcu_read_lock();
412
410 ipcp = ipcctl_pre_down(ns, &msg_ids(ns), msqid, cmd, 413 ipcp = ipcctl_pre_down(ns, &msg_ids(ns), msqid, cmd,
411 &msqid64.msg_perm, msqid64.msg_qbytes); 414 &msqid64.msg_perm, msqid64.msg_qbytes);
412 if (IS_ERR(ipcp)) 415 if (IS_ERR(ipcp)) {
413 return PTR_ERR(ipcp); 416 err = PTR_ERR(ipcp);
417 /* the ipc lock is not held upon failure */
418 goto out_unlock1;
419 }
414 420
415 msq = container_of(ipcp, struct msg_queue, q_perm); 421 msq = container_of(ipcp, struct msg_queue, q_perm);
416 422
417 err = security_msg_queue_msgctl(msq, cmd); 423 err = security_msg_queue_msgctl(msq, cmd);
418 if (err) 424 if (err)
419 goto out_unlock; 425 goto out_unlock0;
420 426
421 switch (cmd) { 427 switch (cmd) {
422 case IPC_RMID: 428 case IPC_RMID:
429 /* freeque unlocks the ipc object and rcu */
423 freeque(ns, ipcp); 430 freeque(ns, ipcp);
424 goto out_up; 431 goto out_up;
425 case IPC_SET: 432 case IPC_SET:
426 if (msqid64.msg_qbytes > ns->msg_ctlmnb && 433 if (msqid64.msg_qbytes > ns->msg_ctlmnb &&
427 !capable(CAP_SYS_RESOURCE)) { 434 !capable(CAP_SYS_RESOURCE)) {
428 err = -EPERM; 435 err = -EPERM;
429 goto out_unlock; 436 goto out_unlock0;
430 } 437 }
431 438
432 err = ipc_update_perm(&msqid64.msg_perm, ipcp); 439 err = ipc_update_perm(&msqid64.msg_perm, ipcp);
433 if (err) 440 if (err)
434 goto out_unlock; 441 goto out_unlock0;
435 442
436 msq->q_qbytes = msqid64.msg_qbytes; 443 msq->q_qbytes = msqid64.msg_qbytes;
437 444
@@ -448,8 +455,11 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
448 default: 455 default:
449 err = -EINVAL; 456 err = -EINVAL;
450 } 457 }
451out_unlock: 458
452 msg_unlock(msq); 459out_unlock0:
460 ipc_unlock_object(&msq->q_perm);
461out_unlock1:
462 rcu_read_unlock();
453out_up: 463out_up:
454 up_write(&msg_ids(ns).rw_mutex); 464 up_write(&msg_ids(ns).rw_mutex);
455 return err; 465 return err;
diff --git a/ipc/sem.c b/ipc/sem.c
index 92ec6c69bab5..b4b892b5c5f8 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1289,39 +1289,44 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
1289 return -EFAULT; 1289 return -EFAULT;
1290 } 1290 }
1291 1291
1292 down_write(&sem_ids(ns).rw_mutex);
1293 rcu_read_lock();
1294
1292 ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd, 1295 ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd,
1293 &semid64.sem_perm, 0); 1296 &semid64.sem_perm, 0);
1294 if (IS_ERR(ipcp)) 1297 if (IS_ERR(ipcp)) {
1295 return PTR_ERR(ipcp); 1298 err = PTR_ERR(ipcp);
1299 /* the ipc lock is not held upon failure */
1300 goto out_unlock1;
1301 }
1296 1302
1297 sma = container_of(ipcp, struct sem_array, sem_perm); 1303 sma = container_of(ipcp, struct sem_array, sem_perm);
1298 1304
1299 err = security_sem_semctl(sma, cmd); 1305 err = security_sem_semctl(sma, cmd);
1300 if (err) { 1306 if (err)
1301 rcu_read_unlock(); 1307 goto out_unlock1;
1302 goto out_up;
1303 }
1304 1308
1305 switch(cmd){ 1309 switch (cmd) {
1306 case IPC_RMID: 1310 case IPC_RMID:
1307 sem_lock(sma, NULL, -1); 1311 sem_lock(sma, NULL, -1);
1312 /* freeary unlocks the ipc object and rcu */
1308 freeary(ns, ipcp); 1313 freeary(ns, ipcp);
1309 goto out_up; 1314 goto out_up;
1310 case IPC_SET: 1315 case IPC_SET:
1311 sem_lock(sma, NULL, -1); 1316 sem_lock(sma, NULL, -1);
1312 err = ipc_update_perm(&semid64.sem_perm, ipcp); 1317 err = ipc_update_perm(&semid64.sem_perm, ipcp);
1313 if (err) 1318 if (err)
1314 goto out_unlock; 1319 goto out_unlock0;
1315 sma->sem_ctime = get_seconds(); 1320 sma->sem_ctime = get_seconds();
1316 break; 1321 break;
1317 default: 1322 default:
1318 rcu_read_unlock();
1319 err = -EINVAL; 1323 err = -EINVAL;
1320 goto out_up; 1324 goto out_unlock1;
1321 } 1325 }
1322 1326
1323out_unlock: 1327out_unlock0:
1324 sem_unlock(sma, -1); 1328 sem_unlock(sma, -1);
1329out_unlock1:
1325 rcu_read_unlock(); 1330 rcu_read_unlock();
1326out_up: 1331out_up:
1327 up_write(&sem_ids(ns).rw_mutex); 1332 up_write(&sem_ids(ns).rw_mutex);
diff --git a/ipc/shm.c b/ipc/shm.c
index e7d51072d1c7..c6b4ad5ce3b7 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -757,31 +757,42 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
757 return -EFAULT; 757 return -EFAULT;
758 } 758 }
759 759
760 down_write(&shm_ids(ns).rw_mutex);
761 rcu_read_lock();
762
760 ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd, 763 ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd,
761 &shmid64.shm_perm, 0); 764 &shmid64.shm_perm, 0);
762 if (IS_ERR(ipcp)) 765 if (IS_ERR(ipcp)) {
763 return PTR_ERR(ipcp); 766 err = PTR_ERR(ipcp);
767 /* the ipc lock is not held upon failure */
768 goto out_unlock1;
769 }
764 770
765 shp = container_of(ipcp, struct shmid_kernel, shm_perm); 771 shp = container_of(ipcp, struct shmid_kernel, shm_perm);
766 772
767 err = security_shm_shmctl(shp, cmd); 773 err = security_shm_shmctl(shp, cmd);
768 if (err) 774 if (err)
769 goto out_unlock; 775 goto out_unlock0;
776
770 switch (cmd) { 777 switch (cmd) {
771 case IPC_RMID: 778 case IPC_RMID:
779 /* do_shm_rmid unlocks the ipc object and rcu */
772 do_shm_rmid(ns, ipcp); 780 do_shm_rmid(ns, ipcp);
773 goto out_up; 781 goto out_up;
774 case IPC_SET: 782 case IPC_SET:
775 err = ipc_update_perm(&shmid64.shm_perm, ipcp); 783 err = ipc_update_perm(&shmid64.shm_perm, ipcp);
776 if (err) 784 if (err)
777 goto out_unlock; 785 goto out_unlock0;
778 shp->shm_ctim = get_seconds(); 786 shp->shm_ctim = get_seconds();
779 break; 787 break;
780 default: 788 default:
781 err = -EINVAL; 789 err = -EINVAL;
782 } 790 }
783out_unlock: 791
784 shm_unlock(shp); 792out_unlock0:
793 ipc_unlock_object(&shp->shm_perm);
794out_unlock1:
795 rcu_read_unlock();
785out_up: 796out_up:
786 up_write(&shm_ids(ns).rw_mutex); 797 up_write(&shm_ids(ns).rw_mutex);
787 return err; 798 return err;
diff --git a/ipc/util.c b/ipc/util.c
index 399821ac0a9a..a0c139f3d1f3 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -746,8 +746,10 @@ int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
746 * It must be called without any lock held and 746 * It must be called without any lock held and
747 * - retrieves the ipc with the given id in the given table. 747 * - retrieves the ipc with the given id in the given table.
748 * - performs some audit and permission check, depending on the given cmd 748 * - performs some audit and permission check, depending on the given cmd
749 * - returns the ipc with both ipc and rw_mutex locks held in case of success 749 * - returns the ipc with the ipc lock held in case of success
750 * or an err-code without any lock held otherwise. 750 * or an err-code without any lock held otherwise.
751 *
752 * Call holding the both the rw_mutex and the rcu read lock.
751 */ 753 */
752struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns, 754struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
753 struct ipc_ids *ids, int id, int cmd, 755 struct ipc_ids *ids, int id, int cmd,
@@ -772,13 +774,10 @@ struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
772 int err = -EPERM; 774 int err = -EPERM;
773 struct kern_ipc_perm *ipcp; 775 struct kern_ipc_perm *ipcp;
774 776
775 down_write(&ids->rw_mutex);
776 rcu_read_lock();
777
778 ipcp = ipc_obtain_object_check(ids, id); 777 ipcp = ipc_obtain_object_check(ids, id);
779 if (IS_ERR(ipcp)) { 778 if (IS_ERR(ipcp)) {
780 err = PTR_ERR(ipcp); 779 err = PTR_ERR(ipcp);
781 goto out_up; 780 goto err;
782 } 781 }
783 782
784 audit_ipc_obj(ipcp); 783 audit_ipc_obj(ipcp);
@@ -789,16 +788,8 @@ struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
789 euid = current_euid(); 788 euid = current_euid();
790 if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid) || 789 if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid) ||
791 ns_capable(ns->user_ns, CAP_SYS_ADMIN)) 790 ns_capable(ns->user_ns, CAP_SYS_ADMIN))
792 return ipcp; 791 return ipcp; /* successful lookup */
793 792err:
794out_up:
795 /*
796 * Unsuccessful lookup, unlock and return
797 * the corresponding error.
798 */
799 rcu_read_unlock();
800 up_write(&ids->rw_mutex);
801
802 return ERR_PTR(err); 793 return ERR_PTR(err);
803} 794}
804 795