]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
priv: add the ability to disable privilege separation
authorVincent Bernat <bernat@luffy.cx>
Fri, 13 Dec 2013 22:25:04 +0000 (23:25 +0100)
committerVincent Bernat <bernat@luffy.cx>
Tue, 31 Dec 2013 14:18:32 +0000 (15:18 +0100)
This is a compile time switch in ./configure. It should only be used for
debugging purposes or when memory and number of processes matter or for
running on platforms without a real `fork()` syscall. We add it to the
NEWS but we make no further mention in the documentation.

NEWS
configure.ac
src/daemon/agent.c
src/daemon/agent_priv.c
src/daemon/lldpd.h
src/daemon/priv-linux.c
src/daemon/priv-seccomp.c
src/daemon/priv.c

diff --git a/NEWS b/NEWS
index 796e8016df00992ee513e89402e83d011eff140c..86205ed472f3f0a706b7e57712b9234586522aa0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ lldpd (0.7.8)
       just don't display it.
   * Features:
     + Android support
+    + Add the possibility to disable privilege separation (lower
+      memory consumption, lower security, don't do it).
 
 lldpd (0.7.7)
   * Features:
index 458beff207e1069be7a8754b3a0ea1cf8f545490..553a17c38cb2d3b55bf06da5f594e23560550ce3 100644 (file)
@@ -209,6 +209,7 @@ AM_CONDITIONAL(HAVE_SYSTEMDSYSTEMUNITDIR,
 lldp_SYSTEMTAP
 
 # Privsep settings
+lldp_ARG_ENABLE([privsep], [Privilege separation], [yes])
 lldp_ARG_WITH([privsep-user], [Which user to use for privilege separation], [_lldpd])
 lldp_ARG_WITH([privsep-group], [Which group to use for privilege separation], [_lldpd])
 lldp_ARG_WITH([privsep-chroot], [Which directory to use to chroot lldpd], [/var/run/lldpd])
@@ -265,6 +266,10 @@ cat <<EOF
   JSON output....: ${with_json-no}
   Oldies support.: $enable_oldies
   seccomp........: ${with_seccomp-no}
+ Privilege separation:
+  Enabled........: $enable_privsep
+  User/group.....: ${with_privsep_user-_lldpd}/${with_privsep_group-_lldpd}
+  Chroot.........: ${with_privsep_chroot-/var/run/lldpd}
 ---------------------------------------------
 
 Check the above options and compile with:
index 0d10dd2eb70aa0d4297337fe99c9e9e01fd62a10..508a4db0538c57ee68d4bef72b2ccc635df689e9 100644 (file)
@@ -1855,9 +1855,11 @@ agent_init(struct lldpd *cfg, char *agentx)
        setenv("MIBS", "", 1);
        setenv("MIBDIRS", "/dev/null", 1);
 
+#ifdef ENABLE_PRIVSEP
        /* We provide our UNIX domain transport */
        log_debug("snmp", "register UNIX domain transport");
        agent_priv_register_domain();
+#endif
 
        if (agentx)
                netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
index 6334cb5e66e1f1faf38f3d6e302bcbc4de89b90c..ee1438250aa1ec13b108a98ea980ae5646c9ca39 100644 (file)
@@ -25,6 +25,7 @@
 #include <unistd.h>
 #include <errno.h>
 
+#ifdef ENABLE_PRIVSEP
 #include <net-snmp/net-snmp-config.h>
 #include <net-snmp/net-snmp-includes.h>
 #include <net-snmp/agent/net-snmp-agent-includes.h>
@@ -204,3 +205,4 @@ agent_priv_register_domain()
        unixDomain.f_create_from_ostring = agent_priv_unix_create_ostring;
        netsnmp_tdomain_register(&unixDomain);
 }
+#endif
index 40b12bebe22f648e0dd5a67e6843687399e5470f..56835763177544f1af9fdbf49a1b4c05879fc976 100644 (file)
@@ -199,8 +199,10 @@ void                agent_init(struct lldpd *, char *);
 void            agent_notify(struct lldpd_hardware *, int, struct lldpd_port *);
 #endif
 
+#ifdef ENABLE_PRIVSEP
 /* agent_priv.c */
 void            agent_priv_register_domain(void);
+#endif
 
 /* client.c */
 int
@@ -212,6 +214,7 @@ client_handle_client(struct lldpd *cfg,
 
 /* priv.c */
 void    priv_init(const char*, int, uid_t, gid_t);
+void    priv_wait(void);
 void    priv_ctl_cleanup(const char *ctlname);
 char           *priv_gethostbyname(void);
 #ifdef HOST_OS_LINUX
@@ -240,7 +243,7 @@ enum priv_cmd {
 };
 
 /* priv-seccomp.c */
-#ifdef USE_SECCOMP
+#if defined USE_SECCOMP && defined ENABLE_PRIVSEP
 int priv_seccomp_init(int, int);
 #endif
 
index 0fbeebad832067de0670cc1d84ab8dcb7946b360..585948b94abb6188d2f1a01987674dce837233ab 100644 (file)
@@ -39,6 +39,7 @@ priv_open(char *file)
        len = strlen(file);
        must_write(PRIV_UNPRIVILEGED, &len, sizeof(int));
        must_write(PRIV_UNPRIVILEGED, file, len + 1);
+       priv_wait();
        must_read(PRIV_UNPRIVILEGED, &rc, sizeof(int));
        if (rc == -1)
                return rc;
@@ -55,6 +56,7 @@ priv_ethtool(char *ifname, void *ethc, size_t length)
        len = strlen(ifname);
        must_write(PRIV_UNPRIVILEGED, &len, sizeof(int));
        must_write(PRIV_UNPRIVILEGED, ifname, len + 1);
+       priv_wait();
        must_read(PRIV_UNPRIVILEGED, &rc, sizeof(int));
        if (rc != 0)
                return rc;
index 796275283f9e97d810953f5a8a2d93ea6aa98701..7eb49d6fff438723780e7dfd012b181eba37c866 100644 (file)
@@ -40,6 +40,8 @@
 # define ARCH_NR       0
 #endif
 
+/* If there is no privilege separation, seccomp is currently useless */
+#ifdef ENABLE_PRIVSEP
 static int monitored = -1;
 static int trapped = 0;
 /**
@@ -181,3 +183,4 @@ failure_scmp:
        seccomp_release(ctx);
        return rc;
 }
+#endif
index 5feae843fbc6576fcdc6508b45a7b19ce7caf85e..68a8d52e679051b4e065364414050d613481ea91 100644 (file)
@@ -67,7 +67,9 @@
 int res_init (void);
 #endif
 
+#ifdef ENABLE_PRIVSEP
 static int monitored = -1;             /* Child */
+#endif
 
 /* Proxies */
 static void
@@ -76,6 +78,7 @@ priv_ping()
        int rc;
        enum priv_cmd cmd = PRIV_PING;
        must_write(PRIV_UNPRIVILEGED, &cmd, sizeof(enum priv_cmd));
+       priv_wait();
        must_read(PRIV_UNPRIVILEGED, &rc, sizeof(int));
        log_debug("privsep", "monitor ready");
 }
@@ -89,6 +92,7 @@ priv_ctl_cleanup(const char *ctlname)
        must_write(PRIV_UNPRIVILEGED, &cmd, sizeof(enum priv_cmd));
        must_write(PRIV_UNPRIVILEGED, &len, sizeof(int));
        must_write(PRIV_UNPRIVILEGED, ctlname, len);
+       priv_wait();
        must_read(PRIV_UNPRIVILEGED, &rc, sizeof(int));
 }
 
@@ -100,6 +104,7 @@ priv_gethostbyname()
        int rc;
        enum priv_cmd cmd = PRIV_GET_HOSTNAME;
        must_write(PRIV_UNPRIVILEGED, &cmd, sizeof(enum priv_cmd));
+       priv_wait();
        must_read(PRIV_UNPRIVILEGED, &rc, sizeof(int));
        if ((buf = (char*)realloc(buf, rc+1)) == NULL)
                fatal("privsep", NULL);
@@ -118,6 +123,7 @@ priv_iface_init(int index, char *iface)
        must_write(PRIV_UNPRIVILEGED, &index, sizeof(int));
        strlcpy(dev, iface, IFNAMSIZ);
        must_write(PRIV_UNPRIVILEGED, dev, IFNAMSIZ);
+       priv_wait();
        must_read(PRIV_UNPRIVILEGED, &rc, sizeof(int));
        if (rc != 0) return -1;
        return receive_fd(PRIV_UNPRIVILEGED);
@@ -132,6 +138,7 @@ priv_iface_multicast(const char *name, u_int8_t *mac, int add)
        must_write(PRIV_UNPRIVILEGED, name, IFNAMSIZ);
        must_write(PRIV_UNPRIVILEGED, mac, ETHER_ADDR_LEN);
        must_write(PRIV_UNPRIVILEGED, &add, sizeof(int));
+       priv_wait();
        must_read(PRIV_UNPRIVILEGED, &rc, sizeof(int));
        return rc;
 }
@@ -145,6 +152,7 @@ priv_iface_description(const char *name, const char *description)
        must_write(PRIV_UNPRIVILEGED, name, IFNAMSIZ);
        must_write(PRIV_UNPRIVILEGED, &len, sizeof(int));
        must_write(PRIV_UNPRIVILEGED, description, len);
+       priv_wait();
        must_read(PRIV_UNPRIVILEGED, &rc, sizeof(int));
        return rc;
 }
@@ -156,6 +164,7 @@ priv_snmp_socket(struct sockaddr_un *addr)
        enum priv_cmd cmd = PRIV_SNMP_SOCKET;
        must_write(PRIV_UNPRIVILEGED, &cmd, sizeof(enum priv_cmd));
        must_write(PRIV_UNPRIVILEGED, addr, sizeof(struct sockaddr_un));
+       priv_wait();
        must_read(PRIV_UNPRIVILEGED, &rc, sizeof(int));
        if (rc < 0)
                return rc;
@@ -348,15 +357,17 @@ static struct dispatch_actions actions[] = {
 
 /* Main loop, run as root */
 static void
-priv_loop(int privileged)
+priv_loop(int privileged, int once)
 {
        enum priv_cmd cmd;
        struct dispatch_actions *a;
 
+#ifdef ENABLE_PRIVSEP
        setproctitle("monitor");
 #ifdef USE_SECCOMP
        if (priv_seccomp_init(privileged, monitored) != 0)
           fatal("privsep", "cannot continue without seccomp setup");
+#endif
 #endif
        while (!may_read(PRIV_PRIVILEGED, &cmd, sizeof(enum priv_cmd))) {
                for (a = actions; a->function != NULL; a++) {
@@ -367,10 +378,23 @@ priv_loop(int privileged)
                }
                if (a->function == NULL)
                        fatal("privsep", "bogus message received");
+               if (once) break;
        }
-       /* Should never be there */
 }
 
+/* This function is a NOOP when privilege separation is enabled. In
+ * the other case, it should be called when we wait an action from the
+ * privileged side. */
+void
+priv_wait() {
+#ifndef ENABLE_PRIVSEP
+       /* We have no remote process on the other side. Let's emulate it. */
+       priv_loop(0, 1);
+#endif
+}
+
+
+#ifdef ENABLE_PRIVSEP
 static void
 priv_exit_rc_status(int rc, int status) {
        switch (rc) {
@@ -517,19 +541,24 @@ priv_setup_chroot(const char *chrootdir)
        close(source);
        close(destination);
 }
+#endif
 
 void
 priv_init(const char *chrootdir, int ctl, uid_t uid, gid_t gid)
 {
 
        int pair[2];
-       gid_t gidset[1];
-        int status;
 
        /* Create socket pair */
        if (socketpair(AF_LOCAL, SOCK_DGRAM, PF_UNSPEC, pair) < 0)
                fatal("privsep", "unable to create socket pair for privilege separation");
 
+       priv_unprivileged_fd(pair[0]);
+       priv_privileged_fd(pair[1]);
+
+#ifdef ENABLE_PRIVSEP
+       gid_t gidset[1];
+        int status;
        /* Spawn off monitor */
        if ((monitored = fork()) < 0)
                fatal("privsep", "unable to fork monitor");
@@ -562,14 +591,12 @@ priv_init(const char *chrootdir, int ctl, uid_t uid, gid_t gid)
                                fatal("privsep", "setreuid() failed");
 #endif
                }
-               priv_unprivileged_fd(pair[0]);
                close(pair[1]);
                priv_ping();
                break;
        default:
                /* We are in the monitor */
                if (ctl != -1) close(ctl);
-               priv_privileged_fd(pair[1]);
                close(pair[0]);
                if (atexit(priv_exit) != 0)
                        fatal("privsep", "unable to set exit function");
@@ -593,8 +620,11 @@ priv_init(const char *chrootdir, int ctl, uid_t uid, gid_t gid)
                 if (waitpid(monitored, &status, WNOHANG) != 0)
                         /* Child is already dead */
                         _exit(1);
-               priv_loop(pair[1]);
+               priv_loop(pair[1], 0);
                exit(0);
        }
+#else
+       log_warnx("priv", "no privilege separation available");
+       priv_ping();
+#endif
 }
-