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 44int 45execl(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} 77DEF_WEAK(execl); 78 79int 80execle(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 114int 115execlp(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 147int 148execv(const char *name, char *const *argv) 149{ 150 (void)execve(name, argv, environ); 151 return (-1); 152} 153 154int 155execvpe(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 228retry: (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; 275done: 276 if (cur) { 277 save_errno = errno; 278 munmap(cur, curlen); 279 errno = save_errno; 280 } 281 return (-1); 282} 283DEF_WEAK(execvpe); 284 285int 286execvp(const char *name, char *const *argv) 287{ 288 return execvpe(name, argv, environ); 289} 290DEF_WEAK(execvp); 291 292