summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/machinectl.xml26
-rw-r--r--man/systemd-nspawn.xml8
-rw-r--r--src/basic/fs-util.c16
-rw-r--r--src/basic/fs-util.h2
-rw-r--r--src/machine/machine-dbus.c84
-rw-r--r--src/nspawn/meson.build23
-rw-r--r--src/nspawn/nspawn-def.h33
-rw-r--r--src/nspawn/nspawn-patch-uid.c121
-rw-r--r--src/nspawn/nspawn-patch-uid.h2
-rw-r--r--src/nspawn/nspawn.c7
-rw-r--r--src/test/test-fs-util.c27
11 files changed, 248 insertions, 101 deletions
diff --git a/man/machinectl.xml b/man/machinectl.xml
index cf46fe8024..8c71880cf2 100644
--- a/man/machinectl.xml
+++ b/man/machinectl.xml
@@ -208,16 +208,16 @@
<varlistentry>
<term><option>--mkdir</option></term>
- <listitem><para>When used with <command>bind</command>, creates
- the destination directory before applying the bind
- mount.</para></listitem>
+ <listitem><para>When used with <command>bind</command>, creates the destination file or directory before
+ applying the bind mount. Note that even though the name of this option suggests that it is suitable only for
+ directories, this option also creates the destination file node to mount over if the the object to mount is not
+ a directory, but a regular file, device node, socket or FIFO.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--read-only</option></term>
- <listitem><para>When used with <command>bind</command>, applies
- a read-only bind mount.</para>
+ <listitem><para>When used with <command>bind</command>, creates a read-only bind mount.</para>
<para>When used with <command>clone</command>, <command>import-raw</command> or <command>import-tar</command> a
read-only container or VM image is created.</para></listitem>
@@ -528,14 +528,16 @@
<varlistentry>
<term><command>bind</command> <replaceable>NAME</replaceable> <replaceable>PATH</replaceable> [<replaceable>PATH</replaceable>]</term>
- <listitem><para>Bind mounts a directory from the host into the specified container. The first directory
- argument is the source directory on the host, the second directory argument is the destination directory in the
- container. When the latter is omitted, the destination path in the container is the same as the source path on
- the host. When combined with the <option>--read-only</option> switch, a ready-only bind mount is created. When
- combined with the <option>--mkdir</option> switch, the destination path is first created before the mount is
- applied. Note that this option is currently only supported for
+ <listitem><para>Bind mounts a file or directory from the host into the specified container. The first path
+ argument is the source file or directory on the host, the second path argument is the destination file or
+ directory in the container. When the latter is omitted, the destination path in the container is the same as
+ the source path on the host. When combined with the <option>--read-only</option> switch, a ready-only bind
+ mount is created. When combined with the <option>--mkdir</option> switch, the destination path is first created
+ before the mount is applied. Note that this option is currently only supported for
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> containers,
- and only if user namespacing (<option>--private-users</option>) is not used.</para></listitem>
+ and only if user namespacing (<option>--private-users</option>) is not used. This command supports bind
+ mounting directories, regular files, device nodes, <constant>AF_UNIX</constant> socket nodes, as well as
+ FIFOs.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index 98ce1529de..1ef6567e48 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -806,7 +806,13 @@
<option>norbind</option> are allowed, controlling whether to create a recursive or a regular bind
mount. Defaults to "rbind". Backslash escapes are interpreted, so <literal>\:</literal> may be used to embed
colons in either path. This option may be specified multiple times for creating multiple independent bind
- mount points. The <option>--bind-ro=</option> option creates read-only bind mounts.</para></listitem>
+ mount points. The <option>--bind-ro=</option> option creates read-only bind mounts.</para>
+
+ <para>Note that when this option is used in combination with <option>--private-users</option>, the resulting
+ mount points will be owned by the <constant>nobody</constant> user. That's because the mount and its files and
+ directories continue to be owned by the relevant host users and groups, which do not exist in the container,
+ and thus show up under the wildcard UID 65534 (nobody). If such bind mounts are created, it is recommended to
+ make them read-only, using <option>--bind-ro=</option>.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 946f779a32..ff8b4e8747 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -104,7 +104,6 @@ int rmdir_parents(const char *path, const char *stop) {
return 0;
}
-
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
struct stat buf;
int ret;
@@ -809,3 +808,18 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
return exists;
}
+
+int access_fd(int fd, int mode) {
+ char p[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
+ int r;
+
+ /* Like access() but operates on an already open fd */
+
+ xsprintf(p, "/proc/self/fd/%i", fd);
+
+ r = access(p, mode);
+ if (r < 0)
+ r = -errno;
+
+ return r;
+}
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index d3342d5cda..9849522f5a 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -98,3 +98,5 @@ static inline void unlink_and_free(char *p) {
free(p);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free);
+
+int access_fd(int fd, int mode);
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index 3cb90be67d..28d05c088a 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -836,11 +836,13 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
bool mount_slave_created = false, mount_slave_mounted = false,
mount_tmp_created = false, mount_tmp_mounted = false,
mount_outside_created = false, mount_outside_mounted = false;
+ _cleanup_free_ char *chased_src = NULL;
+ int read_only, make_file_or_directory;
const char *dest, *src;
Machine *m = userdata;
- int read_only, make_directory;
- pid_t child;
+ struct stat st;
siginfo_t si;
+ pid_t child;
uid_t uid;
int r;
@@ -850,7 +852,7 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
if (m->class != MACHINE_CONTAINER)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
- r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_directory);
+ r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory);
if (r < 0)
return r;
@@ -890,6 +892,15 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
if (laccess(p, F_OK) < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
+ r = chase_symlinks(src, NULL, 0, &chased_src);
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to resolve source path: %m");
+
+ if (lstat(chased_src, &st) < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to stat() source path: %m");
+ if (S_ISLNK(st.st_mode)) /* This shouldn't really happen, given that we just chased the symlinks above, but let's better be safeā€¦ */
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Source directory can't be a symbolic link");
+
/* Our goal is to install a new bind mount into the container,
possibly read-only. This is irritatingly complex
unfortunately, currently.
@@ -916,18 +927,21 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
goto finish;
}
- /* Second, we mount the source directory to a directory inside
- of our MS_SLAVE playground. */
+ /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */
mount_tmp = strjoina(mount_slave, "/mount");
- if (mkdir(mount_tmp, 0700) < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
+ if (S_ISDIR(st.st_mode))
+ r = mkdir(mount_tmp, 0700) < 0 ? -errno : 0;
+ else
+ r = touch(mount_tmp);
+ if (r < 0) {
+ sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
goto finish;
}
mount_tmp_created = true;
- if (mount(src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
- r = sd_bus_error_set_errnof(error, errno, "Failed to mount %s: %m", src);
+ if (mount(chased_src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
+ r = sd_bus_error_set_errnof(error, errno, "Failed to mount %s: %m", chased_src);
goto finish;
}
@@ -940,13 +954,18 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
goto finish;
}
- /* Fourth, we move the new bind mount into the propagation
- * directory. This way it will appear there read-only
+ /* Fourth, we move the new bind mount into the propagation directory. This way it will appear there read-only
* right-away. */
mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
- if (!mkdtemp(mount_outside)) {
- r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
+ if (S_ISDIR(st.st_mode))
+ r = mkdtemp(mount_outside) ? 0 : -errno;
+ else {
+ r = mkostemp_safe(mount_outside);
+ safe_close(r);
+ }
+ if (r < 0) {
+ sd_bus_error_set_errnof(error, errno, "Cannot create propagation file or directory %s: %m", mount_outside);
goto finish;
}
@@ -960,7 +979,10 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
mount_outside_mounted = true;
mount_tmp_mounted = false;
- (void) rmdir(mount_tmp);
+ if (S_ISDIR(st.st_mode))
+ (void) rmdir(mount_tmp);
+ else
+ (void) unlink(mount_tmp);
mount_tmp_created = false;
(void) umount(mount_slave);
@@ -999,8 +1021,14 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
goto child_fail;
}
- if (make_directory)
- (void) mkdir_p(dest, 0755);
+ if (make_file_or_directory) {
+ if (S_ISDIR(st.st_mode))
+ (void) mkdir_p(dest, 0755);
+ else {
+ (void) mkdir_parents(dest, 0755);
+ safe_close(open(dest, O_CREAT|O_EXCL|O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600));
+ }
+ }
/* Fifth, move the mount to the right place inside */
mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
@@ -1042,19 +1070,27 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
finish:
if (mount_outside_mounted)
- umount(mount_outside);
- if (mount_outside_created)
- rmdir(mount_outside);
+ (void) umount(mount_outside);
+ if (mount_outside_created) {
+ if (S_ISDIR(st.st_mode))
+ (void) rmdir(mount_outside);
+ else
+ (void) unlink(mount_outside);
+ }
if (mount_tmp_mounted)
- umount(mount_tmp);
- if (mount_tmp_created)
- rmdir(mount_tmp);
+ (void) umount(mount_tmp);
+ if (mount_tmp_created) {
+ if (S_ISDIR(st.st_mode))
+ (void) rmdir(mount_tmp);
+ else
+ (void) unlink(mount_tmp);
+ }
if (mount_slave_mounted)
- umount(mount_slave);
+ (void) umount(mount_slave);
if (mount_slave_created)
- rmdir(mount_slave);
+ (void) rmdir(mount_slave);
return r;
}
diff --git a/src/nspawn/meson.build b/src/nspawn/meson.build
index b6ac6006ab..7f54ebc6db 100644
--- a/src/nspawn/meson.build
+++ b/src/nspawn/meson.build
@@ -1,25 +1,26 @@
systemd_nspawn_sources = files('''
- nspawn.c
- nspawn-settings.c
- nspawn-settings.h
+ nspawn-cgroup.c
+ nspawn-cgroup.h
+ nspawn-def.h
+ nspawn-expose-ports.c
+ nspawn-expose-ports.h
nspawn-mount.c
nspawn-mount.h
nspawn-network.c
nspawn-network.h
- nspawn-expose-ports.c
- nspawn-expose-ports.h
- nspawn-cgroup.c
- nspawn-cgroup.h
- nspawn-seccomp.c
- nspawn-seccomp.h
+ nspawn-patch-uid.c
+ nspawn-patch-uid.h
nspawn-register.c
nspawn-register.h
+ nspawn-seccomp.c
+ nspawn-seccomp.h
+ nspawn-settings.c
+ nspawn-settings.h
nspawn-setuid.c
nspawn-setuid.h
nspawn-stub-pid1.c
nspawn-stub-pid1.h
- nspawn-patch-uid.c
- nspawn-patch-uid.h
+ nspawn.c
'''.split())
nspawn_gperf_c = custom_target(
diff --git a/src/nspawn/nspawn-def.h b/src/nspawn/nspawn-def.h
new file mode 100644
index 0000000000..fc3c94064c
--- /dev/null
+++ b/src/nspawn/nspawn-def.h
@@ -0,0 +1,33 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+
+/* Note that devpts's gid= parameter parses GIDs as signed values, hence we stay away from the upper half of the 32bit
+ * UID range here. We leave a bit of room at the lower end and a lot of room at the upper end, so that other subsystems
+ * may have their own allocation ranges too. */
+#define UID_SHIFT_PICK_MIN ((uid_t) UINT32_C(0x00080000))
+#define UID_SHIFT_PICK_MAX ((uid_t) UINT32_C(0x6FFF0000))
+
+/* While we are chmod()ing a directory tree, we set the top-level UID base to this "busy" base, so that we can always
+ * recognize trees we are were chmod()ing recursively and got interrupted in */
+#define UID_BUSY_BASE ((uid_t) UINT32_C(0xFFFE0000))
+#define UID_BUSY_MASK ((uid_t) UINT32_C(0xFFFF0000))
diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c
index 063fdb1053..7857b453d6 100644
--- a/src/nspawn/nspawn-patch-uid.c
+++ b/src/nspawn/nspawn-patch-uid.c
@@ -23,13 +23,16 @@
#include <sys/acl.h>
#endif
#include <sys/stat.h>
+#include <sys/statvfs.h>
#include <sys/vfs.h>
#include <unistd.h>
#include "acl-util.h"
#include "dirent-util.h"
#include "fd-util.h"
+#include "fs-util.h"
#include "missing.h"
+#include "nspawn-def.h"
#include "nspawn-patch-uid.h"
#include "stat-util.h"
#include "stdio-util.h"
@@ -289,42 +292,44 @@ static int patch_fd(int fd, const char *name, const struct stat *st, uid_t shift
* user namespaces, however their inodes may relate to host resources or only
* valid in the global user namespace, therefore no patching should be applied.
*/
-static int is_fs_fully_userns_compatible(int fd) {
- struct statfs sfs;
-
- assert(fd >= 0);
-
- if (fstatfs(fd, &sfs) < 0)
- return -errno;
-
- return F_TYPE_EQUAL(sfs.f_type, BINFMTFS_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, CGROUP_SUPER_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, CGROUP2_SUPER_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, DEBUGFS_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, DEVPTS_SUPER_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, EFIVARFS_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, HUGETLBFS_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, MQUEUE_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, PROC_SUPER_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, PSTOREFS_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, SELINUX_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, SMACK_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, SECURITYFS_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, BPF_FS_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, TRACEFS_MAGIC) ||
- F_TYPE_EQUAL(sfs.f_type, SYSFS_MAGIC);
+static int is_fs_fully_userns_compatible(const struct statfs *sfs) {
+
+ assert(sfs);
+
+ return F_TYPE_EQUAL(sfs->f_type, BINFMTFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, CGROUP_SUPER_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, CGROUP2_SUPER_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, DEBUGFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, DEVPTS_SUPER_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, EFIVARFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, HUGETLBFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, MQUEUE_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, PROC_SUPER_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, PSTOREFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, SELINUX_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, SMACK_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, SECURITYFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, BPF_FS_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, TRACEFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs->f_type, SYSFS_MAGIC);
}
static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift, bool is_toplevel) {
+ _cleanup_closedir_ DIR *d = NULL;
bool changed = false;
+ struct statfs sfs;
int r;
assert(fd >= 0);
- /* We generally want to permit crossing of mount boundaries when patching the UIDs/GIDs. However, we
- * probably shouldn't do this for /proc and /sys if that is already mounted into place. Hence, let's
- * stop the recursion when we hit procfs, sysfs or some other special file systems. */
- r = is_fs_fully_userns_compatible(fd);
+ if (fstatfs(fd, &sfs) < 0)
+ return -errno;
+
+ /* We generally want to permit crossing of mount boundaries when patching the UIDs/GIDs. However, we probably
+ * shouldn't do this for /proc and /sys if that is already mounted into place. Hence, let's stop the recursion
+ * when we hit procfs, sysfs or some other special file systems. */
+
+ r = is_fs_fully_userns_compatible(&sfs);
if (r < 0)
goto finish;
if (r > 0) {
@@ -332,26 +337,12 @@ static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift
goto finish;
}
- 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;
- if (r > 0)
- changed = true;
+ /* Also, if we hit a read-only file system, then don't bother, skip the whole subtree */
+ if ((sfs.f_flags & ST_RDONLY) ||
+ access_fd(fd, W_OK) == -EROFS)
+ goto read_only;
if (S_ISDIR(st->st_mode)) {
- _cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
if (!donate_fd) {
@@ -411,7 +402,27 @@ static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift
}
}
+ /* After we descended, also patch the directory itself. It's key to do this in this order so that the top-level
+ * directory is patched as very last object in the tree, so that we can use it as quick indicator whether the
+ * tree is properly chown()ed already. */
+ r = patch_fd(d ? dirfd(d) : fd, NULL, st, shift);
+ if (r == -EROFS)
+ goto read_only;
+ if (r > 0)
+ changed = true;
+
r = changed;
+ goto finish;
+
+read_only:
+ if (!is_toplevel) {
+ _cleanup_free_ char *name = NULL;
+
+ /* 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 = changed;
+ }
finish:
if (donate_fd)
@@ -437,6 +448,11 @@ static int fd_patch_uid_internal(int fd, bool donate_fd, uid_t shift, uid_t rang
goto finish;
}
+ if (shift == UID_BUSY_BASE) {
+ r = -EINVAL;
+ goto finish;
+ }
+
if (range != 0x10000) {
/* We only support containers with 16bit UID ranges for the patching logic */
r = -EOPNOTSUPP;
@@ -459,6 +475,19 @@ 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;
+ /* Before we start recursively chowning, mark the top-level dir as "busy" by chowning it to the "busy"
+ * range. Should we be interrupted in the middle of our work, we'll see it owned by this user and will start
+ * chown()ing it again, unconditionally, as the busy UID is not a valid UID we'd everpick for ourselves. */
+
+ if ((st.st_uid & UID_BUSY_MASK) != UID_BUSY_BASE) {
+ if (fchown(fd,
+ UID_BUSY_BASE | (st.st_uid & ~UID_BUSY_MASK),
+ (gid_t) UID_BUSY_BASE | (st.st_gid & ~(gid_t) UID_BUSY_MASK)) < 0) {
+ r = -errno;
+ goto finish;
+ }
+ }
+
return recurse_fd(fd, donate_fd, &st, shift, true);
finish:
diff --git a/src/nspawn/nspawn-patch-uid.h b/src/nspawn/nspawn-patch-uid.h
index 55d0990016..ff6a7b7647 100644
--- a/src/nspawn/nspawn-patch-uid.h
+++ b/src/nspawn/nspawn-patch-uid.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index de72c37452..e946bf80b6 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -77,6 +77,7 @@
#include "mount-util.h"
#include "netlink-util.h"
#include "nspawn-cgroup.h"
+#include "nspawn-def.h"
#include "nspawn-expose-ports.h"
#include "nspawn-mount.h"
#include "nspawn-network.h"
@@ -106,12 +107,6 @@
#include "user-util.h"
#include "util.h"
-/* Note that devpts's gid= parameter parses GIDs as signed values, hence we stay away from the upper half of the 32bit
- * UID range here. We leave a bit of room at the lower end and a lot of room at the upper end, so that other subsystems
- * may have their own allocation ranges too. */
-#define UID_SHIFT_PICK_MIN ((uid_t) UINT32_C(0x00080000))
-#define UID_SHIFT_PICK_MAX ((uid_t) UINT32_C(0x6FFF0000))
-
/* nspawn is listening on the socket at the path in the constant nspawn_notify_socket_path
* nspawn_notify_socket_path is relative to the container
* the init process in the container pid can send messages to nspawn following the sd_notify(3) protocol */
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index a5871a25b0..e8fe2b3ff1 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -315,6 +315,32 @@ static void test_dot_or_dot_dot(void) {
assert_se(!dot_or_dot_dot("..foo"));
}
+static void test_access_fd(void) {
+ _cleanup_(rmdir_and_freep) char *p = NULL;
+ _cleanup_close_ int fd = -1;
+
+ assert_se(mkdtemp_malloc("/tmp/access-fd.XXXXXX", &p) >= 0);
+
+ fd = open(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+ assert_se(fd >= 0);
+
+ assert_se(access_fd(fd, R_OK) >= 0);
+ assert_se(access_fd(fd, F_OK) >= 0);
+ assert_se(access_fd(fd, W_OK) >= 0);
+
+ assert_se(fchmod(fd, 0000) >= 0);
+
+ assert_se(access_fd(fd, F_OK) >= 0);
+
+ if (geteuid() == 0) {
+ assert_se(access_fd(fd, R_OK) >= 0);
+ assert_se(access_fd(fd, W_OK) >= 0);
+ } else {
+ assert_se(access_fd(fd, R_OK) == -EACCES);
+ assert_se(access_fd(fd, W_OK) == -EACCES);
+ }
+}
+
int main(int argc, char *argv[]) {
test_unlink_noerrno();
test_get_files_in_directory();
@@ -322,6 +348,7 @@ int main(int argc, char *argv[]) {
test_var_tmp();
test_chase_symlinks();
test_dot_or_dot_dot();
+ test_access_fd();
return 0;
}