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 * kill05.c 23 * 24 * DESCRIPTION 25 * Test case to check that kill() fails when passed a pid owned by another 26 * user. 27 * 28 * ALGORITHM 29 * call setup 30 * loop if the -i option was given 31 * setup a shared memory segment to for a flag which will notify 32 * ltpuser1's process that life is not worth living in a continuous loop. 33 * fork a child and set the euid to ltpuser1 34 * set the parents euid to ltpuser2 35 * execute the kill system call on ltpuser1's pid 36 * check the return value 37 * if return value is not -1 38 * issue a FAIL message, break remaining tests and cleanup 39 * if we are doing functional testing 40 * if the errno was set to 1 (Operation not permitted) 41 * issue a PASS message 42 * otherwise 43 * issue a FAIL message 44 * call cleanup 45 * 46 * USAGE 47 * kill05 [-c n] [-e] [-i n] [-I x] [-P x] [-t] 48 * where, -c n : Run n copies concurrently. 49 * -e : Turn on errno logging. 50 * -i n : Execute test n times. 51 * -I x : Execute test for x seconds. 52 * -P x : Pause for x seconds between iterations. 53 * -t : Turn on syscall timing. 54 * 55 * HISTORY 56 * 07/2001 Ported by Wayne Boyer 57 * 58 * 26/02/2008 Renaud Lottiaux (Renaud.Lottiaux (at) kerlabs.com) 59 * - Fix wrong return value check on shmat system call (leading to 60 * segfault in case of error with this syscall). 61 * - Fix deletion of IPC memory segment. Segment was not correctly 62 * deleted due to the change of uid during the test. 63 * 64 * RESTRICTIONS 65 * This test must be run as root. 66 * Looping with the -i option does not work correctly. 67 */ 68 69 #include <sys/types.h> 70 #include <sys/ipc.h> 71 #include <sys/shm.h> 72 #include <sys/wait.h> 73 #include <errno.h> 74 #include <pwd.h> 75 #include <signal.h> 76 #include <string.h> 77 #include <stdio.h> 78 #include <stdlib.h> 79 #include <unistd.h> 80 81 #include "test.h" 82 #include "safe_macros.h" 83 84 extern void rm_shm(int); 85 86 void cleanup(void); 87 void setup(void); 88 void do_child(void); 89 void do_master_child(char **av); 90 91 char *TCID = "kill05"; 92 int TST_TOTAL = 1; 93 int shmid1 = -1; 94 extern key_t semkey; 95 int *flag; 96 97 extern int getipckey(); 98 99 #define TEST_SIG SIGKILL 100 101 int main(int ac, char **av) 102 { 103 pid_t pid; 104 int status; 105 106 tst_parse_opts(ac, av, NULL, NULL); 107 #ifdef UCLINUX 108 maybe_run_child(&do_child, ""); 109 #endif 110 111 setup(); /* global setup */ 112 113 pid = FORK_OR_VFORK(); 114 if (pid == -1) 115 tst_brkm(TBROK, cleanup, "Fork failed"); 116 else if (pid == 0) 117 do_master_child(av); 118 119 if (waitpid(pid, &status, 0) == -1) 120 tst_resm(TBROK | TERRNO, "waitpid failed"); 121 else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 122 tst_resm(TFAIL, "child exited abnormally"); 123 else 124 tst_resm(TPASS, "received expected errno(EPERM)"); 125 cleanup(); 126 tst_exit(); 127 } 128 129 void wait_for_flag(int value) 130 { 131 while (1) { 132 if (*flag == value) 133 break; 134 else 135 sleep(1); 136 } 137 } 138 139 /* 140 * do_master_child() 141 */ 142 void do_master_child(char **av) 143 { 144 pid_t pid1; 145 int status; 146 147 char user1name[] = "nobody"; 148 char user2name[] = "bin"; 149 150 struct passwd *ltpuser1, *ltpuser2; 151 152 tst_count = 0; 153 154 *flag = 0; 155 156 pid1 = FORK_OR_VFORK(); 157 158 if (pid1 == -1) 159 tst_brkm(TBROK | TERRNO, cleanup, "Fork failed"); 160 161 if (pid1 == 0) { 162 ltpuser1 = SAFE_GETPWNAM(NULL, user1name); 163 if (setreuid(ltpuser1->pw_uid, ltpuser1->pw_uid) == -1) { 164 perror("setreuid failed (in child)"); 165 exit(1); 166 } 167 *flag = 1; 168 #ifdef UCLINUX 169 if (self_exec(av[0], "") < 0) { 170 perror("self_exec failed"); 171 exit(1); 172 } 173 #else 174 do_child(); 175 #endif 176 } 177 ltpuser2 = SAFE_GETPWNAM(NULL, user2name); 178 if (setreuid(ltpuser2->pw_uid, ltpuser2->pw_uid) == -1) { 179 perror("seteuid failed"); 180 exit(1); 181 } 182 183 /* wait until child sets its euid */ 184 wait_for_flag(1); 185 186 TEST(kill(pid1, TEST_SIG)); 187 188 /* signal the child that we're done */ 189 *flag = 2; 190 191 if (waitpid(pid1, &status, 0) == -1) { 192 perror("waitpid failed"); 193 exit(1); 194 } 195 196 if (TEST_RETURN != -1) { 197 printf("kill succeeded unexpectedly\n"); 198 exit(1); 199 } 200 201 /* 202 * Check to see if the errno was set to the expected 203 * value of 1 : EPERM 204 */ 205 if (TEST_ERRNO == EPERM) { 206 printf("kill failed with EPERM\n"); 207 exit(0); 208 } 209 perror("kill failed unexpectedly"); 210 exit(1); 211 } 212 213 void do_child(void) 214 { 215 wait_for_flag(2); 216 exit(0); 217 } 218 219 void setup(void) 220 { 221 tst_require_root(); 222 223 TEST_PAUSE; 224 225 tst_tmpdir(); 226 227 semkey = getipckey(); 228 229 if ((shmid1 = shmget(semkey, getpagesize(), 0666 | IPC_CREAT)) == -1) 230 tst_brkm(TBROK, cleanup, "Failed to setup shared memory"); 231 232 if ((flag = shmat(shmid1, 0, 0)) == (int *)-1) 233 tst_brkm(TBROK | TERRNO, cleanup, 234 "Failed to attach shared memory:%d", shmid1); 235 } 236 237 void cleanup(void) 238 { 239 rm_shm(shmid1); 240 241 tst_rmdir(); 242 } 243