tags 24326 + patch pending tags 35325 + patch pending thanks Hi Martin, I've reviewed a patch to sysklogd prepared by Matt Zimmerman, based on previous work by Martin Pitt, that adds supports for running sysklogd as non root and enables such a behavior by default.
I believe it's a valuable change with potential security implications; it's also a well tested one in other derivatives (Ubuntu and all its descendants). Considering all this, I'm hereby declaring my intention to sponsor the NMU prepared by Matt. For your convenience and in the hope to help you out, I'll upload the NMU to DELAYED/15, which won't hit the archive before 15 days from now. Please let me know if you are fine with the changes, so that I can adapt the delay. For all readers: I'm running the modified package without any troubles on a couple of machines, but more testing is always welcome! You can find patched packages at <http://people.debian.org/~zack/sysklogd/>. Please try it out and report any issue. Cheers. -- Stefano Zacchiroli -o- PhD in Computer Science \ PostDoc @ Univ. Paris 7 zack@{upsilon.cc,pps.jussieu.fr,debian.org} -<>- http://upsilon.cc/zack/ Quando anche i santi ti voltano le spalle, | . |. I've fans everywhere ti resta John Fante -- V. Capossela .......| ..: |.......... -- C. Adams
diff -u sysklogd-1.5/syslogd.c sysklogd-1.5/syslogd.c --- sysklogd-1.5/syslogd.c +++ sysklogd-1.5/syslogd.c @@ -46,6 +46,10 @@ * extensive changes by Ralph Campbell * more extensive changes by Eric Allman (again) * + * Wed Nov 24 2004 14:02:48 CET 2004: Martin Pitt + * Added option "-u <user>" to drop privileges to given user after + * initialisation. + * * Steve Lord: Fix UNIX domain socket code, added linux kernel logging * change defines to * SYSLOG_INET - listen on a UDP socket @@ -553,6 +557,9 @@ #include <paths.h> #endif +#include <pwd.h> +#include <grp.h> + #ifndef UTMP_FILE #ifdef UTMP_FILENAME #define UTMP_FILE UTMP_FILENAME @@ -878,6 +885,11 @@ extern char *optarg; int maxfds; + /* user and group id to drop to */ + uid_t uid = 0; + gid_t gid = 0; + const char* username = NULL; + #ifndef TESTING chdir ("/"); #endif @@ -886,7 +898,7 @@ funix[i] = -1; } - while ((ch = getopt(argc, argv, "a:dhf:l:m:np:rs:v")) != EOF) + while ((ch = getopt(argc, argv, "a:dhf:l:m:np:rs:vu:")) != EOF) switch((char)ch) { case 'a': if (nfunix < MAXFUNIX) @@ -934,6 +946,21 @@ case 'v': printf("syslogd %s.%s\n", VERSION, PATCHLEVEL); exit (0); + case 'u': + if (optarg) { + username = strdup (optarg); + struct passwd *pw = getpwnam (username); + if (!pw) { + fprintf (stderr, "User %s does not exist, aborting.\n", username); + exit (1); + } + uid = pw->pw_uid; + gid = pw->pw_gid; + } else { + fputs ("Internal error: -u optarg == NULL!\n", stderr); + exit (1); + } + break; case '?': default: usage(); @@ -1087,6 +1114,19 @@ kill (ppid, SIGTERM); #endif + /* + * Drop privileges if -u was specified + */ + if (username) { + if (initgroups (username, gid) || + setgid (gid) || setuid (uid)) { + perror ("Could not drop to specified user privileges"); + exit (1); + } + free (username); + username = NULL; + } + /* Main loop begins here. */ for (;;) { int nfds; @@ -1239,7 +1279,7 @@ int usage() { fprintf(stderr, "usage: syslogd [-drvh] [-l hostlist] [-m markinterval] [-n] [-p path]\n" \ - " [-s domainlist] [-f conffile]\n"); + " [-s domainlist] [-f conffile] [-u user]\n"); exit(1); } @@ -1603,10 +1643,10 @@ int msglen; char *timestamp; #ifdef __gnu_linux__ - sigset_t mask; + sigset_t mask; #else #ifndef SYSV - sigset_t omask; + sigset_t omask; #endif #endif @@ -1618,9 +1658,9 @@ sigaddset(&mask, SIGALRM); sigprocmask(SIG_BLOCK, &mask, NULL); #else -#ifndef SYSV +# ifndef SYSV omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); -#endif +# endif #endif /* @@ -1660,11 +1700,11 @@ f->f_file = -1; } #ifdef __gnu_linux__ - sigprocmask(SIG_UNBLOCK, &mask, NULL); + sigprocmask(SIG_UNBLOCK, &mask, NULL); #else -#ifndef SYSV +# ifndef SYSV (void) sigsetmask(omask); -#endif +# endif #endif return; } @@ -1731,9 +1771,9 @@ #ifdef __gnu_linux__ sigprocmask(SIG_UNBLOCK, &mask, NULL); #else -#ifndef SYSV +# ifndef SYSV (void) sigsetmask(omask); -#endif +# endif #endif } #if FALSE diff -u sysklogd-1.5/debian/rules sysklogd-1.5/debian/rules --- sysklogd-1.5/debian/rules +++ sysklogd-1.5/debian/rules @@ -39,7 +39,7 @@ build: $(MAKE) DEB="-DDEBRELEASE=\\\"$(revision)\\\"" \ SKFLAGS="$(CFLAGS) -DSYSV -fomit-frame-pointer -fno-strength-reduce" \ - LDFLAGS="" + LDFLAGS="" KLOGD_DEFINES='-DPIDFILE_DIR=\"/var/run/klogd/\"' pod2man --section=8 --lax --center="Debian GNU/Linux" \ --release="Debian Project" debian/syslog-facility.pod \ > syslog-facility.8 diff -u sysklogd-1.5/debian/postinst sysklogd-1.5/debian/postinst --- sysklogd-1.5/debian/postinst +++ sysklogd-1.5/debian/postinst @@ -52,6 +52,8 @@ update-rc.d sysklogd defaults 10 90 >/dev/null + adduser --system --group --no-create-home --quiet syslog + # restarting daemon # if [ -f /etc/init.d/sysklogd ] diff -u sysklogd-1.5/debian/control sysklogd-1.5/debian/control --- sysklogd-1.5/debian/control +++ sysklogd-1.5/debian/control @@ -8,7 +8,7 @@ Package: sysklogd Architecture: any Section: admin -Depends: ${shlibs:Depends}, klogd | linux-kernel-log-daemon, lsb-base +Depends: ${shlibs:Depends}, klogd | linux-kernel-log-daemon, adduser, lsb-base Conflicts: syslogd Provides: syslogd, system-log-daemon Replaces: syslogd @@ -21,7 +21,7 @@ Package: klogd Architecture: any Section: admin -Depends: ${shlibs:Depends}, sysklogd | system-log-daemon, lsb-base +Depends: ${shlibs:Depends}, sysklogd | system-log-daemon, adduser, lsb-base Conflicts: sysklogd (<= 1.3-33) Provides: linux-kernel-log-daemon Replaces: sysklogd diff -u sysklogd-1.5/debian/postrm.klogd sysklogd-1.5/debian/postrm.klogd --- sysklogd-1.5/debian/postrm.klogd +++ sysklogd-1.5/debian/postrm.klogd @@ -4,6 +4,7 @@ if [ "$1" = "purge" ] then + deluser --system --quiet klog || true update-rc.d klogd remove >/dev/null test ! -f /lib/init/rw/sendsigs.omit.d/klogd || \ diff -u sysklogd-1.5/debian/cron.daily sysklogd-1.5/debian/cron.daily --- sysklogd-1.5/debian/cron.daily +++ sysklogd-1.5/debian/cron.daily @@ -24,6 +24,9 @@ test -x /sbin/syslogd || exit 0 test -f /usr/share/sysklogd/dummy || exit 0 +USER=$(ps -C syslogd -o user= | head -n 1) +[ -z "${USER}" ] && USER="root" || true + set -e cd /var/log @@ -35,7 +38,7 @@ for LOG in $logs do if [ -s $LOG ]; then - savelog -g adm -m 640 -u root -c 7 $LOG >/dev/null + savelog -g adm -m 640 -u ${USER} -c 7 $LOG >/dev/null fi done diff -u sysklogd-1.5/debian/rc.klogd sysklogd-1.5/debian/rc.klogd --- sysklogd-1.5/debian/rc.klogd +++ sysklogd-1.5/debian/rc.klogd @@ -12,37 +12,55 @@ PATH=/bin:/usr/bin:/sbin:/usr/sbin -pidfile=/var/run/klogd.pid +pidfile=/var/run/klogd/klogd.pid +kmsgpipe=/var/run/klogd/kmsg +kmsgpidfile=/var/run/klogd/kmsgpipe.pid binpath=/sbin/klogd test -f $binpath || exit 0 -test ! -r /etc/default/klogd || . /etc/default/klogd - . /lib/lsb/init-functions +# Use KLOGD="-k /boot/System.map-$(uname -r)" to specify System.map +# +KLOGD="-P $kmsgpipe" + +test ! -r /etc/default/klogd || . /etc/default/klogd + case "$1" in start) log_begin_msg "Starting kernel log daemon..." - start-stop-daemon --start --quiet --pidfile $pidfile --name klogd --startas $binpath -- $KLOGD + # create klog-writeable pid and fifo directory + mkdir -p /var/run/klogd + chown klog:klog /var/run/klogd + mkfifo -m 700 $kmsgpipe + chown klog:klog $kmsgpipe + + # shovel /proc/kmsg to pipe readable by klogd user + start-stop-daemon --start --pidfile $kmsgpidfile --exec /bin/dd -b -m -- bs=1 if=/proc/kmsg of=$kmsgpipe + + # start klogd as non-root with reading from kmsgpipe + start-stop-daemon --start --quiet --chuid klog --exec $binpath -- $KLOGD log_end_msg $? - test -d /lib/init/rw/sendsigs.omit.d || mkdir -p /lib/init/rw/sendsigs.omit.d - test ! -f /lib/init/rw/sendsigs.omit.d/klogd || rm -f /lib/init/rw/sendsigs.omit.d/klogd - ln -s $pidfile /lib/init/rw/sendsigs.omit.d/klogd ;; stop) log_begin_msg "Stopping kernel log daemon..." - start-stop-daemon --stop --quiet --retry 3 --exec $binpath --pidfile $pidfile + start-stop-daemon --stop --quiet --retry 3 --oknodo --exec $binpath --pidfile $pidfile + # stop kmsgpipe + start-stop-daemon --stop --quiet --oknodo --pidfile $kmsgpidfile + rm -f $kmsgpidfile $kmsgpipe log_end_msg $? ;; restart|force-reload) - log_begin_msg "Reloading kernel log daemon..." - start-stop-daemon --stop --quiet --retry 3 --exec $binpath --pidfile $pidfile - start-stop-daemon --start --quiet --pidfile $pidfile --name klogd --startas $binpath -- $KLOGD - log_end_msg $? + $0 stop + sleep 1 + $0 start + ;; + status) + status_of_proc -p $pidfile $binpath klogd && exit 0 || exit $? ;; *) - log_success_msg "Usage: /etc/init.d/klogd {start|stop|restart|force-reload}" + log_success_msg "Usage: /etc/init.d/klogd {start|stop|restart|force-reload|status}" exit 1 esac diff -u sysklogd-1.5/debian/postinst.klogd sysklogd-1.5/debian/postinst.klogd --- sysklogd-1.5/debian/postinst.klogd +++ sysklogd-1.5/debian/postinst.klogd @@ -25,6 +25,8 @@ update-rc.d klogd defaults 11 89 >/dev/null + adduser --system --quiet --group --no-create-home klog || true + # restarting daemon # if [ -f /etc/init.d/klogd ] diff -u sysklogd-1.5/debian/changelog sysklogd-1.5/debian/changelog --- sysklogd-1.5/debian/changelog +++ sysklogd-1.5/debian/changelog @@ -1,3 +1,20 @@ +sysklogd (1.5-6.1) unstable; urgency=low + + * Non-maintainer upload. + * Merge Ubuntu patch to enable klogd and syslogd to run as non-root users + (Closes: Bug#35325) + - debian/control: add dependency on adduser + - debian/postrm.klogd, postinst.klogd: handle addition/removal of klogd + user + - debian/rc.klogd, default.klogd: run klogd as user klogd + - klogd.c, debian/rules, Makefile, klogd.8: specify location of klogd pid + file + + - syslogd.c, syslogd.8: add -u <user> option + - debian/cron.daily, cron.weekly, rc: run syslogd as user syslogd + + -- Matt Zimmerman <m...@debian.org> Thu, 14 Apr 2011 06:52:27 -0400 + sysklogd (1.5-6) unstable; urgency=low * Remove faulty fclose() call. Thanks to Andrea Morandi and Sean Young diff -u sysklogd-1.5/debian/cron.weekly sysklogd-1.5/debian/cron.weekly --- sysklogd-1.5/debian/cron.weekly +++ sysklogd-1.5/debian/cron.weekly @@ -25,6 +25,9 @@ set -e +USER=$(ps -C syslogd -o user= | head -n 1) +[ -z "${USER}" ] && USER="root" || true + cd /var/log logs=$(syslogd-listfiles --weekly) @@ -34,7 +37,7 @@ for LOG in $logs do if [ -s $LOG ]; then - savelog -g adm -m 640 -u root -c 4 $LOG >/dev/null + savelog -g adm -m 640 -u ${USER} -c 4 $LOG >/dev/null fi done diff -u sysklogd-1.5/debian/rc sysklogd-1.5/debian/rc --- sysklogd-1.5/debian/rc +++ sysklogd-1.5/debian/rc @@ -19,8 +19,31 @@ test -x $binpath || exit 0 +# syslogd options should be set in /etc/default/syslogd +SYSLOGD="" + +# user to run syslogd as - this can overriden in /etc/default/syslogd +USER="syslog" + test ! -r /etc/default/syslogd || . /etc/default/syslogd +# Figure out under which user syslogd should be running as +if echo ${SYSLOGD} | grep -q '^.*-u[[:space:]]*\([[:alnum:]]*\)[[:space:]]*.*$' +then + # A specific user has been set on the command line, try to extract it. + USER=$(echo ${SYSLOGD} | sed -e 's/^.*-u[[:space:]]*\([[:alnum:]]*\)[[:space:]]*.*$/\1/') +else + # By default, run syslogd under the syslog user + SYSLOGD="${SYSLOGD} -u ${USER}" +fi + +# Unable to get the user under which syslogd should be running, stop. +if [ -z "${USER}" ] +then + log_failure_msg "Unable to get syslog user" + exit 1 +fi + . /lib/lsb/init-functions create_xconsole() @@ -36,8 +59,18 @@ else chmod 0640 /dev/xconsole fi - chown root:adm /dev/xconsole + + chown ${USER}:adm /dev/xconsole test ! -x /sbin/restorecon || /sbin/restorecon /dev/xconsole + +} + +fix_log_ownership() +{ + for l in `syslogd-listfiles -a` + do + chown ${USER}:adm $l + done } running() @@ -79,6 +112,7 @@ start) log_begin_msg "Starting system log daemon..." create_xconsole + fix_log_ownership start-stop-daemon --start --quiet --pidfile $pidfile --name syslogd --startas $binpath -- $SYSLOGD log_end_msg $? test -d /lib/init/rw/sendsigs.omit.d || mkdir -p /lib/init/rw/sendsigs.omit.d @@ -92,12 +126,14 @@ ;; reload|force-reload) log_begin_msg "Reloading system log daemon..." + fix_log_ownership start-stop-daemon --stop --quiet --signal 1 --pidfile $pidfile --name syslogd log_end_msg $? ;; restart) log_begin_msg "Restarting system log daemon..." start-stop-daemon --stop --retry 5 --quiet --pidfile $pidfile --name syslogd + fix_log_ownership start-stop-daemon --start --quiet --pidfile $pidfile --name syslogd --startas $binpath -- $SYSLOGD log_end_msg $? ;; diff -u sysklogd-1.5/debian/default.klogd sysklogd-1.5/debian/default.klogd --- sysklogd-1.5/debian/default.klogd +++ sysklogd-1.5/debian/default.klogd @@ -15 +15 @@ -KLOGD="-x" +#KLOGD="-P /var/run/klogd/kmsg -x" only in patch2: unchanged: --- sysklogd-1.5.orig/Makefile +++ sysklogd-1.5/Makefile @@ -70,7 +70,7 @@ SYSLOGD_FLAGS= -DSYSLOG_INET -DSYSLOG_UNIXAF -DNO_SCCS ${FSSTND} \ ${SYSLOGD_PIDNAME} SYSLOG_FLAGS= -DALLOW_KERNEL_LOGGING -KLOGD_FLAGS = ${FSSTND} ${KLOGD_START_DELAY} +KLOGD_FLAGS = ${FSSTND} ${KLOGD_START_DELAY} ${KLOGD_DEFINES} DEB = all: syslogd klogd @@ -102,7 +102,7 @@ ${CC} ${SKFLAGS} ${SYSLOG_FLAGS} -c syslog.c klogd.o: klogd.c klogd.h version.h - ${CC} ${SKFLAGS} ${KLOGD_FLAGS} $(DEB) -c klogd.c + ${CC} -U_FORTIFY_SOURCE ${SKFLAGS} ${KLOGD_FLAGS} $(DEB) -c klogd.c ksym.o: ksym.c klogd.h ksyms.h module.h ${CC} ${SKFLAGS} ${KLOGD_FLAGS} -c ksym.c only in patch2: unchanged: --- sysklogd-1.5.orig/klogd.c +++ sysklogd-1.5/klogd.c @@ -20,6 +20,13 @@ */ /* + * Thu Nov 25 16:48:39 CET 2004: Martin Pitt + * Added option -P to give alternative location of /proc/kmsg ("-" for + * stdin). This allows to run klogd entirely without root privileges. + * + * Added support for macro PIDFILE_DIR which is used as pid file directory + * instead of _PATH_VARRUN. + * * Steve Lord (l...@cray.com) 7th Nov 92 * * Modified to check for kernel info by Dr. G.W. Wettstein 02/17/93. @@ -289,7 +296,9 @@ #define LOG_LINE_LENGTH 1000 #ifndef TESTING -#if defined(FSSTND) +#if defined(PIDFILE_DIR) +static char *PidFile = PIDFILE_DIR "klogd.pid"; +#elif defined(FSSTND) static char *PidFile = _PATH_VARRUN "klogd.pid"; #else static char *PidFile = "/etc/klogd.pid"; @@ -313,6 +322,8 @@ static FILE *output_file = (FILE *) 0; +static char *kmsg_file = NULL; /* NULL means default /proc/kmsg */ + static enum LOGSRC {none, proc, kernel} logsrc; int debugging = 0; @@ -543,6 +554,22 @@ "console output."); } + /* Do we read kernel messages from a pipe? */ + if ( kmsg_file ) { + if ( !strcmp(kmsg_file, "-") ) + kmsg = fileno(stdin); + else { + if ( (kmsg = open(kmsg_file, O_RDONLY)) < 0 ) + { + fprintf(stderr, "klogd: Cannot open kmsg file, " \ + "%d - %s.\n", errno, strerror(errno)); + ksyslog(7, NULL, 0); + exit(1); + } + } + return proc; + } + /* * First do a stat to determine whether or not the proc based * file system is available to get kernel messages from. @@ -990,7 +1017,7 @@ chdir ("/"); #endif /* Parse the command-line. */ - while ((ch = getopt(argc, argv, "c:df:iIk:nopsvx2")) != EOF) + while ((ch = getopt(argc, argv, "c:df:iIk:nopP:svx2")) != EOF) switch((char)ch) { case '2': /* Print lines with symbols twice. */ @@ -1024,6 +1051,9 @@ case 'p': SetParanoiaLevel(1); /* Load symbols on oops. */ break; + case 'P': /* Alternative kmsg file path */ + kmsg_file = strdup(optarg); + break; case 's': /* Use syscall interface. */ use_syscall = 1; break; @@ -1035,7 +1065,6 @@ break; } - /* Set console logging level. */ if ( log_level != (char *) 0 ) { only in patch2: unchanged: --- sysklogd-1.5.orig/klogd.8 +++ sysklogd-1.5/klogd.8 @@ -18,6 +18,9 @@ .RB [ " \-n " ] .RB [ " \-o " ] .RB [ " \-p " ] +.RB [ " \-P " +.I path +] .RB [ " \-s " ] .RB [ " \-k " .I fname @@ -64,6 +67,11 @@ symbol information whenever an Oops string is detected in the kernel message stream. .TP +.B "\-P " path +Use \fIpath\fR instead of /proc/kmsg as the source of the kernel message. +Specify "-" to read from standard input. This allows klogd to run entirely +without root privileges. +.TP .B "\-s" Force \fBklogd\fP to use the system call interface to the kernel message buffers. @@ -94,10 +102,15 @@ .I /proc file system and the syscall (sys_syslog) interface, although ultimately they are one and the same. Klogd is designed to choose -whichever source of information is the most appropriate. It does this -by first checking for the presence of a mounted +whichever source of information is the most appropriate. If the +.B \-P +switch is used, +.B klogd +opens the specified path as the source of kernel log information. Otherwise +.B klogd +checks for the presence of a mounted .I /proc -file system. If this is found the +file system and if this is found the .I /proc/kmsg file is used as the source of kernel log information. If the proc file system is not mounted only in patch2: unchanged: --- sysklogd-1.5.orig/sysklogd.8 +++ sysklogd-1.5/sysklogd.8 @@ -29,6 +29,9 @@ .RB [ " \-s " .I domainlist ] +.RB [ " \-u" +.IB user +] .RB [ " \-v " ] .SH DESCRIPTION .B Sysklogd @@ -150,6 +153,26 @@ no domain would be cut, you will have to specify two domains like: .BR "\-s north.de:infodrom.north.de" . .TP +.BI "\-u" " user" +The +.B syslogd +daemon runs with full root privileges by default. If you specify this +option, the daemon will drop its privileges to the given user (and the +primary group of this user) before starting up logging. This +greatly reduces the potential impact of exploitable security holes in +syslogd. + +.B syslogd +will still open all log files as root at startup. +However, after receiving a +.B SIGHUP +signal (which causes the daemon to restart) the log files will be +reopened as the non-privileged user which fails if the log files are +only writeable by root. If you need to restart the daemon using the +signal, then you have to adapt the permissions of your log files to be +writeable by the specified user (or its primary group). + +.TP .B "\-v" Print version and exit. .SH SIGNALS
signature.asc
Description: Digital signature