Re: pledge ifstated

2017-07-17 Thread Rob Pierce
On Sun, Jul 16, 2017 at 04:47:07PM -0400, Rob Pierce wrote:
> On Thu, Jul 13, 2017 at 09:16:14PM -0400, Rob Pierce wrote:
> > On Mon, Jul 10, 2017 at 01:21:58PM -0400, Rob Pierce wrote:
> > > The following diff is loosely based on the approach that was taken for
> > > pledging mountd. Other code/approaches leveraged from various networking
> > > daemons.
> > > 
> > > This first step moves the ioctl with SIOCGIFDATA call to a privileged
> > > child so we can at least pledge "stdio rpath dns inet proc exec" without
> > > (intentionally) changing existing behaviour.
> > > 
> > > Comments and suggestions welcome.
> > > 
> > > Thanks!
> > > 
> > > Rob
> > 
> > An unnecessary call to log_info snuck in. Here is a clean diff.
> > 
> > Rob
> 
> My original diff to initially pledge ifstated with "stdio rpath dns inet proc
> exec" was incorrectly polling from fetch_ifstate which resulted in the delayed
> completion of that function. This new diff resolves the problem.
> 
> I also changed one instance of fatal to fatalx in sigchld_handler.

Running setproctitle in the parent breaks rcctl.

This diff removes the parent call to setproctitle so rcctl works again.

Rob

Index: Makefile
===
RCS file: /cvs/src/usr.sbin/ifstated/Makefile,v
retrieving revision 1.10
diff -u -p -r1.10 Makefile
--- Makefile20 Jul 2010 02:05:15 -  1.10
+++ Makefile17 Jul 2017 16:38:23 -
@@ -8,7 +8,7 @@ CFLAGS+= -Wmissing-declarations
 CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
 YFLAGS=
 MAN= ifstated.8 ifstated.conf.5
-LDADD+=-levent
+LDADD+=-levent -lutil
 DPADD+= ${LIBEVENT}
 
 .include 
Index: ifstated.c
===
RCS file: /cvs/src/usr.sbin/ifstated/ifstated.c,v
retrieving revision 1.50
diff -u -p -r1.50 ifstated.c
--- ifstated.c  4 Jul 2017 21:09:52 -   1.50
+++ ifstated.c  17 Jul 2017 16:38:23 -
@@ -25,13 +25,16 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 #include 
 
 #include 
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -39,6 +42,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -47,7 +51,9 @@
 #include "log.h"
 
 struct  ifsd_config *conf = NULL, *newconf = NULL;
+struct  imsgbuf ibuf;
 
+pid_t   privchild_pid;
 int opts = 0;
 int opt_inhibit = 0;
 char   *configfile = "/etc/ifstated.conf";
@@ -74,6 +80,7 @@ void  do_action(struct ifsd_action *);
 void   remove_action(struct ifsd_action *, struct ifsd_state *);
 void   remove_expression(struct ifsd_expression *,
struct ifsd_state *);
+void   privchild(int);
 
 __dead void
 usage(void)
@@ -89,6 +96,7 @@ int
 main(int argc, char *argv[])
 {
struct timeval tv;
+   int socks[2];
int ch, rt_fd;
int debug = 0;
unsigned int rtfilter;
@@ -143,6 +151,21 @@ main(int argc, char *argv[])
if (!debug)
daemon(1, 0);
 
+   if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
+   fatal("%s: socketpair", __func__);
+   }
+
+   switch (privchild_pid = fork()) {
+   case -1:
+   fatal("%s: fork", __func__);
+   case 0:
+   close(socks[0]);
+   privchild(socks[1]);
+   }
+   close(socks[1]);
+
+   imsg_init(, socks[0]);
+
event_init();
log_init(debug, LOG_DAEMON);
log_setverbose(opts & IFSD_OPT_VERBOSE);
@@ -160,6 +183,9 @@ main(int argc, char *argv[])
, sizeof(rtfilter)) == -1) /* not fatal */
log_warn("%s: setsockopt tablefilter", __func__);
 
+   if (pledge("stdio rpath dns inet proc exec", NULL) == -1)
+   fatal("pledge");
+
signal_set(_ev, SIGCHLD, sigchld_handler, NULL);
signal_add(_ev, NULL);
 
@@ -252,6 +278,16 @@ rt_msg_handler(int fd, short event, void
 void
 sigchld_handler(int fd, short event, void *arg)
 {
+   pid_t pid;
+   int status;
+
+   do {
+   pid = waitpid(privchild_pid, , WNOHANG);
+   if (pid > 0 && (WIFEXITED(status) || WIFSIGNALED(status)))
+   fatalx("privchild %i exited due to receipt of signal 
%i",
+   privchild_pid, WTERMSIG(status));
+   } while (pid == -1 && errno == EINTR);
+
check_external_status(>initstate);
if (conf->curstate != NULL)
check_external_status(conf->curstate);
@@ -599,29 +635,60 @@ do_action(struct ifsd_action *action)
 void
 fetch_ifstate(void)
 {
+   struct imsg imsg;
struct ifaddrs *i

Re: pledge ifstated

2017-07-16 Thread Rob Pierce
On Thu, Jul 13, 2017 at 09:16:14PM -0400, Rob Pierce wrote:
> On Mon, Jul 10, 2017 at 01:21:58PM -0400, Rob Pierce wrote:
> > The following diff is loosely based on the approach that was taken for
> > pledging mountd. Other code/approaches leveraged from various networking
> > daemons.
> > 
> > This first step moves the ioctl with SIOCGIFDATA call to a privileged
> > child so we can at least pledge "stdio rpath dns inet proc exec" without
> > (intentionally) changing existing behaviour.
> > 
> > Comments and suggestions welcome.
> > 
> > Thanks!
> > 
> > Rob
> 
> An unnecessary call to log_info snuck in. Here is a clean diff.
> 
> Rob

My original diff to initially pledge ifstated with "stdio rpath dns inet proc
exec" was incorrectly polling from fetch_ifstate which resulted in the delayed
completion of that function. This new diff resolves the problem.

I also changed one instance of fatal to fatalx in sigchld_handler.

Regards,

Rob

Index: Makefile
===
RCS file: /cvs/src/usr.sbin/ifstated/Makefile,v
retrieving revision 1.10
diff -u -p -r1.10 Makefile
--- Makefile20 Jul 2010 02:05:15 -  1.10
+++ Makefile16 Jul 2017 20:38:48 -
@@ -8,7 +8,7 @@ CFLAGS+= -Wmissing-declarations
 CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
 YFLAGS=
 MAN= ifstated.8 ifstated.conf.5
-LDADD+=-levent
+LDADD+=-levent -lutil
 DPADD+= ${LIBEVENT}
 
 .include 
Index: ifstated.c
===
RCS file: /cvs/src/usr.sbin/ifstated/ifstated.c,v
retrieving revision 1.50
diff -u -p -r1.50 ifstated.c
--- ifstated.c  4 Jul 2017 21:09:52 -   1.50
+++ ifstated.c  16 Jul 2017 20:38:48 -
@@ -25,13 +25,16 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 #include 
 
 #include 
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -39,6 +42,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -47,7 +51,9 @@
 #include "log.h"
 
 struct  ifsd_config *conf = NULL, *newconf = NULL;
+struct  imsgbuf ibuf;
 
+pid_t   privchild_pid;
 int opts = 0;
 int opt_inhibit = 0;
 char   *configfile = "/etc/ifstated.conf";
@@ -74,6 +80,7 @@ void  do_action(struct ifsd_action *);
 void   remove_action(struct ifsd_action *, struct ifsd_state *);
 void   remove_expression(struct ifsd_expression *,
struct ifsd_state *);
+void   privchild(int);
 
 __dead void
 usage(void)
@@ -89,6 +96,7 @@ int
 main(int argc, char *argv[])
 {
struct timeval tv;
+   int socks[2];
int ch, rt_fd;
int debug = 0;
unsigned int rtfilter;
@@ -143,6 +151,22 @@ main(int argc, char *argv[])
if (!debug)
daemon(1, 0);
 
+   if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
+   fatal("%s: socketpair", __func__);
+   }
+
+   switch (privchild_pid = fork()) {
+   case -1:
+   fatal("%s: fork", __func__);
+   case 0:
+   close(socks[0]);
+   privchild(socks[1]);
+   }
+   close(socks[1]);
+
+   imsg_init(, socks[0]);
+   setproctitle("parent");
+
event_init();
log_init(debug, LOG_DAEMON);
log_setverbose(opts & IFSD_OPT_VERBOSE);
@@ -160,6 +184,9 @@ main(int argc, char *argv[])
, sizeof(rtfilter)) == -1) /* not fatal */
log_warn("%s: setsockopt tablefilter", __func__);
 
+   if (pledge("stdio rpath dns inet proc exec", NULL) == -1)
+   fatal("pledge");
+
signal_set(_ev, SIGCHLD, sigchld_handler, NULL);
signal_add(_ev, NULL);
 
@@ -252,6 +279,16 @@ rt_msg_handler(int fd, short event, void
 void
 sigchld_handler(int fd, short event, void *arg)
 {
+   pid_t pid;
+   int status;
+
+   do {
+   pid = waitpid(privchild_pid, , WNOHANG);
+   if (pid > 0 && (WIFEXITED(status) || WIFSIGNALED(status)))
+   fatalx("privchild %i exited due to receipt of signal 
%i",
+   privchild_pid, WTERMSIG(status));
+   } while (pid == -1 && errno == EINTR);
+
check_external_status(>initstate);
if (conf->curstate != NULL)
check_external_status(conf->curstate);
@@ -599,29 +636,60 @@ do_action(struct ifsd_action *action)
 void
 fetch_ifstate(void)
 {
+   struct imsg imsg;
struct ifaddrs *ifap, *ifa;
char *oname = NULL;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
+   int done = 0, state, rv;
+   ssize_t n;
 
if (getifaddrs() != 0)
err(1, "getifaddrs");
 
for (ifa = ifap; ifa; ifa = ifa->ifa_next) 

Re: pledge ifstated

2017-07-13 Thread Rob Pierce
On Mon, Jul 10, 2017 at 01:21:58PM -0400, Rob Pierce wrote:
> The following diff is loosely based on the approach that was taken for
> pledging mountd. Other code/approaches leveraged from various networking
> daemons.
> 
> This first step moves the ioctl with SIOCGIFDATA call to a privileged
> child so we can at least pledge "stdio rpath dns inet proc exec" without
> (intentionally) changing existing behaviour.
> 
> Comments and suggestions welcome.
> 
> Thanks!
> 
> Rob

An unnecessary call to log_info snuck in. Here is a clean diff.

Rob

Index: Makefile
===
RCS file: /cvs/src/usr.sbin/ifstated/Makefile,v
retrieving revision 1.10
diff -u -p -r1.10 Makefile
--- Makefile20 Jul 2010 02:05:15 -  1.10
+++ Makefile14 Jul 2017 01:12:58 -
@@ -8,7 +8,7 @@ CFLAGS+= -Wmissing-declarations
 CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
 YFLAGS=
 MAN= ifstated.8 ifstated.conf.5
-LDADD+=-levent
+LDADD+=-levent -lutil
 DPADD+= ${LIBEVENT}
 
 .include 
Index: ifstated.c
===
RCS file: /cvs/src/usr.sbin/ifstated/ifstated.c,v
retrieving revision 1.50
diff -u -p -r1.50 ifstated.c
--- ifstated.c  4 Jul 2017 21:09:52 -   1.50
+++ ifstated.c  14 Jul 2017 01:12:58 -
@@ -25,13 +25,16 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 #include 
 
 #include 
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -39,6 +42,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -47,7 +51,9 @@
 #include "log.h"
 
 struct  ifsd_config *conf = NULL, *newconf = NULL;
+struct  imsgbuf ibuf;
 
+pid_t   privchild_pid;
 int opts = 0;
 int opt_inhibit = 0;
 char   *configfile = "/etc/ifstated.conf";
@@ -74,6 +80,7 @@ void  do_action(struct ifsd_action *);
 void   remove_action(struct ifsd_action *, struct ifsd_state *);
 void   remove_expression(struct ifsd_expression *,
struct ifsd_state *);
+void   privchild(int);
 
 __dead void
 usage(void)
@@ -89,6 +96,7 @@ int
 main(int argc, char *argv[])
 {
struct timeval tv;
+   int socks[2];
int ch, rt_fd;
int debug = 0;
unsigned int rtfilter;
@@ -143,6 +151,22 @@ main(int argc, char *argv[])
if (!debug)
daemon(1, 0);
 
+   if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
+   fatal("%s: socketpair", __func__);
+   }
+
+   switch (privchild_pid = fork()) {
+   case -1:
+   fatal("%s: fork", __func__);
+   case 0:
+   close(socks[0]);
+   privchild(socks[1]);
+   }
+   close(socks[1]);
+
+   imsg_init(, socks[0]);
+   setproctitle("parent");
+
event_init();
log_init(debug, LOG_DAEMON);
log_setverbose(opts & IFSD_OPT_VERBOSE);
@@ -160,6 +184,9 @@ main(int argc, char *argv[])
, sizeof(rtfilter)) == -1) /* not fatal */
log_warn("%s: setsockopt tablefilter", __func__);
 
+   if (pledge("stdio rpath dns inet proc exec", NULL) == -1)
+   fatal("pledge");
+
signal_set(_ev, SIGCHLD, sigchld_handler, NULL);
signal_add(_ev, NULL);
 
@@ -252,6 +279,16 @@ rt_msg_handler(int fd, short event, void
 void
 sigchld_handler(int fd, short event, void *arg)
 {
+   pid_t pid;
+   int status;
+
+   do {
+   pid = waitpid(privchild_pid, , WNOHANG);
+   if (pid > 0 && (WIFEXITED(status) || WIFSIGNALED(status)))
+   fatal("privchild %i exited due to receipt of signal %i",
+   privchild_pid, WTERMSIG(status));
+   } while (pid == -1 && errno == EINTR);
+
check_external_status(>initstate);
if (conf->curstate != NULL)
check_external_status(conf->curstate);
@@ -599,29 +636,74 @@ do_action(struct ifsd_action *action)
 void
 fetch_ifstate(void)
 {
+   struct imsg imsg;
struct ifaddrs *ifap, *ifa;
+   struct pollfd pfd[1];
char *oname = NULL;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
+   int done = 0, state, rv;
+   ssize_t n;
 
if (getifaddrs() != 0)
err(1, "getifaddrs");
 
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
struct ifreq ifr;
-   struct if_data ifrdat;
 
if (oname && !strcmp(oname, ifa->ifa_name))
continue;
oname = ifa->ifa_name;
 
strlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
-   ifr.ifr_data = (caddr_t)
-
-   if (ioctl(sock, SIOCGIFDATA, (caddr_t)) == -1)
-   continue;
 
-   scan_ifstate(if_nametoindex(ifa->ifa_name),
-   ifrdat.ifi_link_state, 0);
+   /*
+* synchronous imsg request/response to privchild

pledge ifstated

2017-07-13 Thread Rob Pierce
The following diff is loosely based on the approach that was taken for
pledging mountd. Other code/approaches leveraged from various networking
daemons.

This first step moves the ioctl with SIOCGIFDATA call to a privileged
child so we can at least pledge "stdio rpath dns inet proc exec" without
(intentionally) changing existing behaviour.

Comments and suggestions welcome.

Thanks!

Rob

Index: Makefile
===
RCS file: /cvs/src/usr.sbin/ifstated/Makefile,v
retrieving revision 1.10
diff -u -p -r1.10 Makefile
--- Makefile20 Jul 2010 02:05:15 -  1.10
+++ Makefile13 Jul 2017 16:17:20 -
@@ -8,7 +8,7 @@ CFLAGS+= -Wmissing-declarations
 CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
 YFLAGS=
 MAN= ifstated.8 ifstated.conf.5
-LDADD+=-levent
+LDADD+=-levent -lutil
 DPADD+= ${LIBEVENT}
 
 .include 
Index: ifstated.c
===
RCS file: /cvs/src/usr.sbin/ifstated/ifstated.c,v
retrieving revision 1.50
diff -u -p -r1.50 ifstated.c
--- ifstated.c  4 Jul 2017 21:09:52 -   1.50
+++ ifstated.c  13 Jul 2017 16:17:20 -
@@ -25,13 +25,16 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 #include 
 
 #include 
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -39,6 +42,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -47,7 +51,9 @@
 #include "log.h"
 
 struct  ifsd_config *conf = NULL, *newconf = NULL;
+struct  imsgbuf ibuf;
 
+pid_t   privchild_pid;
 int opts = 0;
 int opt_inhibit = 0;
 char   *configfile = "/etc/ifstated.conf";
@@ -74,6 +80,7 @@ void  do_action(struct ifsd_action *);
 void   remove_action(struct ifsd_action *, struct ifsd_state *);
 void   remove_expression(struct ifsd_expression *,
struct ifsd_state *);
+void   privchild(int);
 
 __dead void
 usage(void)
@@ -89,6 +96,7 @@ int
 main(int argc, char *argv[])
 {
struct timeval tv;
+   int socks[2];
int ch, rt_fd;
int debug = 0;
unsigned int rtfilter;
@@ -143,6 +151,22 @@ main(int argc, char *argv[])
if (!debug)
daemon(1, 0);
 
+   if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
+   fatal("%s: socketpair", __func__);
+   }
+
+   switch (privchild_pid = fork()) {
+   case -1:
+   fatal("%s: fork", __func__);
+   case 0:
+   close(socks[0]);
+   privchild(socks[1]);
+   }
+   close(socks[1]);
+
+   imsg_init(, socks[0]);
+   setproctitle("parent");
+
event_init();
log_init(debug, LOG_DAEMON);
log_setverbose(opts & IFSD_OPT_VERBOSE);
@@ -160,6 +184,9 @@ main(int argc, char *argv[])
, sizeof(rtfilter)) == -1) /* not fatal */
log_warn("%s: setsockopt tablefilter", __func__);
 
+   if (pledge("stdio rpath dns inet proc exec", NULL) == -1)
+   fatal("pledge");
+
signal_set(_ev, SIGCHLD, sigchld_handler, NULL);
signal_add(_ev, NULL);
 
@@ -252,6 +279,16 @@ rt_msg_handler(int fd, short event, void
 void
 sigchld_handler(int fd, short event, void *arg)
 {
+   pid_t pid;
+   int status;
+
+   do {
+   pid = waitpid(privchild_pid, , WNOHANG);
+   if (pid > 0 && (WIFEXITED(status) || WIFSIGNALED(status)))
+   fatal("privchild %i exited due to receipt of signal %i",
+   privchild_pid, WTERMSIG(status));
+   } while (pid == -1 && errno == EINTR);
+
check_external_status(>initstate);
if (conf->curstate != NULL)
check_external_status(conf->curstate);
@@ -599,29 +636,75 @@ do_action(struct ifsd_action *action)
 void
 fetch_ifstate(void)
 {
+   struct imsg imsg;
struct ifaddrs *ifap, *ifa;
+   struct pollfd pfd[1];
char *oname = NULL;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
+   int done = 0, state, rv;
+   ssize_t n;
 
if (getifaddrs() != 0)
err(1, "getifaddrs");
 
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
struct ifreq ifr;
-   struct if_data ifrdat;
 
if (oname && !strcmp(oname, ifa->ifa_name))
continue;
oname = ifa->ifa_name;
 
strlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
-   ifr.ifr_data = (caddr_t)
-
-   if (ioctl(sock, SIOCGIFDATA, (caddr_t)) == -1)
-   continue;
 
-   scan_ifstate(if_nametoindex(ifa->ifa_name),
-   ifrdat.ifi_link_state, 0);
+   /*
+* synchronous imsg request/response to privchild
+*/
+   if (imsg_compose(, IMSG_IFSTATE_REQ, 0, 0, -1, ,
+  sizeof(struct ifreq)) == -1)
+