Just attaching the original patch here in the BTS for reference, rather than relying on the old link (which may go away soon).
-- - mdz
diff -u sysklogd-1.4.1/syslogd.c sysklogd-1.4.1/syslogd.c --- sysklogd-1.4.1/syslogd.c +++ sysklogd-1.4.1/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 @@ -500,6 +504,9 @@ #include <paths.h> #endif +#include <pwd.h> +#include <grp.h> + #ifndef UTMP_FILE #ifdef UTMP_FILENAME #define UTMP_FILE UTMP_FILENAME @@ -821,6 +828,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 @@ -829,7 +841,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) @@ -877,6 +889,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(); @@ -1021,6 +1048,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; @@ -1175,7 +1215,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); } diff -u sysklogd-1.4.1/debian/changelog sysklogd-1.4.1/debian/changelog --- sysklogd-1.4.1/debian/changelog +++ sysklogd-1.4.1/debian/changelog @@ -1,3 +1,40 @@ +sysklogd (1.4.1-16.1) unstable; urgency=low + + * Make syslogd and klogd run as normal user + * syslogd.c: support dropping root privileges to normal user + - added command line option "-u user" + - drop to specified user after opening the log files (so that the log + files can still be owned by root) + - added changelog entry + * sysklogd.8: document -u option + * debian/postinst, debian/postrm: create/remove user 'syslog' + * debian/rc: + - use option "-u syslog" by default + - reloading using the SIGHUP signal does not work with root-owned log + files any more; completely restart the daemon instead + * debian/control: depend on adduser (for the rc script modifications) + * klogd.c: + - add option "-P file" to specify alternative kernel messages file + (instead of /proc/kmsg) + - added macro PIDFILE_DIR which is preferred over _PATH_VARRUN + - added changelog entry + * Makefile: added macro KLOGD_DEFINES for allowing to specify PIDFILE_DIR + (and other macros) without changing the Makefile + * debian/rules: compile klogd to use pidfile in /var/run/klogd + * postinst.klogd: + - sleep a second after stopping the old klogd to avoid "klogd is already + running" failures on restart + - add/remove system user and group "klog" + * postrm.klogd: remove system user and group "klog" on purge + * debian/rc.klogd: + - create klogd pid file in /var/run/klogd/ (klog-writeable directory) + - create a klog-owned fifo /var/run/klogd/kmsg + - start/stop a dd process (running as root) which pipes /proc/kmsg to + /var/run/klogd/kmsg; this allows to run klogd entirely as user 'klogd' + - replaced restarting by calls to stop and start + + -- Martin Pitt <martin.p...@canonical.com> Wed, 24 Nov 2004 14:02:48 +0100 + sysklogd (1.4.1-16) unstable; urgency=medium * applied patch by cph diff -u sysklogd-1.4.1/debian/control sysklogd-1.4.1/debian/control --- sysklogd-1.4.1/debian/control +++ sysklogd-1.4.1/debian/control @@ -6,7 +6,7 @@ Package: sysklogd Architecture: any -Depends: ${shlibs:Depends}, klogd | linux-kernel-log-daemon +Depends: ${shlibs:Depends}, klogd | linux-kernel-log-daemon, adduser Conflicts: syslogd Provides: syslogd, system-log-daemon Replaces: syslogd @@ -18,7 +18,7 @@ Package: klogd Architecture: any -Depends: ${shlibs:Depends}, sysklogd | system-log-daemon +Depends: ${shlibs:Depends}, sysklogd | system-log-daemon, adduser Conflicts: sysklogd (<= 1.3-33) Provides: linux-kernel-log-daemon Replaces: sysklogd diff -u sysklogd-1.4.1/debian/postinst sysklogd-1.4.1/debian/postinst --- sysklogd-1.4.1/debian/postinst +++ sysklogd-1.4.1/debian/postinst @@ -46,6 +46,8 @@ update-rc.d sysklogd defaults 10 90 >/dev/null + adduser --system --group --no-create-home --quiet syslog + # Create logfiles with correct file modes # for LOG in `syslogd-listfiles` `syslogd-listfiles --auth` diff -u sysklogd-1.4.1/debian/postinst.klogd sysklogd-1.4.1/debian/postinst.klogd --- sysklogd-1.4.1/debian/postinst.klogd +++ sysklogd-1.4.1/debian/postinst.klogd @@ -8,11 +8,14 @@ then set +e sh /etc/init.d/klogd stop + sleep 1 set -e fi 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.4.1/debian/postrm sysklogd-1.4.1/debian/postrm --- sysklogd-1.4.1/debian/postrm +++ sysklogd-1.4.1/debian/postrm @@ -5,4 +5,5 @@ if [ "$1" = "purge" ] then + deluser --system --quiet syslog update-rc.d sysklogd remove >/dev/null fi diff -u sysklogd-1.4.1/debian/postrm.klogd sysklogd-1.4.1/debian/postrm.klogd --- sysklogd-1.4.1/debian/postrm.klogd +++ sysklogd-1.4.1/debian/postrm.klogd @@ -5,4 +5,5 @@ if [ "$1" = "purge" ] then + deluser --system --quiet klog || true update-rc.d klogd remove >/dev/null fi diff -u sysklogd-1.4.1/debian/rc sysklogd-1.4.1/debian/rc --- sysklogd-1.4.1/debian/rc +++ sysklogd-1.4.1/debian/rc @@ -11,7 +11,7 @@ # Options for start/restart the daemons # For remote UDP logging use SYSLOGD="-r" # -SYSLOGD="" +SYSLOGD="-u syslog" create_xconsole() { @@ -70,29 +70,13 @@ start-stop-daemon --stop --quiet --exec $binpath --pidfile $pidfile echo "." ;; - reload|force-reload) - echo -n "Reloading system log daemon: syslogd" - start-stop-daemon --stop --quiet --signal 1 --exec $binpath --pidfile $pidfile - echo "." - ;; - restart) + restart|force-reload|reload-or-restart|reload) echo -n "Restarting system log daemon: syslogd" start-stop-daemon --stop --quiet --exec $binpath --pidfile $pidfile sleep 1 start-stop-daemon --start --quiet --exec $binpath -- $SYSLOGD echo "." ;; - reload-or-restart) - if running - then - echo -n "Reloading system log daemon: syslogd" - start-stop-daemon --stop --quiet --signal 1 --exec $binpath --pidfile $pidfile - else - echo -n "Restarting system log daemon: syslogd" - start-stop-daemon --start --quiet --exec $binpath -- $SYSLOGD - fi - echo "." - ;; *) echo "Usage: /etc/init.d/sysklogd {start|stop|reload|restart|force-reload|reload-or-restart}" exit 1 diff -u sysklogd-1.4.1/debian/rc.klogd sysklogd-1.4.1/debian/rc.klogd --- sysklogd-1.4.1/debian/rc.klogd +++ sysklogd-1.4.1/debian/rc.klogd @@ -3,14 +3,16 @@ 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 # Use KLOGD="-k /boot/System.map-$(uname -r)" to specify System.map # -KLOGD="" +KLOGD="-P $kmsgpipe" running() { @@ -50,19 +52,34 @@ case "$1" in start) echo -n "Starting kernel log daemon: klogd" - start-stop-daemon --start --quiet --exec $binpath -- $KLOGD + + # create klog-writeable pid and fifo directory + mkdir -p /var/run/klogd + chown klog:klog /var/run/klogd + mkfifo -m 600 $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 -- if=/proc/kmsg of=$kmsgpipe + + # start klogd as non-root with reading from kmsgpipe + start-stop-daemon --start --quiet --chuid klog --exec $binpath -- $KLOGD echo "." ;; stop) echo -n "Stopping kernel log daemon: klogd" start-stop-daemon --stop --quiet --exec $binpath --pidfile $pidfile + + # stop kmsgpipe + start-stop-daemon --stop --quiet --oknodo --pidfile $kmsgpidfile + rm -f $kmsgpidfile $kmsgpipe + echo "." ;; restart|force-reload) - echo -n "Restarting kernel log daemon: klogd" - start-stop-daemon --stop --quiet --exec $binpath --pidfile $pidfile + $0 stop sleep 1 - start-stop-daemon --start --quiet --exec $binpath -- $KLOGD + $0 start echo "." ;; *) diff -u sysklogd-1.4.1/debian/rules sysklogd-1.4.1/debian/rules --- sysklogd-1.4.1/debian/rules +++ sysklogd-1.4.1/debian/rules @@ -39,7 +39,7 @@ build: $(MAKE) DEB="-DDEBRELEASE=\\\"$(revision)\\\"" \ CFLAGS="$(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 only in patch2: unchanged: --- sysklogd-1.4.1.orig/Makefile +++ sysklogd-1.4.1/Makefile @@ -47,7 +47,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 = .c.o: only in patch2: unchanged: --- sysklogd-1.4.1.orig/sysklogd.8 +++ sysklogd-1.4.1/sysklogd.8 @@ -29,6 +29,9 @@ .RB [ " \-s " .I domainlist ] +.RB [ " \-u" +.IB user +] .RB [ " \-v " ] .LP .SH DESCRIPTION @@ -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. .LP only in patch2: unchanged: --- sysklogd-1.4.1.orig/klogd.c +++ sysklogd-1.4.1/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. @@ -279,7 +286,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"; @@ -303,6 +312,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; @@ -524,6 +535,22 @@ ksyslog(6, NULL, 0); } + /* 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. @@ -994,7 +1021,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. */ @@ -1028,6 +1055,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; @@ -1039,7 +1069,6 @@ break; } - /* Set console logging level. */ if ( log_level != (char *) 0 ) {