1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) International Business Machines Corp., 2001 4f08c3bdfSopenharmony_ci * 03/2001 - Written by Wayne Boyer 5f08c3bdfSopenharmony_ci * 6f08c3bdfSopenharmony_ci * Copyright (c) 2008 Renaud Lottiaux (Renaud.Lottiaux@kerlabs.com) 7f08c3bdfSopenharmony_ci */ 8f08c3bdfSopenharmony_ci 9f08c3bdfSopenharmony_ci/*\ 10f08c3bdfSopenharmony_ci * [Description] 11f08c3bdfSopenharmony_ci * 12f08c3bdfSopenharmony_ci * Test for ENOENT, EEXIST, EINVAL, EACCES, EPERM errors. 13f08c3bdfSopenharmony_ci * 14f08c3bdfSopenharmony_ci * - ENOENT - No segment exists for the given key and IPC_CREAT was not specified. 15f08c3bdfSopenharmony_ci * - EEXIST - the segment exists and IPC_CREAT | IPC_EXCL is given. 16f08c3bdfSopenharmony_ci * - EINVAL - A new segment was to be created and size is less than SHMMIN or 17f08c3bdfSopenharmony_ci * greater than SHMMAX. Or a segment for the given key exists, but size is 18f08c3bdfSopenharmony_ci * gran eater than the size of that segment. 19f08c3bdfSopenharmony_ci * - EACCES - The user does not have permission to access the shared memory segment. 20f08c3bdfSopenharmony_ci * - EPERM - The SHM_HUGETLB flag was specified, but the caller was not 21f08c3bdfSopenharmony_ci * privileged (did not have the CAP_IPC_LOCK capability) and is not a member 22f08c3bdfSopenharmony_ci * of the sysctl_hugetlb_shm_group group. 23f08c3bdfSopenharmony_ci * - ENOMEM - The SHM_HUGETLB flag was specified, the caller was privileged but 24f08c3bdfSopenharmony_ci * not have enough hugepage memory space. 25f08c3bdfSopenharmony_ci */ 26f08c3bdfSopenharmony_ci 27f08c3bdfSopenharmony_ci#include <errno.h> 28f08c3bdfSopenharmony_ci#include <sys/types.h> 29f08c3bdfSopenharmony_ci#include <sys/ipc.h> 30f08c3bdfSopenharmony_ci#include <stdlib.h> 31f08c3bdfSopenharmony_ci#include <pwd.h> 32f08c3bdfSopenharmony_ci#include <sys/shm.h> 33f08c3bdfSopenharmony_ci#include <grp.h> 34f08c3bdfSopenharmony_ci#include "tst_safe_sysv_ipc.h" 35f08c3bdfSopenharmony_ci#include "tst_kconfig.h" 36f08c3bdfSopenharmony_ci#include "tst_test.h" 37f08c3bdfSopenharmony_ci#include "libnewipc.h" 38f08c3bdfSopenharmony_ci#include "lapi/shm.h" 39f08c3bdfSopenharmony_ci 40f08c3bdfSopenharmony_ci#define CONFIG_HUGETLBFS "CONFIG_HUGETLBFS" 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_cistatic int shm_id = -1; 43f08c3bdfSopenharmony_cistatic key_t shmkey, shmkey1; 44f08c3bdfSopenharmony_cistatic struct passwd *pw; 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_cistatic struct tcase { 47f08c3bdfSopenharmony_ci int *shmkey; 48f08c3bdfSopenharmony_ci size_t size; 49f08c3bdfSopenharmony_ci int flags; 50f08c3bdfSopenharmony_ci /*1: nobody expected 0: root expected */ 51f08c3bdfSopenharmony_ci int exp_user; 52f08c3bdfSopenharmony_ci /*1: nobody expected 0: root expected */ 53f08c3bdfSopenharmony_ci int exp_group; 54f08c3bdfSopenharmony_ci int exp_err; 55f08c3bdfSopenharmony_ci} tcases[] = { 56f08c3bdfSopenharmony_ci {&shmkey1, SHM_SIZE, IPC_EXCL, 0, 0, ENOENT}, 57f08c3bdfSopenharmony_ci {&shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL, 0, 0, EEXIST}, 58f08c3bdfSopenharmony_ci {&shmkey1, SHMMIN - 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL}, 59f08c3bdfSopenharmony_ci {&shmkey1, 8192 + 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL}, 60f08c3bdfSopenharmony_ci {&shmkey, SHM_SIZE * 2, IPC_EXCL, 0, 0, EINVAL}, 61f08c3bdfSopenharmony_ci {&shmkey, SHM_SIZE, SHM_RD, 1, 0, EACCES}, 62f08c3bdfSopenharmony_ci {&shmkey1, SHM_SIZE, IPC_CREAT | SHM_HUGETLB, 0, 1, EPERM}, 63f08c3bdfSopenharmony_ci {&shmkey1, SHM_SIZE, IPC_CREAT | SHM_HUGETLB, 0, 0, ENOMEM} 64f08c3bdfSopenharmony_ci}; 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_cistatic int get_hugetlb_exp_error(void) 67f08c3bdfSopenharmony_ci{ 68f08c3bdfSopenharmony_ci long tmp; 69f08c3bdfSopenharmony_ci struct tst_kconfig_var kconfig = { 70f08c3bdfSopenharmony_ci .id = CONFIG_HUGETLBFS, 71f08c3bdfSopenharmony_ci .id_len = sizeof(CONFIG_HUGETLBFS)-1, 72f08c3bdfSopenharmony_ci }; 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci tst_kconfig_read(&kconfig, 1); 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_ci if (kconfig.choice != 'y') { 77f08c3bdfSopenharmony_ci tst_res(TINFO, "SHM_HUGETLB not supported by kernel"); 78f08c3bdfSopenharmony_ci return EINVAL; 79f08c3bdfSopenharmony_ci } 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci if (FILE_LINES_SCANF("/proc/meminfo", "Hugepagesize: %ld", &tmp)) { 82f08c3bdfSopenharmony_ci tst_res(TINFO, "Huge pages not supported by hardware"); 83f08c3bdfSopenharmony_ci return ENOENT; 84f08c3bdfSopenharmony_ci } 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci return 0; 87f08c3bdfSopenharmony_ci} 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_cistatic void do_test(unsigned int n) 90f08c3bdfSopenharmony_ci{ 91f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[n]; 92f08c3bdfSopenharmony_ci pid_t pid; 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_ci if (tc->exp_user == 0 && tc->exp_group == 0) { 95f08c3bdfSopenharmony_ci TST_EXP_FAIL2(shmget(*tc->shmkey, tc->size, tc->flags), tc->exp_err, 96f08c3bdfSopenharmony_ci "shmget(%i, %lu, %i)", *tc->shmkey, tc->size, tc->flags); 97f08c3bdfSopenharmony_ci return; 98f08c3bdfSopenharmony_ci } 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_ci pid = SAFE_FORK(); 101f08c3bdfSopenharmony_ci if (pid == 0) { 102f08c3bdfSopenharmony_ci if (tc->exp_group) { 103f08c3bdfSopenharmony_ci SAFE_SETGROUPS(0, NULL); 104f08c3bdfSopenharmony_ci SAFE_SETGID(pw->pw_gid); 105f08c3bdfSopenharmony_ci } 106f08c3bdfSopenharmony_ci SAFE_SETUID(pw->pw_uid); 107f08c3bdfSopenharmony_ci TST_EXP_FAIL2(shmget(*tc->shmkey, tc->size, tc->flags), tc->exp_err, 108f08c3bdfSopenharmony_ci "shmget(%i, %lu, %i)", *tc->shmkey, tc->size, tc->flags); 109f08c3bdfSopenharmony_ci exit(0); 110f08c3bdfSopenharmony_ci } 111f08c3bdfSopenharmony_ci tst_reap_children(); 112f08c3bdfSopenharmony_ci} 113f08c3bdfSopenharmony_ci 114f08c3bdfSopenharmony_cistatic void setup(void) 115f08c3bdfSopenharmony_ci{ 116f08c3bdfSopenharmony_ci struct rlimit rl = { 0, 0 }; 117f08c3bdfSopenharmony_ci int hugetlb_errno; 118f08c3bdfSopenharmony_ci unsigned int i; 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_ci shmkey = GETIPCKEY(); 121f08c3bdfSopenharmony_ci shmkey1 = GETIPCKEY(); 122f08c3bdfSopenharmony_ci 123f08c3bdfSopenharmony_ci SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &rl); 124f08c3bdfSopenharmony_ci shm_id = SAFE_SHMGET(shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL); 125f08c3bdfSopenharmony_ci pw = SAFE_GETPWNAM("nobody"); 126f08c3bdfSopenharmony_ci hugetlb_errno = get_hugetlb_exp_error(); 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_ci if (!hugetlb_errno) 129f08c3bdfSopenharmony_ci return; 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci for (i = 0; i < ARRAY_SIZE(tcases); i++) { 132f08c3bdfSopenharmony_ci if (tcases[i].flags & SHM_HUGETLB) 133f08c3bdfSopenharmony_ci tcases[i].exp_err = hugetlb_errno; 134f08c3bdfSopenharmony_ci } 135f08c3bdfSopenharmony_ci} 136f08c3bdfSopenharmony_ci 137f08c3bdfSopenharmony_cistatic void cleanup(void) 138f08c3bdfSopenharmony_ci{ 139f08c3bdfSopenharmony_ci if (shm_id >= 0) 140f08c3bdfSopenharmony_ci SAFE_SHMCTL(shm_id, IPC_RMID, NULL); 141f08c3bdfSopenharmony_ci} 142f08c3bdfSopenharmony_ci 143f08c3bdfSopenharmony_cistatic struct tst_test test = { 144f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 145f08c3bdfSopenharmony_ci .needs_root = 1, 146f08c3bdfSopenharmony_ci .forks_child = 1, 147f08c3bdfSopenharmony_ci .setup = setup, 148f08c3bdfSopenharmony_ci .cleanup = cleanup, 149f08c3bdfSopenharmony_ci .test = do_test, 150f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 151f08c3bdfSopenharmony_ci .hugepages = {TST_NO_HUGEPAGES}, 152f08c3bdfSopenharmony_ci .save_restore = (const struct tst_path_val[]) { 153f08c3bdfSopenharmony_ci {"/proc/sys/kernel/shmmax", "8192", TST_SR_TCONF_MISSING | TST_SR_TBROK_RO}, 154f08c3bdfSopenharmony_ci {} 155f08c3bdfSopenharmony_ci }, 156f08c3bdfSopenharmony_ci}; 157