diff --git a/audisp/audispd-pconfig.c b/audisp/audispd-pconfig.c index d334de784..338165370 100644 --- a/audisp/audispd-pconfig.c +++ b/audisp/audispd-pconfig.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "audispd-pconfig.h" #include "private.h" @@ -134,7 +135,7 @@ void clear_pconfig(plugin_conf_t *config) config->restart_cnt = 0; } -int load_pconfig(plugin_conf_t *config, char *file) +int load_pconfig(plugin_conf_t *config, int dirfd, char *file) { int fd, rc, mode, lineno = 1; struct stat st; @@ -143,9 +144,10 @@ int load_pconfig(plugin_conf_t *config, char *file) clear_pconfig(config); - /* open the file */ - mode = O_RDONLY; - rc = open(file, mode); + /* O_PATH avoids blocking, as no read/seek is done. + * We do not pass O_NOFOLLOW, which allows for symlinked configs. + */ + rc = openat(dirfd, file, O_PATH); if (rc < 0) { if (errno != ENOENT) { audit_msg(LOG_ERR, "Error opening %s (%s)", file, @@ -159,7 +161,7 @@ int load_pconfig(plugin_conf_t *config, char *file) fd = rc; /* check the file's permissions: owned by root, not world writable, - * not symlink. + * pointing to regular file. */ if (fstat(fd, &st) < 0) { audit_msg(LOG_ERR, "Error fstat'ing config file (%s)", @@ -179,6 +181,7 @@ int load_pconfig(plugin_conf_t *config, char *file) close(fd); return 1; } + // this checks if the actual file is a regular file. The initial open might have followed a symlink, which is acceptable. if (!S_ISREG(st.st_mode)) { audit_msg(LOG_ERR, "Error - %s is not a regular file", file); @@ -186,6 +189,22 @@ int load_pconfig(plugin_conf_t *config, char *file) return 1; } + // reopen with read perms + char fname[PATH_MAX]; + snprintf(fname, PATH_MAX, "/proc/self/fd/%i", fd); + mode = O_RDONLY; + rc = open(fname, mode); + + if (rc < 0) { + audit_msg(LOG_ERR, "Error - Failed to reopen %s for reading", + file); + close(fd); + return 1; + } + + close(fd); + fd = rc; + /* it's ok, read line by line */ f = fdopen(fd, "rm"); if (f == NULL) { diff --git a/audisp/audispd-pconfig.h b/audisp/audispd-pconfig.h index 3f6c2961a..2d89d116e 100644 --- a/audisp/audispd-pconfig.h +++ b/audisp/audispd-pconfig.h @@ -50,7 +50,7 @@ typedef struct plugin_conf } plugin_conf_t; void clear_pconfig(plugin_conf_t *config); -int load_pconfig(plugin_conf_t *config, char *file); +int load_pconfig(plugin_conf_t *config, int dirfd, char *file); void free_pconfig(plugin_conf_t *config); #endif diff --git a/audisp/audispd.c b/audisp/audispd.c index 2113d4f93..1e624b4c8 100644 --- a/audisp/audispd.c +++ b/audisp/audispd.c @@ -111,16 +111,19 @@ static void load_plugin_conf(conf_llist *plugin) /* read configs */ d = opendir(daemon_config.plugin_dir); if (d) { + int dfd = dirfd(d); + if (dfd < 0) { + closedir(d); + return; + } + struct dirent *e; while ((e = readdir(d))) { plugin_conf_t config; - char fname[PATH_MAX]; const char *ext, *reason = NULL; - if (e->d_type != DT_REG) - reason = "not a regular file"; - else if (e->d_name[0] == '.') + if (e->d_name[0] == '.') reason = "hidden file"; else if (count_dots(e->d_name) > 1) reason = "backup file"; @@ -132,11 +135,8 @@ static void load_plugin_conf(conf_llist *plugin) continue; } - snprintf(fname, sizeof(fname), "%s/%s", - daemon_config.plugin_dir, e->d_name); - clear_pconfig(&config); - if (load_pconfig(&config, fname) == 0) { + if (load_pconfig(&config, dfd, e->d_name) == 0) { /* Push onto config list only if active */ if (config.active == A_YES) plist_append(plugin, &config);