1 /* 2 * Copyright (c) 2005, Bull S.A.. All rights reserved. 3 * Created by: Sebastien Decugis 4 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 * 13 * You should have received a copy of the GNU General Public License along 14 * with this program; if not, write the Free Software Foundation, Inc., 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 17 * This sample test aims to check the following assertion: 18 * 19 * sem_unlink will return -1 and set errno to EACCESS if the process has not 20 * priviledge to unlink the sem. 21 22 * The steps are: 23 * -> open a semaphore with 0744 mask 24 * -> fork 25 * -> change child uid 26 * -> child attempts to unlink the semaphore. It should fail. 27 * -> join the child 28 * -> sem_unlink (should be OK) 29 30 * The test fails if the child process is able to unlink the semaphore. 31 32 */ 33 34 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 35 #define _POSIX_C_SOURCE 200112L 36 37 /* Some of the routines are XSI extensions */ 38 #define _XOPEN_SOURCE 600 39 40 /******************************************************************************/ 41 /*************************** standard includes ********************************/ 42 /******************************************************************************/ 43 #include <pthread.h> 44 #include <stdarg.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 #include <pwd.h> 51 #include <semaphore.h> 52 #include <errno.h> 53 #include <fcntl.h> 54 #include <sys/wait.h> 55 56 /******************************************************************************/ 57 /*************************** Test framework *******************************/ 58 /******************************************************************************/ 59 #include "../testfrmw/testfrmw.h" 60 #include "../testfrmw/testfrmw.c" 61 /* This header is responsible for defining the following macros: 62 * UNRESOLVED(ret, descr); 63 * where descr is a description of the error and ret is an int 64 * (error code for example) 65 * FAILED(descr); 66 * where descr is a short text saying why the test has failed. 67 * PASSED(); 68 * No parameter. 69 * 70 * Both three macros shall terminate the calling process. 71 * The testcase shall not terminate in any other maneer. 72 * 73 * The other file defines the functions 74 * void output_init() 75 * void output(char * string, ...) 76 * 77 * Those may be used to output information. 78 */ 79 80 /******************************************************************************/ 81 /**************************** Configuration ***********************************/ 82 /******************************************************************************/ 83 #ifndef VERBOSE 84 #define VERBOSE 1 85 #endif 86 87 #define SEM_NAME "/sem_unlink_3_1" 88 89 /******************************************************************************/ 90 /*************************** Test case ***********************************/ 91 /******************************************************************************/ 92 93 /* Set the euid of this process to a non-root uid */ 94 /* (from ../sem_open/3-1.c) */ 95 int set_nonroot() 96 { 97 98 struct passwd *pw; 99 setpwent(); 100 /* search for the first user which is non root */ 101 102 while ((pw = getpwent()) != NULL) 103 if (strcmp(pw->pw_name, "root")) 104 break; 105 106 endpwent(); 107 108 if (pw == NULL) { 109 output("There is no other user than current and root.\n"); 110 return 1; 111 } 112 113 if (seteuid(pw->pw_uid) != 0) { 114 if (errno == EPERM) { 115 output 116 ("You don't have permission to change your UID.\n"); 117 return 1; 118 } 119 120 perror("An error occurs when calling seteuid()"); 121 return 1; 122 } 123 124 output("Testing with user '%s' (uid: %d)\n", 125 pw->pw_name, (int)geteuid()); 126 return 0; 127 } 128 129 /* The main test function. */ 130 int main(void) 131 { 132 int ret, status; 133 pid_t ch, ctl; 134 sem_t *sem; 135 136 /* Initialize output */ 137 output_init(); 138 139 /* Create the semaphore */ 140 sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, 0744, 1); 141 142 if ((sem == SEM_FAILED) && (errno == EEXIST)) { 143 sem_unlink(SEM_NAME); 144 sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, 0744, 1); 145 } 146 147 if (sem == SEM_FAILED) { 148 UNRESOLVED(errno, "Failed to create the semaphore"); 149 } 150 151 /* fork */ 152 ch = fork(); 153 154 if (ch == -1) { 155 UNRESOLVED(errno, "Failed to fork"); 156 } 157 158 if (ch == 0) { /* child */ 159 /* connect to the semaphore */ 160 sem = sem_open(SEM_NAME, 0); 161 162 if (sem == SEM_FAILED) { 163 output 164 ("Failed to connect to the semaphore, error %d: %s\n", 165 errno, strerror(errno)); 166 exit(1); 167 } 168 169 /* change euid */ 170 ret = set_nonroot(); 171 172 if (ret) { 173 output("Changing euid failed\n"); 174 exit(1); 175 } 176 177 /* try and unlink, it should fail */ 178 ret = sem_unlink(SEM_NAME); 179 180 if (ret == 0) { 181 output("sem_unlink did not fail in child"); 182 exit(2); 183 } 184 185 if (errno != EACCES) { 186 output 187 ("sem_unlink failed with unexpected error %d: %s\n", 188 errno, strerror(errno)); 189 exit(2); 190 } 191 192 /* Ok, child is done. */ 193 exit(0); 194 } 195 196 /* Parent waits for the child to finish */ 197 ctl = waitpid(ch, &status, 0); 198 199 if (ctl != ch) { 200 UNRESOLVED(errno, "Waitpid returned the wrong PID"); 201 } 202 203 if (!WIFEXITED(status)) { 204 FAILED("Child exited abnormally"); 205 } 206 207 if (WEXITSTATUS(status) == 1) { 208 UNRESOLVED(0, "An error occured in child"); 209 } 210 211 if (WEXITSTATUS(status) == 2) { 212 FAILED("Test failed in child"); 213 } 214 215 if (WEXITSTATUS(status) != 0) { 216 UNRESOLVED(0, "Unexpected return value from child"); 217 } 218 219 /* Unlink */ 220 ret = sem_unlink(SEM_NAME); 221 222 if (ret != 0) { 223 UNRESOLVED(errno, "Failed to unlink the semaphore"); 224 } 225 226 /* Test passed */ 227 #if VERBOSE > 0 228 output("Test passed\n"); 229 230 #endif 231 PASSED; 232 } 233