1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-08 21:17:47 +03:00

Merge pull request #26153 from DaanDeMeyer/repart-remove-userns

mkfs-util: Remove user namespace owner => root mapping
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2023-01-23 21:46:55 +01:00 committed by GitHub
commit d4fc020996
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 109 deletions

View File

@ -425,6 +425,12 @@
target filesystem (e.g symlinks, fifos, sockets and devices on vfat). When an unsupported file type
is encountered, repart will skip copying this file and write a log message about it.</para>
<para>Note that <command>systemd-repart</command> does not change the UIDs/GIDs of any copied files
and directories. When running <command>systemd-repart</command> as an unprivileged user to build an
image of files and directories owned by the same user, you can run <command>systemd-repart</command>
in a user namespace with the current user mapped to the root user to make sure the files and
directories in the image are owned by the root user.</para>
<para>This option cannot be combined with <varname>CopyBlocks=</varname>.</para>
<para>When

View File

@ -3744,13 +3744,7 @@ static int context_copy_blocks(Context *context) {
return 0;
}
static int do_copy_files(
Partition *p,
const char *root,
uid_t override_uid,
gid_t override_gid,
const Set *denylist) {
static int do_copy_files(Partition *p, const char *root, const Set *denylist) {
int r;
assert(p);
@ -3799,14 +3793,14 @@ static int do_copy_files(
r = copy_tree_at(
sfd, ".",
pfd, fn,
override_uid, override_gid,
UID_INVALID, GID_INVALID,
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN,
denylist);
} else
r = copy_tree_at(
sfd, ".",
tfd, ".",
override_uid, override_gid,
UID_INVALID, GID_INVALID,
COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN,
denylist);
if (r < 0)
@ -3844,9 +3838,6 @@ static int do_copy_files(
if (r < 0)
return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target);
if (fchown(tfd, override_uid, override_gid) < 0)
return log_error_errno(r, "Failed to change ownership of %s", *target);
(void) copy_xattr(sfd, tfd, COPY_ALL_XATTRS);
(void) copy_access(sfd, tfd);
(void) copy_times(sfd, tfd, 0);
@ -3856,7 +3847,7 @@ static int do_copy_files(
return 0;
}
static int do_make_directories(Partition *p, uid_t override_uid, gid_t override_gid, const char *root) {
static int do_make_directories(Partition *p, const char *root) {
int r;
assert(p);
@ -3864,7 +3855,7 @@ static int do_make_directories(Partition *p, uid_t override_uid, gid_t override_
STRV_FOREACH(d, p->make_directories) {
r = mkdir_p_root(root, *d, override_uid, override_gid, 0755);
r = mkdir_p_root(root, *d, UID_INVALID, GID_INVALID, 0755);
if (r < 0)
return log_error_errno(r, "Failed to create directory '%s' in file system: %m", *d);
}
@ -3891,11 +3882,11 @@ static int partition_populate_directory(Partition *p, const Set *denylist, char
if (fchmod(rfd, 0755) < 0)
return log_error_errno(errno, "Failed to change mode of temporary directory: %m");
r = do_copy_files(p, root, getuid(), getgid(), denylist);
r = do_copy_files(p, root, denylist);
if (r < 0)
return r;
r = do_make_directories(p, getuid(), getgid(), root);
r = do_make_directories(p, root);
if (r < 0)
return r;
@ -3931,10 +3922,10 @@ static int partition_populate_filesystem(Partition *p, const char *node, const S
if (mount_nofollow_verbose(LOG_ERR, node, fs, p->format, MS_NOATIME|MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL) < 0)
_exit(EXIT_FAILURE);
if (do_copy_files(p, fs, 0, 0, denylist) < 0)
if (do_copy_files(p, fs, denylist) < 0)
_exit(EXIT_FAILURE);
if (do_make_directories(p, 0, 0, fs) < 0)
if (do_make_directories(p, fs) < 0)
_exit(EXIT_FAILURE);
r = syncfs_path(AT_FDCWD, fs);

View File

@ -98,41 +98,11 @@ static int mangle_fat_label(const char *s, char **ret) {
return 0;
}
static int setup_userns(uid_t uid, gid_t gid) {
int r;
/* mkfs programs tend to keep ownership intact when bootstrapping themselves from a root directory.
* However, we'd like for the files to be owned by root instead, so we fork off a user namespace and
* inside of it, map the uid/gid of the root directory to root in the user namespace. mkfs programs
* will pick up on this and the files will be owned by root in the generated filesystem. */
r = write_string_filef("/proc/self/uid_map", WRITE_STRING_FILE_DISABLE_BUFFER,
UID_FMT " " UID_FMT " " UID_FMT, 0u, uid, 1u);
if (r < 0)
return log_error_errno(r,
"Failed to write mapping for "UID_FMT" to /proc/self/uid_map: %m",
uid);
r = write_string_file("/proc/self/setgroups", "deny", WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_error_errno(r, "Failed to write 'deny' to /proc/self/setgroups: %m");
r = write_string_filef("/proc/self/gid_map", WRITE_STRING_FILE_DISABLE_BUFFER,
GID_FMT " " GID_FMT " " GID_FMT, 0u, gid, 1u);
if (r < 0)
return log_error_errno(r,
"Failed to write mapping for "GID_FMT" to /proc/self/gid_map: %m",
gid);
return 0;
}
static int do_mcopy(const char *node, const char *root) {
_cleanup_free_ char *mcopy = NULL;
_cleanup_strv_free_ char **argv = NULL;
_cleanup_close_ int rfd = -EBADF;
_cleanup_free_ DirectoryEntries *de = NULL;
struct stat st;
int r;
assert(node);
@ -182,17 +152,10 @@ static int do_mcopy(const char *node, const char *root) {
if (strv_extend(&argv, "::") < 0)
return log_oom();
if (fstat(rfd, &st) < 0)
return log_error_errno(errno, "Failed to stat '%s': %m", root);
r = safe_fork("(mcopy)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR|FORK_NEW_USERNS|FORK_CLOSE_ALL_FDS, NULL);
r = safe_fork("(mcopy)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR|FORK_CLOSE_ALL_FDS, NULL);
if (r < 0)
return r;
if (r == 0) {
r = setup_userns(st.st_uid, st.st_gid);
if (r < 0)
_exit(EXIT_FAILURE);
/* Avoid failures caused by mismatch in expectations between mkfs.vfat and mcopy by disabling
* the stricter mcopy checks using MTOOLS_SKIP_CHECK. */
execve(mcopy, argv, STRV_MAKE("MTOOLS_SKIP_CHECK=1"));
@ -308,7 +271,6 @@ int make_filesystem(
_cleanup_strv_free_ char **argv = NULL;
_cleanup_(unlink_and_freep) char *protofile = NULL;
char vol_id[CONST_MAX(SD_ID128_UUID_STRING_MAX, 8U + 1U)] = {};
struct stat st;
int r;
assert(node);
@ -527,21 +489,12 @@ int make_filesystem(
if (extra_mkfs_args && strv_extend_strv(&argv, extra_mkfs_args, false) < 0)
return log_oom();
if (root && stat(root, &st) < 0)
return log_error_errno(errno, "Failed to stat %s: %m", root);
r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR|FORK_CLOSE_ALL_FDS|(root ? FORK_NEW_USERNS : 0), NULL);
r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR|FORK_CLOSE_ALL_FDS, NULL);
if (r < 0)
return r;
if (r == 0) {
/* Child */
if (root) {
r = setup_userns(st.st_uid, st.st_gid);
if (r < 0)
_exit(EXIT_FAILURE);
}
execvp(mkfs, argv);
log_error_errno(errno, "Failed to execute %s: %m", mkfs);

View File

@ -119,21 +119,21 @@ last-lba: 2097118"
# 2. Testing with root, root2, home, and swap
cat >"$defs/root.conf" <<EOF
runas testuser tee "$defs/root.conf" <<EOF
[Partition]
Type=root
EOF
ln -s root.conf "$defs/root2.conf"
cat >"$defs/home.conf" <<EOF
runas testuser tee "$defs/home.conf" <<EOF
[Partition]
Type=home
Label=home-first
Label=home-always-too-long-xxxxxxxxxxxxxx-%v
EOF
cat >"$defs/swap.conf" <<EOF
runas testuser tee "$defs/swap.conf" <<EOF
[Partition]
Type=swap
SizeMaxBytes=64M
@ -194,13 +194,13 @@ $imgs/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5
# 3. Testing with root, root2, home, swap, and another partition
cat >"$defs/swap.conf" <<EOF
runas testuser tee "$defs/swap.conf" <<EOF
[Partition]
Type=swap
SizeMaxBytes=64M
EOF
cat >"$defs/extra.conf" <<EOF
runas testuser tee "$defs/extra.conf" <<EOF
[Partition]
Type=linux-generic
Label=custom_label
@ -255,7 +255,7 @@ $imgs/zzz5 : start= 1908696, size= 2285568, type=0FC63DAF-8483-4772-8E79
dd if=/dev/urandom of="$imgs/block-copy" bs=4096 count=10240
cat >"$defs/extra2.conf" <<EOF
runas testuser tee "$defs/extra2.conf" <<EOF
[Partition]
Type=linux-generic
Label=block-copy
@ -288,7 +288,7 @@ $imgs/zzz6 : start= 4194264, size= 2097152, type=0FC63DAF-8483-4772-8E79
# 6. Testing Format=/Encrypt=/CopyFiles=
cat >"$defs/extra3.conf" <<EOF
runas testuser tee "$defs/extra3.conf" <<EOF
[Partition]
Type=linux-generic
Label=luks-format-copy
@ -350,21 +350,21 @@ test_dropin() {
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
cat >"$defs/root.conf" <<EOF
runas testuser tee "$defs/root.conf" <<EOF
[Partition]
Type=swap
SizeMaxBytes=64M
UUID=837c3d67-21b3-478e-be82-7e7f83bf96d3
EOF
mkdir -p "$defs/root.conf.d"
cat >"$defs/root.conf.d/override1.conf" <<EOF
runas testuser mkdir -p "$defs/root.conf.d"
runas testuser tee "$defs/root.conf.d/override1.conf" <<EOF
[Partition]
Label=label1
SizeMaxBytes=32M
EOF
cat >"$defs/root.conf.d/override2.conf" <<EOF
runas testuser tee "$defs/root.conf.d/override2.conf" <<EOF
[Partition]
Label=label2
EOF
@ -408,9 +408,9 @@ test_multiple_definitions() {
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
mkdir -p "$defs/1"
runas testuser mkdir -p "$defs/1"
cat >"$defs/1/root1.conf" <<EOF
runas testuser tee "$defs/1/root1.conf" <<EOF
[Partition]
Type=swap
SizeMaxBytes=32M
@ -418,9 +418,9 @@ UUID=7b93d1f2-595d-4ce3-b0b9-837fbd9e63b0
Label=label1
EOF
mkdir -p "$defs/2"
runas testuser mkdir -p "$defs/2"
cat >"$defs/2/root2.conf" <<EOF
runas testuser tee "$defs/2/root2.conf" <<EOF
[Partition]
Type=swap
SizeMaxBytes=32M
@ -481,14 +481,14 @@ test_copy_blocks() {
# First, create a disk image and verify its in order
cat >"$defs/esp.conf" <<EOF
runas testuser tee "$defs/esp.conf" <<EOF
[Partition]
Type=esp
SizeMinBytes=10M
Format=vfat
EOF
cat >"$defs/usr.conf" <<EOF
runas testuser tee "$defs/usr.conf" <<EOF
[Partition]
Type=usr-${architecture}
SizeMinBytes=10M
@ -496,7 +496,7 @@ Format=ext4
ReadOnly=yes
EOF
cat >"$defs/root.conf" <<EOF
runas testuser tee "$defs/root.conf" <<EOF
[Partition]
Type=root-${architecture}
SizeMinBytes=10M
@ -523,20 +523,20 @@ EOF
# Then, create another image with CopyBlocks=auto
cat >"$defs/esp.conf" <<EOF
runas testuser tee "$defs/esp.conf" <<EOF
[Partition]
Type=esp
CopyBlocks=auto
EOF
cat >"$defs/usr.conf" <<EOF
runas testuser tee "$defs/usr.conf" <<EOF
[Partition]
Type=usr-${architecture}
ReadOnly=yes
CopyBlocks=auto
EOF
cat >"$defs/root.conf" <<EOF
runas testuser tee "$defs/root.conf" <<EOF
[Partition]
Type=root-${architecture}
CopyBlocks=auto
@ -563,7 +563,7 @@ test_unaligned_partition() {
# Operate on an image with unaligned partition.
cat >"$defs/root.conf" <<EOF
runas testuser tee "$defs/root.conf" <<EOF
[Partition]
Type=root-${architecture}
EOF
@ -598,7 +598,7 @@ test_issue_21817() {
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
cat >"$defs/test.conf" <<EOF
runas testuser tee "$defs/test.conf" <<EOF
[Partition]
Type=root
EOF
@ -634,14 +634,14 @@ test_issue_24553() {
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
cat >"$defs/root.conf" <<EOF
runas testuser tee "$defs/root.conf" <<EOF
[Partition]
Type=root
SizeMinBytes=10G
SizeMaxBytes=120G
EOF
cat >"$imgs/partscript" <<EOF
runas testuser tee "$imgs/partscript" <<EOF
label: gpt
label-id: C9FFE979-A415-C449-B729-78C7AA664B10
unit: sectors
@ -679,7 +679,7 @@ EOF
assert_in "$imgs/zzz2 : start= 524328, size= 24641456, type=${root_guid}, uuid=${root_uuid}, name=\"root-${architecture}\"" "$output"
# 3. Multiple partitions with Priority= (small disk)
cat >"$defs/root.conf" <<EOF
runas testuser tee "$defs/root.conf" <<EOF
[Partition]
Type=root
SizeMinBytes=10G
@ -687,7 +687,7 @@ SizeMaxBytes=120G
Priority=100
EOF
cat >"$defs/usr.conf" <<EOF
runas testuser tee "$defs/usr.conf" <<EOF
[Partition]
Type=usr
SizeMinBytes=10M
@ -734,7 +734,7 @@ test_zero_uuid() {
# Test image with zero UUID.
cat >"$defs/root.conf" <<EOF
runas testuser tee "$defs/root.conf" <<EOF
[Partition]
Type=root-${architecture}
UUID=null
@ -760,7 +760,7 @@ test_verity() {
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
cat >"$defs/verity-data.conf" <<EOF
runas testuser tee "$defs/verity-data.conf" <<EOF
[Partition]
Type=root-${architecture}
CopyFiles=${defs}
@ -768,14 +768,14 @@ Verity=data
VerityMatchKey=root
EOF
cat >"$defs/verity-hash.conf" <<EOF
runas testuser tee "$defs/verity-hash.conf" <<EOF
[Partition]
Type=root-${architecture}-verity
Verity=hash
VerityMatchKey=root
EOF
cat >"$defs/verity-sig.conf" <<EOF
runas testuser tee "$defs/verity-sig.conf" <<EOF
[Partition]
Type=root-${architecture}-verity-sig
Verity=signature
@ -783,7 +783,7 @@ VerityMatchKey=root
EOF
# Unfortunately OpenSSL insists on reading some config file, hence provide one with mostly placeholder contents
cat >> "$defs/verity.openssl.cnf" <<EOF
runas testuser tee > "$defs/verity.openssl.cnf" <<EOF
[ req ]
prompt = no
distinguished_name = req_distinguished_name
@ -843,17 +843,17 @@ test_issue_24786() {
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs' '$root'" RETURN
touch "$root/abc"
mkdir "$root/usr"
touch "$root/usr/def"
runas testuser touch "$root/abc"
runas testuser mkdir "$root/usr"
runas testuser touch "$root/usr/def"
cat >"$defs/00-root.conf" <<EOF
runas testuser tee "$defs/00-root.conf" <<EOF
[Partition]
Type=root-${architecture}
CopyFiles=/
EOF
cat >"$defs/10-usr.conf" <<EOF
runas testuser tee "$defs/10-usr.conf" <<EOF
[Partition]
Type=usr-${architecture}
CopyFiles=/usr:/
@ -906,7 +906,7 @@ test_minimize() {
continue
fi
cat >"$defs/root-$format.conf" <<EOF
tee "$defs/root-$format.conf" <<EOF
[Partition]
Type=root-${architecture}
Format=${format}
@ -916,7 +916,7 @@ EOF
done
if ! command -v mksquashfs >/dev/null; then
cat >"$defs/root-squashfs.conf" <<EOF
tee "$defs/root-squashfs.conf" <<EOF
[Partition]
Type=root-${architecture}
Format=squashfs
@ -955,19 +955,19 @@ test_sector() {
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
cat > "$defs/a.conf" <<EOF
tee "$defs/a.conf" <<EOF
[Partition]
Type=root
SizeMaxBytes=15M
SizeMinBytes=15M
EOF
cat > "$defs/b.conf" <<EOF
tee "$defs/b.conf" <<EOF
[Partition]
Type=linux-generic
Weight=250
EOF
cat > "$defs/c.conf" <<EOF
tee "$defs/c.conf" <<EOF
[Partition]
Type=linux-generic
Weight=750