1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * E2BIG - nsops is greater than max number of operations allowed per syscall
4 * EACCESS - calling process does not have permission to alter semaphore
5 * EFAULT - invalid address passed for sops
6 * EINVAL - nonpositive nsops
7 * EINVAL - negative semid
8 * ERANGE - semop + semval > semvmx a maximal semaphore value
9 * EFBIG - sem_num less than zero
10 * EFBIG - sem_num > number of semaphores in a set
11 * EAGAIN - semop = 0 for non-zero semaphore and IPC_NOWAIT passed in flags
12 * EAGAIN - semop = -1 for zero semaphore and IPC_NOWAIT passed in flags
13 * EAGAIN - semop = 0 and timeout happens
14 * EAGAIN - semop = -1 and timeout happens
15 * EFAULT - invalid timeout pointer
16 *
17 * Copyright (c) International Business Machines Corp., 2001
18 * 03/2001 - Written by Wayne Boyer
19 * 10/03/2008 Renaud Lottiaux (Renaud.Lottiaux@kerlabs.com)
20 */
21
22 #define _GNU_SOURCE
23 #include <pwd.h>
24 #include <sys/ipc.h>
25 #include "tst_test.h"
26 #include "libnewipc.h"
27 #include "lapi/sem.h"
28 #include "semop.h"
29
30 static int valid_sem_id = -1;
31 static int noperm_sem_id = -1;
32 static int bad_sem_id = -1;
33 static short sem_op_max, sem_op_1 = 1, sem_op_negative = -1, sem_op_zero = 0;
34 static struct sembuf *faulty_buf;
35 static struct tst_ts timeout;
36 static struct tst_ts *valid_to = &timeout, *invalid_to;
37
38 #define NSOPS 1
39 #define BIGOPS 1024
40
41 static struct test_case_t {
42 int semtimedop_only;
43 int *semid;
44 struct sembuf **buf;
45 short *sem_op;
46 unsigned short ctl_sem_num;
47 unsigned short sem_num;
48 short sem_flg;
49 unsigned t_ops;
50 int arr_val;
51 struct tst_ts **to;
52 int error;
53 } tc[] = {
54 {0, &valid_sem_id, NULL, &sem_op_1, 0, 0, 0, BIGOPS, 1, &valid_to, E2BIG},
55 {0, &noperm_sem_id, NULL, &sem_op_1, 0, 0, 0, NSOPS, 1, &valid_to, EACCES},
56 {0, &valid_sem_id, &faulty_buf, &sem_op_1, 0, 0, 0, NSOPS, 1, &valid_to, EFAULT},
57 {0, &valid_sem_id, NULL, &sem_op_1, 0, 0, 0, 0, 1, &valid_to, EINVAL},
58 {0, &bad_sem_id, NULL, &sem_op_1, 0, 0, 0, NSOPS, 1, &valid_to, EINVAL},
59 {0, &valid_sem_id, NULL, &sem_op_max, 0, 0, 0, 1, 1, &valid_to, ERANGE},
60 {0, &valid_sem_id, NULL, &sem_op_1, 0, -1, SEM_UNDO, 1, 1, &valid_to, EFBIG},
61 {0, &valid_sem_id, NULL, &sem_op_1, 0, PSEMS + 1, SEM_UNDO, 1, 1, &valid_to, EFBIG},
62 {0, &valid_sem_id, NULL, &sem_op_zero, 2, 2, IPC_NOWAIT, 1, 1, &valid_to, EAGAIN},
63 {0, &valid_sem_id, NULL, &sem_op_negative, 2, 2, IPC_NOWAIT, 1, 0, &valid_to, EAGAIN},
64 {1, &valid_sem_id, NULL, &sem_op_zero, 0, 0, SEM_UNDO, 1, 1, &valid_to, EAGAIN},
65 {1, &valid_sem_id, NULL, &sem_op_negative, 0, 0, SEM_UNDO, 1, 0, &valid_to, EAGAIN},
66 {1, &valid_sem_id, NULL, &sem_op_zero, 0, 0, SEM_UNDO, 1, 1, &invalid_to, EFAULT},
67 };
68
setup(void)69 static void setup(void)
70 {
71 struct time64_variants *tv = &variants[tst_variant];
72 struct passwd *ltpuser;
73 key_t semkey;
74 union semun arr;
75 struct seminfo ipc_buf;
76 void *faulty_address;
77
78 tst_res(TINFO, "Testing variant: %s", tv->desc);
79 semop_supported_by_kernel(tv);
80
81 timeout.type = tv->ts_type;
82 tst_ts_set_sec(&timeout, 0);
83 tst_ts_set_nsec(&timeout, 10000);
84
85 ltpuser = SAFE_GETPWNAM("nobody");
86 SAFE_SETUID(ltpuser->pw_uid);
87
88 semkey = GETIPCKEY();
89
90 valid_sem_id = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA);
91 if (valid_sem_id == -1)
92 tst_brk(TBROK | TERRNO, "couldn't create semaphore in setup");
93
94 semkey = GETIPCKEY();
95
96 noperm_sem_id = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL);
97 if (noperm_sem_id == -1)
98 tst_brk(TBROK | TERRNO, "couldn't create semaphore in setup");
99
100 arr.__buf = &ipc_buf;
101 if (semctl(valid_sem_id, 0, IPC_INFO, arr) == -1)
102 tst_brk(TBROK | TERRNO, "semctl() IPC_INFO failed");
103
104 sem_op_max = ipc_buf.semvmx;
105 faulty_address = tst_get_bad_addr(NULL);
106 invalid_to = faulty_address;
107 faulty_buf = faulty_address;
108 }
109
run(unsigned int i)110 static void run(unsigned int i)
111 {
112 struct time64_variants *tv = &variants[tst_variant];
113 union semun arr = {.val = tc[i].arr_val};
114 struct sembuf buf = {
115 .sem_op = *tc[i].sem_op,
116 .sem_flg = tc[i].sem_flg,
117 .sem_num = tc[i].sem_num,
118 };
119 struct sembuf *ptr = &buf;
120 void *to;
121
122 if (tc[i].semtimedop_only && tv->semop) {
123 tst_res(TCONF, "Test not supported for variant");
124 return;
125 }
126
127 if (*tc[i].semid == valid_sem_id) {
128 if (semctl(valid_sem_id, tc[i].ctl_sem_num, SETVAL, arr) == -1)
129 tst_brk(TBROK | TERRNO, "semctl() SETVAL failed");
130 }
131
132 if (tc[i].buf)
133 ptr = *tc[i].buf;
134
135 if (*tc[i].to == invalid_to)
136 to = invalid_to;
137 else
138 to = tst_ts_get(*tc[i].to);
139
140 TEST(call_semop(tv, *(tc[i].semid), ptr, tc[i].t_ops, to));
141
142 if (TST_RET != -1) {
143 tst_res(TFAIL | TTERRNO, "call succeeded unexpectedly");
144 return;
145 }
146
147 if (TST_ERR == tc[i].error) {
148 tst_res(TPASS | TTERRNO, "semop failed as expected");
149 } else {
150 tst_res(TFAIL | TTERRNO,
151 "semop failed unexpectedly; expected: %s",
152 tst_strerrno(tc[i].error));
153 }
154 }
155
cleanup(void)156 static void cleanup(void)
157 {
158 if (valid_sem_id != -1) {
159 if (semctl(valid_sem_id, 0, IPC_RMID) == -1)
160 tst_res(TWARN, "semaphore deletion failed.");
161 }
162
163 if (noperm_sem_id != -1) {
164 if (semctl(noperm_sem_id, 0, IPC_RMID) == -1)
165 tst_res(TWARN, "semaphore deletion failed.");
166 }
167 }
168
169 static struct tst_test test = {
170 .test = run,
171 .tcnt = ARRAY_SIZE(tc),
172 .test_variants = ARRAY_SIZE(variants),
173 .setup = setup,
174 .cleanup = cleanup,
175 .needs_tmpdir = 1,
176 .needs_root = 1,
177 };
178