diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index defca12d1b..f182919673 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -479,7 +479,8 @@
or the host. See:
os-release5.
-
+ Note that usage from user units requires overlayfs support in unprivileged user namespaces,
+ which was first introduced in kernel v5.11.
diff --git a/src/core/execute.c b/src/core/execute.c
index 027e5473b6..94cd198b4d 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -3438,7 +3438,8 @@ static int apply_mount_namespace(
_cleanup_strv_free_ char **empty_directories = NULL, **symlinks = NULL;
const char *tmp_dir = NULL, *var_tmp_dir = NULL;
const char *root_dir = NULL, *root_image = NULL;
- _cleanup_free_ char *creds_path = NULL, *incoming_dir = NULL, *propagate_dir = NULL;
+ _cleanup_free_ char *creds_path = NULL, *incoming_dir = NULL, *propagate_dir = NULL,
+ *extension_dir = NULL;
NamespaceInfo ns_info;
bool needs_sandboxing;
BindMount *bind_mounts = NULL;
@@ -3537,7 +3538,17 @@ static int apply_mount_namespace(
r = -ENOMEM;
goto finalize;
}
- }
+
+ extension_dir = strdup("/run/systemd/unit-extensions");
+ if (!extension_dir) {
+ r = -ENOMEM;
+ goto finalize;
+ }
+ } else
+ if (asprintf(&extension_dir, "/run/user/" UID_FMT "/systemd/unit-extensions", geteuid()) < 0) {
+ r = -ENOMEM;
+ goto finalize;
+ }
r = setup_namespace(root_dir, root_image, context->root_image_options,
&ns_info, context->read_write_paths,
@@ -3566,6 +3577,7 @@ static int apply_mount_namespace(
context->extension_directories,
propagate_dir,
incoming_dir,
+ extension_dir,
root_dir || root_image ? params->notify_socket : NULL,
error_path);
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 77dd473a48..e6293882fe 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -422,12 +422,12 @@ static int append_extensions(
char **hierarchy, **extension_directory;
int r;
- assert(p);
- assert(extension_dir);
-
if (n == 0 && strv_isempty(extension_directories))
return 0;
+ assert(p);
+ assert(extension_dir);
+
/* Prepare a list of overlays, that will have as each element a string suitable for being
* passed as a lowerdir= parameter, so start with the hierarchy on the root.
* The overlays vector will have the same number of elements and will correspond to the
@@ -1999,6 +1999,7 @@ int setup_namespace(
char **extension_directories,
const char *propagate_dir,
const char *incoming_dir,
+ const char *extension_dir,
const char *notify_socket,
char **error_path) {
@@ -2009,7 +2010,7 @@ int setup_namespace(
_cleanup_strv_free_ char **hierarchies = NULL;
MountEntry *m = NULL, *mounts = NULL;
bool require_prefix = false, setup_propagate = false;
- const char *root, *extension_dir = "/run/systemd/unit-extensions";
+ const char *root;
DissectImageFlags dissect_image_flags =
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_REQUIRE_ROOT |
diff --git a/src/core/namespace.h b/src/core/namespace.h
index ae84d2b03b..3ef41d2c62 100644
--- a/src/core/namespace.h
+++ b/src/core/namespace.h
@@ -145,6 +145,7 @@ int setup_namespace(
char **extension_directories,
const char *propagate_dir,
const char *incoming_dir,
+ const char *extension_dir,
const char *notify_socket,
char **error_path);
diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c
index 8dea195745..37acc782eb 100644
--- a/src/test/test-namespace.c
+++ b/src/test/test-namespace.c
@@ -208,6 +208,7 @@ TEST(protect_kernel_logs) {
NULL,
NULL,
NULL,
+ NULL,
NULL);
assert_se(r == 0);
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index cd455a3a5b..7eb29d109d 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -109,6 +109,7 @@ int main(int argc, char *argv[]) {
NULL,
NULL,
NULL,
+ NULL,
NULL);
if (r < 0) {
log_error_errno(r, "Failed to set up namespace: %m");
diff --git a/test/TEST-43-PRIVATEUSER-UNPRIV/test.sh b/test/TEST-43-PRIVATEUSER-UNPRIV/test.sh
index dafcdb58fc..6e1a91a649 100755
--- a/test/TEST-43-PRIVATEUSER-UNPRIV/test.sh
+++ b/test/TEST-43-PRIVATEUSER-UNPRIV/test.sh
@@ -13,6 +13,8 @@ command -v mksquashfs >/dev/null 2>&1 || exit 0
test_append_files() {
(
+ instmods overlay =overlayfs
+ generate_module_dependencies
inst_binary unsquashfs
install_verity_minimal
)
diff --git a/test/units/testsuite-43.sh b/test/units/testsuite-43.sh
index cda1fe1fda..8b755b1a0f 100755
--- a/test/units/testsuite-43.sh
+++ b/test/units/testsuite-43.sh
@@ -84,6 +84,18 @@ mount --bind /tmp/img /tmp/img_bind
runas testuser systemd-run --wait --user --unit=test-root-dir-bind \
-p PrivateUsers=yes -p RootDirectory=/tmp/img_bind \
grep MARKER=1 /etc/os-release
+
+# Unprivileged overlayfs was added to Linux 5.11, so try to detect it first
+mkdir -p /tmp/a /tmp/b /tmp/c
+if unshare --mount --user --map-root-user mount -t overlay overlay /tmp/c -o lowerdir=/tmp/a:/tmp/b; then
+ unsquashfs -no-xattrs -d /tmp/app2 /usr/share/app1.raw
+ runas testuser systemd-run --wait --user --unit=test-extension-dir \
+ -p PrivateUsers=yes -p ExtensionDirectories=/tmp/app2 \
+ -p TemporaryFileSystem=/run -p RootDirectory=/tmp/img \
+ -p MountAPIVFS=yes \
+ grep PORTABLE_PREFIXES=app1 /usr/lib/extension-release.d/extension-release.app2
+fi
+
umount /tmp/img_bind
systemd-analyze log-level info