Below is version 3 of tmpfile white listing.
>From ed06da9a9dea18070cedf0bc2bf3d387b1bd57f0 Mon Sep 17 00:00:00 2001 From: William Douglas <william.doug...@linux.intel.com> Date: Tue, 19 Apr 2011 15:12:19 -0700 Subject: [PATCH] Implement tmpfile white listing. x, in addition to its old behavior, now will protect (recursively) files from removal. D has been modified to also "protect" directories so that r/R won't touch them. src/util.h: Modify rm_rf signature to take a function pointer used to assess if files are protected or not. src/util.c: Update item deletion to check if they are on the protected list and not delete if they are. Also change deleting a folder failure behavior to not report failure if the folder wasn't empty. src/tmpfiles.c: Add new hashmap for filenames that are protected and add paths (post glob expansion) for items that are of type IGNORE_PATH or TRUNCATE_DIRECTORY to that hashmap. --- man/tmpfiles.d.xml | 15 ++++++--------- src/tmpfiles.c | 25 +++++++++++++++++-------- src/util.c | 47 +++++++++++++++++++++++++++++++---------------- src/util.h | 2 +- 4 files changed, 55 insertions(+), 34 deletions(-) diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index abc74ef..aadfb7c 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -115,15 +115,12 @@ d /run/user 0755 root root 10d</programlisting> <varlistentry> <term><varname>x</varname></term> <listitem><para>Ignore a path - during cleaning. Use this type - to exclude paths from clean-up - as controlled with the Age - parameter. Note that lines of - this type do not influence the - effect of r or R lines. Lines - of this type accept - shell-style globs in place of - of normal path + during cleaning or removal. + Use this type to exclude paths + from clean-up as controlled with + the Age parameter. Lines of this + type accept shell-style globs in + place of normal path names.</para></listitem> </varlistentry> diff --git a/src/tmpfiles.c b/src/tmpfiles.c index 1574a19..05b6071 100644 --- a/src/tmpfiles.c +++ b/src/tmpfiles.c @@ -104,6 +104,16 @@ static struct Item* find_glob(Hashmap *h, const char *match) { return NULL; } +static bool protected(const char *key) { + struct Item *i; + + if (!(i = find_glob(globs, key))) + if (!(i = (Item *)hashmap_get(items, key))) + return false; + + return i->type == TRUNCATE_DIRECTORY || i->type == IGNORE_PATH; +} + static void load_unix_sockets(void) { FILE *f = NULL; char line[LINE_MAX]; @@ -229,10 +239,7 @@ static int dir_cleanup( } /* Is there an item configured for this path? */ - if (hashmap_get(items, sub_path)) - continue; - - if (find_glob(globs, sub_path)) + if (protected(sub_path)) continue; if (S_ISDIR(s.st_mode)) { @@ -533,16 +540,18 @@ static int remove_item(Item *i, const char *instance) { break; case REMOVE_PATH: - if (remove(instance) < 0 && errno != ENOENT) { - log_error("remove(%s): %m", instance); - return -errno; + if (!protected(instance)) { + if (remove(instance) < 0 && errno != ENOENT) { + log_error("remove(%s): %m", instance); + return -errno; + } } break; case TRUNCATE_DIRECTORY: case RECURSIVE_REMOVE_PATH: - if ((r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH)) < 0 && + if ((r = rm_rf(instance, false, i->type == RECURSIVE_REMOVE_PATH, protected)) < 0 && r != -ENOENT) { log_error("rm_rf(%s): %s", instance, strerror(-r)); return r; diff --git a/src/util.c b/src/util.c index 5029896..ef67588 100644 --- a/src/util.c +++ b/src/util.c @@ -3077,9 +3077,10 @@ int get_ctty(char **r, dev_t *_devnr) { return 0; } -static int rm_rf_children(int fd, bool only_dirs) { +static int rm_rf_children(int fd, bool only_dirs, const char *path, bool (*protected)(const char *)) { DIR *d; int ret = 0; + char *new_path = NULL; assert(fd >= 0); @@ -3122,39 +3123,51 @@ static int rm_rf_children(int fd, bool only_dirs) { } else is_dir = de->d_type == DT_DIR; + free(new_path); + if (asprintf(&new_path, "%s/%s", path, de->d_name) < 0) { + closedir(d); + return -ENOMEM; + } + if (is_dir) { int subdir_fd; + if (protected && protected(new_path)) + continue; + if ((subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC)) < 0) { if (ret == 0 && errno != ENOENT) ret = -errno; continue; } - if ((r = rm_rf_children(subdir_fd, only_dirs)) < 0) { + if ((r = rm_rf_children(subdir_fd, only_dirs, new_path, protected)) < 0) { if (ret == 0) ret = r; } if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) { - if (ret == 0 && errno != ENOENT) + if (ret == 0 && errno != ENOENT && errno != EEXIST && errno != ENOTEMPTY) ret = -errno; } } else if (!only_dirs) { - if (unlinkat(fd, de->d_name, 0) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; + if (!(protected && protected(new_path))) { + if (unlinkat(fd, de->d_name, 0) < 0) { + if (ret == 0 && errno != ENOENT) + ret = -errno; + } } } } + free(new_path); closedir(d); return ret; } -int rm_rf(const char *path, bool only_dirs, bool delete_root) { +int rm_rf(const char *path, bool only_dirs, bool delete_root, bool (*protected)(const char *)) { int fd; int r; @@ -3165,20 +3178,22 @@ int rm_rf(const char *path, bool only_dirs, bool delete_root) { if (errno != ENOTDIR) return -errno; - if (delete_root && !only_dirs) - if (unlink(path) < 0) - return -errno; + if (!(protected && protected(path))) + if (delete_root && !only_dirs) + if (unlink(path) < 0) + return -errno; return 0; } - r = rm_rf_children(fd, only_dirs); + r = rm_rf_children(fd, only_dirs, path, protected); - if (delete_root) - if (rmdir(path) < 0) { - if (r == 0) - r = -errno; - } + if (!(protected && protected(path))) + if (delete_root) + if (rmdir(path) < 0) { + if (r == 0 && errno != EEXIST && errno != ENOTEMPTY) + r = -errno; + } return r; } diff --git a/src/util.h b/src/util.h index 7fa488b..0d0f2c9 100644 --- a/src/util.h +++ b/src/util.h @@ -350,7 +350,7 @@ int get_ctty(char **r, dev_t *_devnr); int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); -int rm_rf(const char *path, bool only_dirs, bool delete_root); +int rm_rf(const char *path, bool only_dirs, bool delete_root, bool (*protected)(const char *)); cpu_set_t* cpu_set_malloc(unsigned *ncpus); -- 1.7.2.3 -- William Douglas, Intel Open Source Technology Center _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel