Hi,
This time around I think this one looks better than my previous attempts, where
I tried stupidly to grant almost every permission pledge allows.
Hoist the sync_init() part to the top since it calls a setsockopt(2) forbidden
by pledge(2). Then in the default mode (greylisting) spamd(8) needs
"rpath wpath" to at least open "/dev/pf", "flock" to lock the database
/var/db/spamd each time it needs to update it, "proc id" for chroot(2) and
the privdrop section. Finally it also needs "exec" since it will call pfctl(8)
to update the tables with the information it gets from the database. If not in
greylist mode (blacklist) then it only needs "rpath proc id" to chroot(2) and
privdrop. Both modes always needs "inet".
After privdrop the child only needs "stdio inet" since it only accepts
connections and makes decisions on that, although doesn't seem to need more
than "inet" for that.
Any comments?
Index: spamd.c
===================================================================
RCS file: /cvs/src/libexec/spamd/spamd.c,v
retrieving revision 1.130
diff -u -p -u -r1.130 spamd.c
--- spamd.c 10 Sep 2015 13:56:12 -0000 1.130
+++ spamd.c 28 Nov 2015 15:42:47 -0000
@@ -1335,9 +1335,22 @@ main(int argc, char *argv[])
greylist ? " (greylist)" : "",
(syncrecv || syncsend) ? " (sync)" : "");
- if (!greylist)
+ if (syncsend || syncrecv) {
+ syncfd = sync_init(sync_iface, sync_baddr, sync_port);
+ if (syncfd == -1)
+ err(1, "sync init");
+ }
+
+ if (pledge("stdio rpath wpath flock inet proc exec id", NULL) == -1)
+ err(1, "pledge");
+
+ if (!greylist) {
maxblack = maxcon;
- else if (maxblack > maxcon)
+
+ if (pledge("stdio rpath inet proc id", NULL) == -1)
+ err(1, "pledge");
+
+ } else if (maxblack > maxcon)
usage();
rlp.rlim_cur = rlp.rlim_max = maxcon + 15;
@@ -1403,12 +1416,6 @@ main(int argc, char *argv[])
if (bind(conflisten, (struct sockaddr *)&lin, sizeof lin) == -1)
err(1, "bind local");
- if (syncsend || syncrecv) {
- syncfd = sync_init(sync_iface, sync_baddr, sync_port);
- if (syncfd == -1)
- err(1, "sync init");
- }
-
if ((pw = getpwnam("_spamd")) == NULL)
errx(1, "no such user _spamd");
@@ -1492,6 +1499,9 @@ jail:
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
err(1, "failed to drop privs");
+ if (pledge("stdio inet", NULL) == -1)
+ err(1, "pledge");
+
if (listen(smtplisten, 10) == -1)
err(1, "listen");