1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) International Business Machines Corp., 2004 4 * Copyright (c) Linux Test Project, 2004-2017 5 */ 6 7/* 8 * DESCRIPTION 9 * hugeshmctl03 - check for EACCES, and EPERM errors 10 * 11 * ALGORITHM 12 * create a large shared memory segment with root only read & write 13 * permissions fork a child process 14 * if child 15 * set the ID of the child process to that of "ltpuser1" 16 * call do_child() 17 * loop if that option was specified 18 * call shmctl() using three different invalid cases 19 * check the errno value 20 * issue a PASS message if we get EACCES or EPERM 21 * otherwise, the tests fails 22 * issue a FAIL message 23 * call cleanup 24 * if parent 25 * wait for child to exit 26 * remove the large shared memory segment 27 * 28 * HISTORY 29 * 03/2001 - Written by Wayne Boyer 30 * 04/2004 - Updated by Robbie Williamson 31 * 32 * RESTRICTIONS 33 * test must be run as root 34 */ 35 36#include <sys/types.h> 37#include <sys/wait.h> 38#include <limits.h> 39#include "hugetlb.h" 40 41static size_t shm_size; 42static int shm_id_1 = -1; 43static struct shmid_ds buf; 44static uid_t test_uid; 45static char *test_user = "nobody"; 46 47static struct tcase { 48 int *shmid; 49 int cmd; 50 struct shmid_ds *sbuf; 51 int error; 52} tcases[] = { 53 /* EACCES - child has no read permission for segment */ 54 {&shm_id_1, IPC_STAT, &buf, EACCES}, 55 /* EPERM - IPC_SET - child doesn't have permission to change segment */ 56 {&shm_id_1, IPC_SET, &buf, EPERM}, 57 /* EPERM - IPC_RMID - child can not remove the segment */ 58 {&shm_id_1, IPC_RMID, &buf, EPERM}, 59}; 60 61static void do_child(void); 62 63static void test_hugeshmctl(void) 64{ 65 pid_t pid; 66 int status; 67 68 switch (pid = SAFE_FORK()) { 69 case 0: 70 /* set the user ID of the child to the non root user */ 71 SAFE_SETUID(test_uid); 72 do_child(); 73 exit(0); 74 default: 75 SAFE_WAITPID(pid, &status, 0); 76 } 77} 78 79static void do_child(void) 80{ 81 unsigned int i; 82 83 for (i = 0; i < ARRAY_SIZE(tcases); i++) { 84 TEST(shmctl(*(tcases[i].shmid), tcases[i].cmd, tcases[i].sbuf)); 85 if (TST_RET != -1) { 86 tst_res(TFAIL, "shmctl succeeded " 87 "unexpectedly"); 88 continue; 89 } 90 if (TST_ERR == tcases[i].error) 91 tst_res(TPASS | TTERRNO, "shmctl failed " 92 "as expected"); 93 else 94 tst_res(TFAIL | TTERRNO, "shmctl failed " 95 "unexpectedly - expect errno = " 96 "%d, got", tcases[i].error); 97 } 98} 99 100static void setup(void) 101{ 102 long hpage_size; 103 104 if (tst_hugepages == 0) 105 tst_brk(TCONF, "No enough hugepages for testing."); 106 107 hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024; 108 109 shm_size = hpage_size * tst_hugepages / 2; 110 update_shm_size(&shm_size); 111 shmkey = getipckey(); 112 shm_id_1 = shmget(shmkey, shm_size, 113 SHM_HUGETLB | IPC_CREAT | IPC_EXCL | SHM_RW); 114 if (shm_id_1 == -1) 115 tst_brk(TBROK | TERRNO, "shmget"); 116 117 /* get the userid for a non root user */ 118 test_uid = getuserid(test_user); 119} 120 121static void cleanup(void) 122{ 123 rm_shm(shm_id_1); 124} 125 126static struct tst_test test = { 127 .needs_root = 1, 128 .forks_child = 1, 129 .needs_tmpdir = 1, 130 .options = (struct tst_option[]) { 131 {"s:", &nr_opt, "Set the number of the been allocated hugepages"}, 132 {} 133 }, 134 .setup = setup, 135 .cleanup = cleanup, 136 .test_all = test_hugeshmctl, 137 .hugepages = {128, TST_REQUEST}, 138}; 139