1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-18 10:04:04 +03:00

dissect: add new --shift command

This commit is contained in:
Lennart Poettering 2024-11-12 09:44:48 +01:00
parent f979247bb9
commit 7149009417
2 changed files with 72 additions and 2 deletions

View File

@ -62,6 +62,9 @@
<cmdsynopsis>
<command>systemd-dissect</command> <arg choice="opt" rep="repeat">OPTIONS</arg> <arg>--validate</arg> <arg choice="plain"><replaceable>IMAGE</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-dissect</command> <arg choice="opt" rep="repeat">OPTIONS</arg> <arg>--shift</arg> <arg choice="plain"><replaceable>IMAGE</replaceable></arg> <arg choice="plain"><replaceable>UIDBASE</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@ -350,6 +353,27 @@
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--shift</option></term>
<listitem><para>Recursively iterates through all inodes of the specified image and shifts the UIDs
and GIDs the inodes are owned by into the specified UID range. Takes an image path and a UID base as
parameter. The UID base can be specified numerically (in which case it must be a multiple of 65536,
and either 0 or within the container or foreign UID range, as per <ulink
url="https://systemd.io/UIDS-GIDS/">Users, Groups, UIDs and GIDs on systemd Systems</ulink>), or as
the symbolic identifier <literal>foreign</literal> which is shorthand to the foreign UID base. This
command is useful for preparing directory container images for unprivileged use. Note that this
command is intended for images that use the 16bit UIDs/GIDs range only, and it always ignores the
upper 16bit of the current UID/GID ownership, combining the lower 16 bit with the target UID
base.</para>
<para>Use <command>systemd-dissect --shift /some/container/tree foreign</command> to shift a
container image into the foreign UID range, or <command>systemd-dissect --shift /some/container/tree
0</command> to shift it to host UID range.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>

View File

@ -45,6 +45,7 @@
#include "process-util.h"
#include "recurse-dir.h"
#include "sha256.h"
#include "shift-uid.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
@ -68,6 +69,7 @@ static enum {
ACTION_DISCOVER,
ACTION_VALIDATE,
ACTION_MAKE_ARCHIVE,
ACTION_SHIFT,
} arg_action = ACTION_DISSECT;
static char *arg_image = NULL;
static char *arg_root = NULL;
@ -96,6 +98,7 @@ static ImagePolicy *arg_image_policy = NULL;
static bool arg_mtree_hash = true;
static bool arg_via_service = false;
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
static uid_t arg_uid_base = UID_INVALID;
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
@ -128,6 +131,7 @@ static int help(void) {
"%1$s [OPTIONS...] --make-archive IMAGE [TARGET]\n"
"%1$s [OPTIONS...] --discover\n"
"%1$s [OPTIONS...] --validate IMAGE\n"
"%1$s [OPTIONS...] --shift IMAGE UIDBASE\n"
"\n%5$sDissect a Discoverable Disk Image (DDI).%6$s\n\n"
"%3$sOptions:%4$s\n"
" --no-pager Do not pipe output into a pager\n"
@ -172,6 +176,7 @@ static int help(void) {
" --make-archive Convert the DDI to an archive file\n"
" --discover Discover DDIs in well known directories\n"
" --validate Validate image and image policy\n"
" --shift Shift UID range to selected base\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@ -277,6 +282,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VALIDATE,
ARG_MTREE_HASH,
ARG_MAKE_ARCHIVE,
ARG_SHIFT,
ARG_SYSTEM,
ARG_USER,
};
@ -312,6 +318,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "validate", no_argument, NULL, ARG_VALIDATE },
{ "mtree-hash", required_argument, NULL, ARG_MTREE_HASH },
{ "make-archive", no_argument, NULL, ARG_MAKE_ARCHIVE },
{ "shift", no_argument, NULL, ARG_SHIFT },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "user", no_argument, NULL, ARG_USER },
{}
@ -546,6 +553,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_MAKE_ARCHIVE;
break;
case ARG_SHIFT:
arg_action = ACTION_SHIFT;
break;
case ARG_SYSTEM:
system_scope_requested = true;
break;
@ -723,6 +734,33 @@ static int parse_argv(int argc, char *argv[]) {
arg_flags &= ~(DISSECT_IMAGE_PIN_PARTITION_DEVICES|DISSECT_IMAGE_ADD_PARTITION_DEVICES);
break;
case ACTION_SHIFT:
if (optind + 2 != argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected an image path and a UID base as only argument.");
r = parse_image_path_argument(argv[optind], &arg_root, &arg_image);
if (r < 0)
return r;
if (streq(argv[optind + 1], "foreign"))
arg_uid_base = FOREIGN_UID_BASE;
else {
r = parse_uid(argv[optind + 1], &arg_uid_base);
if (r < 0)
return log_error_errno(r, "Failed to parse UID base: %s", argv[optind + 1]);
if ((arg_uid_base & 0xFFFF) != 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected UID base not a multiple of 64K: " UID_FMT, arg_uid_base);
if (arg_uid_base != 0 &&
!uid_is_container(arg_uid_base) &&
!uid_is_foreign(arg_uid_base))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected UID range is not in the container range, nor the foreign one, refusing.");
}
arg_flags |= DISSECT_IMAGE_REQUIRE_ROOT;
break;
default:
assert_not_reached();
}
@ -1436,7 +1474,7 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD
const char *root;
int r;
assert(IN_SET(arg_action, ACTION_LIST, ACTION_MTREE, ACTION_COPY_FROM, ACTION_COPY_TO, ACTION_MAKE_ARCHIVE));
assert(IN_SET(arg_action, ACTION_LIST, ACTION_MTREE, ACTION_COPY_FROM, ACTION_COPY_TO, ACTION_MAKE_ARCHIVE, ACTION_SHIFT));
if (arg_image) {
assert(m);
@ -1691,6 +1729,13 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD
#endif
}
case ACTION_SHIFT:
r = path_patch_uid(root, arg_uid_base, 0x10000);
if (r < 0)
return log_error_errno(r, "Failed to shift UID base: %m");
return 0;
default:
assert_not_reached();
}
@ -2100,7 +2145,7 @@ static int run(int argc, char *argv[]) {
else
r = loop_device_make_by_path(arg_image, open_flags, /* sector_size= */ UINT32_MAX, loop_flags, LOCK_SH, &d);
if (r < 0) {
if (!ERRNO_IS_PRIVILEGE(r) || !IN_SET(arg_action, ACTION_DISSECT, ACTION_LIST, ACTION_MTREE, ACTION_COPY_FROM, ACTION_COPY_TO))
if (!ERRNO_IS_PRIVILEGE(r) || !IN_SET(arg_action, ACTION_DISSECT, ACTION_LIST, ACTION_MTREE, ACTION_COPY_FROM, ACTION_COPY_TO, ACTION_SHIFT))
return log_error_errno(r, "Failed to set up loopback device for %s: %m", arg_image);
log_debug_errno(r, "Lacking permissions to set up loopback block device for %s, using service: %m", arg_image);
@ -2185,6 +2230,7 @@ static int run(int argc, char *argv[]) {
case ACTION_COPY_FROM:
case ACTION_COPY_TO:
case ACTION_MAKE_ARCHIVE:
case ACTION_SHIFT:
return action_list_or_mtree_or_copy_or_make_archive(m, d, userns_fd);
case ACTION_WITH: