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:
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) {