| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 1 | /*- | 
|  | 2 | * Copyright (c) 1991, 1993 | 
|  | 3 | *	The Regents of the University of California.  All rights reserved. | 
|  | 4 | * | 
|  | 5 | * Redistribution and use in source and binary forms, with or without | 
|  | 6 | * modification, are permitted provided that the following conditions | 
|  | 7 | * are met: | 
|  | 8 | * 1. Redistributions of source code must retain the above copyright | 
|  | 9 | *    notice, this list of conditions and the following disclaimer. | 
|  | 10 | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | 11 | *    notice, this list of conditions and the following disclaimer in the | 
|  | 12 | *    documentation and/or other materials provided with the distribution. | 
|  | 13 | * 3. Neither the name of the University nor the names of its contributors | 
|  | 14 | *    may be used to endorse or promote products derived from this software | 
|  | 15 | *    without specific prior written permission. | 
|  | 16 | * | 
|  | 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 
|  | 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
|  | 20 | * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 
|  | 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
|  | 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
|  | 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
|  | 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
|  | 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
|  | 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
|  | 27 | * SUCH DAMAGE. | 
|  | 28 | */ | 
|  | 29 |  | 
|  | 30 | #include <sys/types.h> | 
|  | 31 | #include <sys/uio.h> | 
|  | 32 |  | 
|  | 33 | #include <errno.h> | 
|  | 34 | #include <limits.h> | 
|  | 35 | #include <paths.h> | 
|  | 36 | #include <stdarg.h> | 
|  | 37 | #include <stdio.h> | 
|  | 38 | #include <stdlib.h> | 
|  | 39 | #include <string.h> | 
|  | 40 | #include <unistd.h> | 
|  | 41 |  | 
| Elliott Hughes | 4d215aa | 2017-10-18 15:54:56 -0700 | [diff] [blame] | 42 | #include "private/FdPath.h" | 
| Evgenii Stepanov | 3031a7e | 2022-05-12 15:50:47 -0700 | [diff] [blame] | 43 | #include "private/__bionic_get_shell_path.h" | 
|  | 44 | #include "pthread_internal.h" | 
| Elliott Hughes | 4d215aa | 2017-10-18 15:54:56 -0700 | [diff] [blame] | 45 |  | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 46 | extern "C" char** environ; | 
| Evgenii Stepanov | 3031a7e | 2022-05-12 15:50:47 -0700 | [diff] [blame] | 47 | extern "C" int __execve(const char* pathname, char* const* argv, char* const* envp); | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 48 |  | 
| Elliott Hughes | a1b1bfd | 2020-06-04 08:04:06 -0700 | [diff] [blame] | 49 | enum { ExecL, ExecLE, ExecLP }; | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 50 |  | 
| Elliott Hughes | a1b1bfd | 2020-06-04 08:04:06 -0700 | [diff] [blame] | 51 | template <int variant> | 
|  | 52 | static int __execl(const char* name, const char* argv0, va_list ap) { | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 53 | // Count the arguments. | 
|  | 54 | va_list count_ap; | 
|  | 55 | va_copy(count_ap, ap); | 
|  | 56 | size_t n = 1; | 
|  | 57 | while (va_arg(count_ap, char*) != nullptr) { | 
|  | 58 | ++n; | 
|  | 59 | } | 
|  | 60 | va_end(count_ap); | 
|  | 61 |  | 
|  | 62 | // Construct the new argv. | 
|  | 63 | char* argv[n + 1]; | 
|  | 64 | argv[0] = const_cast<char*>(argv0); | 
|  | 65 | n = 1; | 
|  | 66 | while ((argv[n] = va_arg(ap, char*)) != nullptr) { | 
|  | 67 | ++n; | 
|  | 68 | } | 
|  | 69 |  | 
|  | 70 | // Collect the argp too. | 
| Elliott Hughes | a1b1bfd | 2020-06-04 08:04:06 -0700 | [diff] [blame] | 71 | char** argp = (variant == ExecLE) ? va_arg(ap, char**) : environ; | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 72 |  | 
|  | 73 | va_end(ap); | 
|  | 74 |  | 
| Elliott Hughes | a1b1bfd | 2020-06-04 08:04:06 -0700 | [diff] [blame] | 75 | return (variant == ExecLP) ? execvp(name, argv) : execve(name, argv, argp); | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 76 | } | 
|  | 77 |  | 
|  | 78 | int execl(const char* name, const char* arg, ...) { | 
|  | 79 | va_list ap; | 
|  | 80 | va_start(ap, arg); | 
| Elliott Hughes | a1b1bfd | 2020-06-04 08:04:06 -0700 | [diff] [blame] | 81 | int result = __execl<ExecL>(name, arg, ap); | 
| Mikhail Lappo | 13ec1cf | 2017-03-25 19:02:55 +0100 | [diff] [blame] | 82 | va_end(ap); | 
|  | 83 | return result; | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 84 | } | 
|  | 85 |  | 
|  | 86 | int execle(const char* name, const char* arg, ...) { | 
|  | 87 | va_list ap; | 
|  | 88 | va_start(ap, arg); | 
| Elliott Hughes | a1b1bfd | 2020-06-04 08:04:06 -0700 | [diff] [blame] | 89 | int result = __execl<ExecLE>(name, arg, ap); | 
| Mikhail Lappo | 13ec1cf | 2017-03-25 19:02:55 +0100 | [diff] [blame] | 90 | va_end(ap); | 
|  | 91 | return result; | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 92 | } | 
|  | 93 |  | 
|  | 94 | int execlp(const char* name, const char* arg, ...) { | 
|  | 95 | va_list ap; | 
|  | 96 | va_start(ap, arg); | 
| Elliott Hughes | a1b1bfd | 2020-06-04 08:04:06 -0700 | [diff] [blame] | 97 | int result = __execl<ExecLP>(name, arg, ap); | 
| Mikhail Lappo | 13ec1cf | 2017-03-25 19:02:55 +0100 | [diff] [blame] | 98 | va_end(ap); | 
|  | 99 | return result; | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 100 | } | 
|  | 101 |  | 
|  | 102 | int execv(const char* name, char* const* argv) { | 
|  | 103 | return execve(name, argv, environ); | 
|  | 104 | } | 
|  | 105 |  | 
|  | 106 | int execvp(const char* name, char* const* argv) { | 
|  | 107 | return execvpe(name, argv, environ); | 
|  | 108 | } | 
|  | 109 |  | 
| Elliott Hughes | 3c11590 | 2016-08-24 19:27:04 -0700 | [diff] [blame] | 110 | static int __exec_as_script(const char* buf, char* const* argv, char* const* envp) { | 
|  | 111 | size_t arg_count = 1; | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 112 | while (argv[arg_count] != nullptr) ++arg_count; | 
|  | 113 |  | 
| Elliott Hughes | 3c11590 | 2016-08-24 19:27:04 -0700 | [diff] [blame] | 114 | const char* script_argv[arg_count + 2]; | 
|  | 115 | script_argv[0] = "sh"; | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 116 | script_argv[1] = buf; | 
| Elliott Hughes | 3c11590 | 2016-08-24 19:27:04 -0700 | [diff] [blame] | 117 | memcpy(script_argv + 2, argv + 1, arg_count * sizeof(char*)); | 
| Elliott Hughes | 886370c | 2019-03-21 21:11:41 -0700 | [diff] [blame] | 118 | return execve(__bionic_get_shell_path(), const_cast<char**>(script_argv), envp); | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 119 | } | 
|  | 120 |  | 
|  | 121 | int execvpe(const char* name, char* const* argv, char* const* envp) { | 
|  | 122 | // Do not allow null name. | 
|  | 123 | if (name == nullptr || *name == '\0') { | 
|  | 124 | errno = ENOENT; | 
|  | 125 | return -1; | 
|  | 126 | } | 
|  | 127 |  | 
|  | 128 | // If it's an absolute or relative path name, it's easy. | 
| Elliott Hughes | 3c11590 | 2016-08-24 19:27:04 -0700 | [diff] [blame] | 129 | if (strchr(name, '/') && execve(name, argv, envp) == -1) { | 
| Elliott Hughes | 6361506 | 2016-08-25 17:40:27 -0700 | [diff] [blame] | 130 | if (errno == ENOEXEC) return __exec_as_script(name, argv, envp); | 
|  | 131 | return -1; | 
| Elliott Hughes | 3c11590 | 2016-08-24 19:27:04 -0700 | [diff] [blame] | 132 | } | 
| Elliott Hughes | 1b40aaf | 2016-08-18 10:11:36 -0700 | [diff] [blame] | 133 |  | 
|  | 134 | // Get the path we're searching. | 
|  | 135 | const char* path = getenv("PATH"); | 
|  | 136 | if (path == nullptr) path = _PATH_DEFPATH; | 
|  | 137 |  | 
|  | 138 | // Make a writable copy. | 
|  | 139 | size_t len = strlen(path) + 1; | 
|  | 140 | char writable_path[len]; | 
|  | 141 | memcpy(writable_path, path, len); | 
|  | 142 |  | 
|  | 143 | bool saw_EACCES = false; | 
|  | 144 |  | 
|  | 145 | // Try each element of $PATH in turn... | 
|  | 146 | char* strsep_buf = writable_path; | 
|  | 147 | const char* dir; | 
|  | 148 | while ((dir = strsep(&strsep_buf, ":"))) { | 
|  | 149 | // It's a shell path: double, leading and trailing colons | 
|  | 150 | // mean the current directory. | 
|  | 151 | if (*dir == '\0') dir = const_cast<char*>("."); | 
|  | 152 |  | 
|  | 153 | size_t dir_len = strlen(dir); | 
|  | 154 | size_t name_len = strlen(name); | 
|  | 155 |  | 
|  | 156 | char buf[dir_len + 1 + name_len + 1]; | 
|  | 157 | mempcpy(mempcpy(mempcpy(buf, dir, dir_len), "/", 1), name, name_len + 1); | 
|  | 158 |  | 
|  | 159 | execve(buf, argv, envp); | 
|  | 160 | switch (errno) { | 
|  | 161 | case EISDIR: | 
|  | 162 | case ELOOP: | 
|  | 163 | case ENAMETOOLONG: | 
|  | 164 | case ENOENT: | 
|  | 165 | case ENOTDIR: | 
|  | 166 | break; | 
|  | 167 | case ENOEXEC: | 
|  | 168 | return __exec_as_script(buf, argv, envp); | 
|  | 169 | case EACCES: | 
|  | 170 | saw_EACCES = true; | 
|  | 171 | break; | 
|  | 172 | default: | 
|  | 173 | return -1; | 
|  | 174 | } | 
|  | 175 | } | 
|  | 176 | if (saw_EACCES) errno = EACCES; | 
|  | 177 | return -1; | 
|  | 178 | } | 
| Elliott Hughes | 4d215aa | 2017-10-18 15:54:56 -0700 | [diff] [blame] | 179 |  | 
|  | 180 | int fexecve(int fd, char* const* argv, char* const* envp) { | 
|  | 181 | // execveat with AT_EMPTY_PATH (>= 3.19) seems to offer no advantages. | 
|  | 182 | execve(FdPath(fd).c_str(), argv, envp); | 
|  | 183 | if (errno == ENOENT) errno = EBADF; | 
|  | 184 | return -1; | 
|  | 185 | } | 
| Evgenii Stepanov | 3031a7e | 2022-05-12 15:50:47 -0700 | [diff] [blame] | 186 |  | 
|  | 187 | __attribute__((no_sanitize("memtag"))) int execve(const char* pathname, char* const* argv, | 
|  | 188 | char* const* envp) { | 
| Evgenii Stepanov | 3031a7e | 2022-05-12 15:50:47 -0700 | [diff] [blame] | 189 | return __execve(pathname, argv, envp); | 
|  | 190 | } |