diff options
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, '='); |