Skip to content

Commit 51d6f26

Browse files
committed
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: b488893 ("pid namespaces: changes to show virtual ids to user") Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent 39a4940 commit 51d6f26

File tree

1 file changed

+12
-10
lines changed

1 file changed

+12
-10
lines changed

ipc/sem.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ struct sem {
9898
* - semctl, via SETVAL and SETALL.
9999
* - at task exit when performing undo adjustments (see exit_sem).
100100
*/
101-
int sempid;
101+
struct pid *sempid;
102102
spinlock_t lock; /* spinlock for fine-grained semtimedop */
103103
struct list_head pending_alter; /* pending single-sop operations */
104104
/* that alter the semaphore */
@@ -128,7 +128,7 @@ struct sem_queue {
128128
struct list_head list; /* queue of pending operations */
129129
struct task_struct *sleeper; /* this process */
130130
struct sem_undo *undo; /* undo structure */
131-
int pid; /* process id of requesting process */
131+
struct pid *pid; /* process id of requesting process */
132132
int status; /* completion status of operation */
133133
struct sembuf *sops; /* array of pending operations */
134134
struct sembuf *blocking; /* the operation that blocked */
@@ -628,7 +628,8 @@ SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg)
628628
*/
629629
static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q)
630630
{
631-
int result, sem_op, nsops, pid;
631+
int result, sem_op, nsops;
632+
struct pid *pid;
632633
struct sembuf *sop;
633634
struct sem *curr;
634635
struct sembuf *sops;
@@ -666,7 +667,7 @@ static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q)
666667
sop--;
667668
pid = q->pid;
668669
while (sop >= sops) {
669-
sma->sems[sop->sem_num].sempid = pid;
670+
ipc_update_pid(&sma->sems[sop->sem_num].sempid, pid);
670671
sop--;
671672
}
672673

@@ -753,7 +754,7 @@ static int perform_atomic_semop(struct sem_array *sma, struct sem_queue *q)
753754
un->semadj[sop->sem_num] = undo;
754755
}
755756
curr->semval += sem_op;
756-
curr->sempid = q->pid;
757+
ipc_update_pid(&curr->sempid, q->pid);
757758
}
758759

759760
return 0;
@@ -1160,6 +1161,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
11601161
unlink_queue(sma, q);
11611162
wake_up_sem_queue_prepare(q, -EIDRM, &wake_q);
11621163
}
1164+
ipc_update_pid(&sem->sempid, NULL);
11631165
}
11641166

11651167
/* Remove the semaphore set from the IDR */
@@ -1352,7 +1354,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
13521354
un->semadj[semnum] = 0;
13531355

13541356
curr->semval = val;
1355-
curr->sempid = task_tgid_vnr(current);
1357+
ipc_update_pid(&curr->sempid, task_tgid(current));
13561358
sma->sem_ctime = ktime_get_real_seconds();
13571359
/* maybe some queued-up processes were waiting for this */
13581360
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,
14731475

14741476
for (i = 0; i < nsems; i++) {
14751477
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));
14771479
}
14781480

14791481
ipc_assert_locked_object(&sma->sem_perm);
@@ -1505,7 +1507,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
15051507
err = curr->semval;
15061508
goto out_unlock;
15071509
case GETPID:
1508-
err = curr->sempid;
1510+
err = pid_vnr(curr->sempid);
15091511
goto out_unlock;
15101512
case GETNCNT:
15111513
err = count_semcnt(sma, semnum, 0);
@@ -2024,7 +2026,7 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops,
20242026
queue.sops = sops;
20252027
queue.nsops = nsops;
20262028
queue.undo = un;
2027-
queue.pid = task_tgid_vnr(current);
2029+
queue.pid = task_tgid(current);
20282030
queue.alter = alter;
20292031
queue.dupsop = dupsop;
20302032

@@ -2318,7 +2320,7 @@ void exit_sem(struct task_struct *tsk)
23182320
semaphore->semval = 0;
23192321
if (semaphore->semval > SEMVMX)
23202322
semaphore->semval = SEMVMX;
2321-
semaphore->sempid = task_tgid_vnr(current);
2323+
ipc_update_pid(&semaphore->sempid, task_tgid(current));
23222324
}
23232325
}
23242326
/* maybe some queued-up processes were waiting for this */

0 commit comments

Comments
 (0)