master
c 1,420 lines 42.6 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 sem.c
8
9 Abstract:
10
11 This file is a test for the system V semaphore family of system calls.
12
13 --*/
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <sys/eventfd.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/xattr.h>
23 #include <sys/mman.h>
24 #include <fcntl.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/ipc.h>
28 #include <sys/shm.h>
29 #include <sys/sem.h>
30 #include <sys/prctl.h>
31 #include <sys/wait.h>
32 #include <grp.h>
33 #include <netinet/in.h>
34 #include <netdb.h>
35 #include <time.h>
36 #include <linux/random.h>
37
38 #if !defined(__amd64__) && !defined(__aarch64__)
39
40 #include <sys/capability.h>
41
42 #else
43
44 #include <sys/cdefs.h>
45 #include <linux/capability.h>
46
47 #define _LINUX_CAPABILITY_VERSION_3 0x20080522
48
49 #ifndef O_PATH
50 #define O_PATH 010000000
51 #endif
52
53 #endif
54
55 #include "lxtcommon.h"
56 #include "unittests.h"
57
58 #define LXT_NAME "sem"
59
60 #define SEM_ACCESS_UID 1004
61 #define SEM_ACCESS_GID 1004
62 #define SEM_COUNT (10)
63
64 //
65 // Globals.
66 //
67
68 bool g_VerboseSem = true;
69
70 int SemCtlSyscall(PLXT_ARGS Args);
71
72 int SemGetSyscall(PLXT_ARGS Args);
73
74 int SemOpFlags(PLXT_ARGS Args);
75
76 int SemOpSyscall(PLXT_ARGS Args);
77
78 void SemPrintInfo(struct semid_ds* Stat);
79
80 static const LXT_VARIATION g_LxtVariations[] = {
81 {"semget syscall", SemGetSyscall}, {"semctl syscall", SemCtlSyscall}, {"semop syscall", SemOpSyscall}, {"semop flags", SemOpFlags}};
82
83 int SemTestEntry(int Argc, char* Argv[])
84 {
85
86 LXT_ARGS Args;
87 int Result;
88
89 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
90 LXT_SYNCHRONIZATION_POINT_INIT();
91 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
92
93 ErrorExit:
94 LxtUninitialize();
95 return 0;
96 }
97
98 int SemCtlSyscall(PLXT_ARGS Args)
99
100 {
101
102 struct __user_cap_data_struct CapData[2];
103 struct __user_cap_header_struct CapHeader;
104 int ChildPid;
105 gid_t Gid;
106 int Id;
107 int Index;
108 struct semid_ds OldStat;
109 int Result;
110 struct seminfo SemInfo;
111 struct semid_ds Stat;
112 uid_t Uid;
113 unsigned short Values[SEM_COUNT];
114
115 ChildPid = -1;
116 Uid = getuid();
117 Gid = getgid();
118 LxtCheckErrno(Id = LxtSemGet(IPC_PRIVATE, SEM_COUNT, (IPC_CREAT | IPC_EXCL)));
119 LxtCheckErrno(LxtSemCtl(Id, 0, SEM_STAT, &Stat));
120 LxtCheckEqual(SEM_COUNT, Stat.sem_nsems, "%Iu");
121 LxtCheckEqual(Uid, Stat.sem_perm.uid, "%d");
122 LxtCheckEqual(Gid, Stat.sem_perm.gid, "%d");
123 LxtCheckEqual(Uid, Stat.sem_perm.cuid, "%d");
124 LxtCheckEqual(Gid, Stat.sem_perm.cgid, "%d");
125 LxtCheckNotEqual(0, Stat.sem_ctime, "%Iu");
126 LxtCheckEqual(0, Stat.sem_otime, "%Iu");
127
128 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_STAT, &Stat));
129 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_SET, &Stat));
130 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_INFO, &SemInfo));
131 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_INFO, &SemInfo));
132 LxtCheckErrno(LxtSemCtl(0, 0, IPC_INFO, &SemInfo));
133 LxtCheckErrno(LxtSemCtl(1, 0, IPC_INFO, &SemInfo));
134 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETPID, NULL), "%d");
135 LxtCheckErrnoFailure(LxtSemCtl(Id, SEM_COUNT, GETPID, NULL), EINVAL);
136 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
137 LxtCheckErrnoFailure(LxtSemCtl(Id, SEM_COUNT, GETVAL, NULL), EINVAL);
138 memset(&Values, 0, sizeof(Values));
139 LxtCheckErrno(LxtSemCtl(Id, 0, GETALL, &Values));
140 for (Index = 0; Index < SEM_COUNT; Index += 1)
141 {
142 LxtCheckEqual(Values[Index], LxtSemCtl(Id, Index, GETVAL, NULL), "%d");
143 }
144
145 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETNCNT, NULL), "%d");
146 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETZCNT, NULL), "%d");
147
148 //
149 // Check GETPID and GETVAL again after doing a setval on a single semaphore.
150 //
151
152 Values[0] = 1;
153 LxtCheckErrno(LxtSemCtl(Id, 0, SETVAL, Values[0]));
154 LxtCheckErrnoFailure(LxtSemCtl(Id, SEM_COUNT, SETVAL, Values[0]), EINVAL);
155 LxtCheckEqual(getpid(), LxtSemCtl(Id, 0, GETPID, NULL), "%d");
156 LxtCheckEqual(Values[0], LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
157 LxtCheckErrno(LxtSemCtl(Id, 0, GETALL, &Values));
158 for (Index = 0; Index < SEM_COUNT; Index += 1)
159 {
160 LxtCheckEqual(Values[Index], LxtSemCtl(Id, Index, GETVAL, NULL), "%d");
161 }
162
163 //
164 // Verify the pid and value of the other semaphores has not changed.
165 //
166
167 for (Index = 1; Index < SEM_COUNT; Index += 1)
168 {
169 LxtCheckEqual(0, LxtSemCtl(Id, Index, GETPID, NULL), "%d");
170 LxtCheckEqual(0, LxtSemCtl(Id, Index, GETVAL, NULL), "%d");
171 }
172
173 //
174 // SETALL command.
175 //
176
177 for (Index = 0; Index < SEM_COUNT; Index += 1)
178 {
179 Values[0] = Index;
180 }
181
182 //
183 // Ensure that each semaphore's value has been updated. Interestingly the
184 // last pid value is not updated by the SETALL command.
185 //
186
187 LxtCheckErrno(LxtSemCtl(Id, 0, SETALL, &Values));
188 for (Index = 0; Index < SEM_COUNT; Index += 1)
189 {
190 if (Index == 0)
191 {
192 LxtCheckEqual(getpid(), LxtSemCtl(Id, Index, GETPID, NULL), "%d");
193 }
194 else
195 {
196 LxtCheckEqual(0, LxtSemCtl(Id, Index, GETPID, NULL), "%d");
197 }
198
199 LxtCheckEqual(Values[Index], LxtSemCtl(Id, Index, GETVAL, NULL), "%d");
200 }
201
202 memset(Values, 0, sizeof(Values));
203 Values[1] = -1;
204 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, SETALL, &Values), ERANGE);
205
206 //
207 // Create a child without the CAP_IPC_OWNER capability.
208 //
209
210 LxtCheckErrno(ChildPid = fork());
211 if (ChildPid == 0)
212 {
213
214 //
215 // Drop the CAP_IPC_OWNER capability.
216 //
217
218 memset(&CapHeader, 0, sizeof(CapHeader));
219 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
220 LxtCheckErrno(LxtCapGet(&CapHeader, CapData)) LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
221 CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted &= ~CAP_TO_MASK(CAP_IPC_OWNER);
222 CapData[0].effective = CapData[0].permitted;
223 CapData[1].effective = CapData[1].permitted;
224 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
225
226 //
227 // Verify commands that requires the IPC_OWNER capability now fail.
228 //
229
230 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, SEM_STAT, &Stat), EACCES);
231 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, IPC_STAT, &Stat), EACCES);
232
233 //
234 // Change the UID and verify commands fail.
235 //
236
237 LxtCheckErrno(setuid(SEM_ACCESS_UID));
238 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, IPC_SET, &Stat), EPERM);
239 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, IPC_RMID, NULL), EPERM);
240
241 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, IPC_STAT, &Stat), EACCES);
242 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, SEM_STAT, &Stat), EACCES);
243
244 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_INFO, &SemInfo));
245 LxtCheckErrno(LxtSemCtl(0, 0, IPC_INFO, &SemInfo));
246 Result = LXT_RESULT_SUCCESS;
247 goto ErrorExit;
248 }
249
250 //
251 // Wait for the child to exit.
252 //
253
254 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
255
256 //
257 // Invalid parameter variations.
258 //
259
260 //
261 // Ensure IPC_SET cannot set invalid mode bits (they are silently ignored).
262 //
263
264 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_STAT, &Stat));
265 Stat.sem_perm.mode = -1;
266 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_SET, &Stat));
267 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_STAT, &Stat));
268 LxtCheckEqual(Stat.sem_perm.mode, 0777, "%o");
269
270 //
271 // Ensure the uid and gid cannot be set to -1.
272 //
273
274 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_STAT, &OldStat));
275 Stat = OldStat;
276 Stat.sem_perm.uid = -1;
277 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, IPC_SET, &Stat), EINVAL);
278 Stat = OldStat;
279 Stat.sem_perm.gid = -1;
280 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, IPC_SET, &Stat), EINVAL);
281 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_STAT, &Stat));
282 LxtCheckEqual(Stat.sem_perm.uid, OldStat.sem_perm.uid, "%d");
283 LxtCheckEqual(Stat.sem_perm.gid, OldStat.sem_perm.gid, "%d");
284
285 LxtCheckErrnoFailure(LxtSemCtl(Id, -1, GETPID, NULL), EINVAL);
286 LxtCheckErrnoFailure(LxtSemCtl(Id, SEM_COUNT, GETPID, NULL), EINVAL);
287 LxtCheckErrnoFailure(LxtSemCtl(Id, -1, GETVAL, NULL), EINVAL);
288 LxtCheckErrnoFailure(LxtSemCtl(Id, SEM_COUNT, GETVAL, NULL), EINVAL);
289 LxtCheckErrnoFailure(LxtSemCtl(Id, -1, SETVAL, 0), EINVAL);
290 LxtCheckErrnoFailure(LxtSemCtl(Id, SEM_COUNT, SETVAL, 0), EINVAL);
291 LxtCheckErrnoFailure(LxtSemCtl(Id, -1, GETNCNT, NULL), EINVAL);
292 LxtCheckErrnoFailure(LxtSemCtl(Id, SEM_COUNT, GETNCNT, NULL), EINVAL);
293 LxtCheckErrnoFailure(LxtSemCtl(Id, -1, GETZCNT, NULL), EINVAL);
294 LxtCheckErrnoFailure(LxtSemCtl(Id, SEM_COUNT, GETZCNT, NULL), EINVAL);
295
296 LxtCheckErrnoFailure(LxtSemCtl(-1, 0, SEM_STAT, &Stat), EINVAL);
297 LxtCheckErrnoFailure(LxtSemCtl(-1, 0, IPC_STAT, &Stat), EINVAL);
298 LxtCheckErrnoFailure(LxtSemCtl(-1, 0, IPC_SET, &Stat), EINVAL);
299 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, IPC_INFO, NULL), EFAULT);
300 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, IPC_INFO, -1), EFAULT);
301 LxtCheckErrnoFailure(LxtSemCtl(0, 0, IPC_INFO, NULL), EFAULT);
302 LxtCheckErrnoFailure(LxtSemCtl(0, 0, IPC_INFO, -1), EFAULT);
303 LxtCheckErrnoFailure(LxtSemCtl(-1, 0, GETPID, NULL), EINVAL);
304 LxtCheckErrnoFailure(LxtSemCtl(Id, SEM_COUNT, GETPID, NULL), EINVAL);
305 LxtCheckErrnoFailure(LxtSemCtl(-1, 0, GETVAL, NULL), EINVAL);
306 LxtCheckErrnoFailure(LxtSemCtl(Id, SEM_COUNT, GETVAL, NULL), EINVAL);
307 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, GETALL, NULL), EFAULT);
308 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, GETALL, -1), EFAULT);
309 LxtCheckErrnoFailure(LxtSemCtl(-1, 0, GETNCNT, NULL), EINVAL);
310 LxtCheckErrnoFailure(LxtSemCtl(-1, 0, GETZCNT, NULL), EINVAL);
311 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, SETALL, NULL), EFAULT);
312 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, SETALL, -1), EFAULT);
313
314 ErrorExit:
315 if (ChildPid == 0)
316 {
317 _exit(Result);
318 }
319
320 if (Id != -1)
321 {
322 LxtSemCtl(Id, 0, IPC_RMID, NULL);
323 }
324
325 return Result;
326 }
327
328 int SemGetSyscall(PLXT_ARGS Args)
329
330 {
331
332 struct __user_cap_data_struct CapData[2];
333 struct __user_cap_header_struct CapHeader;
334 int ChildPid;
335 int Id;
336 key_t Key;
337 int Mode;
338 size_t Result;
339 struct semid_ds Stat;
340 time_t Time;
341
342 ChildPid = -1;
343 Id = -1;
344
345 //
346 // Create a key, verify that creating the key with the IPC_EXCL flag fails.
347 //
348
349 Mode = 0000;
350 LxtLogInfo("Mode %o", Mode);
351 LxtCheckErrno(LxtGetrandom(&Key, sizeof(Key), 0));
352 LxtLogInfo("Key = %u", Key);
353 LxtCheckErrno(Id = LxtSemGet(Key, SEM_COUNT, (IPC_CREAT | IPC_EXCL | Mode)));
354 LxtLogInfo("Id = %d", Id);
355 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_STAT, &Stat));
356 SemPrintInfo(&Stat);
357 LxtCheckEqual(Key, Stat.sem_perm.__key, "%Iu");
358 LxtCheckEqual(SEM_COUNT, Stat.sem_nsems, "%Iu");
359 LxtCheckEqual(0, Stat.sem_otime, "%Iu");
360 LxtCheckNotEqual(0, Stat.sem_ctime, "%Iu");
361 LxtCheckEqual(Mode, Stat.sem_perm.mode, "%o");
362 LxtCheckEqual(getuid(), Stat.sem_perm.cuid, "%d");
363 LxtCheckEqual(getuid(), Stat.sem_perm.uid, "%d");
364 LxtCheckEqual(getgid(), Stat.sem_perm.cgid, "%d");
365 LxtCheckEqual(getgid(), Stat.sem_perm.gid, "%d");
366
367 //
368 // semget with IPC_CREAT or IPC_EXCL when the region already exists.
369 //
370
371 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, IPC_CREAT), "%Iu");
372 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, IPC_EXCL), "%Iu");
373 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, 0), "%Iu");
374
375 //
376 // semget with count = 0 should succeed.
377 //
378
379 LxtCheckEqual(Id, LxtSemGet(Key, 0, 0), "%Iu");
380
381 //
382 // Create a child with a different uid and gid that does not have the
383 // IPC_OWNER capability.
384 //
385
386 LxtCheckErrno(ChildPid = fork());
387 if (ChildPid == 0)
388 {
389 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
390 LxtCheckErrno(setgid(SEM_ACCESS_GID));
391 LxtCheckErrno(setuid(SEM_ACCESS_UID));
392 memset(&CapData, 0, sizeof(CapData));
393 memset(&CapHeader, 0, sizeof(CapHeader));
394 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
395 CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
396 CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
397 CapData[0].effective = CapData[0].permitted;
398 CapData[1].effective = CapData[1].permitted;
399 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
400
401 //
402 // These should succeed because the child still has the IPC_OWNER cap.
403 //
404
405 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, IPC_CREAT), "%Iu");
406 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, IPC_EXCL), "%Iu");
407 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, 0777), "%Iu");
408 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, 0666), "%Iu");
409 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, 0600), "%Iu");
410 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, 0060), "%Iu");
411 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, 0006), "%Iu");
412 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, 0), "%Iu");
413
414 //
415 // Drop all group membership and the CAP_IPC_OWNER capability and
416 // attempt to call semget with unmatching mode bits.
417 //
418
419 LxtCheckErrno(Result = setgroups(0, NULL));
420 memset(&CapData, 0, sizeof(CapData));
421 memset(&CapHeader, 0, sizeof(CapHeader));
422 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
423 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
424 LxtCheckErrnoFailure(LxtSemGet(Key, SEM_COUNT, 0777), EACCES);
425 LxtCheckErrnoFailure(LxtSemGet(Key, SEM_COUNT, 0666), EACCES);
426 LxtCheckErrnoFailure(LxtSemGet(Key, SEM_COUNT, 0600), EACCES);
427 LxtCheckErrnoFailure(LxtSemGet(Key, SEM_COUNT, 0060), EACCES);
428 LxtCheckErrnoFailure(LxtSemGet(Key, SEM_COUNT, 0006), EACCES);
429
430 //
431 // Use the same permission as before, these should succeed.
432 //
433
434 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, IPC_CREAT), "%Iu");
435 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, IPC_EXCL), "%Iu");
436 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, 0), "%Iu");
437 goto ErrorExit;
438 }
439
440 //
441 // Wait for the child to exit.
442 //
443
444 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
445
446 //
447 // Invalid parameter variations.
448 //
449
450 //
451 // semget with IPC_CREAT | IPC_EXCL when the region already exists, should
452 // succeed with only IPC_EXCL.
453 //
454
455 LxtCheckErrnoFailure(LxtSemGet(Key, SEM_COUNT, (IPC_CREAT | IPC_EXCL)), EEXIST);
456
457 //
458 // semget with a known key and a size that does not match.
459 //
460
461 LxtCheckErrnoFailure(LxtSemGet(Key, (SEM_COUNT * 2), 0), EINVAL);
462 LxtCheckErrnoFailure(LxtSemGet(Key, SEM_COUNT + 1, 0), EINVAL);
463
464 //
465 // N.B. There appears to be no error checking for invalid flags, only the
466 // presence of valid flags.
467 //
468 // -1 includes the IPC_EXCL flag so this should return EEXIST.
469 //
470
471 LxtCheckErrnoFailure(LxtSemGet(Key, SEM_COUNT, -1), EEXIST);
472 LxtCheckEqual(Id, LxtSemGet(Key, SEM_COUNT, (-1 & ~IPC_EXCL)), "%Iu");
473
474 //
475 // Delete the region and create a new one with a size of one byte.
476 //
477
478 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_RMID, &Stat));
479 LxtCheckErrnoFailure(LxtSemCtl(Id, 0, IPC_RMID, NULL), EINVAL);
480 Id = -1;
481 LxtCheckErrno(Id = LxtSemGet(IPC_PRIVATE, 1, 0));
482 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_STAT, &Stat));
483 LxtCheckEqual(1, Stat.sem_nsems, "%Iu");
484
485 //
486 // Delete the region and create a new region with a size of zero bytes
487 // (should fail).
488 //
489
490 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_RMID, &Stat));
491 Id = -1;
492 LxtCheckErrnoFailure(Id = LxtSemGet(IPC_PRIVATE, 0, 0), EINVAL);
493
494 ErrorExit:
495 if (ChildPid == 0)
496 {
497 _exit(Result);
498 }
499
500 if (Id != -1)
501 {
502 LxtSemCtl(Id, 0, IPC_RMID, NULL);
503 }
504
505 return Result;
506 }
507
508 int SemCloneChild(void* Param)
509 {
510
511 int Id;
512 int Result;
513
514 Id = *((int*)Param);
515 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
516 LxtCheckEqual(0, LxtSemCtl(Id, 1, GETVAL, NULL), "%d");
517 LxtCheckErrno(unshare(CLONE_SYSVSEM));
518
519 //
520 // Verify the values did not change.
521 //
522
523 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
524 LxtCheckEqual(0, LxtSemCtl(Id, 1, GETVAL, NULL), "%d");
525 Result = LXT_RESULT_SUCCESS;
526
527 ErrorExit:
528 exit(Result);
529 }
530
531 int SemCloneThread(void* Param)
532 {
533
534 long long Data;
535 int Event;
536 int Result;
537
538 Event = *((int*)Param);
539 LxtCheckErrno(read(Event, &Data, sizeof(Data)));
540
541 //
542 // Just exit the thread, not the thread group, on success.
543 //
544
545 syscall(SYS_exit, 0);
546
547 ErrorExit:
548 exit(Result);
549 }
550
551 int SemOpFlags(PLXT_ARGS Args)
552 {
553 int ChildPid;
554 LXT_CLONE_ARGS CloneArgs;
555 long long EventData;
556 int Flags;
557 int Id;
558 struct sembuf Operations[SEM_COUNT];
559 size_t Result;
560 char* SharedStack;
561 int SharedEvent;
562 pid_t SharedTid;
563 struct semid_ds Stat;
564 int StackSize;
565 int Status;
566 char* UnsharedStack;
567 int UnsharedEvent;
568 pid_t UnsharedTid;
569 unsigned short Values[SEM_COUNT];
570
571 ChildPid = -1;
572 EventData = 1;
573 Id = -1;
574 SharedEvent = -1;
575 SharedStack = NULL;
576 UnsharedEvent = -1;
577 UnsharedStack = NULL;
578 memset(Operations, 0, sizeof(Operations));
579
580 LXT_SYNCHRONIZATION_POINT_START();
581
582 //
583 // Create a semaphore set.
584 //
585
586 LxtCheckErrno(Id = LxtSemGet(IPC_PRIVATE, SEM_COUNT, (IPC_CREAT | IPC_EXCL)));
587
588 //
589 // Test the nowait flag.
590 //
591
592 Operations[0].sem_num = 0;
593 Operations[0].sem_op = -1;
594 Operations[0].sem_flg = IPC_NOWAIT;
595 LxtCheckErrnoFailure(LxtSemOp(Id, Operations, 1), EAGAIN);
596
597 //
598 // Increment the first semaphore.
599 //
600
601 Operations[0].sem_num = 0;
602 Operations[0].sem_op = 1;
603 Operations[0].sem_flg = 0;
604 LxtCheckErrno(LxtSemOp(Id, Operations, 1));
605
606 //
607 // Create a child.
608 //
609
610 LxtCheckErrno(ChildPid = fork());
611 if (ChildPid == 0)
612 {
613
614 //
615 // Decrement the first semaphore and increment the second semaphore,
616 // both with the undo flag set.
617 //
618
619 Operations[0].sem_num = 0;
620 Operations[0].sem_op = -1;
621 Operations[0].sem_flg = SEM_UNDO;
622 Operations[1].sem_num = 1;
623 Operations[1].sem_op = 1;
624 Operations[1].sem_flg = SEM_UNDO;
625 LxtCheckErrno(LxtSemOp(Id, Operations, 2));
626 goto ErrorExit;
627 }
628
629 //
630 // Wait for the child to exit.
631 //
632
633 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
634
635 //
636 // Ensure the child's operations were undone.
637 //
638
639 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
640 LxtCheckEqual(0, LxtSemCtl(Id, 1, GETVAL, NULL), "%d");
641
642 //
643 // Ensure the wait can still be satisfied.
644 //
645
646 Operations[0].sem_num = 0;
647 Operations[0].sem_op = -1;
648 Operations[0].sem_flg = 0;
649 LxtCheckErrno(LxtSemOp(Id, Operations, 1));
650 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
651
652 //
653 // Create a child.
654 //
655
656 LxtCheckErrno(ChildPid = fork());
657 if (ChildPid == 0)
658 {
659
660 //
661 // Set the first semaphore to the max with the undo flag specified and
662 // lower the count without the undo flag specified.
663 //
664
665 Operations[0].sem_num = 0;
666 Operations[0].sem_op = 0x7fff;
667 Operations[0].sem_flg = SEM_UNDO;
668 Operations[1].sem_num = 0;
669 Operations[1].sem_op = -0x7fff;
670 Operations[1].sem_flg = 0;
671 LxtCheckErrno(LxtSemOp(Id, Operations, 2));
672 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
673
674 LXT_SYNCHRONIZATION_POINT();
675 LXT_SYNCHRONIZATION_POINT();
676
677 Operations[0].sem_num = 0;
678 Operations[0].sem_op = 1;
679 Operations[0].sem_flg = 0;
680 LxtCheckErrno(LxtSemOp(Id, Operations, 1));
681 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
682 LXT_SYNCHRONIZATION_POINT();
683 LXT_SYNCHRONIZATION_POINT();
684 goto ErrorExit;
685 }
686
687 //
688 // Wait for child to perform first operation.
689 //
690
691 LXT_SYNCHRONIZATION_POINT();
692 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
693 LXT_SYNCHRONIZATION_POINT();
694
695 //
696 // Wait for child to perform second operation.
697 //
698
699 LXT_SYNCHRONIZATION_POINT();
700 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
701 LXT_SYNCHRONIZATION_POINT();
702
703 //
704 // Wait for the child to exit and ensure the count does not drop below
705 // zero.
706 //
707
708 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
709 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
710
711 //
712 // Create a child.
713 //
714
715 LxtCheckErrno(ChildPid = fork());
716 if (ChildPid == 0)
717 {
718
719 //
720 // Set the first semaphore to the max without the undo flag specified and
721 // lower the count with the undo flag specified.
722 //
723
724 Operations[0].sem_num = 0;
725 Operations[0].sem_op = 0x7fff;
726 Operations[0].sem_flg = 0;
727 Operations[1].sem_num = 0;
728 Operations[1].sem_op = -0x7fff;
729 Operations[1].sem_flg = SEM_UNDO;
730 LxtCheckErrno(LxtSemOp(Id, Operations, 2));
731 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
732
733 LXT_SYNCHRONIZATION_POINT();
734 LXT_SYNCHRONIZATION_POINT();
735
736 Operations[0].sem_num = 0;
737 Operations[0].sem_op = 1;
738 Operations[0].sem_flg = 0;
739 LxtCheckErrno(LxtSemOp(Id, Operations, 1));
740 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
741 LXT_SYNCHRONIZATION_POINT();
742 LXT_SYNCHRONIZATION_POINT();
743 goto ErrorExit;
744 }
745
746 //
747 // Wait for child to perform first operation.
748 //
749
750 LXT_SYNCHRONIZATION_POINT();
751 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
752 LXT_SYNCHRONIZATION_POINT();
753
754 //
755 // Wait for child to perform second operation.
756 //
757
758 LXT_SYNCHRONIZATION_POINT();
759 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
760 LXT_SYNCHRONIZATION_POINT();
761
762 //
763 // Wait for the child to exit and ensure the count does not exceed the max
764 // semaphore value.
765 //
766
767 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
768 LxtCheckEqual(0x7fff, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
769 LxtCheckErrno(LxtSemCtl(Id, 0, SETVAL, 0));
770
771 //
772 // Validate semctl SETVAL clears undo adjustments.
773 //
774
775 LxtCheckErrno(ChildPid = fork());
776 if (ChildPid == 0)
777 {
778
779 //
780 // Set the first semaphore to the max with the undo flag specified and
781 // lower the count without the undo flag specified.
782 //
783
784 Operations[0].sem_num = 0;
785 Operations[0].sem_op = 0x7fff;
786 Operations[0].sem_flg = 0;
787 Operations[1].sem_num = 0;
788 Operations[1].sem_op = -0x7fff;
789 Operations[1].sem_flg = SEM_UNDO;
790 LxtCheckErrno(LxtSemOp(Id, Operations, 2));
791 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
792
793 LXT_SYNCHRONIZATION_POINT();
794 LXT_SYNCHRONIZATION_POINT();
795
796 Operations[0].sem_num = 0;
797 Operations[0].sem_op = 1;
798 Operations[0].sem_flg = 0;
799 LxtCheckErrno(LxtSemOp(Id, Operations, 1));
800 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
801 LXT_SYNCHRONIZATION_POINT();
802 LXT_SYNCHRONIZATION_POINT();
803 goto ErrorExit;
804 }
805
806 //
807 // Wait for child to perform first operation.
808 //
809
810 LXT_SYNCHRONIZATION_POINT();
811 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
812 LXT_SYNCHRONIZATION_POINT();
813
814 //
815 // Wait for child to perform second operation and set the semaphore value
816 // to zero. This should remove the pending semaphore adjustment.
817 //
818
819 LXT_SYNCHRONIZATION_POINT();
820 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
821 LxtCheckErrno(LxtSemCtl(Id, 0, SETVAL, 0));
822 LXT_SYNCHRONIZATION_POINT();
823
824 //
825 // Wait for the child to exit and ensure the adjustment was not applied.
826 //
827
828 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
829 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
830
831 //
832 // Create a child, verify when the child unshares the semaphore adjustments
833 // are cleared.
834 //
835
836 memset(Values, 0, sizeof(Values));
837 LxtCheckErrno(LxtSemCtl(Id, 0, SETALL, &Values));
838 LxtCheckErrno(LxtSemCtl(Id, 1, SETVAL, 1));
839 LxtCheckErrno(ChildPid = fork());
840 if (ChildPid == 0)
841 {
842
843 //
844 // Increment one semaphore and decrement another both with the undo
845 // flag set.
846 //
847
848 Operations[0].sem_num = 0;
849 Operations[0].sem_op = 1;
850 Operations[0].sem_flg = SEM_UNDO;
851 Operations[1].sem_num = 1;
852 Operations[1].sem_op = -1;
853 Operations[1].sem_flg = SEM_UNDO;
854 LxtCheckErrno(LxtSemOp(Id, Operations, 2));
855 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
856 LxtCheckEqual(0, LxtSemCtl(Id, 1, GETVAL, NULL), "%d");
857 LxtCheckErrno(unshare(CLONE_SYSVSEM));
858
859 //
860 // Ensure the state was undone.
861 //
862
863 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
864 LxtCheckEqual(1, LxtSemCtl(Id, 1, GETVAL, NULL), "%d");
865 LXT_SYNCHRONIZATION_POINT();
866 LXT_SYNCHRONIZATION_POINT();
867 goto ErrorExit;
868 }
869
870 //
871 // Wait for child to unshare.
872 //
873
874 LXT_SYNCHRONIZATION_POINT();
875
876 //
877 // Ensure the child's operations were undone.
878 //
879
880 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
881 LxtCheckEqual(1, LxtSemCtl(Id, 1, GETVAL, NULL), "%d");
882 LXT_SYNCHRONIZATION_POINT();
883
884 //
885 // Wait for the child to exit.
886 //
887
888 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
889
890 //
891 // Reset semaphore state.
892 //
893
894 memset(Values, 0, sizeof(Values));
895 LxtCheckErrno(LxtSemCtl(Id, 0, SETALL, &Values));
896 LxtCheckErrno(LxtSemCtl(Id, 1, SETVAL, 1));
897 Operations[0].sem_num = 0;
898 Operations[0].sem_op = 1;
899 Operations[0].sem_flg = SEM_UNDO;
900 Operations[1].sem_num = 1;
901 Operations[1].sem_op = -1;
902 Operations[1].sem_flg = SEM_UNDO;
903 LxtCheckErrno(LxtSemOp(Id, Operations, 2));
904
905 //
906 // Clone a child to share the same SystemV semaphore adjustment structure.
907 //
908
909 LxtCheckResult(LxtClone(SemCloneChild, &Id, CLONE_SYSVSEM | SIGCHLD, &CloneArgs));
910
911 //
912 // Wait for child to exit.
913 //
914
915 LxtCheckResult(LxtWaitPidPoll(CloneArgs.CloneId, 0));
916
917 //
918 // Values should not have changed yet.
919 //
920
921 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
922 LxtCheckEqual(0, LxtSemCtl(Id, 1, GETVAL, NULL), "%d");
923
924 //
925 // Create two threads, one sharing the semaphore adjustment structure
926 // and one not.
927 //
928
929 Flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
930
931 StackSize = 1024 * 1024;
932
933 LxtCheckErrno(SharedEvent = eventfd(0, EFD_SEMAPHORE));
934 SharedStack = malloc(StackSize);
935 LxtCheckResult(clone(SemCloneThread, SharedStack + StackSize, Flags | CLONE_SYSVSEM, &SharedEvent, &SharedTid, NULL, &SharedTid));
936
937 LxtCheckErrno(UnsharedEvent = eventfd(0, EFD_SEMAPHORE));
938 UnsharedStack = malloc(StackSize);
939 LxtCheckResult(clone(SemCloneThread, UnsharedStack + StackSize, Flags, &UnsharedEvent, &UnsharedTid, NULL, &UnsharedTid));
940
941 //
942 // Unshare; since there is still a thread sharing, adjustments should
943 // not occur.
944 //
945
946 LxtCheckErrno(unshare(CLONE_SYSVSEM));
947 LxtCheckEqual(1, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
948 LxtCheckEqual(0, LxtSemCtl(Id, 1, GETVAL, NULL), "%d");
949
950 //
951 // Signal the sharing thread and wait for it to exit; adjustments should
952 // occur shortly thereafter.
953 //
954
955 LxtCheckErrno(write(SharedEvent, &EventData, sizeof(EventData)));
956 LxtCheckErrno(LxtJoinThread(&SharedTid));
957 usleep(100000);
958 LxtCheckEqual(0, LxtSemCtl(Id, 0, GETVAL, NULL), "%d");
959 LxtCheckEqual(1, LxtSemCtl(Id, 1, GETVAL, NULL), "%d");
960
961 //
962 // Signal the unshared thread to clean things up.
963 //
964
965 LxtCheckErrno(write(UnsharedEvent, &EventData, sizeof(EventData)));
966 LxtCheckErrno(LxtJoinThread(&UnsharedTid));
967
968 ErrorExit:
969 LXT_SYNCHRONIZATION_POINT_END();
970 if (ChildPid == 0)
971 {
972 _exit(Result);
973 }
974
975 if (Id != -1)
976 {
977 LxtSemCtl(Id, 0, IPC_RMID, NULL);
978 }
979
980 if (SharedEvent != -1)
981 {
982 close(SharedEvent);
983 }
984
985 if (UnsharedEvent != -1)
986 {
987 close(SharedEvent);
988 }
989
990 free(SharedStack);
991 free(UnsharedStack);
992 return Result;
993 }
994
995 int SemOpSyscall(PLXT_ARGS Args)
996
997 {
998 struct __user_cap_data_struct CapData[2];
999 struct __user_cap_header_struct CapHeader;
1000 int ChildPid;
1001 int Id;
1002 int Index;
1003 int Mode;
1004 struct sembuf Operations[SEM_COUNT];
1005 size_t Result;
1006 struct semid_ds Stat;
1007 int Status;
1008 time_t Time;
1009 struct timespec Timeout;
1010 unsigned short Values[SEM_COUNT];
1011
1012 ChildPid = -1;
1013 Id = -1;
1014 memset(Operations, 0, sizeof(Operations));
1015 memset(Values, 0, sizeof(Values));
1016
1017 LXT_SYNCHRONIZATION_POINT_START();
1018
1019 //
1020 // Create a semaphore with zero mode bits.
1021 //
1022
1023 Mode = 0000;
1024 LxtLogInfo("Mode %o", Mode);
1025 LxtCheckErrno(Id = LxtSemGet(IPC_PRIVATE, SEM_COUNT, (IPC_CREAT | IPC_EXCL | Mode)));
1026 LxtLogInfo("Id = %d", Id);
1027
1028 //
1029 // Create a child with a different uid and gid that does not have the
1030 // IPC_OWNER capability.
1031 //
1032
1033 LxtCheckErrno(ChildPid = fork());
1034 if (ChildPid == 0)
1035 {
1036 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
1037 LxtCheckErrno(setgid(SEM_ACCESS_GID));
1038 LxtCheckErrno(setuid(SEM_ACCESS_UID));
1039 memset(&CapData, 0, sizeof(CapData));
1040 memset(&CapHeader, 0, sizeof(CapHeader));
1041 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1042 CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
1043 CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
1044 CapData[0].effective = CapData[0].permitted;
1045 CapData[1].effective = CapData[1].permitted;
1046 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1047
1048 //
1049 // These should succeed because the child still has the IPC_OWNER cap.
1050 //
1051
1052 memset(Operations, 0, sizeof(Operations));
1053 LxtCheckErrno(LxtSemOp(Id, Operations, SEM_COUNT));
1054
1055 //
1056 // Drop all group membership and the CAP_IPC_OWNER capability and
1057 // attempt to call semget with unmatching mode bits.
1058 //
1059
1060 LxtCheckErrno(Result = setgroups(0, NULL));
1061 memset(&CapData, 0, sizeof(CapData));
1062 memset(&CapHeader, 0, sizeof(CapHeader));
1063 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1064 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1065
1066 //
1067 // Attempt to issue operations, these should fail.
1068 //
1069
1070 LxtCheckErrnoFailure(LxtSemOp(Id, Operations, SEM_COUNT), EACCES);
1071 goto ErrorExit;
1072 }
1073
1074 //
1075 // Wait for the child to exit.
1076 //
1077
1078 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1079
1080 //
1081 // Create a new readable semaphore.
1082 //
1083
1084 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_RMID, NULL));
1085 Mode = 0004;
1086 LxtLogInfo("Mode %o", Mode);
1087 LxtCheckErrno(Id = LxtSemGet(IPC_PRIVATE, SEM_COUNT, (IPC_CREAT | IPC_EXCL | Mode)));
1088 LxtLogInfo("Id = %d", Id);
1089
1090 //
1091 // Create a child with a different uid and gid that does not have the
1092 // IPC_OWNER capability.
1093 //
1094
1095 LxtCheckErrno(ChildPid = fork());
1096 if (ChildPid == 0)
1097 {
1098 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
1099 LxtCheckErrno(setgid(SEM_ACCESS_GID));
1100 LxtCheckErrno(setuid(SEM_ACCESS_UID));
1101 memset(&CapData, 0, sizeof(CapData));
1102 memset(&CapHeader, 0, sizeof(CapHeader));
1103 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1104 CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
1105 CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
1106 CapData[0].effective = CapData[0].permitted;
1107 CapData[1].effective = CapData[1].permitted;
1108 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1109
1110 //
1111 // These should succeed because the child still has the IPC_OWNER cap.
1112 //
1113
1114 memset(Operations, 0, sizeof(Operations));
1115 LxtCheckErrno(LxtSemOp(Id, Operations, SEM_COUNT));
1116
1117 //
1118 // Drop all group membership and the CAP_IPC_OWNER capability and
1119 // attempt to call semget with unmatching mode bits.
1120 //
1121
1122 LxtCheckErrno(Result = setgroups(0, NULL));
1123 memset(&CapData, 0, sizeof(CapData));
1124 memset(&CapHeader, 0, sizeof(CapHeader));
1125 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1126 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1127
1128 //
1129 // Attempt to issue a "wait for zero" operation, this should succeed
1130 // and return immediately because the value is zero.
1131 //
1132
1133 LxtCheckErrno(LxtSemOp(Id, Operations, SEM_COUNT));
1134
1135 //
1136 // Attempt to increment the semaphore, this should fail.
1137 //
1138
1139 Operations[1].sem_num = 0;
1140 Operations[1].sem_op = 1;
1141 LxtCheckErrnoFailure(LxtSemOp(Id, &Operations[1], 1), EACCES);
1142
1143 //
1144 // Attempt to decrement the semaphore, this should fail.
1145 //
1146
1147 Operations[2].sem_num = 0;
1148 Operations[2].sem_op = -1;
1149 LxtCheckErrnoFailure(LxtSemOp(Id, &Operations[2], 1), EACCES);
1150
1151 //
1152 // Attempt the increment and wait operations after a wait for zero that
1153 // succeeds.
1154 //
1155
1156 LxtCheckErrnoFailure(LxtSemOp(Id, Operations, 3), EACCES);
1157 goto ErrorExit;
1158 }
1159
1160 //
1161 // Wait for the child to exit.
1162 //
1163
1164 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1165
1166 //
1167 // Create a new writable semaphore.
1168 //
1169
1170 LxtCheckErrno(LxtSemCtl(Id, 0, IPC_RMID, NULL));
1171 Mode = 0002;
1172 LxtLogInfo("Mode %o", Mode);
1173 LxtCheckErrno(Id = LxtSemGet(IPC_PRIVATE, SEM_COUNT, (IPC_CREAT | IPC_EXCL | Mode)));
1174 LxtLogInfo("Id = %d", Id);
1175
1176 //
1177 // Create a child with a different uid and gid that does not have the
1178 // IPC_OWNER capability.
1179 //
1180
1181 LxtCheckErrno(ChildPid = fork());
1182 if (ChildPid == 0)
1183 {
1184 LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
1185 LxtCheckErrno(setgid(SEM_ACCESS_GID));
1186 LxtCheckErrno(setuid(SEM_ACCESS_UID));
1187 memset(&CapData, 0, sizeof(CapData));
1188 memset(&CapHeader, 0, sizeof(CapHeader));
1189 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1190 CapData[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
1191 CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted |= CAP_TO_MASK(CAP_IPC_OWNER);
1192 CapData[0].effective = CapData[0].permitted;
1193 CapData[1].effective = CapData[1].permitted;
1194 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1195
1196 //
1197 // These should succeed because the child still has the IPC_OWNER cap.
1198 //
1199
1200 memset(Operations, 0, sizeof(Operations));
1201 LxtCheckErrno(LxtSemOp(Id, Operations, SEM_COUNT));
1202
1203 //
1204 // Drop all group membership and the CAP_IPC_OWNER capability and
1205 // attempt to call semget with unmatching mode bits.
1206 //
1207
1208 LxtCheckErrno(Result = setgroups(0, NULL));
1209 memset(&CapData, 0, sizeof(CapData));
1210 memset(&CapHeader, 0, sizeof(CapHeader));
1211 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
1212 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
1213
1214 //
1215 // Attempt to issue a "wait for zero" operation, this should fail.
1216 //
1217
1218 memset(Operations, 0, sizeof(Operations));
1219 LxtCheckErrnoFailure(LxtSemOp(Id, Operations, SEM_COUNT), EACCES);
1220
1221 //
1222 // Attempt to increment the semaphore, this should succeed.
1223 //
1224
1225 Operations[0].sem_num = 0;
1226 Operations[0].sem_op = 1;
1227 LxtCheckErrno(LxtSemOp(Id, Operations, 1));
1228
1229 //
1230 // Attempt to decrement the semaphore, this should succeed.
1231 //
1232
1233 Operations[0].sem_num = 0;
1234 Operations[0].sem_op = -1;
1235 LxtCheckErrno(LxtSemOp(Id, Operations, 1));
1236
1237 //
1238 // Fill the operations buffer with a combination of valid operations
1239 // and operations that the caller does not have permission to do. The
1240 // parent will verify the semaphore values are adjusted correctly.
1241 //
1242
1243 memset(Operations, 0, sizeof(Operations));
1244 Operations[0].sem_num = 0;
1245 Operations[0].sem_op = 1;
1246
1247 Operations[1].sem_num = 1;
1248 Operations[1].sem_op = 1;
1249
1250 Operations[2].sem_num = 2;
1251 Operations[2].sem_op = 0;
1252
1253 Operations[3].sem_num = 3;
1254 Operations[3].sem_op = 1;
1255
1256 Operations[4].sem_num = 2;
1257 Operations[4].sem_op = 0;
1258
1259 LxtCheckErrno(LxtSemOp(Id, Operations, 3));
1260 LxtCheckErrno(LxtSemOp(Id, &Operations[1], 2));
1261 LxtCheckErrno(LxtSemOp(Id, &Operations[1], 3));
1262 LxtCheckErrno(LxtSemOp(Id, &Operations[2], 2));
1263 LxtCheckErrno(LxtSemOp(Id, &Operations[2], 3));
1264 LxtCheckErrnoFailure(LxtSemOp(Id, &Operations[2], 1), EACCES);
1265 LXT_SYNCHRONIZATION_POINT(); // (1)
1266
1267 //
1268 // Wait for parent to query.
1269 //
1270
1271 LXT_SYNCHRONIZATION_POINT(); // (2)
1272
1273 //
1274 // Test how overflow is handled. It looks like there is a per-semaphore
1275 // rolling count that is checked before any operations are performed.
1276 //
1277
1278 memset(Operations, 0, sizeof(Operations));
1279 Operations[0].sem_op = 32767;
1280 Operations[1].sem_op = 1;
1281 LxtCheckErrno(LxtSemOp(Id, Operations, 1));
1282 LxtCheckErrnoFailure(LxtSemOp(Id, &Operations[1], 1), ERANGE);
1283 LXT_SYNCHRONIZATION_POINT(); // (3)
1284
1285 //
1286 // Wait for parent to query.
1287 //
1288
1289 LXT_SYNCHRONIZATION_POINT(); // (4)
1290 LxtCheckErrnoFailure(LxtSemOp(Id, Operations, 2), ERANGE);
1291 LXT_SYNCHRONIZATION_POINT(); // (5)
1292
1293 LXT_SYNCHRONIZATION_POINT(); // (6)
1294 memset(Operations, 0, sizeof(Operations));
1295 Operations[0].sem_op = 32767;
1296 Operations[1].sem_op = -1;
1297 Operations[2].sem_op = 2;
1298 Operations[3].sem_op = -1;
1299 LxtCheckErrnoFailure(LxtSemOp(Id, Operations, 4), ERANGE);
1300 LXT_SYNCHRONIZATION_POINT(); // (7)
1301
1302 memset(Operations, 0, sizeof(Operations));
1303 Operations[0].sem_op = -1;
1304 Operations[1].sem_op = 32767;
1305 Operations[2].sem_op = 1;
1306 LXT_SYNCHRONIZATION_POINT(); // (8)
1307 LxtLogInfo("child semop");
1308 LxtCheckErrnoFailure(LxtSemOp(Id, Operations, 4), ERANGE);
1309 LxtLogInfo("child return");
1310 LXT_SYNCHRONIZATION_POINT(); // (9)
1311 goto ErrorExit;
1312 }
1313
1314 //
1315 // Wait for the child to do the first semop and query the values.
1316 //
1317
1318 LXT_SYNCHRONIZATION_POINT(); // (1)
1319 LxtCheckErrno(LxtSemCtl(Id, 0, GETALL, &Values));
1320 LxtCheckEqual(1, Values[0], "%u");
1321 LxtCheckEqual(3, Values[1], "%u");
1322 LxtCheckEqual(3, Values[3], "%u");
1323 memset(Values, 0, sizeof(Values));
1324 LxtCheckErrno(LxtSemCtl(Id, 0, SETALL, &Values));
1325 LXT_SYNCHRONIZATION_POINT(); // (2)
1326
1327 LXT_SYNCHRONIZATION_POINT(); // (3)
1328 LxtCheckErrno(LxtSemCtl(Id, 0, GETALL, &Values));
1329 LxtCheckEqual(32767, Values[0], "%u");
1330 memset(Values, 0, sizeof(Values));
1331 LxtCheckErrno(LxtSemCtl(Id, 0, SETALL, &Values));
1332 LXT_SYNCHRONIZATION_POINT(); // (4)
1333
1334 LXT_SYNCHRONIZATION_POINT(); // (5)
1335 LxtCheckErrno(LxtSemCtl(Id, 0, GETALL, &Values));
1336 LxtCheckEqual(0, Values[0], "%u");
1337
1338 LXT_SYNCHRONIZATION_POINT(); // (6)
1339 LxtCheckErrno(LxtSemCtl(Id, 0, GETALL, &Values));
1340 LxtCheckEqual(0, Values[0], "%u");
1341 memset(Values, 0, sizeof(Values));
1342 LxtCheckErrno(LxtSemCtl(Id, 0, SETALL, &Values));
1343 LXT_SYNCHRONIZATION_POINT(); // (7)
1344
1345 LXT_SYNCHRONIZATION_POINT(); // (8)
1346 Operations[0].sem_num = 0;
1347 Operations[0].sem_op = 1;
1348 sleep(1);
1349 LxtCheckErrno(LxtSemOp(Id, Operations, 1));
1350 LXT_SYNCHRONIZATION_POINT(); // (9)
1351 LxtCheckErrno(LxtSemCtl(Id, 0, GETALL, &Values));
1352 LxtCheckEqual(1, Values[0], "%u");
1353
1354 //
1355 // Wait for the child to exit.
1356 //
1357
1358 LxtCheckErrno(LxtWaitPidPoll(ChildPid, LXT_RESULT_SUCCESS));
1359
1360 //
1361 // Invalid parameter variations.
1362 //
1363
1364 LxtCheckErrnoFailure(LxtSemOp(Id, NULL, 0), EINVAL);
1365 LxtCheckErrnoFailure(LxtSemOp(Id, NULL, 501), E2BIG);
1366 LxtCheckErrnoFailure(LxtSemOp(Id, NULL, 1), EFAULT);
1367 LxtCheckErrnoFailure(LxtSemOp(Id, -1, 1), EFAULT);
1368 LxtCheckErrnoFailure(LxtSemOp(-1, NULL, 0), EINVAL);
1369 LxtCheckErrnoFailure(LxtSemOp(-1, NULL, 1), EINVAL);
1370
1371 LxtCheckErrnoFailure(LxtSemTimedOp(Id, NULL, 0, NULL), EINVAL);
1372 LxtCheckErrnoFailure(LxtSemTimedOp(Id, NULL, 501, NULL), E2BIG);
1373 LxtCheckErrnoFailure(LxtSemTimedOp(Id, NULL, 1, NULL), EFAULT);
1374 LxtCheckErrnoFailure(LxtSemTimedOp(Id, -1, 1, NULL), EFAULT);
1375 LxtCheckErrnoFailure(LxtSemTimedOp(Id, Operations, 1, -1), EFAULT);
1376 LxtCheckErrnoFailure(LxtSemTimedOp(-1, NULL, 0, NULL), EINVAL);
1377 LxtCheckErrnoFailure(LxtSemTimedOp(-1, NULL, 1, -1), EINVAL);
1378 Timeout.tv_sec = 0;
1379 Timeout.tv_nsec = 999999999 + 1;
1380 LxtCheckErrnoFailure(LxtSemTimedOp(Id, Operations, 1, &Timeout), EINVAL);
1381 Timeout.tv_sec = -1;
1382 Timeout.tv_nsec = 0;
1383 LxtCheckErrnoFailure(LxtSemTimedOp(Id, Operations, 1, &Timeout), EINVAL);
1384
1385 ErrorExit:
1386 LXT_SYNCHRONIZATION_POINT_END();
1387 if (ChildPid == 0)
1388 {
1389 _exit(Result);
1390 }
1391
1392 if (Id != -1)
1393 {
1394 LxtSemCtl(Id, 0, IPC_RMID, NULL);
1395 }
1396
1397 return Result;
1398 }
1399
1400 void SemPrintInfo(struct semid_ds* Stat)
1401
1402 {
1403
1404 if (g_VerboseSem == false)
1405 {
1406 return;
1407 }
1408
1409 LxtLogInfo("sem_perm.__key %u", Stat->sem_perm.__key);
1410 LxtLogInfo("sem_perm.uid %u", Stat->sem_perm.uid);
1411 LxtLogInfo("sem_perm.gid %u", Stat->sem_perm.gid);
1412 LxtLogInfo("sem_perm.cuid %u", Stat->sem_perm.cuid);
1413 LxtLogInfo("sem_perm.cgid %u", Stat->sem_perm.cgid);
1414 LxtLogInfo("sem_perm.mode %o", Stat->sem_perm.mode);
1415 LxtLogInfo("sem_perm.__seq %d", Stat->sem_perm.__seq);
1416 LxtLogInfo("sem_otime %Iu", Stat->sem_otime);
1417 LxtLogInfo("sem_ctime %Iu", Stat->sem_ctime);
1418 LxtLogInfo("sem_nsems %Iu", Stat->sem_nsems);
1419 return;
1420 }