]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn: when readjusting UID/GID ownership of OS trees, skip read-only subtrees 3093/head
authorLennart Poettering <lennart@poettering.net>
Mon, 25 Apr 2016 10:48:05 +0000 (12:48 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 25 Apr 2016 10:50:13 +0000 (12:50 +0200)
This should allow tools like rkt to pre-mount read-only subtrees in the OS
tree, without breaking the patching code.

Note that the code will still fail, if the top-level directory is already
read-only.

src/basic/fd-util.c
src/basic/fd-util.h
src/nspawn/nspawn-patch-uid.c

index ec9560cd07702d80603d427d890037e6d405e1b9..3d46d708c7b766cbf966a9a9f85fec3a4ab6e0d4 100644 (file)
 #include <unistd.h>
 
 #include "fd-util.h"
+#include "fs-util.h"
 #include "macro.h"
 #include "missing.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "socket-util.h"
+#include "stdio-util.h"
 #include "util.h"
 
 int close_nointr(int fd) {
@@ -356,3 +358,11 @@ bool fdname_is_valid(const char *s) {
 
         return p - s < 256;
 }
+
+int fd_get_path(int fd, char **ret) {
+        char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+
+        xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+
+        return readlink_malloc(procfs_path, ret);
+}
index 44528c6e35f97c965d8cc40e98314054eec052fa..b86e41698acb58afaa5c9e1079626feba4130fdf 100644 (file)
@@ -72,6 +72,8 @@ void cmsg_close_all(struct msghdr *mh);
 
 bool fdname_is_valid(const char *s);
 
+int fd_get_path(int fd, char **ret);
+
 /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */
 #define ERRNO_IS_DISCONNECT(r) \
         IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH)
index 429c45a3a77f32ead13883aa30096be128da44ca..c7382d412d44b8c8c574b0f5ea2c238d9cccb13a 100644 (file)
@@ -303,7 +303,7 @@ static int is_procfs_sysfs_or_suchlike(int fd) {
                F_TYPE_EQUAL(sfs.f_type, SYSFS_MAGIC);
 }
 
-static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift) {
+static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift, bool is_toplevel) {
         bool changed = false;
         int r;
 
@@ -321,6 +321,18 @@ static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift
         }
 
         r = patch_fd(fd, NULL, st, shift);
+        if (r == -EROFS) {
+                _cleanup_free_ char *name = NULL;
+
+                if (!is_toplevel) {
+                        /* When we hit a ready-only subtree we simply skip it, but log about it. */
+                        (void) fd_get_path(fd, &name);
+                        log_debug("Skippping read-only file or directory %s.", strna(name));
+                        r = 0;
+                }
+
+                goto finish;
+        }
         if (r < 0)
                 goto finish;
 
@@ -369,7 +381,7 @@ static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift
 
                                 }
 
-                                r = recurse_fd(subdir_fd, true, &fst, shift);
+                                r = recurse_fd(subdir_fd, true, &fst, shift, false);
                                 if (r < 0)
                                         goto finish;
                                 if (r > 0)
@@ -433,7 +445,7 @@ static int fd_patch_uid_internal(int fd, bool donate_fd, uid_t shift, uid_t rang
         if (((uint32_t) (st.st_uid ^ shift) >> 16) == 0)
                 return 0;
 
-        return recurse_fd(fd, donate_fd, &st, shift);
+        return recurse_fd(fd, donate_fd, &st, shift, true);
 
 finish:
         if (donate_fd)