lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | /* Copyright (C) 2004 Manuel Novoa III |
| 2 | * |
| 3 | * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. |
| 4 | */ |
| 5 | |
| 6 | /* Jan 1, 2004 |
| 7 | * Initial version of a SUSv3 compliant exec*() functions. |
| 8 | * Feb 17, 2004 |
| 9 | * Sigh... Fall back to alloca() if munmap() is broken on uClinux. |
| 10 | */ |
| 11 | |
| 12 | /* NOTE: Strictly speaking, there could be problems from accessing |
| 13 | * __environ in multithreaded programs. The only way around this |
| 14 | * that I see is to essentially lock __environ access (modifying |
| 15 | * the setenv code), make a copy of the environment table (just the |
| 16 | * pointers since the strings themselves are never freed), and then |
| 17 | * unlock prior to the execve call. If that fails, then we'd need |
| 18 | * to free the storage allocated for the copy. Better ideas anyone? |
| 19 | */ |
| 20 | |
| 21 | #include <stdio.h> |
| 22 | #include <stdlib.h> |
| 23 | #include <string.h> |
| 24 | #include <errno.h> |
| 25 | #include <stdarg.h> |
| 26 | #include <limits.h> |
| 27 | #include <unistd.h> |
| 28 | #include <sys/mman.h> |
| 29 | |
| 30 | |
| 31 | |
| 32 | /**********************************************************************/ |
| 33 | #define EXEC_FUNC_COMMON 0 |
| 34 | #define EXEC_FUNC_EXECVP 1 |
| 35 | #if defined(__ARCH_USE_MMU__) |
| 36 | |
| 37 | /* We have an MMU, so use alloca() to grab space for buffers and arg lists. */ |
| 38 | |
| 39 | # define EXEC_ALLOC_SIZE(VAR) /* nothing to do */ |
| 40 | # define EXEC_ALLOC(SIZE,VAR,FUNC) alloca((SIZE)) |
| 41 | # define EXEC_FREE(PTR,VAR) ((void)0) |
| 42 | |
| 43 | #else |
| 44 | |
| 45 | /* We do not have an MMU, so using alloca() is not an option (as this will |
| 46 | * easily overflow the stack in most setups). Less obviously, using malloc() |
| 47 | * is not an option either since malloc()ed memory can leak in from a vfork()ed |
| 48 | * child into the parent as no one is around after the child calls exec*() to |
| 49 | * free() the memory. Therefore, we must use mmap() and unmap() directly, |
| 50 | * caching the result as we go. This way we minimize the leak by reusing the |
| 51 | * memory with every call to an exec*(). |
| 52 | * |
| 53 | * To prevent recursive use of the same cached memory, we have to give execvp() |
| 54 | * its own cache. Here are the nested exec calls (a/-: alloc/no-alloc): |
| 55 | * execve(-) -> calls straight to kernel |
| 56 | * execl(a) -> execve(-) |
| 57 | * execlp(a) -> execvp(a) !! recursive usage !! |
| 58 | * execle(a) -> execve(-) |
| 59 | * execv(-) -> execve(-) |
| 60 | * execvp(a) -> execve(-) |
| 61 | */ |
| 62 | |
| 63 | # define EXEC_ALLOC_SIZE(VAR) /* nothing to do */ |
| 64 | # define EXEC_ALLOC(SIZE,VAR,FUNC) __exec_alloc((SIZE), FUNC) |
| 65 | # define EXEC_FREE(PTR,VAR) ((void)0) |
| 66 | |
| 67 | extern void *__exec_alloc(size_t size, int func) attribute_hidden; |
| 68 | |
| 69 | # ifdef L___exec_alloc |
| 70 | |
| 71 | void attribute_hidden *__exec_alloc(size_t size, int func) |
| 72 | { |
| 73 | static void *common_cache, *execvp_cache; |
| 74 | static size_t common_size, execvp_size; |
| 75 | |
| 76 | void **cache = (func ? &execvp_cache : &common_cache); |
| 77 | size_t *cache_size = (func ? &execvp_size : &common_size); |
| 78 | |
| 79 | if (*cache_size >= size) |
| 80 | return *cache; |
| 81 | else if (*cache) |
| 82 | munmap(*cache, *cache_size); |
| 83 | |
| 84 | *cache_size = size; |
| 85 | return *cache = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); |
| 86 | |
| 87 | /* We don't actually handle OOM in the exec funcs ... |
| 88 | if (*cache != MAP_FAILED) |
| 89 | return *cache; |
| 90 | else |
| 91 | return (*cache = NULL); |
| 92 | */ |
| 93 | } |
| 94 | |
| 95 | # endif |
| 96 | |
| 97 | #endif |
| 98 | /**********************************************************************/ |
| 99 | #ifdef L_execl |
| 100 | |
| 101 | int execl(const char *path, const char *arg, ...) |
| 102 | { |
| 103 | EXEC_ALLOC_SIZE(size) /* Do NOT add a semicolon! */ |
| 104 | int n; |
| 105 | char **argv; |
| 106 | char **p; |
| 107 | va_list args; |
| 108 | |
| 109 | n = 0; |
| 110 | va_start(args, arg); |
| 111 | do { |
| 112 | ++n; |
| 113 | } while (va_arg(args, char *)); |
| 114 | va_end(args); |
| 115 | |
| 116 | p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size, EXEC_FUNC_COMMON); |
| 117 | |
| 118 | p[0] = (char *)arg; |
| 119 | |
| 120 | va_start(args, arg); |
| 121 | do { |
| 122 | *++p = va_arg(args, char *); |
| 123 | } while (--n); |
| 124 | va_end(args); |
| 125 | |
| 126 | n = execve(path, (char *const *) argv, __environ); |
| 127 | |
| 128 | EXEC_FREE(argv, size); |
| 129 | |
| 130 | return n; |
| 131 | } |
| 132 | libc_hidden_def(execl) |
| 133 | |
| 134 | #endif |
| 135 | /**********************************************************************/ |
| 136 | #ifdef L_execv |
| 137 | |
| 138 | int execv(__const char *path, char *__const argv[]) |
| 139 | { |
| 140 | return execve(path, argv, __environ); |
| 141 | } |
| 142 | libc_hidden_def(execv) |
| 143 | |
| 144 | #endif |
| 145 | /**********************************************************************/ |
| 146 | #ifdef L_execle |
| 147 | |
| 148 | int execle(const char *path, const char *arg, ...) |
| 149 | { |
| 150 | EXEC_ALLOC_SIZE(size) /* Do NOT add a semicolon! */ |
| 151 | int n; |
| 152 | char **argv; |
| 153 | char **p; |
| 154 | char *const *envp; |
| 155 | va_list args; |
| 156 | |
| 157 | n = 0; |
| 158 | va_start(args, arg); |
| 159 | do { |
| 160 | ++n; |
| 161 | } while (va_arg(args, char *)); |
| 162 | envp = va_arg(args, char *const *); /* Varies from execl and execlp. */ |
| 163 | va_end(args); |
| 164 | |
| 165 | p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size, EXEC_FUNC_COMMON); |
| 166 | |
| 167 | p[0] = (char *)arg; |
| 168 | |
| 169 | va_start(args, arg); |
| 170 | do { |
| 171 | *++p = va_arg(args, char *); |
| 172 | } while (--n); |
| 173 | va_end(args); |
| 174 | |
| 175 | n = execve(path, (char *const *) argv, envp); |
| 176 | |
| 177 | EXEC_FREE(argv, size); |
| 178 | |
| 179 | return n; |
| 180 | } |
| 181 | libc_hidden_def(execle) |
| 182 | |
| 183 | #endif |
| 184 | /**********************************************************************/ |
| 185 | #ifdef L_execlp |
| 186 | |
| 187 | int execlp(const char *file, const char *arg, ...) |
| 188 | { |
| 189 | EXEC_ALLOC_SIZE(size) /* Do NOT add a semicolon! */ |
| 190 | int n; |
| 191 | char **argv; |
| 192 | char **p; |
| 193 | va_list args; |
| 194 | |
| 195 | n = 0; |
| 196 | va_start(args, arg); |
| 197 | do { |
| 198 | ++n; |
| 199 | } while (va_arg(args, char *)); |
| 200 | va_end(args); |
| 201 | |
| 202 | p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size, EXEC_FUNC_COMMON); |
| 203 | |
| 204 | p[0] = (char *)arg; |
| 205 | |
| 206 | va_start(args, arg); |
| 207 | do { |
| 208 | *++p = va_arg(args, char *); |
| 209 | } while (--n); |
| 210 | va_end(args); |
| 211 | |
| 212 | n = execvp(file, (char *const *) argv); |
| 213 | |
| 214 | EXEC_FREE(argv, size); |
| 215 | |
| 216 | return n; |
| 217 | } |
| 218 | libc_hidden_def(execlp) |
| 219 | |
| 220 | #endif |
| 221 | /**********************************************************************/ |
| 222 | #ifdef L_execvp |
| 223 | |
| 224 | |
| 225 | /* Use a default path that matches glibc behavior, since SUSv3 says |
| 226 | * this is implementation-defined. The default is current working dir, |
| 227 | * /bin, and then /usr/bin. */ |
| 228 | static const char default_path[] = ":/bin:/usr/bin"; |
| 229 | |
| 230 | int execvp(const char *path, char *const argv[]) |
| 231 | { |
| 232 | char *buf = NULL; |
| 233 | char *p; |
| 234 | char *e; |
| 235 | char *s0; |
| 236 | char *s; |
| 237 | EXEC_ALLOC_SIZE(size = 0) /* Do NOT add a semicolon! */ |
| 238 | size_t len; |
| 239 | size_t plen; |
| 240 | |
| 241 | if (!path || !*path) { /* Comply with SUSv3. */ |
| 242 | BAD: |
| 243 | __set_errno(ENOENT); |
| 244 | return -1; |
| 245 | } |
| 246 | |
| 247 | if (strchr(path, '/')) { |
| 248 | execve(path, argv, __environ); |
| 249 | if (errno == ENOEXEC) { |
| 250 | char **nargv; |
| 251 | EXEC_ALLOC_SIZE(size2) /* Do NOT add a semicolon! */ |
| 252 | size_t n; |
| 253 | RUN_BIN_SH: |
| 254 | /* Need the dimension - 1. We omit counting the trailing |
| 255 | * NULL but we actually omit the first entry. */ |
| 256 | for (n=0 ; argv[n] ; n++) {} |
| 257 | nargv = (char **) EXEC_ALLOC((n+2) * sizeof(char *), size2, EXEC_FUNC_EXECVP); |
| 258 | nargv[0] = argv[0]; |
| 259 | nargv[1] = (char *)path; |
| 260 | memcpy(nargv+2, argv+1, n*sizeof(char *)); |
| 261 | execve("/bin/sh", nargv, __environ); |
| 262 | EXEC_FREE(nargv, size2); |
| 263 | } |
| 264 | } else { |
| 265 | if ((p = getenv("PATH")) != NULL) { |
| 266 | if (!*p) { |
| 267 | goto BAD; |
| 268 | } |
| 269 | } else { |
| 270 | p = (char *) default_path; |
| 271 | } |
| 272 | |
| 273 | plen = strlen(path); |
| 274 | if (plen > (FILENAME_MAX - 1)) { |
| 275 | ALL_TOO_LONG: |
| 276 | __set_errno(ENAMETOOLONG); |
| 277 | return -1; |
| 278 | } |
| 279 | len = (FILENAME_MAX - 1) - plen; |
| 280 | |
| 281 | buf = EXEC_ALLOC(FILENAME_MAX, size, EXEC_FUNC_EXECVP); |
| 282 | { |
| 283 | int seen_small = 0; |
| 284 | s0 = buf + len; |
| 285 | memcpy(s0, path, plen+1); |
| 286 | |
| 287 | do { |
| 288 | s = s0; |
| 289 | e = strchrnul(p, ':'); |
| 290 | if (e > p) { |
| 291 | plen = e - p; |
| 292 | if (e[-1] != '/') { |
| 293 | ++plen; |
| 294 | } |
| 295 | if (plen > len) { |
| 296 | goto NEXT; |
| 297 | } |
| 298 | s -= plen; |
| 299 | memcpy(s, p, plen); |
| 300 | s[plen-1] = '/'; |
| 301 | } |
| 302 | |
| 303 | execve(s, argv, __environ); |
| 304 | |
| 305 | seen_small = 1; |
| 306 | |
| 307 | if (errno == ENOEXEC) { |
| 308 | path = s; |
| 309 | goto RUN_BIN_SH; |
| 310 | } |
| 311 | |
| 312 | NEXT: |
| 313 | if (!*e) { |
| 314 | if (!seen_small) { |
| 315 | goto ALL_TOO_LONG; |
| 316 | } |
| 317 | break; |
| 318 | } |
| 319 | p = e + 1; |
| 320 | } while (1); |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | EXEC_FREE(buf, size); |
| 325 | |
| 326 | return -1; |
| 327 | } |
| 328 | libc_hidden_def(execvp) |
| 329 | |
| 330 | #endif |
| 331 | /**********************************************************************/ |