aboutsummaryrefslogtreecommitdiffstats
path: root/nldev-handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'nldev-handler.c')
-rw-r--r--nldev-handler.c80
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, '=');