summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2020-05-24 05:47:14 +0000
committerRoy Marples <roy@marples.name>2020-05-24 05:47:14 +0000
commit12b0db43b2a139744fbcf04824390fcb1de445ea (patch)
tree5cde5e68c8d6710d707d8a54da0de97d856b7602
parentc572835e98da5a186f7453f3daa2aec765ef2d9b (diff)
downloaddhcpcd-12b0db43b2a139744fbcf04824390fcb1de445ea.tar.xz
privsep: Allow Linux to work without needing any mounts
-rw-r--r--BUILDING.md6
-rwxr-xr-xconfigure3
-rw-r--r--hooks/00-linux17
-rw-r--r--src/common.c23
-rw-r--r--src/if-linux.c131
-rw-r--r--src/ipv6.c7
-rw-r--r--src/ipv6nd.c10
-rw-r--r--src/privsep-bsd.c12
-rw-r--r--src/privsep-linux.c62
-rw-r--r--src/privsep-root.c26
-rw-r--r--src/privsep-root.h2
-rw-r--r--src/privsep.h3
12 files changed, 110 insertions, 192 deletions
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++;
@@ -511,6 +520,11 @@ ps_root_recvmsgcb(void *arg, struct ps_msghdr *psm, struct msghdr *msg)
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);
break;
@@ -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