Loading...
gen/FreeBSD/exec.c Libc-763.13 Libc-1725.40.4
--- Libc/Libc-763.13/gen/FreeBSD/exec.c
+++ Libc/Libc-1725.40.4/gen/FreeBSD/exec.c
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
@@ -10,7 +12,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -35,7 +37,6 @@
 
 #include "namespace.h"
 #include <sys/param.h>
-#include <sys/types.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <unistd.h>
@@ -48,7 +49,14 @@
 #include "un-namespace.h"
 #include "libc_private.h"
 
-extern char **environ;
+#include <crt_externs.h>
+#define environ (*_NSGetEnviron())
+
+static const char execvPe_err_preamble[] = "execvP: ";
+static const char execvPe_err_trailer[] = ": path too long\n";
+
+int
+_execvpe(const char *name, char * const argv[], char * const envp[]);
 
 int
 execl(const char *name, const char *arg, ...)
@@ -131,9 +139,7 @@
 }
 
 int
-execv(name, argv)
-	const char *name;
-	char * const *argv;
+execv(const char *name, char * const *argv)
 {
 	(void)_execve(name, argv, environ);
 	return (-1);
@@ -152,16 +158,20 @@
 	const char **memp;
 	size_t cnt, lp, ln;
 	int eacces, save_errno;
-	char *cur, buf[MAXPATHLEN];
-	const char *p, *bp;
+	char buf[MAXPATHLEN];
+	const char *bp, *np, *op, *p;
 	struct stat sb;
 
 	eacces = 0;
 
 	/* If it's an absolute or relative path name, it's easy. */
-	if (index(name, '/')) {
+	if (strchr(name, '/')) {
 		bp = name;
-		cur = NULL;
+#ifdef __APPLE__
+		/* Used to differentiate PATH search vs. not afterwards. */
+		path = NULL;
+#endif
+		op = NULL;
 		goto retry;
 	}
 	bp = buf;
@@ -172,23 +182,30 @@
 		return (-1);
 	}
 
-	cur = alloca(strlen(path) + 1);
-	if (cur == NULL) {
-		errno = ENOMEM;
-		return (-1);
-	}
-	strcpy(cur, path);
-	while ((p = strsep(&cur, ":")) != NULL) {
+	op = path;
+	ln = strlen(name);
+	while (op != NULL) {
+		np = strchrnul(op, ':');
+
 		/*
 		 * It's a SHELL path -- double, leading and trailing colons
 		 * mean the current directory.
 		 */
-		if (*p == '\0') {
+		if (np == op) {
+			/* Empty component. */
 			p = ".";
 			lp = 1;
-		} else
-			lp = strlen(p);
-		ln = strlen(name);
+		} else {
+			/* Non-empty component. */
+			p = op;
+			lp = np - op;
+		}
+
+		/* Advance to the next component or terminate after this. */
+		if (*np == '\0')
+			op = NULL;
+		else
+			op = np + 1;
 
 		/*
 		 * If the path is too long complain.  This is a possible
@@ -196,10 +213,11 @@
 		 * the user may execute the wrong program.
 		 */
 		if (lp + ln + 2 > sizeof(buf)) {
-			(void)_write(STDERR_FILENO, "execvP: ", 8);
+			(void)_write(STDERR_FILENO, execvPe_err_preamble,
+			    sizeof(execvPe_err_preamble) - 1);
 			(void)_write(STDERR_FILENO, p, lp);
-			(void)_write(STDERR_FILENO, ": path too long\n",
-			    16);
+			(void)_write(STDERR_FILENO, execvPe_err_trailer,
+			    sizeof(execvPe_err_trailer) - 1);
 			continue;
 		}
 		bcopy(p, buf, lp);
@@ -218,14 +236,28 @@
 		case ENOEXEC:
 			for (cnt = 0; argv[cnt]; ++cnt)
 				;
-			memp = alloca((cnt + 2) * sizeof(char *));
+
+			/*
+			 * cnt may be 0 above; always allocate at least
+			 * 3 entries so that we can at least fit "sh", bp, and
+			 * the NULL terminator.  We can rely on cnt to take into
+			 * account the NULL terminator in all other scenarios,
+			 * as we drop argv[0].
+			 */
+			memp = alloca(MAX(3, cnt + 2) * sizeof(char *));
 			if (memp == NULL) {
 				/* errno = ENOMEM; XXX override ENOEXEC? */
 				goto done;
 			}
-			memp[0] = "sh";
-			memp[1] = bp;
-			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
+			if (cnt > 0) {
+				memp[0] = argv[0];
+				memp[1] = bp;
+				bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
+			} else {
+				memp[0] = "sh";
+				memp[1] = bp;
+				memp[2] = NULL;
+			}
  			(void)_execve(_PATH_BSHELL,
 			    __DECONST(char **, memp), envp);
 			goto done;
@@ -257,10 +289,22 @@
 			goto done;
 		}
 	}
+
 	if (eacces)
 		errno = EACCES;
+#ifdef __APPLE__
+	/*
+	 * Preserve errno from execve(2) if it wasn't a PATH search, or
+	 * if it was a PATH search and we bailed out early.  Note that every
+	 * branch in the loop jumps to the `done` label to preserve errno, so
+	 * this is more of a defensive check.
+	 */
+	else if (path != NULL && op == NULL)
+#else
 	else
+#endif
 		errno = ENOENT;
+	/* else use existing errno from _execve */
 done:
 	return (-1);
 }
@@ -271,7 +315,7 @@
 	return execvPe(name, path, argv, environ);
 }
 
-int
+__private_extern__ int
 _execvpe(const char *name, char * const argv[], char * const envp[])
 {
 	const char *path;