diff mbox series

[2/2] ports: Add wrappers for posix_spawn/posix_spawnp

Message ID 20241003113018.3531433-2-richard.purdie@linuxfoundation.org
State New
Headers show
Series [1/2] pseudo_util: Fix null pointer dereference for null envp | expand

Commit Message

Richard Purdie Oct. 3, 2024, 11:30 a.m. UTC
Add wrappers for the posix_spawn functions since they're being increasingly
used on modern Linux, e.g. in python 3.13 after:
https://github.com/python/cpython/commit/2b93f5224216d10f8119373e72b5c2b3984e0af6

They can be handled similarly to execve and use the setupenvp functionality.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 ports/common/guts/posix_spawn.c  | 34 ++++++++++++
 ports/common/guts/posix_spawnp.c | 34 ++++++++++++
 ports/common/portdefs.h          |  1 +
 ports/common/pseudo_wrappers.c   | 95 ++++++++++++++++++++++++++++++++
 ports/common/wrapfuncs.in        |  2 +
 5 files changed, 166 insertions(+)
 create mode 100644 ports/common/guts/posix_spawn.c
 create mode 100644 ports/common/guts/posix_spawnp.c
 create mode 100644 ports/common/portdefs.h
diff mbox series

Patch

diff --git a/ports/common/guts/posix_spawn.c b/ports/common/guts/posix_spawn.c
new file mode 100644
index 0000000..def14c8
--- /dev/null
+++ b/ports/common/guts/posix_spawn.c
@@ -0,0 +1,34 @@ 
+/*
+ * Copyright (c) 2024 Linux Foundation
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * static int
+ * weap_posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp) {
+ *	int rc = -1;
+ */
+	char * const *new_environ;
+	/* note:  we don't canonicalize this, because we are intentionally
+	 * NOT redirecting execs into the chroot environment.  If you try
+	 * to execute /bin/sh, you get the actual /bin/sh, not
+	 * <CHROOT>/bin/sh.  This allows use of basic utilities.  This
+	 * design will likely be revisited.
+	 */
+        if (antimagic == 0) {
+		const char *path_guess = pseudo_exec_path(path, 0);
+                pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0);
+        }
+
+	new_environ = pseudo_setupenvp(envp);
+	if (pseudo_has_unload(new_environ))
+		new_environ = pseudo_dropenvp(new_environ);
+
+	/* if exec() fails, we may end up taking signals unexpectedly...
+	 * not much we can do about that.
+	 */
+	sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
+	rc = real_posix_spawn(pid, path, file_actions, attrp, argv, new_environ);
+
+/*	return rc;
+ * }
+ */
diff --git a/ports/common/guts/posix_spawnp.c b/ports/common/guts/posix_spawnp.c
new file mode 100644
index 0000000..b2e1fc8
--- /dev/null
+++ b/ports/common/guts/posix_spawnp.c
@@ -0,0 +1,34 @@ 
+/*
+ * Copyright (c) 2024 Linux Foundation
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * static int
+ * wrap_posix_spawnp(pid_t *pid, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp) {
+ *	int rc = -1;
+ */
+	char * const *new_environ;
+	/* note:  we don't canonicalize this, because we are intentionally
+	 * NOT redirecting execs into the chroot environment.  If you try
+	 * to execute /bin/sh, you get the actual /bin/sh, not
+	 * <CHROOT>/bin/sh.  This allows use of basic utilities.  This
+	 * design will likely be revisited.
+	 */
+        if (antimagic == 0) {
+		const char *path_guess = pseudo_exec_path(file, 1);
+                pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0);
+        }
+
+	new_environ = pseudo_setupenvp(envp);
+	if (pseudo_has_unload(new_environ))
+		new_environ = pseudo_dropenvp(new_environ);
+
+	/* if exec() fails, we may end up taking signals unexpectedly...
+	 * not much we can do about that.
+	 */
+	sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
+	rc = real_posix_spawnp(pid, file, file_actions, attrp, argv, new_environ);
+
+/*	return rc;
+ * }
+ */
diff --git a/ports/common/portdefs.h b/ports/common/portdefs.h
new file mode 100644
index 0000000..e6233bc
--- /dev/null
+++ b/ports/common/portdefs.h
@@ -0,0 +1 @@ 
+#include <spawn.h>
diff --git a/ports/common/pseudo_wrappers.c b/ports/common/pseudo_wrappers.c
index 92dfaa8..2cbc946 100644
--- a/ports/common/pseudo_wrappers.c
+++ b/ports/common/pseudo_wrappers.c
@@ -411,3 +411,98 @@  wrap_fork(void) {
 	return rc;
 }
 
+
+int
+posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp) {
+	sigset_t saved;
+
+	int rc = -1;
+	PROFILE_START;
+
+	if (!pseudo_check_wrappers() || !real_posix_spawn) {
+		/* rc was initialized to the "failure" value */
+		pseudo_enosys("posix_spawn");
+		PROFILE_DONE;
+		return rc;
+	}
+
+	pseudo_debug(PDBGF_WRAPPER, "called: posix_spawn\n");
+	pseudo_sigblock(&saved);
+	if (pseudo_getlock()) {
+		errno = EBUSY;
+		sigprocmask(SIG_SETMASK, &saved, NULL);
+		PROFILE_DONE;
+		return -1;
+	}
+
+	int save_errno;
+
+	/* exec*() use this to restore the sig mask */
+	pseudo_saved_sigmask = saved;
+	rc = wrap_posix_spawn(pid, path, file_actions, attrp, argv, envp);
+
+	save_errno = errno;
+	pseudo_droplock();
+	sigprocmask(SIG_SETMASK, &saved, NULL);
+	pseudo_debug(PDBGF_WRAPPER, "completed: posix_spawn\n");
+	errno = save_errno;
+	PROFILE_DONE;
+	return rc;
+}
+
+int
+posix_spawnp(pid_t *pid, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp) {
+	sigset_t saved;
+
+	int rc = -1;
+	PROFILE_START;
+
+	if (!pseudo_check_wrappers() || !real_posix_spawnp) {
+		/* rc was initialized to the "failure" value */
+		pseudo_enosys("posix_spawn");
+		PROFILE_DONE;
+		return rc;
+	}
+
+	pseudo_debug(PDBGF_WRAPPER, "called: posix_spawnp\n");
+	pseudo_sigblock(&saved);
+	if (pseudo_getlock()) {
+		errno = EBUSY;
+		sigprocmask(SIG_SETMASK, &saved, NULL);
+		PROFILE_DONE;
+		return -1;
+	}
+
+	int save_errno;
+
+	/* exec*() use this to restore the sig mask */
+	pseudo_saved_sigmask = saved;
+	rc = wrap_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
+
+	save_errno = errno;
+	pseudo_droplock();
+	sigprocmask(SIG_SETMASK, &saved, NULL);
+	pseudo_debug(PDBGF_WRAPPER, "completed: posix_spawnp\n");
+	errno = save_errno;
+	PROFILE_DONE;
+	return rc;
+}
+
+
+static int
+wrap_posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp) {
+	int rc = -1;
+
+#include "guts/posix_spawn.c"
+
+	return rc;
+}
+
+static int
+wrap_posix_spawnp(pid_t *pid, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp) {
+	int rc = -1;
+
+#include "guts/posix_spawnp.c"
+
+	return rc;
+}
diff --git a/ports/common/wrapfuncs.in b/ports/common/wrapfuncs.in
index 17440f9..9a44ac1 100644
--- a/ports/common/wrapfuncs.in
+++ b/ports/common/wrapfuncs.in
@@ -5,3 +5,5 @@  int execv(const char *file, char *const *argv); /* hand_wrapped=1 */
 int execve(const char *file, char *const *argv, char *const *envp); /* hand_wrapped=1 */
 int execvp(const char *file, char *const *argv); /* hand_wrapped=1 */
 int fork(void); /* hand_wrapped=1 */
+int posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp); /* hand_wrapped=1 */
+int posix_spawnp(pid_t *pid, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp); /* hand_wrapped=1 */