Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Add `pkg_emit_sandbox_call` to make a sandbox.
Vsevolod Stakhov committed 12 years ago
commit 6c0d4cf5a1d8a66706bf8b2a4054ba18a1e87550
parent df83f86
4 files changed +99 -0
modified libpkg/pkg.h.in
@@ -1339,6 +1339,11 @@ struct pkg_event_conflict {
	struct pkg_event_conflict *next;
};

+
/*
+
 * Capsicum sandbox callbacks
+
 */
+
typedef int (*pkg_sandbox_cb)(int fd, void *user_data);
+

/**
 * Event type used to report progress or problems.
 */
@@ -1362,6 +1367,7 @@ typedef enum {
	PKG_EVENT_INCREMENTAL_UPDATE,
	PKG_EVENT_QUERY_YESNO,
	PKG_EVENT_QUERY_SELECT,
+
	PKG_EVENT_SANDBOX_CALL,
	/* errors */
	PKG_EVENT_ERROR,
	PKG_EVENT_ERRNO,
@@ -1499,6 +1505,11 @@ struct pkg_event {
			int ncnt;
			int deft;
		} e_query_select;
+
		struct {
+
			pkg_sandbox_cb call;
+
			int fd;
+
			void *userdata;
+
		} e_sandbox_call;
	};
};

modified libpkg/pkg_event.c
@@ -823,6 +823,21 @@ pkg_emit_query_select(const char *msg, const char **items, int ncnt, int deft)
	return ret;
}

+
int
+
pkg_emit_sandbox_call(pkg_sandbox_cb call, int fd, void *ud)
+
{
+
	struct pkg_event ev;
+
	int ret;
+

+
	ev.type = PKG_EVENT_SANDBOX_CALL;
+
	ev.e_sandbox_call.call = call;
+
	ev.e_sandbox_call.fd = fd;
+
	ev.e_sandbox_call.userdata = ud;
+

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

void
pkg_debug(int level, const char *fmt, ...)
{
modified libpkg/private/event.h
@@ -57,6 +57,7 @@ void pkg_emit_developer_mode(const char *fmt, ...);
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);


#endif
modified src/event.c
@@ -29,10 +29,18 @@
 */

#include <sys/param.h>
+
#include <sys/types.h>
+
#include <sys/wait.h>
+

+
#ifdef HAVE_CAPSICUM
+
#include <sys/capability.h>
+
#endif

#include <err.h>
#include <string.h>
#include <unistd.h>
+
#include <errno.h>
+
#include <sysexits.h>

#include "pkg.h"
#include "progressmeter.h"
@@ -59,6 +67,66 @@ print_status_begin(struct sbuf *msg)
		sbuf_printf(msg, "[%d/%d] ", nbdone, nbactions);
}

+
static int
+
event_sandboxed_call(pkg_sandbox_cb func, int fd, void *ud)
+
{
+
	pid_t pid;
+
	int	status, ret;
+

+
	pid = fork();
+

+
	switch(pid) {
+
	case -1:
+
		warn("fork failed");
+
		return (EPKG_FATAL);
+
		break;
+
	case 0:
+
		break;
+
	default:
+
		/* 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
+
	cap_rights_init(&rights, CAP_READ|CAP_MMAP_R|CAP_SEEK|CAP_LOOKUP|CAP_FSTAT);
+
	if (cap_rights_limit(fileno(fd), &rights) < 0 && errno != ENOSYS ) {
+
		warn("cap_rights_limit() failed");
+
		return (EPKG_FATAL);
+
	}
+

+
	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(fd, ud);
+

+
	_exit(ret);
+
}
+

int
event_callback(void *data, struct pkg_event *ev)
{
@@ -354,6 +422,10 @@ event_callback(void *data, struct pkg_event *ev)
		return query_select(ev->e_query_select.msg, ev->e_query_select.items,
			ev->e_query_select.ncnt, ev->e_query_select.deft);
		break;
+
	case PKG_EVENT_SANDBOX_CALL:
+
		return ( event_sandboxed_call(ev->e_sandbox_call.call,
+
				ev->e_sandbox_call.fd,
+
				ev->e_sandbox_call.userdata) );
	default:
		break;
	}