summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-04-25 12:48:05 +0200
committerLennart Poettering <lennart@poettering.net>2016-04-25 12:50:13 +0200
commit4aeb20f5aaec25ef969989b64d37377913b2a1ef (patch)
tree27044cdb74a1204974cbafba58628dc4a8ef1984
parent88cd066e11aef5dd73b563c1753ad8bf4dfd9f62 (diff)
nspawn: when readjusting UID/GID ownership of OS trees, skip read-only subtrees
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.
-rw-r--r--src/basic/fd-util.c10
-rw-r--r--src/basic/fd-util.h2
-rw-r--r--src/nspawn/nspawn-patch-uid.c18
3 files changed, 27 insertions, 3 deletions
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
index ec9560cd07..3d46d708c7 100644
--- a/src/basic/fd-util.c
+++ b/src/basic/fd-util.c
@@ -25,11 +25,13 @@
#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);
+}
diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h
index 44528c6e35..b86e41698a 100644
--- a/src/basic/fd-util.h
+++ b/src/basic/fd-util.h
@@ -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)
diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c
index 429c45a3a7..c7382d412d 100644
--- a/src/nspawn/nspawn-patch-uid.c
+++ b/src/nspawn/nspawn-patch-uid.c
@@ -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)