11b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes/*- 21b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * Copyright (c) 1991, 1993 31b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * The Regents of the University of California. All rights reserved. 41b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * 51b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * Redistribution and use in source and binary forms, with or without 61b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * modification, are permitted provided that the following conditions 71b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * are met: 81b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * 1. Redistributions of source code must retain the above copyright 91b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * notice, this list of conditions and the following disclaimer. 101b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * 2. Redistributions in binary form must reproduce the above copyright 111b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * notice, this list of conditions and the following disclaimer in the 121b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * documentation and/or other materials provided with the distribution. 131b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * 3. Neither the name of the University nor the names of its contributors 141b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * may be used to endorse or promote products derived from this software 151b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * without specific prior written permission. 161b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * 171b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes * SUCH DAMAGE. 281b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes */ 291b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 301b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes#include <sys/types.h> 311b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes#include <sys/uio.h> 321b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 331b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes#include <errno.h> 341b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes#include <limits.h> 351b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes#include <paths.h> 361b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes#include <stdarg.h> 371b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes#include <stdio.h> 381b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes#include <stdlib.h> 391b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes#include <string.h> 401b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes#include <unistd.h> 411b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 424d215aad85cd9cba3e815eafb8c56eb5218eafb1Elliott Hughes#include "private/FdPath.h" 434d215aad85cd9cba3e815eafb8c56eb5218eafb1Elliott Hughes 441b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughesextern "C" char** environ; 451b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 461b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughesenum ExecVariant { kIsExecL, kIsExecLE, kIsExecLP }; 471b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 481b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughesstatic int __execl(const char* name, const char* argv0, ExecVariant variant, va_list ap) { 491b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes // Count the arguments. 501b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes va_list count_ap; 511b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes va_copy(count_ap, ap); 521b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes size_t n = 1; 531b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes while (va_arg(count_ap, char*) != nullptr) { 541b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes ++n; 551b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes } 561b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes va_end(count_ap); 571b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 581b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes // Construct the new argv. 591b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes char* argv[n + 1]; 601b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes argv[0] = const_cast<char*>(argv0); 611b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes n = 1; 621b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes while ((argv[n] = va_arg(ap, char*)) != nullptr) { 631b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes ++n; 641b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes } 651b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 661b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes // Collect the argp too. 671b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes char** argp = (variant == kIsExecLE) ? va_arg(ap, char**) : environ; 681b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 691b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes va_end(ap); 701b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 711b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes return (variant == kIsExecLP) ? execvp(name, argv) : execve(name, argv, argp); 721b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes} 731b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 741b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughesint execl(const char* name, const char* arg, ...) { 751b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes va_list ap; 761b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes va_start(ap, arg); 7713ec1cf3da6f92defec62492a4a94ada4ee35aafMikhail Lappo int result = __execl(name, arg, kIsExecL, ap); 7813ec1cf3da6f92defec62492a4a94ada4ee35aafMikhail Lappo va_end(ap); 7913ec1cf3da6f92defec62492a4a94ada4ee35aafMikhail Lappo return result; 801b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes} 811b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 821b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughesint execle(const char* name, const char* arg, ...) { 831b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes va_list ap; 841b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes va_start(ap, arg); 8513ec1cf3da6f92defec62492a4a94ada4ee35aafMikhail Lappo int result = __execl(name, arg, kIsExecLE, ap); 8613ec1cf3da6f92defec62492a4a94ada4ee35aafMikhail Lappo va_end(ap); 8713ec1cf3da6f92defec62492a4a94ada4ee35aafMikhail Lappo return result; 881b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes} 891b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 901b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughesint execlp(const char* name, const char* arg, ...) { 911b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes va_list ap; 921b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes va_start(ap, arg); 9313ec1cf3da6f92defec62492a4a94ada4ee35aafMikhail Lappo int result = __execl(name, arg, kIsExecLP, ap); 9413ec1cf3da6f92defec62492a4a94ada4ee35aafMikhail Lappo va_end(ap); 9513ec1cf3da6f92defec62492a4a94ada4ee35aafMikhail Lappo return result; 961b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes} 971b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 981b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughesint execv(const char* name, char* const* argv) { 991b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes return execve(name, argv, environ); 1001b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes} 1011b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1021b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughesint execvp(const char* name, char* const* argv) { 1031b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes return execvpe(name, argv, environ); 1041b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes} 1051b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1063c1159024c5ca3e85d4fd076f39712da4b27ed34Elliott Hughesstatic int __exec_as_script(const char* buf, char* const* argv, char* const* envp) { 1073c1159024c5ca3e85d4fd076f39712da4b27ed34Elliott Hughes size_t arg_count = 1; 1081b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes while (argv[arg_count] != nullptr) ++arg_count; 1091b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1103c1159024c5ca3e85d4fd076f39712da4b27ed34Elliott Hughes const char* script_argv[arg_count + 2]; 1113c1159024c5ca3e85d4fd076f39712da4b27ed34Elliott Hughes script_argv[0] = "sh"; 1121b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes script_argv[1] = buf; 1133c1159024c5ca3e85d4fd076f39712da4b27ed34Elliott Hughes memcpy(script_argv + 2, argv + 1, arg_count * sizeof(char*)); 1143c1159024c5ca3e85d4fd076f39712da4b27ed34Elliott Hughes return execve(_PATH_BSHELL, const_cast<char**>(script_argv), envp); 1151b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes} 1161b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1171b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughesint execvpe(const char* name, char* const* argv, char* const* envp) { 1181b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes // Do not allow null name. 1191b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes if (name == nullptr || *name == '\0') { 1201b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes errno = ENOENT; 1211b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes return -1; 1221b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes } 1231b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1241b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes // If it's an absolute or relative path name, it's easy. 1253c1159024c5ca3e85d4fd076f39712da4b27ed34Elliott Hughes if (strchr(name, '/') && execve(name, argv, envp) == -1) { 12663615066d9f0b0b1c653c91a9b305e6c292c835aElliott Hughes if (errno == ENOEXEC) return __exec_as_script(name, argv, envp); 12763615066d9f0b0b1c653c91a9b305e6c292c835aElliott Hughes return -1; 1283c1159024c5ca3e85d4fd076f39712da4b27ed34Elliott Hughes } 1291b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1301b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes // Get the path we're searching. 1311b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes const char* path = getenv("PATH"); 1321b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes if (path == nullptr) path = _PATH_DEFPATH; 1331b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1341b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes // Make a writable copy. 1351b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes size_t len = strlen(path) + 1; 1361b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes char writable_path[len]; 1371b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes memcpy(writable_path, path, len); 1381b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1391b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes bool saw_EACCES = false; 1401b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1411b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes // Try each element of $PATH in turn... 1421b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes char* strsep_buf = writable_path; 1431b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes const char* dir; 1441b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes while ((dir = strsep(&strsep_buf, ":"))) { 1451b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes // It's a shell path: double, leading and trailing colons 1461b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes // mean the current directory. 1471b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes if (*dir == '\0') dir = const_cast<char*>("."); 1481b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1491b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes size_t dir_len = strlen(dir); 1501b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes size_t name_len = strlen(name); 1511b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1521b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes char buf[dir_len + 1 + name_len + 1]; 1531b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes mempcpy(mempcpy(mempcpy(buf, dir, dir_len), "/", 1), name, name_len + 1); 1541b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes 1551b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes execve(buf, argv, envp); 1561b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes switch (errno) { 1571b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes case EISDIR: 1581b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes case ELOOP: 1591b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes case ENAMETOOLONG: 1601b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes case ENOENT: 1611b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes case ENOTDIR: 1621b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes break; 1631b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes case ENOEXEC: 1641b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes return __exec_as_script(buf, argv, envp); 1651b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes case EACCES: 1661b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes saw_EACCES = true; 1671b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes break; 1681b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes default: 1691b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes return -1; 1701b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes } 1711b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes } 1721b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes if (saw_EACCES) errno = EACCES; 1731b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes return -1; 1741b40aafe3f192f0fdccc04e75cc48b0ed74bc23eElliott Hughes} 1754d215aad85cd9cba3e815eafb8c56eb5218eafb1Elliott Hughes 1764d215aad85cd9cba3e815eafb8c56eb5218eafb1Elliott Hughesint fexecve(int fd, char* const* argv, char* const* envp) { 1774d215aad85cd9cba3e815eafb8c56eb5218eafb1Elliott Hughes // execveat with AT_EMPTY_PATH (>= 3.19) seems to offer no advantages. 1784d215aad85cd9cba3e815eafb8c56eb5218eafb1Elliott Hughes execve(FdPath(fd).c_str(), argv, envp); 1794d215aad85cd9cba3e815eafb8c56eb5218eafb1Elliott Hughes if (errno == ENOENT) errno = EBADF; 1804d215aad85cd9cba3e815eafb8c56eb5218eafb1Elliott Hughes return -1; 1814d215aad85cd9cba3e815eafb8c56eb5218eafb1Elliott Hughes} 182