diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2015-03-15 15:30:01 +0100 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2015-03-15 15:30:01 +0100 |
commit | 311b810b9e2660231935c085429d94c5567b9522 (patch) | |
tree | 3c999c7533395ff7b38b92ed19cbc4f0068d8a1a /nldev-handler.c | |
parent | ba51e3b67883f80462b667aa776e89168347739d (diff) | |
download | nldev-311b810b9e2660231935c085429d94c5567b9522.tar.bz2 nldev-311b810b9e2660231935c085429d94c5567b9522.tar.xz |
pass over the netlink socket to handler instead of using a pipe
hand over the netlink socket directly to the handler and let handler
read from netlink instead of forwarding the message via pipe.
This simplifies the logic of the longtime running netlink daemon and
it simplifies the handling of partially read messages since all reading
happens is done by the handler.
Diffstat (limited to 'nldev-handler.c')
-rw-r--r-- | nldev-handler.c | 80 |
1 files changed, 74 insertions, 6 deletions
diff --git a/nldev-handler.c b/nldev-handler.c index 4fa6e2a..f4f7eb4 100644 --- a/nldev-handler.c +++ b/nldev-handler.c @@ -1,12 +1,17 @@ +#include <errno.h> #include <fcntl.h> #include <poll.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> + #include <sys/types.h> #include <sys/wait.h> +#include <sys/socket.h> + +#include <linux/netlink.h> #include "log.h" @@ -33,21 +38,31 @@ child(char *runpath) void usage(void) { - die("usage: %s [-d] [-r run]\n", argv0); + die("usage: %s [-dku] [-f subsystem] [-r run]\n", argv0); } int main(int argc, char *argv[]) { struct pollfd fds; int r; - static char buf[16384]; char *runpath = "/bin/mdev"; char *subsystem = NULL; + int showudev, showkernel; + + showudev = 1; + showkernel = 1; + ARGBEGIN { case 'd': dodebug = 1; break; + case 'k': + showudev = 0; + break; + case 'u': + showkernel = 0; + break; case 'r': runpath = EARGF(usage()); break; @@ -66,6 +81,13 @@ int main(int argc, char *argv[]) size_t len; int i, slen; char *key, *value; + struct iovec iov; + char cbuf[CMSG_SPACE(sizeof(struct ucred))]; + char buf[16384]; + struct cmsghdr *chdr; + struct ucred *cred; + struct msghdr hdr; + struct sockaddr_nl cnls; clearenv(); setenv("PATH", "/sbin:/bin", 1); @@ -73,11 +95,57 @@ int main(int argc, char *argv[]) if (!(fds.revents & POLLIN)) continue; - len = read(fds.fd, buf, sizeof(buf)-1); - buf[len] = 0; - dbg("Got %u bytes", len); + iov.iov_base = &buf; + iov.iov_len = sizeof(buf); + memset(&hdr, 0, sizeof(hdr)); + hdr.msg_iov = &iov; + hdr.msg_iovlen = 1; + hdr.msg_control = cbuf; + hdr.msg_controllen = sizeof(cbuf); + hdr.msg_name = &cnls; + hdr.msg_namelen = sizeof(cnls); + + len = recvmsg(fds.fd, &hdr, 0); + if (len < 0) { + if (errno == EINTR) + continue; + edie("recvmsg"); + } + if (len < 32 || len >= sizeof(buf)) + continue; + + chdr = CMSG_FIRSTHDR(&hdr); + if (chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS) + continue; + + /* + * Don't allow anyone but root to send us messages. + * + * We will allow users to send us messages, when + * udev is enabled. Udev is just a toy you should + * only use for testing. + */ + cred = (struct ucred *)CMSG_DATA(chdr); + if (cred->uid != 0 && !showudev) + continue; + + if (!memcmp(buf, "libudev", 8)) { + /* + * Receiving messages from udev is insecure. + */ + if (!showudev) + continue; + } else { + if (!showkernel) + continue; + /* + * Kernel messages shouldn't come from the + * userspace. + */ + if (cnls.nl_pid > 0) + continue; + } - slen = 0; for (i = 0; i < len; i += slen + 1) { key = buf + i; value = strchr(key, '='); |