aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2018-03-23 02:11:29 -0400
committerEric W. Biederman <ebiederm@xmission.com>2018-03-27 16:53:55 -0400
commit51d6f2635b39709ee5e62479be23d423b760292c (patch)
treedab790cf23f3ab3ed923effcb1f7d4f6e5526702
parent39a4940eaa185910bb802ca9829c12268fd2c855 (diff)
ipc/sem: Fix semctl(..., GETPID, ...) between pid namespaces
Today the last process to update a semaphore is remembered and reported in the pid namespace of that process. If there are processes in any other pid namespace querying that process id with GETPID the result will be unusable nonsense as it does not make any sense in your own pid namespace. Due to ipc_update_pid I don't think you will be able to get System V ipc semaphores into a troublesome cache line ping-pong. Using struct pids from separate process are not a problem because they do not share a cache line. Using struct pid from different threads of the same process are unlikely to be a problem as the reference count update can be avoided. Further linux futexes are a much better tool for the job of mutual exclusion between processes than System V semaphores. So I expect programs that are performance limited by their interprocess mutual exclusion primitive will be using futexes. So while it is possible that enhancing the storage of the last rocess of a System V semaphore from an integer to a struct pid will cause a performance regression because of the effect of frequently updating the pid reference count. I don't expect that to happen in practice. This change updates semctl(..., GETPID, ...) to return the process id of the last process to update a semphore inthe pid namespace of the calling process. Fixes: b488893a390e ("pid namespaces: changes to show virtual ids to user") Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r--ipc/sem.c22
1 files changed, 12 insertions, 10 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index d661c491b0a5..47b263960524 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -98,7 +98,7 @@ struct sem {
98 * - semctl, via SETVAL and SETALL. 98 * - semctl, via SETVAL and SETALL.
99 * - at task exit when performing undo adjustments (see exit_sem). 99 * - at task exit when performing undo adjustments (see exit_sem).
100 */ 100 */
101 int sempid; 101 struct pid *sempid;
102 spinlock_t lock; /* spinlock for fine-grained semtimedop */ 102 spinlock_t lock; /* spinlock for fine-grained semtimedop */
103 struct list_head pending_alter; /* pending single-sop operations */ 103 struct list_head pending_alter; /* pending single-sop operations */
104 /* that alter the semaphore */ 104 /* that alter the semaphore */
@@ -128,7 +128,7 @@ struct sem_queue {
128 struct list_head list; /* queue of pending operations */ 128 struct list_head list; /* queue of pending operations */
129 struct task_struct *sleeper; /* this process */ 129 struct task_struct *sleeper; /* this process */
130 struct sem_undo *undo; /* undo structure */ 130 struct sem_undo *undo; /* undo structure */
131 int pid; /* process id of requesting process */ 131 struct pid *pid; /* process id of requesting process */
132 int status; /* completion status of operation */ 132 int status; /* completion status of operation */
133 struct sembuf *sops; /* array of pending operations */ 133 struct sembuf *sops; /* array of pending operations */
134 struct sembuf *blocking; /* the operation that blocked */ 134 struct sembuf *blocking; /* the operation that blocked */
@@ -628,7 +628,8 @@ SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg)
628 */ 628 */
629static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q) 629static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q)
630{ 630{
631 int result, sem_op, nsops, pid; 631 int result, sem_op, nsops;
632 struct pid *pid;
632 struct sembuf *sop; 633 struct sembuf *sop;
633 struct sem *curr; 634 struct sem *curr;
634 struct sembuf *sops; 635 struct sembuf *sops;
@@ -666,7 +667,7 @@ static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q)
666 sop--; 667 sop--;
667 pid = q->pid; 668 pid = q->pid;
668 while (sop >= sops) { 669 while (sop >= sops) {
669 sma->sems[sop->sem_num].sempid = pid; 670 ipc_update_pid(&sma->sems[sop->sem_num].sempid, pid);
670 sop--; 671 sop--;
671 } 672 }
672 673
@@ -753,7 +754,7 @@ static int perform_atomic_semop(struct sem_array *sma, struct sem_queue *q)
753 un->semadj[sop->sem_num] = undo; 754 un->semadj[sop->sem_num] = undo;
754 } 755 }
755 curr->semval += sem_op; 756 curr->semval += sem_op;
756 curr->sempid = q->pid; 757 ipc_update_pid(&curr->sempid, q->pid);
757 } 758 }
758 759
759 return 0; 760 return 0;
@@ -1160,6 +1161,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
1160 unlink_queue(sma, q); 1161 unlink_queue(sma, q);
1161 wake_up_sem_queue_prepare(q, -EIDRM, &wake_q); 1162 wake_up_sem_queue_prepare(q, -EIDRM, &wake_q);
1162 } 1163 }
1164 ipc_update_pid(&sem->sempid, NULL);
1163 } 1165 }
1164 1166
1165 /* Remove the semaphore set from the IDR */ 1167 /* Remove the semaphore set from the IDR */
@@ -1352,7 +1354,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
1352 un->semadj[semnum] = 0; 1354 un->semadj[semnum] = 0;
1353 1355
1354 curr->semval = val; 1356 curr->semval = val;
1355 curr->sempid = task_tgid_vnr(current); 1357 ipc_update_pid(&curr->sempid, task_tgid(current));
1356 sma->sem_ctime = ktime_get_real_seconds(); 1358 sma->sem_ctime = ktime_get_real_seconds();
1357 /* maybe some queued-up processes were waiting for this */ 1359 /* maybe some queued-up processes were waiting for this */
1358 do_smart_update(sma, NULL, 0, 0, &wake_q); 1360 do_smart_update(sma, NULL, 0, 0, &wake_q);
@@ -1473,7 +1475,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
1473 1475
1474 for (i = 0; i < nsems; i++) { 1476 for (i = 0; i < nsems; i++) {
1475 sma->sems[i].semval = sem_io[i]; 1477 sma->sems[i].semval = sem_io[i];
1476 sma->sems[i].sempid = task_tgid_vnr(current); 1478 ipc_update_pid(&sma->sems[i].sempid, task_tgid(current));
1477 } 1479 }
1478 1480
1479 ipc_assert_locked_object(&sma->sem_perm); 1481 ipc_assert_locked_object(&sma->sem_perm);
@@ -1505,7 +1507,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
1505 err = curr->semval; 1507 err = curr->semval;
1506 goto out_unlock; 1508 goto out_unlock;
1507 case GETPID: 1509 case GETPID:
1508 err = curr->sempid; 1510 err = pid_vnr(curr->sempid);
1509 goto out_unlock; 1511 goto out_unlock;
1510 case GETNCNT: 1512 case GETNCNT:
1511 err = count_semcnt(sma, semnum, 0); 1513 err = count_semcnt(sma, semnum, 0);
@@ -2024,7 +2026,7 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops,
2024 queue.sops = sops; 2026 queue.sops = sops;
2025 queue.nsops = nsops; 2027 queue.nsops = nsops;
2026 queue.undo = un; 2028 queue.undo = un;
2027 queue.pid = task_tgid_vnr(current); 2029 queue.pid = task_tgid(current);
2028 queue.alter = alter; 2030 queue.alter = alter;
2029 queue.dupsop = dupsop; 2031 queue.dupsop = dupsop;
2030 2032
@@ -2318,7 +2320,7 @@ void exit_sem(struct task_struct *tsk)
2318 semaphore->semval = 0; 2320 semaphore->semval = 0;
2319 if (semaphore->semval > SEMVMX) 2321 if (semaphore->semval > SEMVMX)
2320 semaphore->semval = SEMVMX; 2322 semaphore->semval = SEMVMX;
2321 semaphore->sempid = task_tgid_vnr(current); 2323 ipc_update_pid(&semaphore->sempid, task_tgid(current));
2322 } 2324 }
2323 } 2325 }
2324 /* maybe some queued-up processes were waiting for this */ 2326 /* maybe some queued-up processes were waiting for this */