diff options
-rw-r--r-- | nldev-handler.c | 80 | ||||
-rw-r--r-- | nldev.c | 133 |
2 files changed, 88 insertions, 125 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, '='); @@ -24,44 +24,22 @@ #include "arg.h" #include "log.h" -int listfd = -1; int dofork = 0; -struct handler { - int fd; - int argc; - char **argv; -}; - -void -spawn_handler(struct handler *child) +pid_t +spawn_handler(int fd, char **argv) { - int pipefd[2]; - - if (pipe(pipefd) == -1) - edie("pipe"); - pid_t pid = fork(); if (pid < 0) edie("fork"); if (pid == 0) { - close(pipefd[1]); - dup2(pipefd[0], 0); - execv(child->argv[0], child->argv); + dup2(fd, 0); + execv(argv[0], argv); edie("execl"); } - close(pipefd[0]); - child->fd = pipefd[1]; -} - -int -write_to_handler(struct handler *child, const char *buf, size_t count) -{ - if (child->fd == -1) - spawn_handler(child); - return write(child->fd, buf, count); + return pid; } void @@ -129,25 +107,13 @@ init_netlink_socket(void) void usage(void) { - die("usage: %s [-hdb] [-ku] [-- run [...]]\n", argv0); + die("usage: %s [-bd] -- runpath [...]\n", argv0); } int main(int argc, char *argv[]) { - struct sockaddr_nl cnls; - struct pollfd fds[2]; - struct msghdr hdr; - struct iovec iov; - char buf[4097], cbuf[CMSG_SPACE(sizeof(struct ucred))]; - struct cmsghdr *chdr; - struct ucred *cred; - int len, showudev, showkernel; - - struct handler child; - - showkernel = 1; - showudev = 1; + struct pollfd fds; ARGBEGIN { case 'b': @@ -156,27 +122,12 @@ main(int argc, char *argv[]) case 'd': dodebug = 1; break; - case 'k': - showudev = 0; - break; - case 'u': - showkernel = 0; - break; default: usage(); } ARGEND; - child.fd = -1; - child.argc = argc; - child.argv = argv; - - fds[0].events = POLLIN; - fds[0].fd = init_netlink_socket(); - - fds[1].fd = child.fd; - fds[1].events = POLLERR; - - listfd = fds[0].fd; + fds.events = POLLIN; + fds.fd = init_netlink_socket(); if (dofork) { if (daemon(0, 0) < 0) @@ -186,68 +137,12 @@ main(int argc, char *argv[]) initsignals(); - while (poll(fds, 2, -1) > -1) { - if (fds[1].revents & POLLERR) { - dbg("handler exited"); - close(child.fd); - fds[1].fd = child.fd = -1; - } - - if (!(fds[0].revents & POLLIN)) - continue; - - 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[0].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; + while (poll(&fds, 1, -1) > -1) { + if (fds.revents & POLLIN) { + int status; + pid_t childpid = spawn_handler(fds.fd, argv); + waitpid(childpid, &status, 0); } - write_to_handler(&child, buf, len); - fds[1].fd = child.fd; } return 0; |