[PATCH] Implement tmpfile white listing.
William Douglas
william.douglas at linux.intel.com
Tue Apr 19 15:12:19 PDT 2011
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
More information about the systemd-devel
mailing list