1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2015 Garrett D'Amore <garrett@damore.org> 14 */ 15 16 /* 17 * This program tests that fexecve works properly. 18 */ 19 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <fcntl.h> 24 #include <err.h> 25 #include <errno.h> 26 #include <unistd.h> 27 #include <note.h> 28 #include <sys/utsname.h> 29 #include <sys/wait.h> 30 #include "test_common.h" 31 32 int extra_debug = 0; 33 34 struct utsname un; 35 36 void 37 forkit(char *msg, const char *expect, void (*postfn)(void)) 38 { 39 int fd; 40 FILE *f; 41 pid_t pid; 42 char *ptr = NULL; 43 size_t cap = 0; 44 int wstat; 45 int rv; 46 test_t t; 47 char fname[32]; 48 49 (void) strcpy(fname, "/tmp/testXXXXXX"); 50 t = test_start(msg); 51 52 fd = mkstemp(fname); 53 if (fd < 0) { 54 test_failed(t, "mkstemp failed: %s", strerror(errno)); 55 return; 56 } 57 58 /* don't leave it in the filesystem */ 59 (void) unlink(fname); 60 61 pid = vfork(); 62 switch (pid) { 63 case -1: 64 test_failed(t, "vfork failed: %s", strerror(errno)); 65 return; 66 case 0: 67 if (dup2(fd, 1) < 0) { 68 test_failed(t, "dup2 failed: %s", strerror(errno)); 69 exit(9); 70 } 71 postfn(); 72 exit(0); 73 default: 74 break; 75 } 76 77 /* parent */ 78 f = fdopen(fd, "r"); 79 if (f == NULL) { 80 (void) close(fd); 81 test_failed(t, "fdopen failed: %s", strerror(errno)); 82 (void) wait(NULL); 83 return; 84 } 85 if (waitpid(pid, &wstat, NULL) < 0) { 86 test_failed(t, "wait failed: %s", strerror(errno)); 87 (void) fclose(f); 88 return; 89 } 90 if (!WIFEXITED(wstat) || WEXITSTATUS(wstat) != 0) { 91 test_failed(t, "child failed: %#x", wstat); 92 (void) fclose(f); 93 return; 94 } 95 (void) lseek(fd, 0, SEEK_SET); 96 if ((rv = getline(&ptr, &cap, f)) < 1) { 97 test_failed(t, "child gave no data: %d", rv); 98 (void) fclose(f); 99 return; 100 } 101 (void) fclose(f); 102 103 if (strncmp(ptr, expect, strlen(expect)) != 0) { 104 test_failed(t, "%s != %s", ptr, expect); 105 return; 106 } 107 108 (void) free(ptr); 109 test_passed(t); 110 } 111 112 void 113 case_badf(void) 114 { 115 int fd = -1; 116 int rv; 117 char *args[] = { "uname", NULL }; 118 char *env[] = { NULL }; 119 120 rv = fexecve(fd, args, env); 121 if (rv != -1) { 122 (void) printf("rv is not -1\n"); 123 (void) exit(0); 124 } 125 if (errno != EBADF) { 126 (void) printf("err %d(%s) != EBADF\n", errno, strerror(errno)); 127 (void) exit(0); 128 } 129 (void) printf("GOOD\n"); 130 (void) exit(0); 131 } 132 133 void 134 case_notexec(void) 135 { 136 int fd; 137 int rv; 138 char *args[] = { "uname", NULL }; 139 char *env[] = { NULL }; 140 141 fd = open("/usr/bin/uname", O_RDONLY); 142 143 rv = fexecve(fd, args, env); 144 if (rv != -1) { 145 (void) printf("rv is not -1\n"); 146 (void) exit(0); 147 } 148 (void) printf("FAILURE\n"); 149 (void) exit(0); 150 } 151 152 void 153 case_uname(void) 154 { 155 int fd; 156 char *args[] = { "uname", NULL }; 157 char *env[] = { NULL }; 158 159 fd = open("/usr/bin/uname", O_EXEC); 160 if (fd < 0) { 161 (void) printf("failed to open /usr/bin/uname: %s", 162 strerror(errno)); 163 (void) exit(0); 164 } 165 166 (void) fexecve(fd, args, env); 167 (void) printf("EXEC FAILED: %s\n", strerror(errno)); 168 (void) exit(0); 169 } 170 171 void 172 case_uname_r(void) 173 { 174 int fd; 175 char *args[] = { "uname", "-r", NULL }; 176 char *env[] = { NULL }; 177 178 fd = open("/usr/bin/uname", O_EXEC); 179 if (fd < 0) { 180 (void) printf("failed to open /usr/bin/uname: %s", 181 strerror(errno)); 182 (void) exit(0); 183 } 184 185 (void) fexecve(fd, args, env); 186 (void) printf("EXEC FAILED: %s\n", strerror(errno)); 187 (void) exit(0); 188 } 189 190 void 191 test_fexecve_badf(void) 192 { 193 forkit("fexecve (bad FD)", "GOOD\n", case_badf); 194 } 195 196 void 197 test_fexecve_notexec(void) 198 { 199 forkit("fexecve (not O_EXEC)", un.sysname, case_notexec); 200 } 201 202 void 203 test_fexecve_uname(void) 204 { 205 forkit("fexecve (uname)", un.sysname, case_uname); 206 } 207 208 void 209 test_fexecve_uname_r(void) 210 { 211 forkit("fexecve (uname)", un.release, case_uname_r); 212 } 213 214 int 215 main(int argc, char **argv) 216 { 217 int optc; 218 219 (void) uname(&un); 220 221 while ((optc = getopt(argc, argv, "dfD")) != EOF) { 222 switch (optc) { 223 case 'd': 224 test_set_debug(); 225 break; 226 case 'f': 227 test_set_force(); 228 break; 229 case 'D': 230 test_set_debug(); 231 extra_debug++; 232 break; 233 default: 234 (void) fprintf(stderr, "Usage: %s [-dfD]\n", argv[0]); 235 exit(1); 236 } 237 } 238 239 test_fexecve_badf(); 240 test_fexecve_notexec(); 241 test_fexecve_uname(); 242 test_fexecve_uname_r(); 243 244 exit(0); 245 }