1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * NAME 22 * shmctl02.c 23 * 24 * DESCRIPTION 25 * shmctl02 - check for EACCES, EFAULT and EINVAL errors 26 * 27 * ALGORITHM 28 * create a shared memory segment without read or write permissions 29 * create a shared memory segment with read & write permissions 30 * loop if that option was specified 31 * call shmctl() using five different invalid cases 32 * check the errno value 33 * issue a PASS message if we get EACCES, EFAULT or EINVAL 34 * otherwise, the tests fails 35 * issue a FAIL message 36 * call cleanup 37 * 38 * USAGE: <for command-line> 39 * shmctl02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 40 * where, -c n : Run n copies concurrently. 41 * -e : Turn on errno logging. 42 * -i n : Execute test n times. 43 * -I x : Execute test for x seconds. 44 * -P x : Pause for x seconds between iterations. 45 * -t : Turn on syscall timing. 46 * 47 * HISTORY 48 * 03/2001 - Written by Wayne Boyer 49 * 50 * 06/03/2008 Renaud Lottiaux (Renaud.Lottiaux (at) kerlabs.com) 51 * - Fix concurrency issue. The second key used for this test could 52 * conflict with the key from another task. 53 * 54 * RESTRICTIONS 55 * none 56 */ 57 58 #include "ipcshm.h" 59 #include <pwd.h> 60 61 char *TCID = "shmctl02"; 62 char nobody_uid[] = "nobody"; 63 struct passwd *ltpuser; 64 65 int shm_id_1 = -1; 66 int shm_id_2 = -1; 67 int shm_id_3 = -1; 68 69 struct shmid_ds buf; 70 71 struct test_case_t { 72 int *shmid; 73 int cmd; 74 struct shmid_ds *sbuf; 75 int error; 76 } TC[] = { 77 /* EACCES - segment has no read or write permissions */ 78 { 79 &shm_id_1, IPC_STAT, &buf, EACCES}, 80 /* EFAULT - IPC_SET & buf isn't valid */ 81 { 82 &shm_id_2, IPC_SET, (struct shmid_ds *)-1, EFAULT}, 83 /* EFAULT - IPC_STAT & buf isn't valid */ 84 { 85 &shm_id_2, IPC_STAT, (struct shmid_ds *)-1, EFAULT}, 86 /* EINVAL - the shmid is not valid */ 87 { 88 &shm_id_3, IPC_STAT, &buf, EINVAL}, 89 /* EINVAL - the command is not valid */ 90 { 91 &shm_id_2, -1, &buf, EINVAL}, 92 /* EPERM - the command is only valid for the super-user */ 93 { 94 &shm_id_2, SHM_LOCK, &buf, EPERM}, 95 /* EPERM - the command is only valid for the super-user */ 96 { 97 &shm_id_2, SHM_UNLOCK, &buf, EPERM} 98 }; 99 100 int TST_TOTAL = ARRAY_SIZE(TC); 101 102 int main(int ac, char **av) 103 { 104 int lc; 105 int i; 106 107 tst_parse_opts(ac, av, NULL, NULL); 108 109 setup(); /* global setup */ 110 111 /* The following loop checks looping state if -i option given */ 112 113 for (lc = 0; TEST_LOOPING(lc); lc++) { 114 /* reset tst_count in case we are looping */ 115 tst_count = 0; 116 117 /* loop through the test cases */ 118 for (i = 0; i < TST_TOTAL; i++) { 119 /* 120 * use the TEST() macro to make the call 121 */ 122 123 TEST(shmctl(*(TC[i].shmid), TC[i].cmd, TC[i].sbuf)); 124 125 if ((TEST_RETURN != -1) && (i < 5)) { 126 tst_resm(TFAIL, "call succeeded unexpectedly"); 127 continue; 128 } 129 130 if (TEST_ERRNO == TC[i].error) { 131 tst_resm(TPASS, "expected failure - errno = " 132 "%d : %s", TEST_ERRNO, 133 strerror(TEST_ERRNO)); 134 } else { 135 if (i >= 5) 136 tst_resm(TCONF, 137 "shmctl() did not fail for non-root user." 138 "This may be okay for your distribution."); 139 else 140 tst_resm(TFAIL, "call failed with an " 141 "unexpected error - %d : %s", 142 TEST_ERRNO, 143 strerror(TEST_ERRNO)); 144 } 145 } 146 } 147 148 cleanup(); 149 150 tst_exit(); 151 } 152 153 /* 154 * setup() - performs all the ONE TIME setup for this test. 155 */ 156 void setup(void) 157 { 158 key_t shmkey2; 159 160 tst_require_root(); 161 162 /* Switch to nobody user for correct error code collection */ 163 ltpuser = getpwnam(nobody_uid); 164 if (setuid(ltpuser->pw_uid) == -1) { 165 tst_resm(TINFO, "setuid failed to " 166 "to set the effective uid to %d", ltpuser->pw_uid); 167 perror("setuid"); 168 } 169 170 tst_sig(NOFORK, DEF_HANDLER, cleanup); 171 172 TEST_PAUSE; 173 174 /* 175 * Create a temporary directory and cd into it. 176 * This helps to ensure that a unique msgkey is created. 177 * See ../lib/libipc.c for more information. 178 */ 179 tst_tmpdir(); 180 181 /* get an IPC resource key */ 182 shmkey = getipckey(); 183 184 /* create a shared memory segment without read or write permissions */ 185 if ((shm_id_1 = shmget(shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL)) == -1) { 186 tst_brkm(TBROK, cleanup, "couldn't create shared memory " 187 "segment #1 in setup()"); 188 } 189 190 /* Get an new IPC resource key. */ 191 shmkey2 = getipckey(); 192 193 /* create a shared memory segment with read and write permissions */ 194 if ((shm_id_2 = shmget(shmkey2, SHM_SIZE, IPC_CREAT | IPC_EXCL | 195 SHM_RW)) == -1) { 196 tst_brkm(TBROK, cleanup, "couldn't create shared memory " 197 "segment #2 in setup()"); 198 } 199 } 200 201 /* 202 * cleanup() - performs all the ONE TIME cleanup for this test at completion 203 * or premature exit. 204 */ 205 void cleanup(void) 206 { 207 /* if they exist, remove the shared memory resources */ 208 rm_shm(shm_id_1); 209 rm_shm(shm_id_2); 210 211 tst_rmdir(); 212 213 } 214