Hi,

It seems that switchd(8) suffers from the same issue I reported yesterday about
eigrpd(8), the daemon when it's shutdown never deletes the unix control socket
because that is being done from a chrooted process.

This one nevertheless took a little bit more effort since I had to disentangle
2 struct event and 1 fd from struct control_sock into their own
struct control_state, just like we have on other daemons.

Also updated the pledge(2)s accordingly moving "cpath" from the chrooted proc
to the main proc.

Regression tests passed without issues and switchctl(8) also didn't complain.

Comments? OK?

Index: control.c
===================================================================
RCS file: /cvs/src/usr.sbin/switchd/control.c,v
retrieving revision 1.8
diff -u -p -u -r1.8 control.c
--- control.c   17 Jan 2017 22:10:56 -0000      1.8
+++ control.c   2 Aug 2018 09:04:28 -0000
@@ -70,11 +70,10 @@ control_run(struct privsep *ps, struct p
        /*
         * pledge in the control process:
         * stdio - for malloc and basic I/O including events.
-        * cpath - for managing the control socket.
         * unix - for the control socket.
         * recvfd - for the proc fd exchange.
         */
-       if (pledge("stdio cpath unix recvfd", NULL) == -1)
+       if (pledge("stdio unix recvfd", NULL) == -1)
                fatal("pledge");
 }
 
@@ -171,7 +170,7 @@ control_init(struct privsep *ps, struct 
        }
 
        socket_set_blockmode(fd, BM_NONBLOCK);
-       cs->cs_fd = fd;
+       control_state.fd = fd;
        cs->cs_env = env;
 
        return (0);
@@ -183,27 +182,27 @@ control_listen(struct control_sock *cs)
        if (cs->cs_name == NULL)
                return (0);
 
-       if (listen(cs->cs_fd, CONTROL_BACKLOG) == -1) {
+       if (listen(control_state.fd, CONTROL_BACKLOG) == -1) {
                log_warn("%s: listen", __func__);
                return (-1);
        }
 
-       event_set(&cs->cs_ev, cs->cs_fd, EV_READ,
+       event_set(&control_state.ev, control_state.fd, EV_READ,
            control_accept, cs);
-       event_add(&cs->cs_ev, NULL);
-       evtimer_set(&cs->cs_evt, control_accept, cs);
+       event_add(&control_state.ev, NULL);
+       evtimer_set(&control_state.evt, control_accept, cs);
 
        return (0);
 }
 
 void
-control_cleanup(struct control_sock *cs)
+control_cleanup(char *path)
 {
-       if (cs->cs_name == NULL)
+       if (path == NULL)
                return;
-       event_del(&cs->cs_ev);
-       event_del(&cs->cs_evt);
-       (void)unlink(cs->cs_name);
+       event_del(&control_state.ev);
+       event_del(&control_state.evt);
+       (void)unlink(path);
 }
 
 /* ARGSUSED */
@@ -216,7 +215,7 @@ control_accept(int listenfd, short event
        struct sockaddr_un       sun;
        struct ctl_conn         *c;
 
-       event_add(&cs->cs_ev, NULL);
+       event_add(&control_state.ev, NULL);
        if ((event & EV_TIMEOUT))
                return;
 
@@ -230,8 +229,8 @@ control_accept(int listenfd, short event
                if (errno == ENFILE || errno == EMFILE) {
                        struct timeval evtpause = { 1, 0 };
 
-                       event_del(&cs->cs_ev);
-                       evtimer_add(&cs->cs_evt, &evtpause);
+                       event_del(&control_state.ev);
+                       evtimer_add(&control_state.evt, &evtpause);
                } else if (errno != EWOULDBLOCK && errno != EINTR &&
                    errno != ECONNABORTED)
                        log_warn("%s: accept", __func__);
@@ -287,9 +286,9 @@ control_close(int fd, struct control_soc
        close(c->iev.ibuf.fd);
 
        /* Some file descriptors are available again. */
-       if (evtimer_pending(&cs->cs_evt, NULL)) {
-               evtimer_del(&cs->cs_evt);
-               event_add(&cs->cs_ev, NULL);
+       if (evtimer_pending(&control_state.evt, NULL)) {
+               evtimer_del(&control_state.evt);
+               event_add(&control_state.ev, NULL);
        }
 
        free(c);
Index: proc.c
===================================================================
RCS file: /cvs/src/usr.sbin/switchd/proc.c,v
retrieving revision 1.12
diff -u -p -u -r1.12 proc.c
--- proc.c      29 May 2017 12:56:26 -0000      1.12
+++ proc.c      2 Aug 2018 09:04:28 -0000
@@ -475,9 +475,6 @@ proc_shutdown(struct privsep_proc *p)
 {
        struct privsep  *ps = p->p_ps;
 
-       if (p->p_id == PROC_CONTROL && ps)
-               control_cleanup(&ps->ps_csock);
-
        if (p->p_shutdown != NULL)
                (*p->p_shutdown)();
 
Index: proc.h
===================================================================
RCS file: /cvs/src/usr.sbin/switchd/proc.h,v
retrieving revision 1.6
diff -u -p -u -r1.6 proc.h
--- proc.h      9 Jan 2017 14:49:22 -0000       1.6
+++ proc.h      2 Aug 2018 09:04:28 -0000
@@ -23,11 +23,14 @@
 #ifndef _PROC_H
 #define _PROC_H
 
+struct {
+       struct event    ev;
+       struct event    evt;
+       int             fd;
+} control_state;
+
 struct control_sock {
        const char      *cs_name;
-       struct event     cs_ev;
-       struct event     cs_evt;
-       int              cs_fd;
        int              cs_restricted;
        void            *cs_env;
 
@@ -160,7 +163,7 @@ int  proc_flush_imsg(struct privsep *, e
 /* control.c */
 int     control_init(struct privsep *, struct control_sock *);
 int     control_listen(struct control_sock *);
-void    control_cleanup(struct control_sock *);
+void    control_cleanup(char *);
 struct ctl_conn
        *control_connbyfd(int);
 void    control(struct privsep *, struct privsep_proc *);
Index: switchd.c
===================================================================
RCS file: /cvs/src/usr.sbin/switchd/switchd.c,v
retrieving revision 1.15
diff -u -p -u -r1.15 switchd.c
--- switchd.c   9 Jan 2017 14:49:22 -0000       1.15
+++ switchd.c   2 Aug 2018 09:04:28 -0000
@@ -196,11 +196,12 @@ main(int argc, char *argv[])
         * stdio - for malloc and basic I/O including events.
         * rpath - for reload to open and read the configuration files.
         * wpath - for accessing the /dev/switch device.
+        * cpath - for managing the control socket.
         * inet - for opening OpenFlow and device sockets.
         * dns - for resolving host in the configuration files.
         * sendfd - send sockets to child processes on reload.
         */
-       if (pledge("stdio rpath wpath inet dns sendfd", NULL) == -1)
+       if (pledge("stdio rpath wpath cpath inet dns sendfd", NULL) == -1)
                fatal("pledge");
 
        event_init();
@@ -472,6 +473,8 @@ parent_dispatch_control(int fd, struct p
 void
 parent_shutdown(struct switchd *sc)
 {
+       control_cleanup(SWITCHD_SOCKET);
+
        proc_kill(&sc->sc_ps);
 
        free(sc);

Reply via email to