Skip to content

Instantly share code, notes, and snippets.

@brynet
Created February 18, 2016 19:37
Show Gist options
  • Save brynet/803e8ebf83aa128433f5 to your computer and use it in GitHub Desktop.
Save brynet/803e8ebf83aa128433f5 to your computer and use it in GitHub Desktop.
pledge(2) for fdm
diff --git a/child.c b/child.c
index 70b915e..0c3b33b 100644
--- a/child.c
+++ b/child.c
@@ -129,6 +129,21 @@ child_start(struct children *children, uid_t uid, gid_t gid,
if (geteuid() == 0)
dropto(uid, gid);
+#ifdef HAVE_PLEDGE
+ struct child_fetch_data *cfd = child->data;
+ if (!cfd->needs_exec && cfd->op == FDMOP_FETCH) {
+ /* Revokes "proc" promise, i.e: fork/kill */
+ if (pledge("stdio rpath wpath cpath fattr flock getpw inet dns", NULL) == -1) {
+ fatal("pledge");
+ }
+ } else if (cfd->op == FDMOP_POLL) {
+ /* Revokes "cpath proc" promises */
+ if (pledge("stdio rpath tmppath inet dns", NULL) == -1) {
+ fatal("pledge");
+ }
+ }
+#endif
+
io = io_create(fds[1], NULL, IO_LF);
n = start(child, io);
io_close(io);
diff --git a/configure.ac b/configure.ac
index 5793c2d..5ea9e9f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -102,6 +102,11 @@ if test "x$found_libssl" = xno; then
AC_MSG_ERROR("libssl not found")
fi
+AC_CHECK_FUNC(pledge, found_pledge=yes, found_pledge=no)
+if test "x$found_pledge" = xyes; then
+ AC_DEFINE(HAVE_PLEDGE)
+fi
+
AC_CHECK_DECL(strlcpy, found_strlcpy=yes, found_strlcpy=no)
if test "x$found_strlcpy" = xyes; then
AC_DEFINE(HAVE_STRLCPY)
diff --git a/fdm.c b/fdm.c
index cbe44a2..ea3731b 100644
--- a/fdm.c
+++ b/fdm.c
@@ -732,6 +732,32 @@ retry:
goto out;
}
+#ifdef HAVE_PLEDGE
+ if (conf.needs_exec && op == FDMOP_FETCH) {
+ log_debug2("pledge fetch exec");
+ if (pledge("stdio rpath wpath cpath fattr flock getpw inet dns proc exec", NULL) == -1) {
+ log_warnx("pledge");
+ exit(1);
+ }
+ } else if (!conf.needs_exec && op == FDMOP_FETCH) {
+ log_debug2("pledge fetch noexec");
+ if (pledge("stdio rpath wpath cpath fattr flock getpw inet dns proc", NULL) == -1) {
+ log_warnx("pledge");
+ exit(1);
+ }
+ } else if (op == FDMOP_POLL) {
+ /*
+ * The "tmppath" promise is for shm cache, covered
+ * above by "wpath cpath".
+ */
+ log_debug2("pledge poll");
+ if (pledge("stdio rpath cpath tmppath inet dns proc", NULL) == -1) {
+ log_warnx("pledge");
+ exit(1);
+ }
+ }
+#endif
+
/* Initialise the child process arrays. */
ARRAY_INIT(&children);
ARRAY_INIT(&dead_children);
@@ -761,6 +787,7 @@ retry:
cfd = xmalloc(sizeof *cfd);
cfd->account = a;
cfd->op = op;
+ cfd->needs_exec = conf.needs_exec;
cfd->children = &children;
child = child_start(&children,
conf.child_uid, conf.child_gid,
diff --git a/fdm.h b/fdm.h
index 7702e4f..69ead0c 100644
--- a/fdm.h
+++ b/fdm.h
@@ -453,6 +453,7 @@ ARRAY_DECL(children, struct child *);
struct child_fetch_data {
struct account *account;
enum fdmop op;
+ int needs_exec;
struct children *children;
};
@@ -622,6 +623,7 @@ struct conf {
u_int purge_after;
enum decision impl_act;
int max_accts;
+ int needs_exec;
char *lock_file;
int lock_wait;
diff --git a/parse.y b/parse.y
index c837be5..76cf292 100644
--- a/parse.y
+++ b/parse.y
@@ -1109,6 +1109,7 @@ actitem: execpipe strv
if (*$2 == '\0')
yyerror("invalid command");
+ conf.needs_exec = 1;
$$ = xcalloc(1, sizeof *$$);
$$->deliver = &deliver_pipe;
@@ -1125,6 +1126,7 @@ actitem: execpipe strv
if (*$2 == '\0')
yyerror("invalid command");
+ conf.needs_exec = 1;
$$ = xcalloc(1, sizeof *$$);
$$->deliver = &deliver_rewrite;
@@ -1601,6 +1603,7 @@ expritem: not TOKALL
if (*$3 == '\0' || ($3[0] == '|' && $3[1] == '\0'))
yyerror("invalid command");
+ conf.needs_exec = 1;
if ($7 == -1 && $9.str == NULL)
yyerror("return code or regexp must be specified");
@@ -2246,6 +2249,7 @@ fetchtype: poptype server userpassnetrc poponly apop verify uidl tls1 starttls
data->pipecmd = $3;
if (data->pipecmd == NULL || *data->pipecmd == '\0')
yyerror("invalid pipe command");
+ conf.needs_exec = 1;
data->apop = $6;
data->path = $5.path;
data->only = $5.only;
@@ -2305,6 +2309,7 @@ fetchtype: poptype server userpassnetrc poponly apop verify uidl tls1 starttls
data->pipecmd = $3;
if (data->pipecmd == NULL || *data->pipecmd == '\0')
yyerror("invalid pipe command");
+ conf.needs_exec = 1;
data->only = $6;
}
| TOKSTDIN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment