1 /* $OpenBSD: exec.c,v 1.25 2023/09/06 03:51:20 jsg Exp $ */
2 /*-
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/types.h>
32 #include <sys/uio.h>
33 #include <sys/mman.h>
34
35 #include <errno.h>
36 #include <limits.h>
37 #include <paths.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43
44 int
execl(const char * name,const char * arg,...)45 execl(const char *name, const char *arg, ...)
46 {
47 va_list ap;
48 char **argv;
49 size_t maplen;
50 int save_errno, n, error;
51
52 va_start(ap, arg);
53 n = 1;
54 while (va_arg(ap, char *) != NULL)
55 n++;
56 va_end(ap);
57
58 maplen = (n + 1) * sizeof(*argv);
59 argv = mmap(NULL, maplen, PROT_WRITE|PROT_READ,
60 MAP_ANON|MAP_PRIVATE, -1, 0);
61 if (argv == MAP_FAILED)
62 return (-1);
63
64 va_start(ap, arg);
65 n = 1;
66 argv[0] = (char *)arg;
67 while ((argv[n] = va_arg(ap, char *)) != NULL)
68 n++;
69 va_end(ap);
70
71 error = execve(name, argv, environ);
72 save_errno = errno;
73 munmap(argv, maplen);
74 errno = save_errno;
75 return (error);
76 }
77 DEF_WEAK(execl);
78
79 int
execle(const char * name,const char * arg,...)80 execle(const char *name, const char *arg, ...)
81 {
82 va_list ap;
83 char **argv, **envp;
84 size_t maplen;
85 int save_errno, n, error;
86
87 va_start(ap, arg);
88 n = 1;
89 while (va_arg(ap, char *) != NULL)
90 n++;
91 va_end(ap);
92
93 maplen = (n + 1) * sizeof(*argv);
94 argv = mmap(NULL, maplen, PROT_WRITE|PROT_READ,
95 MAP_ANON|MAP_PRIVATE, -1, 0);
96 if (argv == MAP_FAILED)
97 return (-1);
98
99 va_start(ap, arg);
100 n = 1;
101 argv[0] = (char *)arg;
102 while ((argv[n] = va_arg(ap, char *)) != NULL)
103 n++;
104 envp = va_arg(ap, char **);
105 va_end(ap);
106
107 error = execve(name, argv, envp);
108 save_errno = errno;
109 munmap(argv, maplen);
110 errno = save_errno;
111 return error;
112 }
113
114 int
execlp(const char * name,const char * arg,...)115 execlp(const char *name, const char *arg, ...)
116 {
117 va_list ap;
118 char **argv;
119 size_t maplen;
120 int save_errno, n, error;
121
122 va_start(ap, arg);
123 n = 1;
124 while (va_arg(ap, char *) != NULL)
125 n++;
126 va_end(ap);
127
128 maplen = (n + 1) * sizeof(*argv);
129 argv = mmap(NULL, maplen, PROT_WRITE|PROT_READ,
130 MAP_ANON|MAP_PRIVATE, -1, 0);
131 if (argv == MAP_FAILED)
132 return (-1);
133
134 va_start(ap, arg);
135 n = 1;
136 argv[0] = (char *)arg;
137 while ((argv[n] = va_arg(ap, char *)) != NULL)
138 n++;
139 va_end(ap);
140 error = execvp(name, argv);
141 save_errno = errno;
142 munmap(argv, maplen);
143 errno = save_errno;
144 return error;
145 }
146
147 int
execv(const char * name,char * const * argv)148 execv(const char *name, char *const *argv)
149 {
150 (void)execve(name, argv, environ);
151 return (-1);
152 }
153
154 int
execvpe(const char * name,char * const * argv,char * const * envp)155 execvpe(const char *name, char *const *argv, char *const *envp)
156 {
157 char **memp;
158 int cnt;
159 size_t lp, ln, curlen;
160 char *p;
161 int eacces = 0;
162 char *bp, *cur, *path, buf[PATH_MAX];
163 size_t maplen;
164 int save_errno;
165
166 /*
167 * Do not allow null name
168 */
169 if (name == NULL || *name == '\0') {
170 errno = ENOENT;
171 return (-1);
172 }
173
174 /* If it's an absolute or relative path name, it's easy. */
175 if (strchr(name, '/')) {
176 bp = (char *)name;
177 cur = path = NULL;
178 goto retry;
179 }
180 bp = buf;
181
182 /* Get the path we're searching. */
183 if (!(path = getenv("PATH")))
184 path = _PATH_DEFPATH;
185
186 curlen = strlen(path) + 1;
187 cur = mmap(NULL, curlen, PROT_WRITE|PROT_READ,
188 MAP_ANON|MAP_PRIVATE, -1, 0);
189 if (cur == MAP_FAILED)
190 return (-1);
191
192 strlcpy(cur, path, curlen);
193 path = cur;
194 while ((p = strsep(&cur, ":"))) {
195 /*
196 * It's a SHELL path -- double, leading and trailing colons
197 * mean the current directory.
198 */
199 if (!*p) {
200 p = ".";
201 lp = 1;
202 } else
203 lp = strlen(p);
204 ln = strlen(name);
205
206 /*
207 * If the path is too long complain. This is a possible
208 * security issue; given a way to make the path too long
209 * the user may execute the wrong program.
210 */
211 if (lp + ln + 2 > sizeof(buf)) {
212 struct iovec iov[3];
213
214 iov[0].iov_base = "execvp: ";
215 iov[0].iov_len = 8;
216 iov[1].iov_base = p;
217 iov[1].iov_len = lp;
218 iov[2].iov_base = ": path too long\n";
219 iov[2].iov_len = 16;
220 (void)writev(STDERR_FILENO, iov, 3);
221 continue;
222 }
223 bcopy(p, buf, lp);
224 buf[lp] = '/';
225 bcopy(name, buf + lp + 1, ln);
226 buf[lp + ln + 1] = '\0';
227
228 retry: (void)execve(bp, argv, envp);
229 switch(errno) {
230 case E2BIG:
231 goto done;
232 case EISDIR:
233 case ELOOP:
234 case ENAMETOOLONG:
235 case ENOENT:
236 break;
237 case ENOEXEC:
238 for (cnt = 0; argv[cnt]; ++cnt)
239 ;
240
241 maplen = (cnt + 2) * sizeof(char *);
242 memp = mmap(NULL, maplen, PROT_WRITE|PROT_READ,
243 MAP_ANON|MAP_PRIVATE, -1, 0);
244 if (memp == MAP_FAILED)
245 goto done;
246
247 memp[0] = "sh";
248 memp[1] = bp;
249 bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
250 (void)execve(_PATH_BSHELL, memp, envp);
251 save_errno = errno;
252 munmap(memp, maplen);
253 errno = save_errno;
254 goto done;
255 case ENOMEM:
256 goto done;
257 case ENOTDIR:
258 break;
259 case ETXTBSY:
260 /*
261 * We used to retry here, but sh(1) doesn't.
262 */
263 goto done;
264 case EACCES:
265 eacces = 1;
266 break;
267 default:
268 goto done;
269 }
270 }
271 if (eacces)
272 errno = EACCES;
273 else if (!errno)
274 errno = ENOENT;
275 done:
276 if (cur) {
277 save_errno = errno;
278 munmap(cur, curlen);
279 errno = save_errno;
280 }
281 return (-1);
282 }
283 DEF_WEAK(execvpe);
284
285 int
execvp(const char * name,char * const * argv)286 execvp(const char *name, char *const *argv)
287 {
288 return execvpe(name, argv, environ);
289 }
290 DEF_WEAK(execvp);
291
292