From: Roy Marples Date: Sun, 24 May 2020 05:47:14 +0000 (+0000) Subject: privsep: Allow Linux to work without needing any mounts X-Git-Tag: v9.1.0~29 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=12b0db43b2a139744fbcf04824390fcb1de445ea;p=thirdparty%2Fdhcpcd.git privsep: Allow Linux to work without needing any mounts --- diff --git a/BUILDING.md b/BUILDING.md index fb21c9f7..3540557d 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -161,9 +161,3 @@ copied to `$(libexecdir)/dhcpcd-hooks` for use. The configure program attempts to find hooks for systems you have installed. To add more simply `./configure -with-hook=ntp.conf` - -If running privilege separation and on Linux then the `00-linux` hook is -**mandatory**. -If you choose not to run it, then you are responsible for setting up the -needed mount points: `/dev`, `/proc`, `/sys`, `/run/udev` -as well as sorting out `/dev/log` if it points to something outside of `/dev`. diff --git a/configure b/configure index 853587fb..73be11e6 100755 --- a/configure +++ b/configure @@ -1766,9 +1766,6 @@ if cd hooks; then done cd .. fi -if [ "$OS" = linux ]; then - HOOKS="$HOOKS${HOOKS:+ }00-linux" -fi echo "HOOKSCRIPTS= $HOOKS" >>$CONFIG_MK echo "EGHOOKSCRIPTS= $EGHOOKS" >>$CONFIG_MK diff --git a/hooks/00-linux b/hooks/00-linux deleted file mode 100644 index f2a09213..00000000 --- a/hooks/00-linux +++ /dev/null @@ -1,17 +0,0 @@ -# setup chroot mounts - -if [ "$reason" = CHROOT ] && [ -n "$chroot" ]; then - # Special case /dev/log - if [ -h /dev/log ]; then - devlogdir=$(dirname $(readlink /dev/log)) - else - devlogdir= - fi - for d in /dev /proc /sys /run/udev $devlogdir; do - [ -d "$d" ] || continue - if ! mountpoint -q "$chroot$d"; then - mkdir -p "$chroot$d" - mount --bind $d "$chroot$d" - fi - done -fi diff --git a/src/common.c b/src/common.c index 41528f33..ddab3042 100644 --- a/src/common.c +++ b/src/common.c @@ -109,28 +109,17 @@ ssize_t readfile(const char *file, void *data, size_t len) { int fd; - struct stat st; - ssize_t bytes = -1; + ssize_t bytes; fd = open(file, O_RDONLY); if (fd == -1) return -1; - - if (fstat(fd, &st) != 0) - goto out; - if (!S_ISREG(st.st_mode)) { - errno = EINVAL; - goto out; - } - if ((size_t)st.st_size > len) { - errno = E2BIG; - goto out; - } bytes = read(fd, data, len); - -out: - if (fd != -1) - close(fd); + close(fd); + if ((size_t)bytes == len) { + errno = ENOBUFS; + return -1; + } return bytes; } diff --git a/src/if-linux.c b/src/if-linux.c index 32d380c4..dc0cf25b 100644 --- a/src/if-linux.c +++ b/src/if-linux.c @@ -149,7 +149,7 @@ static int if_addressexists(struct interface *, struct in_addr *); #define PROC_INET6 "/proc/net/if_inet6" #define PROC_PROMOTE "/proc/sys/net/ipv4/conf/%s/promote_secondaries" -#define SYS_BRIDGE "/sys/class/net/%s/bridge" +#define SYS_BRIDGE "/sys/class/net/%s/bridge/bridge_id" #define SYS_LAYER2 "/sys/class/net/%s/device/layer2" #define SYS_TUNTAP "/sys/class/net/%s/tun_flags" @@ -220,53 +220,44 @@ if_machinearch(char *str, size_t len) } static int -check_proc_int(const char *path) +check_proc_int(struct dhcpcd_ctx *ctx, const char *path) { - FILE *fp; - int i; + char buf[64]; + int error, i; - fp = fopen(path, "r"); - if (fp == NULL) + if (dhcp_readfile(ctx, path, buf, sizeof(buf)) == -1) return -1; - if (fscanf(fp, "%d", &i) != 1) - i = -1; - fclose(fp); + i = (int)strtoi(buf, NULL, 0, INT_MIN, INT_MAX, &error); + if (error != 0 && error != ENOTSUP) { + errno = error; + return -1; + } return i; } static int -check_proc_hex(const char *path, unsigned int *value) +check_proc_uint(struct dhcpcd_ctx *ctx, const char *path, unsigned int *u) { - FILE *fp; - int i; + char buf[64]; + int error; - fp = fopen(path, "r"); - if (fp == NULL) + if (dhcp_readfile(ctx, path, buf, sizeof(buf)) == -1) return -1; - i = fscanf(fp, "%x", value) == 1 ? 0 : -1; - fclose(fp); - return i; + *u = (unsigned int)strtou(buf, NULL, 0, 0, UINT_MAX, &error); + if (error != 0 && error != ENOTSUP) { + errno = error; + return error; + } + return 0; } static ssize_t if_writepathuint(struct dhcpcd_ctx *ctx, const char *path, unsigned int val) { - FILE *fp; - ssize_t r; + char buf[64]; -#ifdef PRIVSEP - if (ctx->options & DHCPCD_PRIVSEP) - return ps_root_writepathuint(ctx, path, val); -#else - UNUSED(ctx); -#endif - - fp = fopen(path, "w"); - if (fp == NULL) - return -1; - r = fprintf(fp, "%u\n", val); - fclose(fp); - return r; + snprintf(buf, sizeof(buf), "%u\n", val); + return dhcp_writefile(ctx, path, 0664, buf, sizeof(buf)); } int @@ -283,7 +274,7 @@ if_init(struct interface *ifp) * This matches the behaviour of BSD which makes coding dhcpcd * a little easier as there's just one behaviour. */ snprintf(path, sizeof(path), PROC_PROMOTE, ifp->name); - n = check_proc_int(path); + n = check_proc_int(ifp->ctx, path); if (n == -1) return errno == ENOENT ? 0 : -1; if (n == 1) @@ -299,7 +290,7 @@ if_conf(struct interface *ifp) /* Some qeth setups require the use of the broadcast flag. */ snprintf(path, sizeof(path), SYS_LAYER2, ifp->name); - n = check_proc_int(path); + n = check_proc_int(ifp->ctx, path); if (n == -1) return errno == ENOENT ? 0 : -1; if (n == 0) @@ -308,34 +299,33 @@ if_conf(struct interface *ifp) } static bool -if_bridge(const char *ifname) +if_bridge(struct dhcpcd_ctx *ctx, const char *ifname) { - char path[sizeof(SYS_BRIDGE) + IF_NAMESIZE]; - struct stat sb; + char path[sizeof(SYS_BRIDGE) + IF_NAMESIZE], buf[64]; snprintf(path, sizeof(path), SYS_BRIDGE, ifname); - if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) - return true; - return false; + if (dhcp_readfile(ctx, path, buf, sizeof(buf)) == -1) + return false; + return true; } static bool -if_tap(const char *ifname) +if_tap(struct dhcpcd_ctx *ctx, const char *ifname) { char path[sizeof(SYS_TUNTAP) + IF_NAMESIZE]; - unsigned int n; + unsigned int u; snprintf(path, sizeof(path), SYS_TUNTAP, ifname); - if (check_proc_hex(path, &n) == -1) + if (check_proc_uint(ctx, path, &u) == -1) return false; - return n & IFF_TAP; + return u & IFF_TAP; } bool -if_ignore(__unused struct dhcpcd_ctx *ctx, const char *ifname) +if_ignore(struct dhcpcd_ctx *ctx, const char *ifname) { - if (if_tap(ifname) || if_bridge(ifname)) + if (if_tap(ctx, ifname) || if_bridge(ctx, ifname)) return true; return false; } @@ -1866,14 +1856,19 @@ int if_addrflags6(const struct interface *ifp, const struct in6_addr *addr, __unused const char *alias) { - FILE *fp; + char buf[PS_BUFLEN], *bp = buf, *line; + ssize_t buflen; char *p, ifaddress[33], address[33], name[IF_NAMESIZE + 1]; unsigned int ifindex; int prefix, scope, flags, i; - fp = fopen(PROC_INET6, "r"); - if (fp == NULL) + buflen = dhcp_readfile(ifp->ctx, PROC_INET6, buf, sizeof(buf)); + if (buflen == -1) + return -1; + if ((size_t)buflen == sizeof(buf)) { + errno = ENOBUFS; return -1; + } p = ifaddress; for (i = 0; i < (int)sizeof(addr->s6_addr); i++) { @@ -1881,23 +1876,20 @@ if_addrflags6(const struct interface *ifp, const struct in6_addr *addr, } *p = '\0'; - while (fscanf(fp, "%32[a-f0-9] %x %x %x %x %"TOSTRING(IF_NAMESIZE)"s\n", - address, &ifindex, &prefix, &scope, &flags, name) == 6) - { - if (strlen(address) != 32) { - fclose(fp); + while ((line = get_line(&bp, &buflen)) != NULL) { + if (sscanf(line, + "%32[a-f0-9] %x %x %x %x %"TOSTRING(IF_NAMESIZE)"s\n", + address, &ifindex, &prefix, &scope, &flags, name) != 6 || + strlen(address) != 32) + { errno = EINVAL; return -1; } if (strcmp(name, ifp->name) == 0 && strcmp(ifaddress, address) == 0) - { - fclose(fp); return flags; - } } - fclose(fp); errno = ESRCH; return -1; } @@ -1972,11 +1964,12 @@ static const char *p_neigh = "/proc/sys/net/ipv6/neigh"; void if_setup_inet6(const struct interface *ifp) { + struct dhcpcd_ctx *ctx = ifp->ctx; int ra; char path[256]; /* The kernel cannot make stable private addresses. */ - if (if_disable_autolinklocal(ifp->ctx, ifp->index) == -1) + if (if_disable_autolinklocal(ctx, ifp->index) == -1 && errno != ENODEV) logdebug("%s: if_disable_autolinklocal", ifp->name); /* @@ -1987,21 +1980,21 @@ if_setup_inet6(const struct interface *ifp) return; snprintf(path, sizeof(path), "%s/%s/autoconf", p_conf, ifp->name); - ra = check_proc_int(path); + ra = check_proc_int(ctx, path); if (ra != 1 && ra != -1) { - if (if_writepathuint(ifp->ctx, path, 0) == -1) + if (if_writepathuint(ctx, path, 0) == -1) logerr("%s: %s", __func__, path); } snprintf(path, sizeof(path), "%s/%s/accept_ra", p_conf, ifp->name); - ra = check_proc_int(path); + ra = check_proc_int(ctx, path); if (ra == -1) { /* The sysctl probably doesn't exist, but this isn't an * error as such so just log it and continue */ if (errno != ENOENT) logerr("%s: %s", __func__, path); } else if (ra != 0) { - if (if_writepathuint(ifp->ctx, path, 0) == -1) + if (if_writepathuint(ctx, path, 0) == -1) logerr("%s: %s", __func__, path); } } @@ -2040,14 +2033,18 @@ if_applyra(const struct ra *rap) int ip6_forwarding(const char *ifname) { - char path[256]; - int val; + char path[256], buf[64]; + int error, i; if (ifname == NULL) ifname = "all"; snprintf(path, sizeof(path), "%s/%s/forwarding", p_conf, ifname); - val = check_proc_int(path); - return val == -1 ? 0 : val; + if (readfile(path, buf, sizeof(buf)) == -1) + return 0; + i = (int)strtoi(buf, NULL, 0, INT_MIN, INT_MAX, &error); + if (error != 0) + return -1; + return error != 0 ? 0 : i; } #endif /* INET6 */ diff --git a/src/ipv6.c b/src/ipv6.c index c1e23588..71b51bc7 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -1106,6 +1106,13 @@ ipv6_anyglobal(struct interface *sifp) if (ifp != sifp && !forwarding) continue; #else +#if defined(PRIVSEP) && defined(__linux__) + if (IN_PRIVSEP(sifp->ctx)) { + if (ifp != sifp && + ps_root_ip6forwarding(sifp->ctx, ifp->name) != 1) + continue; + } else +#endif if (ifp != sifp && ip6_forwarding(ifp->name) != 1) continue; #endif diff --git a/src/ipv6nd.c b/src/ipv6nd.c index 924dc9de..e56fd413 100644 --- a/src/ipv6nd.c +++ b/src/ipv6nd.c @@ -524,11 +524,13 @@ ipv6nd_advertise(struct ipv6_addr *ia) na->nd_na_type = ND_NEIGHBOR_ADVERT; na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE; -#ifdef HAVE_PLEDGE - if (ps_root_ip6_forwarding(ctx) == 1) -#else - if (ip6_forwarding(ifp->name) == 1) +#if defined(PRIVSEP) && (defined(__linux__) || defined(HAVE_PLEDGE)) + if (IN_PRIVSEP(ctx)) { + if (ps_root_ip6forwarding(ctx, ifp->name) == 1) + na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER; + } else #endif + if (ip6_forwarding(ifp->name) == 1) na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER; na->nd_na_target = ia->addr; diff --git a/src/privsep-bsd.c b/src/privsep-bsd.c index e73984e4..bf17ce9f 100644 --- a/src/privsep-bsd.c +++ b/src/privsep-bsd.c @@ -151,8 +151,6 @@ ps_root_os(struct ps_msghdr *psm, struct msghdr *msg) #ifdef HAVE_PLEDGE case PS_IOCTLINDIRECT: return ps_root_doindirectioctl(psm->ps_flags, data, len); - case PS_IP6FORWARDING: - return ip6_forwarding(NULL); #endif default: errno = ENOTSUP; @@ -210,14 +208,4 @@ ps_root_indirectioctl(struct dhcpcd_ctx *ctx, unsigned long request, return -1; return ps_root_readerror(ctx, data, len); } - -ssize_t -ps_root_ip6forwarding(struct dhcpcd_ctx *ctx) -{ - - if (ps_sendcmd(ctx, ctx->ps_root_fd, - PS_IP6FORWARDING, 0, NULL, 0) == -1) - return -1; - return ps_root_readerror(ctx, NULL, 0); -} #endif diff --git a/src/privsep-linux.c b/src/privsep-linux.c index 98403f5c..6b6400a0 100644 --- a/src/privsep-linux.c +++ b/src/privsep-linux.c @@ -64,50 +64,13 @@ out: return retval; } -static ssize_t -ps_root_dowritepathuint(const void *data, size_t len) -{ - const char *path = data; - size_t plen; - unsigned int val; - int fd; - ssize_t r; - - if (len < sizeof(plen)) { - errno = EINVAL; - return -1; - } - - memcpy(&plen, path, sizeof(plen)); - path += sizeof(plen); - if (sizeof(plen) + plen + sizeof(val) > len) { - errno = EINVAL; - return -1; - } - - memcpy(&val, path + plen, sizeof(val)); - - fd = open(path, O_WRONLY); - if (fd == -1) - return -1; - r = dprintf(fd, "%u", val); - close(fd); - - return r; -} - ssize_t ps_root_os(struct ps_msghdr *psm, struct msghdr *msg) { - struct iovec *iov = msg->msg_iov; - void *data = iov->iov_base; - size_t len = iov->iov_len; switch (psm->ps_cmd) { case PS_ROUTE: return ps_root_dosendnetlink((int)psm->ps_flags, msg); - case PS_WRITEPATHUINT: - return ps_root_dowritepathuint(data, len); default: errno = ENOTSUP; return -1; @@ -123,28 +86,3 @@ ps_root_sendnetlink(struct dhcpcd_ctx *ctx, int protocol, struct msghdr *msg) return -1; return ps_root_readerror(ctx, NULL, 0); } - -ssize_t -ps_root_writepathuint(struct dhcpcd_ctx *ctx, const char *path, - unsigned int val) -{ - char buf[PS_BUFLEN], *p = buf; - size_t plen = strlen(path) + 1; - size_t len = sizeof(plen) + plen + sizeof(val); - - if (len > sizeof(buf)) { - errno = ENOBUFS; - return -1; - } - - memcpy(p, &plen, sizeof(plen)); - p += sizeof(plen); - memcpy(p, path, plen); - p += plen; - memcpy(p, &val, sizeof(val)); - - if (ps_sendcmd(ctx, ctx->ps_root_fd, PS_WRITEPATHUINT, - 0, buf, len) == -1) - return -1; - return ps_root_readerror(ctx, NULL, 0); -} diff --git a/src/privsep-root.c b/src/privsep-root.c index 716a55c4..b4216760 100644 --- a/src/privsep-root.c +++ b/src/privsep-root.c @@ -295,6 +295,14 @@ ps_root_validpath(const struct dhcpcd_ctx *ctx, uint16_t cmd, const char *path) return true; if (strncmp(RUNDIR, path, strlen(RUNDIR)) == 0) return true; + +#ifdef __linux__ + if (strncmp("/proc/net/", path, strlen("/proc/net/")) == 0 || + strncmp("/proc/sys/net/", path, strlen("/proc/sys/net/")) == 0 || + strncmp("/sys/class/net/", path, strlen("/sys/class/net/")) == 0) + return true; +#endif + errno = EPERM; return false; } @@ -310,6 +318,7 @@ ps_root_dowritefile(const struct dhcpcd_ctx *ctx, errno = EINVAL; return -1; } + if (!ps_root_validpath(ctx, PS_WRITEFILE, file)) return -1; nc++; @@ -510,6 +519,11 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg) err = ps_root_dogetifaddrs(&rdata, &rlen); free_rdata = true; break; +#endif +#if defined(__linux__) || defined(HAVE_PLEDGE) + case PS_IP6FORWARDING: + err = ip6_forwarding(data); + break; #endif default: err = ps_root_os(psm, msg); @@ -800,3 +814,15 @@ err: return -1; } #endif + +#if defined(__linux__) || defined(HAVE_PLEDGE) +ssize_t +ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname) +{ + + if (ps_sendcmd(ctx, ctx->ps_root_fd, + PS_IP6FORWARDING, 0, ifname, strlen(ifname) + 1) == -1) + return -1; + return ps_root_readerror(ctx, NULL, 0); +} +#endif diff --git a/src/privsep-root.h b/src/privsep-root.h index bf02bb5f..998c7830 100644 --- a/src/privsep-root.h +++ b/src/privsep-root.h @@ -37,6 +37,7 @@ int ps_root_stop(struct dhcpcd_ctx *ctx); ssize_t ps_root_readerror(struct dhcpcd_ctx *, void *, size_t); ssize_t ps_root_mreaderror(struct dhcpcd_ctx *, void **, size_t *); ssize_t ps_root_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t); +ssize_t ps_root_ip6forwarding(struct dhcpcd_ctx *, const char *); ssize_t ps_root_unlink(struct dhcpcd_ctx *, const char *); ssize_t ps_root_filemtime(struct dhcpcd_ctx *, const char *, time_t *); ssize_t ps_root_readfile(struct dhcpcd_ctx *, const char *, void *, size_t); @@ -52,7 +53,6 @@ ssize_t ps_root_ioctllink(struct dhcpcd_ctx *, unsigned long, void *, size_t); ssize_t ps_root_ioctl6(struct dhcpcd_ctx *, unsigned long, void *, size_t); ssize_t ps_root_indirectioctl(struct dhcpcd_ctx *, unsigned long, const char *, void *, size_t); -ssize_t ps_root_ip6forwarding(struct dhcpcd_ctx *); #endif #ifdef __linux__ ssize_t ps_root_sendnetlink(struct dhcpcd_ctx *, int, struct msghdr *); diff --git a/src/privsep.h b/src/privsep.h index b98813e5..09bfa897 100644 --- a/src/privsep.h +++ b/src/privsep.h @@ -57,9 +57,6 @@ #define PS_IP6FORWARDING 0x0104 #define PS_GETIFADDRS 0x0105 -/* Linux commands */ -#define PS_WRITEPATHUINT 0x0201 - /* Process commands */ #define PS_START 0x4000 #define PS_STOP 0x8000