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 
42 #include "private/__bionic_get_shell_path.h"
43 #include "private/FdPath.h"
44 
45 extern "C" char** environ;
46 
47 enum { ExecL, ExecLE, ExecLP };
48 
49 template <int variant>
__execl(const char * name,const char * argv0,va_list ap)50 static int __execl(const char* name, const char* argv0, va_list ap) {
51   // Count the arguments.
52   va_list count_ap;
53   va_copy(count_ap, ap);
54   size_t n = 1;
55   while (va_arg(count_ap, char*) != nullptr) {
56     ++n;
57   }
58   va_end(count_ap);
59 
60   // Construct the new argv.
61   char* argv[n + 1];
62   argv[0] = const_cast<char*>(argv0);
63   n = 1;
64   while ((argv[n] = va_arg(ap, char*)) != nullptr) {
65     ++n;
66   }
67 
68   // Collect the argp too.
69   char** argp = (variant == ExecLE) ? va_arg(ap, char**) : environ;
70 
71   va_end(ap);
72 
73   return (variant == ExecLP) ? execvp(name, argv) : execve(name, argv, argp);
74 }
75 
execl(const char * name,const char * arg,...)76 int execl(const char* name, const char* arg, ...) {
77   va_list ap;
78   va_start(ap, arg);
79   int result = __execl<ExecL>(name, arg, ap);
80   va_end(ap);
81   return result;
82 }
83 
execle(const char * name,const char * arg,...)84 int execle(const char* name, const char* arg, ...) {
85   va_list ap;
86   va_start(ap, arg);
87   int result = __execl<ExecLE>(name, arg, ap);
88   va_end(ap);
89   return result;
90 }
91 
execlp(const char * name,const char * arg,...)92 int execlp(const char* name, const char* arg, ...) {
93   va_list ap;
94   va_start(ap, arg);
95   int result = __execl<ExecLP>(name, arg, ap);
96   va_end(ap);
97   return result;
98 }
99 
execv(const char * name,char * const * argv)100 int execv(const char* name, char* const* argv) {
101   return execve(name, argv, environ);
102 }
103 
execvp(const char * name,char * const * argv)104 int execvp(const char* name, char* const* argv) {
105   return execvpe(name, argv, environ);
106 }
107 
__exec_as_script(const char * buf,char * const * argv,char * const * envp)108 static int __exec_as_script(const char* buf, char* const* argv, char* const* envp) {
109   size_t arg_count = 1;
110   while (argv[arg_count] != nullptr) ++arg_count;
111 
112   const char* script_argv[arg_count + 2];
113   script_argv[0] = "sh";
114   script_argv[1] = buf;
115   memcpy(script_argv + 2, argv + 1, arg_count * sizeof(char*));
116   return execve(__bionic_get_shell_path(), const_cast<char**>(script_argv), envp);
117 }
118 
execvpe(const char * name,char * const * argv,char * const * envp)119 int execvpe(const char* name, char* const* argv, char* const* envp) {
120   // Do not allow null name.
121   if (name == nullptr || *name == '\0') {
122     errno = ENOENT;
123     return -1;
124   }
125 
126   // If it's an absolute or relative path name, it's easy.
127   if (strchr(name, '/') && execve(name, argv, envp) == -1) {
128     if (errno == ENOEXEC) return __exec_as_script(name, argv, envp);
129     return -1;
130   }
131 
132   // Get the path we're searching.
133   const char* path = getenv("PATH");
134   if (path == nullptr) path = _PATH_DEFPATH;
135 
136   // Make a writable copy.
137   size_t len = strlen(path) + 1;
138   char writable_path[len];
139   memcpy(writable_path, path, len);
140 
141   bool saw_EACCES = false;
142 
143   // Try each element of $PATH in turn...
144   char* strsep_buf = writable_path;
145   const char* dir;
146   while ((dir = strsep(&strsep_buf, ":"))) {
147     // It's a shell path: double, leading and trailing colons
148     // mean the current directory.
149     if (*dir == '\0') dir = const_cast<char*>(".");
150 
151     size_t dir_len = strlen(dir);
152     size_t name_len = strlen(name);
153 
154     char buf[dir_len + 1 + name_len + 1];
155     mempcpy(mempcpy(mempcpy(buf, dir, dir_len), "/", 1), name, name_len + 1);
156 
157     execve(buf, argv, envp);
158     switch (errno) {
159     case EISDIR:
160     case ELOOP:
161     case ENAMETOOLONG:
162     case ENOENT:
163     case ENOTDIR:
164       break;
165     case ENOEXEC:
166       return __exec_as_script(buf, argv, envp);
167     case EACCES:
168       saw_EACCES = true;
169       break;
170     default:
171       return -1;
172     }
173   }
174   if (saw_EACCES) errno = EACCES;
175   return -1;
176 }
177 
fexecve(int fd,char * const * argv,char * const * envp)178 int fexecve(int fd, char* const* argv, char* const* envp) {
179   // execveat with AT_EMPTY_PATH (>= 3.19) seems to offer no advantages.
180   execve(FdPath(fd).c_str(), argv, envp);
181   if (errno == ENOENT) errno = EBADF;
182   return -1;
183 }
184