From 40826f4ed0b325961d23f1e5dda45215bdb120c0 Mon Sep 17 00:00:00 2001 From: Jakub Filak Date: Wed, 30 Sep 2015 14:13:35 +0200 Subject: [PATCH] lib: add convenient wrappers for ensuring writable dir Replace lchown with fchown and chmod with fchmod. Related to CVE-2015-5287 Related: #1262252 Signed-off-by: Jakub Filak --- src/daemon/abrtd.c | 19 ------------------- src/include/libabrt.h | 6 ++++++ src/lib/hooklib.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/daemon/abrtd.c b/src/daemon/abrtd.c index b8426dd..b1252d2 100644 --- a/src/daemon/abrtd.c +++ b/src/daemon/abrtd.c @@ -158,25 +158,6 @@ static gboolean handle_signal_cb(GIOChannel *gio, GIOCondition condition, gpoint return TRUE; /* "please don't remove this event" */ } -static void ensure_writable_dir(const char *dir, mode_t mode, const char *user) -{ - struct stat sb; - - if (mkdir(dir, mode) != 0 && errno != EEXIST) - perror_msg_and_die("Can't create '%s'", dir); - if (stat(dir, &sb) != 0 || !S_ISDIR(sb.st_mode)) - error_msg_and_die("'%s' is not a directory", dir); - - struct passwd *pw = getpwnam(user); - if (!pw) - perror_msg_and_die("Can't find user '%s'", user); - - if ((sb.st_uid != pw->pw_uid || sb.st_gid != pw->pw_gid) && lchown(dir, pw->pw_uid, pw->pw_gid) != 0) - perror_msg_and_die("Can't set owner %u:%u on '%s'", (unsigned int)pw->pw_uid, (unsigned int)pw->pw_gid, dir); - if ((sb.st_mode & 07777) != mode && chmod(dir, mode) != 0) - perror_msg_and_die("Can't set mode %o on '%s'", mode, dir); -} - static void sanitize_dump_dir_rights(void) { /* We can't allow everyone to create dumps: otherwise users can flood diff --git a/src/include/libabrt.h b/src/include/libabrt.h index 21ce440..2510a77 100644 --- a/src/include/libabrt.h +++ b/src/include/libabrt.h @@ -42,6 +42,12 @@ int low_free_space(unsigned setting_MaxCrashReportsSize, const char *dump_locati #define trim_problem_dirs abrt_trim_problem_dirs void trim_problem_dirs(const char *dirname, double cap_size, const char *exclude_path); +#define ensure_writable_dir_id abrt_ensure_writable_dir_uid_git +void ensure_writable_dir_uid_gid(const char *dir, mode_t mode, uid_t uid, gid_t gid); +#define ensure_writable_dir abrt_ensure_writable_dir +void ensure_writable_dir(const char *dir, mode_t mode, const char *user); +#define ensure_writable_dir_group abrt_ensure_writable_dir_group +void ensure_writable_dir_group(const char *dir, mode_t mode, const char *user, const char *group); #define run_unstrip_n abrt_run_unstrip_n char *run_unstrip_n(const char *dump_dir_name, unsigned timeout_sec); #define get_backtrace abrt_get_backtrace diff --git a/src/lib/hooklib.c b/src/lib/hooklib.c index 8e93663..160a011 100644 --- a/src/lib/hooklib.c +++ b/src/lib/hooklib.c @@ -428,6 +428,52 @@ char* problem_data_save(problem_data_t *pd) return problem_id; } +void ensure_writable_dir_uid_gid(const char *dir, mode_t mode, uid_t uid, gid_t gid) +{ + struct stat sb; + int dir_fd; + + if (mkdir(dir, mode) != 0 && errno != EEXIST) + perror_msg_and_die("Can't create '%s'", dir); + + dir_fd = open(dir, O_DIRECTORY | O_NOFOLLOW); + if (dir_fd < 0) + perror_msg_and_die("Can't open directory '%s'", dir); + + if (fstat(dir_fd, &sb) != 0) + perror_msg_and_die("Can't stat directory '%s'", dir); + + if ((sb.st_uid != uid || sb.st_gid != gid) && fchown(dir_fd, uid, gid) != 0) + perror_msg_and_die("Can't set owner %u:%u on '%s'", (unsigned int)uid, (unsigned int)gid, dir); + + if ((sb.st_mode & 07777) != mode && fchmod(dir_fd, mode) != 0) + perror_msg_and_die("Can't set mode %o on '%s'", mode, dir); + + close(dir_fd); +} + +void ensure_writable_dir(const char *dir, mode_t mode, const char *user) +{ + struct passwd *pw = getpwnam(user); + if (!pw) + perror_msg_and_die("Can't find user '%s'", user); + + ensure_writable_dir_uid_gid(dir, mode, pw->pw_uid, pw->pw_gid); +} + +void ensure_writable_dir_group(const char *dir, mode_t mode, const char *user, const char *group) +{ + struct passwd *pw = getpwnam(user); + if (!pw) + perror_msg_and_die("Can't find user '%s'", user); + + struct group *gr = getgrnam(group); + if (!gr) + perror_msg_and_die("Can't find group '%s'", group); + + ensure_writable_dir_uid_gid(dir, mode, pw->pw_uid, gr->gr_gid); +} + bool dir_is_in_dump_location(const char *dir_name) { unsigned len = strlen(g_settings_dump_location); -- 1.8.3.1