Adding security and nasty comments. - nldev - NetLink DEVice manager; a lightweight netlink frontend for mdev.
       
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
 (DIR) commit e2d4a797b6364fd79fc6102d866f074409604815
 (DIR) parent e2c236b300e4fa9f4f7fdb672251892c2be3e149
 (HTM) 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(-)
       ---
 (DIR) 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}
 (DIR) 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
 (DIR) 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) {