From 325f919847cb23044d203501140d9030903cfe12 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sun, 19 Aug 2018 11:07:17 +0200 Subject: [PATCH] usyslogd: chroot into log dir and drop privileges Signed-off-by: David Oberhollenzer --- services/usyslogd | 2 +- syslogd/logfile.c | 15 ------- syslogd/main.c | 105 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 105 insertions(+), 17 deletions(-) diff --git a/services/usyslogd b/services/usyslogd index 60520c5..6b378d9 100644 --- a/services/usyslogd +++ b/services/usyslogd @@ -1,5 +1,5 @@ description "starting usyslogd" -exec usyslogd --rotate-replace --max-size 8192 +exec usyslogd --chroot --rotate-replace --max-size 8192 type respawn limit 5 target boot after vfs diff --git a/syslogd/logfile.c b/syslogd/logfile.c index 6240905..513b027 100644 --- a/syslogd/logfile.c +++ b/syslogd/logfile.c @@ -29,9 +29,6 @@ #include "util.h" -#define SYSLOG_PATH PREFIXPATH "/var/log" - - static const enum_map_t levels[] = { { "emergency", 0 }, { "alert", 1 }, @@ -204,18 +201,6 @@ static int file_backend_init(log_backend_t *backend, int flags, { log_backend_file_t *log = (log_backend_file_t *)backend; - if (mkdir(SYSLOG_PATH, 0755)) { - if (errno != EEXIST) { - perror("mkdir " SYSLOG_PATH); - return -1; - } - } - - if (chdir(SYSLOG_PATH)) { - perror("cd " SYSLOG_PATH); - return -1; - } - log->flags = flags; log->maxsize = sizelimit; return 0; diff --git a/syslogd/main.c b/syslogd/main.c index e89b287..e2cc804 100644 --- a/syslogd/main.c +++ b/syslogd/main.c @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include "backend.h" #include "proto.h" @@ -32,6 +35,9 @@ #define SYSLOG_SOCKET PREFIXPATH "/dev/log" +#define SYSLOG_PATH PREFIXPATH "/var/log" +#define DEFAULT_USER "syslogd" +#define DEFAULT_GROUP "syslogd" #define GPL_URL "https://gnu.org/licenses/gpl.html" @@ -41,6 +47,9 @@ static const struct option long_opts[] = { { "version", no_argument, NULL, 'V' }, { "rotate-replace", no_argument, NULL, 'r' }, { "max-size", required_argument, NULL, 'm' }, + { "user", required_argument, NULL, 'u' }, + { "group", required_argument, NULL, 'g' }, + { "chroot", required_argument, NULL, 'c' }, { NULL, 0, NULL, 0 }, }; @@ -59,7 +68,12 @@ const char *usage_string = " -h, --help Print this help text and exit\n" " -V, --version Print version information and exit\n" " -r, --rotate-replace Replace old log files when doing log rotation.\n" -" -m, --max-size Automatically rotate log files bigger than this.\n"; +" -m, --max-size Automatically rotate log files bigger than this.\n" +" -u, --user Run the syslog daemon as this user. If not set,\n" +" try to use the user '" DEFAULT_USER "'.\n" +" -g, --group Run the syslog daemon as this group. If not set,\n" +" try to use the group '" DEFAULT_GROUP "'.\n" +" -c, --chroot If set, do a chroot into the log file path.\n"; @@ -67,6 +81,9 @@ static volatile sig_atomic_t syslog_run = 1; static volatile sig_atomic_t syslog_rotate = 0; static int log_flags = 0; static size_t max_size = 0; +static uid_t uid = 0; +static gid_t gid = 0; +static bool dochroot = false; @@ -117,9 +134,17 @@ static int handle_data(int fd) static void process_options(int argc, char **argv) { + struct passwd *pw = getpwnam(DEFAULT_USER); + struct group *grp = getgrnam(DEFAULT_GROUP); char *end; int i; + if (pw != NULL) + uid = pw->pw_uid; + + if (grp != NULL) + gid = grp->gr_gid; + for (;;) { i = getopt_long(argc, argv, short_opts, long_opts, NULL); if (i == -1) @@ -138,6 +163,28 @@ static void process_options(int argc, char **argv) goto fail; } break; + case 'u': + pw = getpwnam(optarg); + if (pw == NULL) { + fprintf(stderr, "Cannot get UID for user %s\n", + optarg); + goto fail; + } + uid = pw->pw_uid; + break; + case 'g': + grp = getgrnam(optarg); + if (grp == NULL) { + fprintf(stderr, + "Cannot get GID for group %s\n", + optarg); + goto fail; + } + gid = grp->gr_gid; + break; + case 'c': + dochroot = true; + break; case 'h': fputs(usage_string, stdout); exit(EXIT_SUCCESS); @@ -154,6 +201,51 @@ fail: exit(EXIT_FAILURE); } +static int chroot_setup(void) +{ + if (mkdir(SYSLOG_PATH, 0750)) { + if (errno != EEXIST) { + perror("mkdir " SYSLOG_PATH); + return -1; + } + } + + if (uid > 0 && gid > 0 && chown(SYSLOG_PATH, uid, gid) != 0) { + perror("chown " SYSLOG_PATH); + return -1; + } + + if (chmod(SYSLOG_PATH, 0750)) { + perror("chmod " SYSLOG_PATH); + return -1; + } + + if (chdir(SYSLOG_PATH)) { + perror("cd " SYSLOG_PATH); + return -1; + } + + if (dochroot && chroot(SYSLOG_PATH) != 0) { + perror("chroot " SYSLOG_PATH); + return -1; + } + + return 0; +} + +static int user_setup(void) +{ + if (gid > 0 && setresgid(gid, gid, gid) != 0) { + perror("setgid"); + return -1; + } + if (uid > 0 && setresuid(uid, uid, uid) != 0) { + perror("setuid"); + return -1; + } + return 0; +} + int main(int argc, char **argv) { int sfd, status = EXIT_FAILURE; @@ -166,6 +258,17 @@ int main(int argc, char **argv) if (sfd < 0) return EXIT_FAILURE; + if (uid > 0 && gid > 0 && chown(SYSLOG_SOCKET, uid, gid) != 0) { + perror("chown " SYSLOG_SOCKET); + return -1; + } + + if (chroot_setup()) + return EXIT_FAILURE; + + if (user_setup()) + return EXIT_FAILURE; + if (logmgr->init(logmgr, log_flags, max_size)) goto out;