Blame SOURCES/0644-tmpfiles-use-safe_glob.patch

17b0f1
From 2f9ee3163c44a71c99fe104daf01d4d9ab51d2c9 Mon Sep 17 00:00:00 2001
17b0f1
From: Jan Synacek <jsynacek@redhat.com>
17b0f1
Date: Mon, 28 May 2018 10:52:52 +0200
17b0f1
Subject: [PATCH] tmpfiles: use safe_glob()
17b0f1
17b0f1
This filters out "." and ".." from glob results. Fixes #5655 and #5644.
17b0f1
17b0f1
Any judgements on whether the path is "safe" are removed. We will not remove
17b0f1
"/" under any name (including "/../" and such), but we will remove stuff that
17b0f1
is specified using paths that include "//", "/./" and "/../". Such paths can be
17b0f1
created when joining strings automatically, or for other reasons, and people
17b0f1
generally know what ".." and "." is.
17b0f1
17b0f1
Tests are added to make sure that the helper functions behave as expected.
17b0f1
17b0f1
Original commit: 84e72b5ef445ffb256bc4add4209c4c9c9855206
17b0f1
Resolves: #1436004
17b0f1
---
17b0f1
 src/shared/util.c       | 63 +++++++++++++++++++++++++++++++++++++++--
17b0f1
 src/shared/util.h       |  2 ++
17b0f1
 src/tmpfiles/tmpfiles.c | 11 ++-----
17b0f1
 3 files changed, 66 insertions(+), 10 deletions(-)
17b0f1
17b0f1
diff --git a/src/shared/util.c b/src/shared/util.c
17b0f1
index 3216f004ad..78967103a6 100644
17b0f1
--- a/src/shared/util.c
17b0f1
+++ b/src/shared/util.c
17b0f1
@@ -49,7 +49,6 @@
17b0f1
 #include <dlfcn.h>
17b0f1
 #include <sys/wait.h>
17b0f1
 #include <sys/time.h>
17b0f1
-#include <glob.h>
17b0f1
 #include <grp.h>
17b0f1
 #include <sys/mman.h>
17b0f1
 #include <sys/vfs.h>
17b0f1
@@ -3370,7 +3369,7 @@ static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bo
17b0f1
         /* We refuse to clean the root file system with this
17b0f1
          * call. This is extra paranoia to never cause a really
17b0f1
          * seriously broken system. */
17b0f1
-        if (path_equal(path, "/")) {
17b0f1
+        if (path_equal_or_files_same(path, "/")) {
17b0f1
                 log_error("Attempted to remove entire root file system, and we can't allow that.");
17b0f1
                 return -EPERM;
17b0f1
         }
17b0f1
@@ -5096,6 +5095,66 @@ int in_group(const char *name) {
17b0f1
         return in_gid(gid);
17b0f1
 }
17b0f1
 
17b0f1
+static void closedir_wrapper(void* v) {
17b0f1
+        (void) closedir(v);
17b0f1
+}
17b0f1
+
17b0f1
+static bool dot_or_dot_dot(const char *path) {
17b0f1
+        if (!path)
17b0f1
+                return false;
17b0f1
+        if (path[0] != '.')
17b0f1
+                return false;
17b0f1
+        if (path[1] == 0)
17b0f1
+                return true;
17b0f1
+        if (path[1] != '.')
17b0f1
+                return false;
17b0f1
+
17b0f1
+        return path[2] == 0;
17b0f1
+}
17b0f1
+
17b0f1
+static struct dirent* readdir_no_dot(DIR *dirp) {
17b0f1
+        struct dirent* d;
17b0f1
+
17b0f1
+        for (;;) {
17b0f1
+                d = readdir(dirp);
17b0f1
+                if (d && dot_or_dot_dot(d->d_name))
17b0f1
+                        continue;
17b0f1
+                return d;
17b0f1
+        }
17b0f1
+}
17b0f1
+
17b0f1
+int safe_glob(const char *path, int flags, glob_t *pglob) {
17b0f1
+        int k;
17b0f1
+
17b0f1
+        /* We want to set GLOB_ALTDIRFUNC ourselves, don't allow it to be set. */
17b0f1
+        assert(!(flags & GLOB_ALTDIRFUNC));
17b0f1
+
17b0f1
+        if (!pglob->gl_closedir)
17b0f1
+                pglob->gl_closedir = closedir_wrapper;
17b0f1
+        if (!pglob->gl_readdir)
17b0f1
+                pglob->gl_readdir = (struct dirent *(*)(void *)) readdir_no_dot;
17b0f1
+        if (!pglob->gl_opendir)
17b0f1
+                pglob->gl_opendir = (void *(*)(const char *)) opendir;
17b0f1
+        if (!pglob->gl_lstat)
17b0f1
+                pglob->gl_lstat = lstat;
17b0f1
+        if (!pglob->gl_stat)
17b0f1
+                pglob->gl_stat = stat;
17b0f1
+
17b0f1
+        errno = 0;
17b0f1
+        k = glob(path, flags | GLOB_ALTDIRFUNC, NULL, pglob);
17b0f1
+
17b0f1
+        if (k == GLOB_NOMATCH)
17b0f1
+                return -ENOENT;
17b0f1
+        if (k == GLOB_NOSPACE)
17b0f1
+                return -ENOMEM;
17b0f1
+        if (k != 0)
17b0f1
+                return errno > 0 ? -errno : -EIO;
17b0f1
+        if (strv_isempty(pglob->gl_pathv))
17b0f1
+                return -ENOENT;
17b0f1
+
17b0f1
+        return 0;
17b0f1
+}
17b0f1
+
17b0f1
 int glob_exists(const char *path) {
17b0f1
         _cleanup_globfree_ glob_t g = {};
17b0f1
         int k;
17b0f1
diff --git a/src/shared/util.h b/src/shared/util.h
17b0f1
index 998f882bbb..cf096aa07b 100644
17b0f1
--- a/src/shared/util.h
17b0f1
+++ b/src/shared/util.h
17b0f1
@@ -44,6 +44,7 @@
17b0f1
 #include <mntent.h>
17b0f1
 #include <sys/socket.h>
17b0f1
 #include <sys/inotify.h>
17b0f1
+#include <glob.h>
17b0f1
 
17b0f1
 #if SIZEOF_PID_T == 4
17b0f1
 #  define PID_PRI PRIi32
17b0f1
@@ -595,6 +596,7 @@ char* gid_to_name(gid_t gid);
17b0f1
 
17b0f1
 int glob_exists(const char *path);
17b0f1
 int glob_extend(char ***strv, const char *path);
17b0f1
+int safe_glob(const char *path, int flags, glob_t *pglob);
17b0f1
 
17b0f1
 int dirent_ensure_type(DIR *d, struct dirent *de);
17b0f1
 
17b0f1
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
17b0f1
index 5212d72f56..8a75efb229 100644
17b0f1
--- a/src/tmpfiles/tmpfiles.c
17b0f1
+++ b/src/tmpfiles/tmpfiles.c
17b0f1
@@ -1095,19 +1095,14 @@ static int item_do_children(Item *i, const char *path, action_t action) {
17b0f1
 
17b0f1
 static int glob_item(Item *i, action_t action, bool recursive) {
17b0f1
         _cleanup_globfree_ glob_t g = {
17b0f1
-                .gl_closedir = (void (*)(void *)) closedir,
17b0f1
-                .gl_readdir = (struct dirent *(*)(void *)) readdir,
17b0f1
                 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
17b0f1
-                .gl_lstat = lstat,
17b0f1
-                .gl_stat = stat,
17b0f1
         };
17b0f1
         int r = 0, k;
17b0f1
         char **fn;
17b0f1
 
17b0f1
-        errno = 0;
17b0f1
-        k = glob(i->path, GLOB_NOSORT|GLOB_BRACE|GLOB_ALTDIRFUNC, NULL, &g);
17b0f1
-        if (k != 0 && k != GLOB_NOMATCH)
17b0f1
-                return log_error_errno(errno ?: EIO, "glob(%s) failed: %m", i->path);
17b0f1
+        k = safe_glob(i->path, GLOB_NOSORT|GLOB_BRACE, &g);
17b0f1
+        if (k < 0 && k != -ENOENT)
17b0f1
+                return log_error_errno(k, "glob(%s) failed: %m", i->path);
17b0f1
 
17b0f1
         STRV_FOREACH(fn, g.gl_pathv) {
17b0f1
                 k = action(i, *fn);