Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Add `PKG_EVENT_SANDBOX_GET_STRING` event.
Vsevolod Stakhov committed 12 years ago
commit ee9037360bce2d1223b67c13dc63d79427cf331c
parent ab7b488
4 files changed +122 -0
modified libpkg/pkg.h.in
@@ -1368,6 +1368,7 @@ typedef enum {
	PKG_EVENT_QUERY_YESNO,
	PKG_EVENT_QUERY_SELECT,
	PKG_EVENT_SANDBOX_CALL,
+
	PKG_EVENT_SANDBOX_GET_STRING,
	/* errors */
	PKG_EVENT_ERROR,
	PKG_EVENT_ERRNO,
@@ -1510,6 +1511,12 @@ struct pkg_event {
			int fd;
			void *userdata;
		} e_sandbox_call;
+
		struct {
+
			pkg_sandbox_cb call;
+
			void *userdata;
+
			char **result;
+
			int64_t *len;
+
		} e_sandbox_call_str;
	};
};

modified libpkg/pkg_event.c
@@ -824,6 +824,22 @@ pkg_emit_query_select(const char *msg, const char **items, int ncnt, int deft)
}

int
+
pkg_emit_sandbox_get_string(pkg_sandbox_cb call, void *ud, char **str, int64_t *len)
+
{
+
	struct pkg_event ev;
+
	int ret;
+

+
	ev.type = PKG_EVENT_SANDBOX_GET_STRING;
+
	ev.e_sandbox_call_str.call = call;
+
	ev.e_sandbox_call_str.userdata = ud;
+
	ev.e_sandbox_call_str.result = str;
+
	ev.e_sandbox_call_str.len = len;
+

+
	ret = pkg_emit_event(&ev);
+
	return ret;
+
}
+

+
int
pkg_emit_sandbox_call(pkg_sandbox_cb call, int fd, void *ud)
{
	struct pkg_event ev;
modified libpkg/private/event.h
@@ -58,6 +58,7 @@ void pkg_emit_package_not_found(const char *);
void pkg_emit_incremental_update(int updated, int removed, int added, int processed);
void pkg_debug(int level, const char *fmt, ...);
int pkg_emit_sandbox_call(pkg_sandbox_cb call, int fd, void *ud);
+
int pkg_emit_sandbox_get_string(pkg_sandbox_cb call, void *ud, char **str, int64_t *len);


#endif
modified src/event.c
@@ -31,6 +31,7 @@
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
+
#include <sys/socket.h>

#ifdef HAVE_CAPSICUM
#include <sys/capability.h>
@@ -41,6 +42,7 @@
#include <unistd.h>
#include <errno.h>
#include <sysexits.h>
+
#include <signal.h>

#include "pkg.h"
#include "progressmeter.h"
@@ -127,6 +129,95 @@ event_sandboxed_call(pkg_sandbox_cb func, int fd, void *ud)
	_exit(ret);
}

+
static int
+
event_sandboxed_get_string(pkg_sandbox_cb func, char **result, int64_t *len,
+
		void *ud)
+
{
+
	pid_t pid;
+
	int	status, ret = EPKG_OK;
+
	int pair[2];
+
	int64_t res_len = 0;
+

+
	if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
+
		warn("socketpair failed");
+
		return (EPKG_FATAL);
+
	}
+

+
	pid = fork();
+

+
	switch(pid) {
+
	case -1:
+
		warn("fork failed");
+
		return (EPKG_FATAL);
+
		break;
+
	case 0:
+
		break;
+
	default:
+
		close(pair[0]);
+
		/*
+
		 * We use blocking IO here as if the child is terminated we would have
+
		 * EINTR here
+
		 */
+
		if (read(pair[1], &res_len, sizeof(res_len)) == -1) {
+
			ret = EPKG_FATAL;
+
		}
+
		else {
+
			/* Fill the result buffer */
+
			*len = res_len;
+
			*result = malloc(res_len);
+
			if (*result == NULL) {
+
				warn("malloc failed");
+
				kill(pid, SIGTERM);
+
				ret = EPKG_FATAL;
+
			}
+
			else {
+
				if (read(pair[1], *result, res_len) == -1) {
+
					ret = EPKG_FATAL;
+
					free(*result);
+
					kill(pid, SIGTERM);
+
				}
+
			}
+
		}
+
		/* Parent process */
+
		while (waitpid(pid, &status, 0) == -1) {
+
			if (errno != EINTR) {
+
				warn("Sandboxed process pid=%d", (int)pid);
+
				ret = -1;
+
				break;
+
			}
+
		}
+

+
		if (WIFEXITED(status)) {
+
			ret = WEXITSTATUS(status);
+
		}
+
		if (WIFSIGNALED(status)) {
+
			/* Process got some terminating signal, hence stop the loop */
+
			fprintf(stderr, "Sandboxed process pid=%d terminated abnormally by signal: %d\n",
+
					(int)pid, WTERMSIG(status));
+
			ret = -1;
+
		}
+
		return (ret);
+
	}
+

+
	/* Here comes child process */
+
#ifdef HAVE_CAPSICUM
+
	close(pair[1]);
+

+
	if (cap_enter() < 0 && errno != ENOSYS) {
+
		warn("cap_enter() failed");
+
		return (EPKG_FATAL);
+
	}
+
#endif
+

+
	/*
+
	 * XXX: if capsicum is not enabled we basically have no idea of how to
+
	 * make a sandbox
+
	 */
+
	ret = func(pair[0], ud);
+

+
	_exit(ret);
+
}
+

int
event_callback(void *data, struct pkg_event *ev)
{
@@ -426,6 +517,13 @@ event_callback(void *data, struct pkg_event *ev)
		return ( event_sandboxed_call(ev->e_sandbox_call.call,
				ev->e_sandbox_call.fd,
				ev->e_sandbox_call.userdata) );
+
		break;
+
	case PKG_EVENT_SANDBOX_GET_STRING:
+
		return ( event_sandboxed_get_string(ev->e_sandbox_call_str.call,
+
				ev->e_sandbox_call_str.result,
+
				ev->e_sandbox_call_str.len,
+
				ev->e_sandbox_call_str.userdata) );
+
		break;
	default:
		break;
	}