Commit message: journald: don't accept arbitrarily sized journal data fields

https://bugzilla.redhat.com/show_bug.cgi?id=858746
CVE: CVE-2013-4391
CWE: CWE-189
Vulnerability description: Integer overflow in the valid_user_field function in journal/journald-native.c in systemd allows remote attackers to cause a denial of service (crash) and possibly execute arbitrary code via a large journal data field, which triggers a heap-based buffer overflow.

Project: systemd
File: journald-native.c

int server_open_native_socket(Server*s) {
        union sockaddr_union sa;
        int one, r;
        struct epoll_event ev;

        assert(s);

        if (s->native_fd < 0) {

                s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
                if (s->native_fd < 0) {
                        log_error("socket() failed: %m");
                        return -errno;
                }

                zero(sa);
                sa.un.sun_family = AF_UNIX;
                strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));

                unlink(sa.un.sun_path);

                r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
                if (r < 0) {
                        log_error("bind() failed: %m");
                        return -errno;
                }

                chmod(sa.un.sun_path, 0666);
        } else
                fd_nonblock(s->native_fd, 1);

        one = 1;
        r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
        if (r < 0) {
                log_error("SO_PASSCRED failed: %m");
                return -errno;
        }

#ifdef HAVE_SELINUX
        one = 1;
        r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
        if (r < 0)
                log_warning("SO_PASSSEC failed: %m");
#endif

        one = 1;
        r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
        if (r < 0) {
                log_error("SO_TIMESTAMP failed: %m");
                return -errno;
        }

        zero(ev);
        ev.events = EPOLLIN;
        ev.data.fd = s->native_fd;
        if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->native_fd, &ev) < 0) {
                log_error("Failed to add native server fd to epoll object: %m");
                return -errno;
        }

        return 0;
}

Project: systemd
File: journald-native.c

void server_process_native_file(
                Server *s,
                int fd,
                struct ucred *ucred,
                struct timeval *tv,
                const char *label, size_t label_len) {

        struct stat st;
        void *p;
        ssize_t n;

        assert(s);
        assert(fd >= 0);

        /* Data is in the passed file, since it didn't fit in a
         * datagram. We can't map the file here, since clients might
         * then truncate it and trigger a SIGBUS for us. So let's
         * stupidly read it */

        if (fstat(fd, &st) < 0) {
                log_error("Failed to stat passed file, ignoring: %m");
                return;
        }

        if (!S_ISREG(st.st_mode)) {
                log_error("File passed is not regular. Ignoring.");
                return;
        }

        if (st.st_size <= 0)
                return;

        if (st.st_size > ENTRY_SIZE_MAX) {
                log_error("File passed too large. Ignoring.");
                return;
        }

        p = malloc(st.st_size);
        if (!p) {
                log_oom();
                return;
        }

        n = pread(fd, p, st.st_size, 0);
        if (n < 0)
                log_error("Failed to read file, ignoring: %s", strerror(-n));
        else if (n > 0)
                server_process_native_message(s, p, n, ucred, tv, label, label_len);

        free(p);
}

Project: systemd
File: journald-native.c

 static bool valid_user_field(const char *p, size_t l) {
         const char *a;
        /* We kinda enforce POSIX syntax recommendations for
           environment variables here, but make a couple of additional
           requirements.

           http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */

        /* No empty field names */
        if (l <= 0)
                return false;

        /* Don't allow names longer than 64 chars */
        if (l > 64)
                return false;

        /* Variables starting with an underscore are protected */
        if (p[0] == '_')
                return false;

        /* Don't allow digits as first character */
        if (p[0] >= '0' && p[0] <= '9')
                return false;

        /* Only allow A-Z0-9 and '_' */
        for (a = p; a < p + l; a++)
                if (!((*a >= 'A' && *a <= 'Z') ||
                      (*a >= '0' && *a <= '9') ||
                      *a == '_'))
                        return false;

        return true;
}