From a75023719c4aff3b82ab3e0daf65185a373c0d61 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sat, 15 Nov 2008 08:42:35 +0100 Subject: [PATCH] More privilege separation --- src/lldpd.c | 77 +++++++++--------------------------- src/lldpd.h | 16 ++++---- src/priv.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 132 insertions(+), 73 deletions(-) diff --git a/src/lldpd.c b/src/lldpd.c index f995465a..a235d056 100644 --- a/src/lldpd.c +++ b/src/lldpd.c @@ -50,7 +50,6 @@ void usage(void); int lldpd_iface_init(struct lldpd *, struct lldpd_hardware *); int lldpd_iface_init_vlan(struct lldpd *, struct lldpd_vif *); void lldpd_iface_init_mtu(struct lldpd *, struct lldpd_hardware *); -int lldpd_iface_init_socket(struct lldpd *, struct lldpd_hardware *); int lldpd_iface_close(struct lldpd *, struct lldpd_hardware *); void lldpd_iface_multicast(struct lldpd *, const char *, int); @@ -182,25 +181,6 @@ lldpd_iface_init_mtu(struct lldpd *global, struct lldpd_hardware *hardware) hardware->h_mtu = ifr.ifr_mtu; } -int -lldpd_iface_init_socket(struct lldpd *global, struct lldpd_hardware *hardware) -{ - struct sockaddr_ll sa; - - /* Open listening socket to receive/send frames */ - if ((hardware->h_raw = socket(PF_PACKET, SOCK_RAW, - htons(ETH_P_ALL))) < 0) - return errno; - memset(&sa, 0, sizeof(sa)); - sa.sll_family = AF_PACKET; - sa.sll_protocol = 0; - sa.sll_ifindex = if_nametoindex(hardware->h_ifname); - if (bind(hardware->h_raw, (struct sockaddr*)&sa, sizeof(sa)) < 0) - return errno; - - return 0; -} - int lldpd_iface_init_vlan(struct lldpd *global, struct lldpd_vif *vif) { @@ -208,7 +188,7 @@ lldpd_iface_init_vlan(struct lldpd *global, struct lldpd_vif *vif) short int filter; lldpd_iface_init_mtu(global, (struct lldpd_hardware*)vif); - status = lldpd_iface_init_socket(global, (struct lldpd_hardware*)vif); + status = priv_iface_init((struct lldpd_hardware*)vif, -1); if (status != 0) return status; @@ -233,15 +213,13 @@ lldpd_iface_init_vlan(struct lldpd *global, struct lldpd_vif *vif) int lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware) { - struct sockaddr_ll sa; int master; /* Bond device */ char if_bond[IFNAMSIZ]; - int un = 1; int status; short int filter; lldpd_iface_init_mtu(global, hardware); - status = lldpd_iface_init_socket(global, hardware); + status = priv_iface_init(hardware, -1); if (status != 0) return status; @@ -255,25 +233,13 @@ lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware) hardware->h_raw_real = hardware->h_raw; hardware->h_master = master; hardware->h_raw = -1; - if ((hardware->h_raw = socket(PF_PACKET, SOCK_RAW, - htons(ETH_P_ALL))) < 0) - return errno; - memset(&sa, 0, sizeof(sa)); - sa.sll_family = AF_PACKET; - sa.sll_protocol = 0; - sa.sll_ifindex = master; - if (bind(hardware->h_raw, (struct sockaddr*)&sa, - sizeof(sa)) < 0) - return errno; - /* With bonding, we need to listen to bond device. We use - * setsockopt() PACKET_ORIGDEV to get physical device instead of - * bond device */ - if (setsockopt(hardware->h_raw, SOL_PACKET, - PACKET_ORIGDEV, &un, sizeof(un)) == -1) { - LLOG_WARN("unable to setsockopt for master bonding device of %s. " - "You will get inaccurate results", - hardware->h_ifname); - } + status = priv_iface_init(hardware, master); + if (status != 0) { + close(hardware->h_raw_real); + if (hardware->h_raw != -1) + close(hardware->h_raw); + return status; + } } if (global->g_multi) @@ -297,23 +263,18 @@ lldpd_iface_init(struct lldpd *global, struct lldpd_hardware *hardware) void lldpd_iface_multicast(struct lldpd *global, const char *name, int remove) { - struct ifreq ifr; - int i; - + int i, rc; + for (i=0; global->g_protocols[i].mode != 0; i++) { if (!global->g_protocols[i].enabled) continue; - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); - memcpy(ifr.ifr_hwaddr.sa_data, - global->g_protocols[i].mac, ETH_ALEN); - if (ioctl(global->g_sock, (remove)?SIOCDELMULTI:SIOCADDMULTI, - &ifr) < 0) { - if (errno == ENOENT) - return; - LLOG_INFO("unable to %s %s address to multicast filter for %s", - (remove)?"delete":"add", - global->g_protocols[i].name, - name); + if ((rc = priv_iface_multicast(name, + global->g_protocols[i].mac, !remove)) != 0) { + errno = rc; + if (errno != ENOENT) + LLOG_INFO("unable to %s %s address to multicast filter for %s", + (remove)?"delete":"add", + global->g_protocols[i].name, + name); } } } diff --git a/src/lldpd.h b/src/lldpd.h index 6156822b..61614ccd 100644 --- a/src/lldpd.h +++ b/src/lldpd.h @@ -328,13 +328,15 @@ void client_handle_shutdown(struct lldpd *, struct hmsg *, struct hmsg *); /* priv.c */ -void priv_init(); -void priv_fork(); -int priv_ctl_create(); -void priv_ctl_cleanup(); -char *priv_gethostbyname(); -int priv_open(char*); -int priv_ethtool(char*, struct ethtool_cmd*); +void priv_init(); +void priv_fork(); +int priv_ctl_create(); +void priv_ctl_cleanup(); +char *priv_gethostbyname(); +int priv_open(char*); +int priv_ethtool(char*, struct ethtool_cmd*); +int priv_iface_init(struct lldpd_hardware *, int); +int priv_iface_multicast(char *, u_int8_t *, int); /* privsep_fdpass.c */ int receive_fd(int); diff --git a/src/priv.c b/src/priv.c index fd26a8fa..f4a01e36 100644 --- a/src/priv.c +++ b/src/priv.c @@ -34,6 +34,7 @@ #include #include #include +#include enum { PRIV_FORK, @@ -42,6 +43,8 @@ enum { PRIV_GET_HOSTNAME, PRIV_OPEN, PRIV_ETHTOOL, + PRIV_IFACE_INIT, + PRIV_IFACE_MULTICAST, }; static int may_read(int, void *, size_t); @@ -50,6 +53,7 @@ static void must_write(int, void *, size_t); int remote; /* Other side */ int monitored = -1; /* Child */ +int sock = -1; /* Proxies */ @@ -135,6 +139,34 @@ priv_ethtool(char *ifname, struct ethtool_cmd *ethc) return rc; } +int +priv_iface_init(struct lldpd_hardware *hardware, int master) +{ + int cmd, rc; + cmd = PRIV_IFACE_INIT; + must_write(remote, &cmd, sizeof(int)); + must_write(remote, &master, sizeof(int)); + must_write(remote, hardware->h_ifname, IFNAMSIZ); + must_read(remote, &rc, sizeof(int)); + if (rc != 0) + return rc; /* It's errno */ + hardware->h_raw = receive_fd(remote); + return 0; +} + +int +priv_iface_multicast(char *name, u_int8_t *mac, int add) +{ + int cmd, rc; + cmd = PRIV_IFACE_MULTICAST; + must_write(remote, &cmd, sizeof(cmd)); + must_write(remote, name, IFNAMSIZ); + must_write(remote, mac, ETH_ALEN); + must_write(remote, &add, sizeof(int)); + must_read(remote, &rc, sizeof(int)); + return rc; +} + void asroot_fork() { @@ -240,7 +272,7 @@ asroot_ethtool() { struct ifreq ifr; struct ethtool_cmd ethc; - int len, rc, sock; + int len, rc; char *ifname; memset(&ifr, 0, sizeof(ifr)); @@ -252,12 +284,6 @@ asroot_ethtool() strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t)ðc; ethc.cmd = ETHTOOL_GSET; - if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - LLOG_WARN("[priv]: unable to get a socket"); - must_write(remote, &sock, sizeof(int)); - free(ifname); - return; - } if ((rc = ioctl(sock, SIOCETHTOOL, &ifr)) != 0) { LLOG_WARN("[priv]: unable to ioctl ETHTOOL for %s", ifname); must_write(remote, &rc, sizeof(int)); @@ -265,11 +291,76 @@ asroot_ethtool() close(sock); return; } - close(sock); must_write(remote, &rc, sizeof(int)); must_write(remote, ðc, sizeof(struct ethtool_cmd)); } +void +asroot_iface_init() +{ + struct sockaddr_ll sa; + int un = 1; + int s, master; + char ifname[IFNAMSIZ]; + + must_read(remote, &master, sizeof(int)); + must_read(remote, ifname, IFNAMSIZ); + + /* Open listening socket to receive/send frames */ + if ((s = socket(PF_PACKET, SOCK_RAW, + htons(ETH_P_ALL))) < 0) { + must_write(remote, &errno, sizeof(errno)); + return; + } + memset(&sa, 0, sizeof(sa)); + sa.sll_family = AF_PACKET; + sa.sll_protocol = 0; + if (master == -1) + sa.sll_ifindex = if_nametoindex(ifname); + else + sa.sll_ifindex = master; + if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) { + must_write(remote, &errno, sizeof(errno)); + close(s); + return; + } + + if (master != -1) { + /* With bonding, we need to listen to bond device. We use + * setsockopt() PACKET_ORIGDEV to get physical device instead of + * bond device */ + if (setsockopt(s, SOL_PACKET, + PACKET_ORIGDEV, &un, sizeof(un)) == -1) { + LLOG_WARN("[priv]: unable to setsockopt for master bonding device of %s. " + "You will get inaccurate results", + ifname); + } + } + errno = 0; + must_write(remote, &errno, sizeof(errno)); + send_fd(remote, s); + close(s); +} + +void +asroot_iface_multicast() +{ + int add, rc = 0; + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + must_read(remote, ifr.ifr_name, IFNAMSIZ); + must_read(remote, ifr.ifr_hwaddr.sa_data, ETH_ALEN); + must_read(remote, &add, sizeof(int)); + + if (ioctl(sock, (add)?SIOCADDMULTI:SIOCDELMULTI, + &ifr) < 0) { + must_write(remote, &errno, sizeof(errno)); + return; + } + + must_write(remote, &rc, sizeof(rc)); +} + struct dispatch_actions { int msg; void(*function)(void); @@ -282,6 +373,8 @@ struct dispatch_actions actions[] = { {PRIV_GET_HOSTNAME, asroot_gethostbyname}, {PRIV_OPEN, asroot_open}, {PRIV_ETHTOOL, asroot_ethtool}, + {PRIV_IFACE_INIT, asroot_iface_init}, + {PRIV_IFACE_MULTICAST, asroot_iface_multicast}, {-1, NULL} }; @@ -390,6 +483,9 @@ priv_init() close(pair[0]); if (atexit(priv_exit) != 0) fatal("[priv]: unable to set exit function"); + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + fatal("[priv]: unable to get a socket"); + } signal(SIGALRM, sig_pass_to_chld); signal(SIGTERM, sig_pass_to_chld); -- 2.47.2