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