Submitted By: Robert Connolly (ashes) Date: 2005-01-23 Initial Package Version: 1.4.1 Upstream Status: Not submitted Origin: http://cvsweb.openwall.com/cgi/cvsweb.cgi/Owl/packages/sysklogd/ sysklogd-1.4.1-caen-owl-klogd-drop-root.diff v1.1 sysklogd-1.4.1-caen-owl-syslogd-drop-root.diff v1.1 Description: This patch adds privilege seperation for syslogd and klogd. diff -Naur sysklogd-1.4.1.orig/klogd.8 sysklogd-1.4.1/klogd.8 --- sysklogd-1.4.1.orig/klogd.8 2005-01-22 18:49:55.000000000 +0000 +++ sysklogd-1.4.1/klogd.8 2005-01-23 10:59:57.208384154 +0000 @@ -3,8 +3,9 @@ .\" Sun Jul 30 01:35:55 MET: Martin Schulze: Updates .\" Sun Nov 19 23:22:21 MET: Martin Schulze: Updates .\" Mon Aug 19 09:42:08 CDT 1996: Dr. G.W. Wettstein: Updates +.\" Thu Feb 17 2000: Chris Wing: Unprivileged klogd feature .\" -.TH KLOGD 8 "21 August, 1999" "Version 1.4" "Linux System Administration" +.TH KLOGD 8 "8 October, 2001" "Version 1.4.1+CAEN/OW" "Linux System Administration" .SH NAME klogd \- Kernel Log Daemon .LP @@ -17,6 +18,12 @@ .RB [ " \-f " .I fname ] +.RB [ " \-u " +.I username +] +.RB [ " \-j " +.I chroot_dir +] .RB [ " \-iI " ] .RB [ " \-n " ] .RB [ " \-o " ] @@ -46,6 +53,20 @@ .BI "\-f " file Log messages to the specified filename rather than to the syslog facility. .TP +.BI "\-u " username +Tells klogd to become the specified user and drop root privileges before +starting logging. +.TP +.BI "\-j " chroot_dir +Tells klogd to +.BR chroot (2) +into this directory after initializing. +This option is only valid if the \-u option is also used to run klogd +without root privileges. +Note that the use of this option will prevent \-i and \-I from working +unless you set up the chroot directory in such a way that klogd can still +read the kernel module symbols. +.TP .BI "\-i \-I" Signal the currently executing klogd daemon. Both of these switches control the loading/reloading of symbol information. The \-i switch signals the diff -Naur sysklogd-1.4.1.orig/klogd.c sysklogd-1.4.1/klogd.c --- sysklogd-1.4.1.orig/klogd.c 2005-01-22 18:49:55.000000000 +0000 +++ sysklogd-1.4.1/klogd.c 2005-01-23 10:59:57.212383035 +0000 @@ -258,6 +258,8 @@ #include #include #include +#include +#include #include "klogd.h" #include "ksyms.h" #ifndef TESTING @@ -308,6 +310,9 @@ int debugging = 0; int symbols_twice = 0; +char *server_user = NULL; +char *chroot_dir = NULL; +int log_flags = 0; /* Function prototypes. */ extern int ksyslog(int type, char *buf, int len); @@ -528,8 +533,9 @@ * First do a stat to determine whether or not the proc based * file system is available to get kernel messages from. */ - if ( use_syscall || - ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)) ) + if (!server_user && + (use_syscall || + ((stat(_PATH_KLOG, &sb) < 0) && (errno == ENOENT)))) { /* Initialize kernel logging. */ ksyslog(1, NULL, 0); @@ -977,6 +983,27 @@ } +static int drop_root(void) +{ + struct passwd *pw; + + if (!(pw = getpwnam(server_user))) return -1; + + if (!pw->pw_uid) return -1; + + if (chroot_dir) { + if (chroot(chroot_dir)) return -1; + if (chdir("/")) return -1; + } + + if (setgroups(0, NULL)) return -1; + if (setgid(pw->pw_gid)) return -1; + if (setuid(pw->pw_uid)) return -1; + + return 0; +} + + int main(argc, argv) int argc; @@ -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:u:j:iIk:nopsvx2")) != EOF) switch((char)ch) { case '2': /* Print lines with symbols twice. */ @@ -1016,6 +1043,10 @@ case 'I': SignalDaemon(SIGUSR2); return(0); + case 'j': /* chroot 'j'ail */ + chroot_dir = optarg; + log_flags |= LOG_NDELAY; + break; case 'k': /* Kernel symbol file. */ symfile = optarg; break; @@ -1031,6 +1062,9 @@ case 's': /* Use syscall interface. */ use_syscall = 1; break; + case 'u': /* Run as this user */ + server_user = optarg; + break; case 'v': printf("klogd %s.%s\n", VERSION, PATCHLEVEL); exit (1); @@ -1039,6 +1073,10 @@ break; } + if (chroot_dir && !server_user) { + fputs("'-j' is only valid with '-u'", stderr); + exit(1); + } /* Set console logging level. */ if ( log_level != (char *) 0 ) @@ -1136,7 +1174,7 @@ } } else - openlog("kernel", 0, LOG_KERN); + openlog("kernel", log_flags, LOG_KERN); /* Handle one-shot logging. */ @@ -1163,6 +1201,11 @@ InitMsyms(); } + if (server_user && drop_root()) { + syslog(LOG_ALERT, "klogd: failed to drop root"); + Terminate(); + } + /* The main loop. */ while (1) { diff -Naur sysklogd-1.4.1.orig/sysklogd.8 sysklogd-1.4.1/sysklogd.8 --- sysklogd-1.4.1.orig/sysklogd.8 2005-01-22 18:49:55.000000000 +0000 +++ sysklogd-1.4.1/sysklogd.8 2005-01-23 11:00:07.985367732 +0000 @@ -29,6 +29,9 @@ .RB [ " \-s " .I domainlist ] +.RB [ " \-u" +.IB username +] .RB [ " \-v " ] .LP .SH DESCRIPTION @@ -150,6 +153,19 @@ no domain would be cut, you will have to specify two domains like: .BR "\-s north.de:infodrom.north.de" . .TP +.BI "\-u " "username" +This causes the +.B syslogd +daemon to become the named user before starting up logging. + +Note that when this option is in use, +.B syslogd +will open all log files as root when the daemon is first started; +however, after a +.B SIGHUP +the files will be reopened as the non-privileged user. You should +take this into account when deciding the ownership of the log files. +.TP .B "\-v" Print version and exit. .LP diff -Naur sysklogd-1.4.1.orig/syslogd.c sysklogd-1.4.1/syslogd.c --- sysklogd-1.4.1.orig/syslogd.c 2005-01-22 18:49:55.000000000 +0000 +++ sysklogd-1.4.1/syslogd.c 2005-01-23 11:05:40.747216393 +0000 @@ -491,6 +491,10 @@ #include #include #include + +#include +#include + #ifndef TESTING #include "pidfile.h" #endif @@ -735,6 +739,7 @@ char **LocalHosts = NULL; /* these hosts are logged with their hostname */ int NoHops = 1; /* Can we bounce syslog messages through an intermediate host. */ +char *server_user = NULL; /* user name to run server as */ extern int errno; @@ -776,6 +781,21 @@ static int create_inet_socket(); #endif +static int drop_root(void) +{ + struct passwd *pw; + + if (!(pw = getpwnam(server_user))) return -1; + + if (!pw->pw_uid) return -1; + + if (initgroups(server_user, pw->pw_gid)) return -1; + if (setgid(pw->pw_gid)) return -1; + if (setuid(pw->pw_uid)) return -1; + + return 0; +} + int main(argc, argv) int argc; char **argv; @@ -829,7 +849,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:u:v")) != EOF) switch((char)ch) { case 'a': if (nfunix < MAXFUNIX) @@ -874,6 +894,9 @@ } StripDomains = crunch_list(optarg); break; + case 'u': + server_user = optarg; + break; case 'v': printf("syslogd %s.%s\n", VERSION, PATCHLEVEL); exit (0); @@ -1021,6 +1044,11 @@ kill (ppid, SIGTERM); #endif + if (server_user && drop_root()) { + dprintf("syslogd: failed to drop root\n"); + exit(1); + } + /* Main loop begins here. */ for (;;) { int nfds; @@ -1175,7 +1203,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 username]\n"); exit(1); }