nldev

NetLink DEVice manager; a lightweight netlink frontend for mdev.
git clone git://r-36.net/nldev
Log | Files | Refs | LICENSE

commit e2d4a797b6364fd79fc6102d866f074409604815
parent e2c236b300e4fa9f4f7fdb672251892c2be3e149
Author: Christoph Lohmann <20h@r-36.net>
Date:   Sat, 28 Apr 2012 10:59:36 +0200

Adding security and nasty comments.

Diffstat:
config.mk | 2+-
nldev.1 | 4++--
nldev.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
3 files changed, 62 insertions(+), 11 deletions(-)

diff --git a/config.mk b/config.mk @@ -13,7 +13,7 @@ INCS = -I. -I/usr/include LIBS = -L/usr/lib -lc # flags -CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE +CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_GNU_SOURCE CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} LDFLAGS = -static -g ${LIBS} #LDFLAGS = -s ${LIBS} diff --git a/nldev.1 b/nldev.1 @@ -13,7 +13,7 @@ .Op Fl d .Op Fl b .Op Fl k -.Op Fl l +.Op Fl u .Op Fl f Ar subsystem .Op Fl r Ar runpath .Ek @@ -51,7 +51,7 @@ Show usage. Only show netlink messages from the kernel. . .Bd -filled -.It Fl l +.It Fl u Only show netlink messages from libudev. . .It Fl r Ar runpath diff --git a/nldev.c b/nldev.c @@ -92,7 +92,7 @@ child(char *runpath) int fd, pid; if (!(pid = fork())) { - if (dofork) { + if (dofork && !dodebug) { fd = open("/dev/null", O_RDWR); if (fd >= 0) { if (write(0, 0, 0) < 0) @@ -153,15 +153,20 @@ initsignals(void) void usage(void) { - die("usage: %s [-hdb] [-kl] [-f subsystem] [-r run]\n", argv0); + die("usage: %s [-hdb] [-ku] [-f subsystem] [-r run]\n", argv0); } int main(int argc, char *argv[]) { - struct sockaddr_nl nls; + struct sockaddr_nl nls, cnls; struct pollfd fds; - char buf[4097], *subsystem, *runpath, *key, *value; + struct msghdr hdr; + struct iovec iov; + char buf[4097], *subsystem, *runpath, *key, *value, + cbuf[CMSG_SPACE(sizeof(struct ucred))]; + struct cmsghdr *chdr; + struct ucred *cred; int i, len, slen, showudev, showkernel; showkernel = 1; @@ -182,7 +187,7 @@ main(int argc, char *argv[]) case 'k': showudev = 0; break; - case 'l': + case 'u': showkernel = 0; break; case 'r': @@ -208,6 +213,11 @@ main(int argc, char *argv[]) sizeof(slen)) < 0) { edie("setsockopt"); } + slen = 1; + if (setsockopt(fds.fd, SOL_SOCKET, SO_PASSCRED, &slen, + sizeof(slen)) < 0) { + edie("setsockopt"); + } if (bind(fds.fd, (void *)&nls, sizeof(nls))) edie("bind"); @@ -234,16 +244,57 @@ main(int argc, char *argv[]) unsetenv("MINOR"); unsetenv("FIRMWARE"); - len = recv(fds.fd, buf, sizeof(buf)-1, MSG_DONTWAIT); - if (len < 0) + 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); + + printf("recvmsg\n"); + len = recvmsg(fds.fd, &hdr, 0); + if (len < 0 && errno == EINTR) + continue; + printf("check 2\n"); + if (len < 32 || len >= sizeof(buf)) edie("recv"); - if (strstr(buf, "libudev")) { + printf("chdr\n"); + chdr = CMSG_FIRSTHDR(&hdr); + if (chdr == NULL || chdr->cmsg_type != SCM_CREDENTIALS) + continue; + printf("cred\n"); + + /* + * 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; + + printf("libudev\n"); + 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.pid > 0) + continue; } for (i = 0; i < len; i += slen + 1) {