xref: /openbsd/lib/libc/gen/exec.c (revision 0999998a)
1 /*	$OpenBSD: exec.c,v 1.24 2021/09/22 20:40:06 deraadt 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
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
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
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
148 execv(const char *name, char *const *argv)
149 {
150 	(void)execve(name, argv, environ);
151 	return (-1);
152 }
153 
154 int
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, n;
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
286 execvp(const char *name, char *const *argv)
287 {
288     return execvpe(name, argv, environ);
289 }
290 DEF_WEAK(execvp);
291 
292