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 }