Compare commits
7 Commits
990307c3da
...
44aaddad06
Author | SHA1 | Date |
---|---|---|
Steve Dodd | 44aaddad06 | |
Zbigniew Jędrzejewski-Szmek | 3fb01017ee | |
Aurelien Jarno | f9252236c8 | |
Luca Boccassi | 427353f668 | |
Luca Boccassi | 9ece644435 | |
Luca Boccassi | bc8d56d305 | |
Luca Boccassi | c20acbb2bd |
|
@ -90,6 +90,10 @@ systemctl:
|
||||||
|
|
||||||
* `$SYSTEMCTL_SKIP_SYSV=1` — if set, do not call out to SysV compatibility hooks.
|
* `$SYSTEMCTL_SKIP_SYSV=1` — if set, do not call out to SysV compatibility hooks.
|
||||||
|
|
||||||
|
* `$SYSTEMD_LOG_SECCOMP=1` — if set, system calls blocked by seccomp filtering,
|
||||||
|
for example in systemd-nspawn, will be logged to the audit log, if the current
|
||||||
|
kernel version supports this.
|
||||||
|
|
||||||
systemd-nspawn:
|
systemd-nspawn:
|
||||||
|
|
||||||
* `$SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=1` — if set, force nspawn into unified
|
* `$SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=1` — if set, force nspawn into unified
|
||||||
|
|
|
@ -149,11 +149,53 @@
|
||||||
<term><varname>RootImageOptions=</varname></term>
|
<term><varname>RootImageOptions=</varname></term>
|
||||||
|
|
||||||
<listitem><para>Takes a comma-separated list of mount options that will be used on disk images specified by
|
<listitem><para>Takes a comma-separated list of mount options that will be used on disk images specified by
|
||||||
<varname>RootImage=</varname>. Optionally a partition number can be prefixed, followed by colon, in
|
<varname>RootImage=</varname>. Optionally a partition name can be prefixed, followed by colon, in
|
||||||
case the image has multiple partitions, otherwise partition number 0 is implied.
|
case the image has multiple partitions, otherwise partition name <literal>root</literal> is implied.
|
||||||
Options for multiple partitions can be specified in a single line with space separators. Assigning an empty
|
Options for multiple partitions can be specified in a single line with space separators. Assigning an empty
|
||||||
string removes previous assignments. For a list of valid mount options, please refer to
|
string removes previous assignments. Duplicated options are ignored. For a list of valid mount options, please
|
||||||
<citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
refer to <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||||
|
|
||||||
|
<para>Valid partition names follow the <ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable
|
||||||
|
Partitions Specification</ulink>.</para>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<title>Accepted partition names</title>
|
||||||
|
|
||||||
|
<tgroup cols='1'>
|
||||||
|
<colspec colname='partition' />
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Partition Name</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>root</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>root-secondary</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>home</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>srv</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>esp</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>xbootldr</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>tmp</entry>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<entry>var</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</table>
|
||||||
|
|
||||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -268,13 +310,19 @@
|
||||||
system hierarchy from a block device node or loopback file, but the destination directory can be
|
system hierarchy from a block device node or loopback file, but the destination directory can be
|
||||||
specified as well as mount options. This option expects a whitespace separated list of mount
|
specified as well as mount options. This option expects a whitespace separated list of mount
|
||||||
definitions. Each definition consists of a colon-separated tuple of source path and destination
|
definitions. Each definition consists of a colon-separated tuple of source path and destination
|
||||||
directory. Each mount definition may be prefixed with <literal>-</literal>, in which case it will be
|
definitions, optionally followed by another colon and a list of mount options.</para>
|
||||||
|
|
||||||
|
<para>Mount options may be defined as a single comma-separated list of options, in which case they
|
||||||
|
will be implicitly applied to the root partition on the image, or a series of colon-separated tuples
|
||||||
|
of partition name and mount options. Valid partition names and mount options are the same as for
|
||||||
|
<varname>RootImageOptions=</varname> setting described above.</para>
|
||||||
|
|
||||||
|
<para>Each mount definition may be prefixed with <literal>-</literal>, in which case it will be
|
||||||
ignored when its source path does not exist. The source argument is a path to a block device node or
|
ignored when its source path does not exist. The source argument is a path to a block device node or
|
||||||
regular file. If source or destination contain a <literal>:</literal>, it needs to be escaped as
|
regular file. If source or destination contain a <literal>:</literal>, it needs to be escaped as
|
||||||
<literal>\:</literal>.
|
<literal>\:</literal>. The device node or file system image file needs to follow the same rules as
|
||||||
The device node or file system image file needs to follow the same rules as specified
|
specified for <varname>RootImage=</varname>. Any mounts created with this option are specific to the
|
||||||
for <varname>RootImage=</varname>. Any mounts created with this option are specific to the unit, and
|
unit, and are not visible in the host's mount table.</para>
|
||||||
are not visible in the host's mount table.</para>
|
|
||||||
|
|
||||||
<para>These settings may be used more than once, each usage appends to the unit's list of mount
|
<para>These settings may be used more than once, each usage appends to the unit's list of mount
|
||||||
paths. If the empty string is assigned, the entire list of mount paths defined prior to this is
|
paths. If the empty string is assigned, the entire list of mount paths defined prior to this is
|
||||||
|
|
|
@ -802,12 +802,14 @@ static int property_get_root_image_options(
|
||||||
assert(property);
|
assert(property);
|
||||||
assert(reply);
|
assert(reply);
|
||||||
|
|
||||||
r = sd_bus_message_open_container(reply, 'a', "(us)");
|
r = sd_bus_message_open_container(reply, 'a', "(ss)");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
LIST_FOREACH(mount_options, m, c->root_image_options) {
|
LIST_FOREACH(mount_options, m, c->root_image_options) {
|
||||||
r = sd_bus_message_append(reply, "(us)", m->partition_number, m->options);
|
r = sd_bus_message_append(reply, "(ss)",
|
||||||
|
partition_designator_to_string(m->partition_designator),
|
||||||
|
m->options);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -832,18 +834,39 @@ static int property_get_mount_images(
|
||||||
assert(property);
|
assert(property);
|
||||||
assert(reply);
|
assert(reply);
|
||||||
|
|
||||||
r = sd_bus_message_open_container(reply, 'a', "(ssb)");
|
r = sd_bus_message_open_container(reply, 'a', "(ssba(ss))");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
for (size_t i = 0; i < c->n_mount_images; i++) {
|
for (size_t i = 0; i < c->n_mount_images; i++) {
|
||||||
|
MountOptions *m;
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(reply, SD_BUS_TYPE_STRUCT, "ssba(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
r = sd_bus_message_append(
|
r = sd_bus_message_append(
|
||||||
reply, "(ssb)",
|
reply, "ssb",
|
||||||
c->mount_images[i].source,
|
c->mount_images[i].source,
|
||||||
c->mount_images[i].destination,
|
c->mount_images[i].destination,
|
||||||
c->mount_images[i].ignore_enoent);
|
c->mount_images[i].ignore_enoent);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
r = sd_bus_message_open_container(reply, 'a', "(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
LIST_FOREACH(mount_options, m, c->mount_images[i].mount_options) {
|
||||||
|
r = sd_bus_message_append(reply, "(ss)",
|
||||||
|
partition_designator_to_string(m->partition_designator),
|
||||||
|
m->options);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = sd_bus_message_close_container(reply);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
r = sd_bus_message_close_container(reply);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sd_bus_message_close_container(reply);
|
return sd_bus_message_close_container(reply);
|
||||||
|
@ -891,13 +914,13 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||||
SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootImageOptions", "a(us)", property_get_root_image_options, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootImageOptions", "a(ss)", property_get_root_image_options, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootHash", "ay", property_get_root_hash, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootHash", "ay", property_get_root_hash, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootHashPath", "s", NULL, offsetof(ExecContext, root_hash_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootHashPath", "s", NULL, offsetof(ExecContext, root_hash_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootHashSignature", "ay", property_get_root_hash_sig, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootHashSignature", "ay", property_get_root_hash_sig, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootHashSignaturePath", "s", NULL, offsetof(ExecContext, root_hash_sig_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootHashSignaturePath", "s", NULL, offsetof(ExecContext, root_hash_sig_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("MountImages", "a(ssb)", property_get_mount_images, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("MountImages", "a(ssba(ss))", property_get_mount_images, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
@ -1338,6 +1361,74 @@ static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(capability, "t", uint64_t, uint6
|
||||||
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(namespace_flag, "t", uint64_t, unsigned long, "%" PRIu64, namespace_flags_to_string);
|
static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(namespace_flag, "t", uint64_t, unsigned long, "%" PRIu64, namespace_flags_to_string);
|
||||||
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(mount_flags, "t", uint64_t, unsigned long, "%" PRIu64, mount_propagation_flags_to_string_with_check);
|
static BUS_DEFINE_SET_TRANSIENT_TO_STRING(mount_flags, "t", uint64_t, unsigned long, "%" PRIu64, mount_propagation_flags_to_string_with_check);
|
||||||
|
|
||||||
|
/* ret_format_str is an accumulator, so if it has any pre-existing content, new options will be appended to it */
|
||||||
|
static int read_mount_options(sd_bus_message *message, sd_bus_error *error, MountOptions **ret_options, char **ret_format_str, const char *separator) {
|
||||||
|
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
||||||
|
_cleanup_free_ char *format_str = NULL;
|
||||||
|
const char *mount_options, *partition;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(message);
|
||||||
|
assert(ret_options);
|
||||||
|
assert(ret_format_str);
|
||||||
|
assert(separator);
|
||||||
|
|
||||||
|
r = sd_bus_message_enter_container(message, 'a', "(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) {
|
||||||
|
_cleanup_free_ char *previous = NULL, *escaped = NULL;
|
||||||
|
_cleanup_free_ MountOptions *o = NULL;
|
||||||
|
int partition_designator;
|
||||||
|
|
||||||
|
if (chars_intersect(mount_options, WHITESPACE))
|
||||||
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
|
"Invalid mount options string, contains whitespace character(s): %s", mount_options);
|
||||||
|
|
||||||
|
partition_designator = partition_designator_from_string(partition);
|
||||||
|
if (partition_designator < 0)
|
||||||
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid partition name %s", partition);
|
||||||
|
|
||||||
|
/* Need to store them in the unit with the escapes, so that they can be parsed again */
|
||||||
|
escaped = shell_escape(mount_options, ":");
|
||||||
|
if (!escaped)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
previous = TAKE_PTR(format_str);
|
||||||
|
format_str = strjoin(previous, previous ? separator : "", partition, ":", escaped);
|
||||||
|
if (!format_str)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
o = new(MountOptions, 1);
|
||||||
|
if (!o)
|
||||||
|
return -ENOMEM;
|
||||||
|
*o = (MountOptions) {
|
||||||
|
.partition_designator = partition_designator,
|
||||||
|
.options = strdup(mount_options),
|
||||||
|
};
|
||||||
|
if (!o->options)
|
||||||
|
return -ENOMEM;
|
||||||
|
LIST_APPEND(mount_options, options, TAKE_PTR(o));
|
||||||
|
}
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_exit_container(message);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!LIST_IS_EMPTY(options)) {
|
||||||
|
char *final = strjoin(*ret_format_str, !isempty(*ret_format_str) ? separator : "", format_str);
|
||||||
|
if (!final)
|
||||||
|
return -ENOMEM;
|
||||||
|
free_and_replace(*ret_format_str, final);
|
||||||
|
LIST_JOIN(mount_options, *ret_options, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int bus_exec_context_set_transient_property(
|
int bus_exec_context_set_transient_property(
|
||||||
Unit *u,
|
Unit *u,
|
||||||
ExecContext *c,
|
ExecContext *c,
|
||||||
|
@ -1371,39 +1462,8 @@ int bus_exec_context_set_transient_property(
|
||||||
if (streq(name, "RootImageOptions")) {
|
if (streq(name, "RootImageOptions")) {
|
||||||
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
||||||
_cleanup_free_ char *format_str = NULL;
|
_cleanup_free_ char *format_str = NULL;
|
||||||
const char *mount_options;
|
|
||||||
unsigned partition_number;
|
|
||||||
|
|
||||||
r = sd_bus_message_enter_container(message, 'a', "(us)");
|
r = read_mount_options(message, error, &options, &format_str, " ");
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
while ((r = sd_bus_message_read(message, "(us)", &partition_number, &mount_options)) > 0) {
|
|
||||||
_cleanup_free_ char *previous = TAKE_PTR(format_str);
|
|
||||||
_cleanup_free_ MountOptions *o = NULL;
|
|
||||||
|
|
||||||
if (chars_intersect(mount_options, WHITESPACE))
|
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
|
||||||
"Invalid mount options string, contains whitespace character(s): %s", mount_options);
|
|
||||||
|
|
||||||
if (asprintf(&format_str, "%s%s%u:%s", strempty(previous), previous ? " " : "", partition_number, mount_options) < 0)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
o = new(MountOptions, 1);
|
|
||||||
if (!o)
|
|
||||||
return -ENOMEM;
|
|
||||||
*o = (MountOptions) {
|
|
||||||
.partition_number = partition_number,
|
|
||||||
.options = strdup(mount_options),
|
|
||||||
};
|
|
||||||
if (!o->options)
|
|
||||||
return -ENOMEM;
|
|
||||||
LIST_APPEND(mount_options, options, TAKE_PTR(o));
|
|
||||||
}
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_bus_message_exit_container(message);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -2938,13 +2998,23 @@ int bus_exec_context_set_transient_property(
|
||||||
char *source, *destination;
|
char *source, *destination;
|
||||||
int permissive;
|
int permissive;
|
||||||
|
|
||||||
r = sd_bus_message_enter_container(message, 'a', "(ssb)");
|
r = sd_bus_message_enter_container(message, 'a', "(ssba(ss))");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
while ((r = sd_bus_message_read(message, "(ssb)", &source, &destination, &permissive)) > 0) {
|
for (;;) {
|
||||||
|
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
||||||
|
_cleanup_free_ char *source_escaped = NULL, *destination_escaped = NULL;
|
||||||
char *tuple;
|
char *tuple;
|
||||||
|
|
||||||
|
r = sd_bus_message_enter_container(message, 'r', "ssba(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_read(message, "ssb", &source, &destination, &permissive);
|
||||||
|
if (r <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
if (!path_is_absolute(source))
|
if (!path_is_absolute(source))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not absolute.", source);
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not absolute.", source);
|
||||||
if (!path_is_normalized(source))
|
if (!path_is_normalized(source))
|
||||||
|
@ -2954,15 +3024,37 @@ int bus_exec_context_set_transient_property(
|
||||||
if (!path_is_normalized(destination))
|
if (!path_is_normalized(destination))
|
||||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is not normalized.", destination);
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path %s is not normalized.", destination);
|
||||||
|
|
||||||
tuple = strjoin(format_str, format_str ? " " : "", permissive ? "-" : "", source, ":", destination);
|
/* Need to store them in the unit with the escapes, so that they can be parsed again */
|
||||||
|
source_escaped = shell_escape(source, ":");
|
||||||
|
if (!source_escaped)
|
||||||
|
return -ENOMEM;
|
||||||
|
destination_escaped = shell_escape(destination, ":");
|
||||||
|
if (!destination_escaped)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
tuple = strjoin(format_str,
|
||||||
|
format_str ? " " : "",
|
||||||
|
permissive ? "-" : "",
|
||||||
|
source_escaped,
|
||||||
|
":",
|
||||||
|
destination_escaped);
|
||||||
if (!tuple)
|
if (!tuple)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
free_and_replace(format_str, tuple);
|
free_and_replace(format_str, tuple);
|
||||||
|
|
||||||
|
r = read_mount_options(message, error, &options, &format_str, ":");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_exit_container(message);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
r = mount_image_add(&mount_images, &n_mount_images,
|
r = mount_image_add(&mount_images, &n_mount_images,
|
||||||
&(MountImage) {
|
&(MountImage) {
|
||||||
.source = source,
|
.source = source,
|
||||||
.destination = destination,
|
.destination = destination,
|
||||||
|
.mount_options = options,
|
||||||
.ignore_enoent = permissive,
|
.ignore_enoent = permissive,
|
||||||
});
|
});
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -4634,7 +4634,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||||
fprintf(f, "%sRootImageOptions:", prefix);
|
fprintf(f, "%sRootImageOptions:", prefix);
|
||||||
LIST_FOREACH(mount_options, o, c->root_image_options)
|
LIST_FOREACH(mount_options, o, c->root_image_options)
|
||||||
if (!isempty(o->options))
|
if (!isempty(o->options))
|
||||||
fprintf(f, " %u:%s", o->partition_number, o->options);
|
fprintf(f, " %s:%s",
|
||||||
|
partition_designator_to_string(o->partition_designator),
|
||||||
|
o->options);
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5035,11 +5037,20 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||||
fprintf(f, "%d\n", c->syscall_errno);
|
fprintf(f, "%d\n", c->syscall_errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < c->n_mount_images; i++)
|
for (i = 0; i < c->n_mount_images; i++) {
|
||||||
fprintf(f, "%sMountImages: %s%s:%s\n", prefix,
|
MountOptions *o;
|
||||||
|
|
||||||
|
fprintf(f, "%sMountImages: %s%s:%s%s", prefix,
|
||||||
c->mount_images[i].ignore_enoent ? "-": "",
|
c->mount_images[i].ignore_enoent ? "-": "",
|
||||||
c->mount_images[i].source,
|
c->mount_images[i].source,
|
||||||
c->mount_images[i].destination);
|
c->mount_images[i].destination,
|
||||||
|
LIST_IS_EMPTY(c->mount_images[i].mount_options) ? "": ":");
|
||||||
|
LIST_FOREACH(mount_options, o, c->mount_images[i].mount_options)
|
||||||
|
fprintf(f, "%s:%s",
|
||||||
|
partition_designator_to_string(o->partition_designator),
|
||||||
|
o->options);
|
||||||
|
fprintf(f, "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool exec_context_maintains_privileges(const ExecContext *c) {
|
bool exec_context_maintains_privileges(const ExecContext *c) {
|
||||||
|
|
|
@ -1429,9 +1429,10 @@ int config_parse_root_image_options(
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
||||||
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
|
char **first = NULL, **second = NULL;
|
||||||
ExecContext *c = data;
|
ExecContext *c = data;
|
||||||
const Unit *u = userdata;
|
const Unit *u = userdata;
|
||||||
const char *p = rvalue;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
|
@ -1444,44 +1445,32 @@ int config_parse_root_image_options(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
r = strv_split_colon_pairs(&l, rvalue);
|
||||||
_cleanup_free_ char *mount_options_resolved = NULL, *first = NULL, *tuple = NULL;
|
|
||||||
const char *mount_options = NULL, *second = NULL;
|
|
||||||
MountOptions *o = NULL;
|
|
||||||
unsigned int partition_number = 0;
|
|
||||||
|
|
||||||
r = extract_first_word(&p, &tuple, WHITESPACE, EXTRACT_UNQUOTE);
|
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
if (r == -ENOMEM)
|
if (r == -ENOMEM)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
|
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
second = tuple;
|
STRV_FOREACH_PAIR(first, second, l) {
|
||||||
r = extract_first_word(&second, &first, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
|
MountOptions *o = NULL;
|
||||||
if (r == 0)
|
_cleanup_free_ char *mount_options_resolved = NULL;
|
||||||
continue;
|
const char *mount_options = NULL, *partition = "root";
|
||||||
if (r == -ENOMEM)
|
int partition_designator;
|
||||||
return log_oom();
|
|
||||||
if (r < 0) {
|
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s: %s", lvalue, rvalue);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Format is either '0:foo' or 'foo' (0 is implied) */
|
/* Format is either 'root:foo' or 'foo' (root is implied) */
|
||||||
if (!isempty(second) && second[-1] == ':') {
|
if (!isempty(*second)) {
|
||||||
mount_options = second;
|
partition = *first;
|
||||||
r = safe_atou(first, &partition_number);
|
mount_options = *second;
|
||||||
if (r < 0) {
|
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse partition number from \"%s\", ignoring: %m", first);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else
|
} else
|
||||||
mount_options = first;
|
mount_options = *first;
|
||||||
|
|
||||||
|
partition_designator = partition_designator_from_string(partition);
|
||||||
|
if (partition_designator < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Invalid partition name %s, ignoring", partition);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
r = unit_full_printf(u, mount_options, &mount_options_resolved);
|
r = unit_full_printf(u, mount_options, &mount_options_resolved);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", mount_options);
|
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", mount_options);
|
||||||
|
@ -1492,10 +1481,10 @@ int config_parse_root_image_options(
|
||||||
if (!o)
|
if (!o)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
*o = (MountOptions) {
|
*o = (MountOptions) {
|
||||||
.partition_number = partition_number,
|
.partition_designator = partition_designator,
|
||||||
.options = TAKE_PTR(mount_options_resolved),
|
.options = TAKE_PTR(mount_options_resolved),
|
||||||
};
|
};
|
||||||
LIST_APPEND(mount_options, options, o);
|
LIST_APPEND(mount_options, options, TAKE_PTR(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* empty spaces/separators only */
|
/* empty spaces/separators only */
|
||||||
|
@ -4633,10 +4622,9 @@ int config_parse_mount_images(
|
||||||
void *data,
|
void *data,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
|
||||||
ExecContext *c = data;
|
ExecContext *c = data;
|
||||||
const Unit *u = userdata;
|
const Unit *u = userdata;
|
||||||
char **source = NULL, **destination = NULL;
|
const char *p = rvalue;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
|
@ -4650,23 +4638,31 @@ int config_parse_mount_images(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = strv_split_colon_pairs(&l, rvalue);
|
for (;;) {
|
||||||
if (r == -ENOMEM)
|
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
||||||
return log_oom();
|
_cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
|
||||||
if (r < 0) {
|
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
STRV_FOREACH_PAIR(source, destination, l) {
|
|
||||||
_cleanup_free_ char *sresolved = NULL, *dresolved = NULL;
|
_cleanup_free_ char *sresolved = NULL, *dresolved = NULL;
|
||||||
|
const char *q = NULL;
|
||||||
char *s = NULL;
|
char *s = NULL;
|
||||||
bool permissive = false;
|
bool permissive = false;
|
||||||
|
|
||||||
r = unit_full_printf(u, *source, &sresolved);
|
r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
q = tuple;
|
||||||
|
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
r = unit_full_printf(u, first, &sresolved);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
"Failed to resolve unit specifiers in \"%s\", ignoring: %m", *source);
|
"Failed to resolve unit specifiers in \"%s\", ignoring: %m", first);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4680,15 +4676,15 @@ int config_parse_mount_images(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (isempty(*destination)) {
|
if (isempty(second)) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Missing destination in %s, ignoring: %s", lvalue, rvalue);
|
log_syntax(unit, LOG_ERR, filename, line, 0, "Missing destination in %s, ignoring: %s", lvalue, rvalue);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = unit_full_printf(u, *destination, &dresolved);
|
r = unit_full_printf(u, second, &dresolved);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
"Failed to resolve specifiers in \"%s\", ignoring: %m", *destination);
|
"Failed to resolve specifiers in \"%s\", ignoring: %m", second);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4696,10 +4692,62 @@ int config_parse_mount_images(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *partition = NULL, *mount_options = NULL, *mount_options_resolved = NULL;
|
||||||
|
MountOptions *o = NULL;
|
||||||
|
int partition_designator;
|
||||||
|
|
||||||
|
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
/* Single set of options, applying to the root partition/single filesystem */
|
||||||
|
if (r == 1) {
|
||||||
|
r = unit_full_printf(u, partition, &mount_options_resolved);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", first);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
o = new(MountOptions, 1);
|
||||||
|
if (!o)
|
||||||
|
return log_oom();
|
||||||
|
*o = (MountOptions) {
|
||||||
|
.partition_designator = PARTITION_ROOT,
|
||||||
|
.options = TAKE_PTR(mount_options_resolved),
|
||||||
|
};
|
||||||
|
LIST_APPEND(mount_options, options, o);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
partition_designator = partition_designator_from_string(partition);
|
||||||
|
if (partition_designator < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Invalid partition name %s, ignoring", partition);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
r = unit_full_printf(u, mount_options, &mount_options_resolved);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", mount_options);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
o = new(MountOptions, 1);
|
||||||
|
if (!o)
|
||||||
|
return log_oom();
|
||||||
|
*o = (MountOptions) {
|
||||||
|
.partition_designator = partition_designator,
|
||||||
|
.options = TAKE_PTR(mount_options_resolved),
|
||||||
|
};
|
||||||
|
LIST_APPEND(mount_options, options, o);
|
||||||
|
}
|
||||||
|
|
||||||
r = mount_image_add(&c->mount_images, &c->n_mount_images,
|
r = mount_image_add(&c->mount_images, &c->n_mount_images,
|
||||||
&(MountImage) {
|
&(MountImage) {
|
||||||
.source = s,
|
.source = s,
|
||||||
.destination = dresolved,
|
.destination = dresolved,
|
||||||
|
.mount_options = options,
|
||||||
.ignore_enoent = permissive,
|
.ignore_enoent = permissive,
|
||||||
});
|
});
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -73,7 +73,7 @@ typedef struct MountEntry {
|
||||||
char *options_malloc;
|
char *options_malloc;
|
||||||
unsigned long flags; /* Mount flags used by EMPTY_DIR and TMPFS. Do not include MS_RDONLY here, but please use read_only. */
|
unsigned long flags; /* Mount flags used by EMPTY_DIR and TMPFS. Do not include MS_RDONLY here, but please use read_only. */
|
||||||
unsigned n_followed;
|
unsigned n_followed;
|
||||||
LIST_FIELDS(MountEntry, mount_entry);
|
LIST_HEAD(MountOptions, image_options);
|
||||||
} MountEntry;
|
} MountEntry;
|
||||||
|
|
||||||
/* If MountAPIVFS= is used, let's mount /sys and /proc into the it, but only as a fallback if the user hasn't mounted
|
/* If MountAPIVFS= is used, let's mount /sys and /proc into the it, but only as a fallback if the user hasn't mounted
|
||||||
|
@ -247,6 +247,7 @@ static void mount_entry_done(MountEntry *p) {
|
||||||
p->path_malloc = mfree(p->path_malloc);
|
p->path_malloc = mfree(p->path_malloc);
|
||||||
p->source_malloc = mfree(p->source_malloc);
|
p->source_malloc = mfree(p->source_malloc);
|
||||||
p->options_malloc = mfree(p->options_malloc);
|
p->options_malloc = mfree(p->options_malloc);
|
||||||
|
p->image_options = mount_options_free_all(p->image_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int append_access_mounts(MountEntry **p, char **strv, MountMode mode, bool forcibly_require_prefix) {
|
static int append_access_mounts(MountEntry **p, char **strv, MountMode mode, bool forcibly_require_prefix) {
|
||||||
|
@ -339,6 +340,7 @@ static int append_mount_images(MountEntry **p, const MountImage *mount_images, s
|
||||||
.path_const = m->destination,
|
.path_const = m->destination,
|
||||||
.mode = MOUNT_IMAGES,
|
.mode = MOUNT_IMAGES,
|
||||||
.source_const = m->source,
|
.source_const = m->source,
|
||||||
|
.image_options = m->mount_options,
|
||||||
.ignore = m->ignore_enoent,
|
.ignore = m->ignore_enoent,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -925,10 +927,10 @@ static int mount_images(const MountEntry *m) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to create loop device for image: %m");
|
return log_debug_errno(r, "Failed to create loop device for image: %m");
|
||||||
|
|
||||||
r = dissect_image(loop_device->fd, root_hash_decoded, root_hash_size, verity_data, NULL, dissect_image_flags, &dissected_image);
|
r = dissect_image(loop_device->fd, root_hash_decoded, root_hash_size, verity_data, m->image_options, dissect_image_flags, &dissected_image);
|
||||||
/* No partition table? Might be a single-filesystem image, try again */
|
/* No partition table? Might be a single-filesystem image, try again */
|
||||||
if (!verity_data && r < 0 && r == -ENOPKG)
|
if (!verity_data && r < 0 && r == -ENOPKG)
|
||||||
r = dissect_image(loop_device->fd, root_hash_decoded, root_hash_size, verity_data, NULL, dissect_image_flags|DISSECT_IMAGE_NO_PARTITION_TABLE, &dissected_image);
|
r = dissect_image(loop_device->fd, root_hash_decoded, root_hash_size, verity_data, m->image_options, dissect_image_flags|DISSECT_IMAGE_NO_PARTITION_TABLE, &dissected_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to dissect image: %m");
|
return log_debug_errno(r, "Failed to dissect image: %m");
|
||||||
|
|
||||||
|
@ -1838,6 +1840,7 @@ MountImage* mount_image_free_many(MountImage *m, size_t *n) {
|
||||||
for (i = 0; i < *n; i++) {
|
for (i = 0; i < *n; i++) {
|
||||||
free(m[i].source);
|
free(m[i].source);
|
||||||
free(m[i].destination);
|
free(m[i].destination);
|
||||||
|
mount_options_free_all(m[i].mount_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(m);
|
free(m);
|
||||||
|
@ -1847,6 +1850,8 @@ MountImage* mount_image_free_many(MountImage *m, size_t *n) {
|
||||||
|
|
||||||
int mount_image_add(MountImage **m, size_t *n, const MountImage *item) {
|
int mount_image_add(MountImage **m, size_t *n, const MountImage *item) {
|
||||||
_cleanup_free_ char *s = NULL, *d = NULL;
|
_cleanup_free_ char *s = NULL, *d = NULL;
|
||||||
|
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
||||||
|
MountOptions *i;
|
||||||
MountImage *c;
|
MountImage *c;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
@ -1861,6 +1866,23 @@ int mount_image_add(MountImage **m, size_t *n, const MountImage *item) {
|
||||||
if (!d)
|
if (!d)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
LIST_FOREACH(mount_options, i, item->mount_options) {
|
||||||
|
_cleanup_(mount_options_free_allp) MountOptions *o;
|
||||||
|
|
||||||
|
o = new(MountOptions, 1);
|
||||||
|
if (!o)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*o = (MountOptions) {
|
||||||
|
.partition_designator = i->partition_designator,
|
||||||
|
.options = strdup(i->options),
|
||||||
|
};
|
||||||
|
if (!o->options)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
LIST_APPEND(mount_options, options, TAKE_PTR(o));
|
||||||
|
}
|
||||||
|
|
||||||
c = reallocarray(*m, *n + 1, sizeof(MountImage));
|
c = reallocarray(*m, *n + 1, sizeof(MountImage));
|
||||||
if (!c)
|
if (!c)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1870,6 +1892,7 @@ int mount_image_add(MountImage **m, size_t *n, const MountImage *item) {
|
||||||
c[(*n) ++] = (MountImage) {
|
c[(*n) ++] = (MountImage) {
|
||||||
.source = TAKE_PTR(s),
|
.source = TAKE_PTR(s),
|
||||||
.destination = TAKE_PTR(d),
|
.destination = TAKE_PTR(d),
|
||||||
|
.mount_options = TAKE_PTR(options),
|
||||||
.ignore_enoent = item->ignore_enoent,
|
.ignore_enoent = item->ignore_enoent,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ typedef struct NamespaceInfo NamespaceInfo;
|
||||||
typedef struct BindMount BindMount;
|
typedef struct BindMount BindMount;
|
||||||
typedef struct TemporaryFileSystem TemporaryFileSystem;
|
typedef struct TemporaryFileSystem TemporaryFileSystem;
|
||||||
typedef struct MountImage MountImage;
|
typedef struct MountImage MountImage;
|
||||||
typedef struct MountEntry MountEntry;
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
@ -77,6 +76,7 @@ struct TemporaryFileSystem {
|
||||||
struct MountImage {
|
struct MountImage {
|
||||||
char *source;
|
char *source;
|
||||||
char *destination;
|
char *destination;
|
||||||
|
LIST_HEAD(MountOptions, mount_options);
|
||||||
bool ignore_enoent;
|
bool ignore_enoent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1695,6 +1695,9 @@ static int oci_seccomp_arch_from_string(const char *name, uint32_t *ret) {
|
||||||
{ "SCMP_ARCH_PPC", SCMP_ARCH_PPC },
|
{ "SCMP_ARCH_PPC", SCMP_ARCH_PPC },
|
||||||
{ "SCMP_ARCH_PPC64", SCMP_ARCH_PPC64 },
|
{ "SCMP_ARCH_PPC64", SCMP_ARCH_PPC64 },
|
||||||
{ "SCMP_ARCH_PPC64LE", SCMP_ARCH_PPC64LE },
|
{ "SCMP_ARCH_PPC64LE", SCMP_ARCH_PPC64LE },
|
||||||
|
#ifdef SCMP_ARCH_RISCV64
|
||||||
|
{ "SCMP_ARCH_RISCV64", SCMP_ARCH_RISCV64 },
|
||||||
|
#endif
|
||||||
{ "SCMP_ARCH_S390", SCMP_ARCH_S390 },
|
{ "SCMP_ARCH_S390", SCMP_ARCH_S390 },
|
||||||
{ "SCMP_ARCH_S390X", SCMP_ARCH_S390X },
|
{ "SCMP_ARCH_S390X", SCMP_ARCH_S390X },
|
||||||
{ "SCMP_ARCH_X32", SCMP_ARCH_X32 },
|
{ "SCMP_ARCH_X32", SCMP_ARCH_X32 },
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "condition.h"
|
#include "condition.h"
|
||||||
#include "coredump-util.h"
|
#include "coredump-util.h"
|
||||||
#include "cpu-set-util.h"
|
#include "cpu-set-util.h"
|
||||||
|
#include "dissect-image.h"
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "exec-util.h"
|
#include "exec-util.h"
|
||||||
#include "exit-status.h"
|
#include "exit-status.h"
|
||||||
|
@ -1456,6 +1457,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(field, "RootImageOptions")) {
|
if (streq(field, "RootImageOptions")) {
|
||||||
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
|
char **first = NULL, **second = NULL;
|
||||||
const char *p = eq;
|
const char *p = eq;
|
||||||
|
|
||||||
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
||||||
|
@ -1466,44 +1469,26 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
r = sd_bus_message_open_container(m, 'v', "a(us)");
|
r = sd_bus_message_open_container(m, 'v', "a(ss)");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
r = sd_bus_message_open_container(m, 'a', "(us)");
|
r = sd_bus_message_open_container(m, 'a', "(ss)");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
for (;;) {
|
r = strv_split_colon_pairs(&l, p);
|
||||||
_cleanup_free_ char *first = NULL, *tuple = NULL;
|
|
||||||
const char *mount_options = NULL, *second = NULL;
|
|
||||||
unsigned partition_number = 0;
|
|
||||||
|
|
||||||
r = extract_first_word(&p, &tuple, WHITESPACE, EXTRACT_UNQUOTE);
|
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse argument: %m");
|
return log_error_errno(r, "Failed to parse argument: %m");
|
||||||
|
|
||||||
second = tuple;
|
STRV_FOREACH_PAIR(first, second, l) {
|
||||||
r = extract_first_word(&second, &first, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
|
/* Format is either 'root:foo' or 'foo' (root is implied) */
|
||||||
if (r == 0)
|
if (!isempty(*second) && partition_designator_from_string(*first) < 0)
|
||||||
continue;
|
return bus_log_create_error(-EINVAL);
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to parse argument: %m");
|
|
||||||
|
|
||||||
/* Format is either '0:foo' or 'foo' (0 is implied) */
|
r = sd_bus_message_append(m, "(ss)",
|
||||||
if (!isempty(second) && second[-1] == ':') {
|
!isempty(*second) ? *first : "root",
|
||||||
mount_options = second;
|
!isempty(*second) ? *second : *first);
|
||||||
r = safe_atou(first, &partition_number);
|
|
||||||
if (r < 0) {
|
|
||||||
log_error_errno(r, "Failed to parse partition number from %s: %m", first);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
mount_options = first;
|
|
||||||
|
|
||||||
r = sd_bus_message_append(m, "(us)", partition_number, mount_options);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
}
|
}
|
||||||
|
@ -1524,8 +1509,6 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(field, "MountImages")) {
|
if (streq(field, "MountImages")) {
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
|
||||||
char **source = NULL, **destination = NULL;
|
|
||||||
const char *p = eq;
|
const char *p = eq;
|
||||||
|
|
||||||
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
||||||
|
@ -1536,33 +1519,85 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
r = sd_bus_message_open_container(m, 'v', "a(ssb)");
|
r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
r = sd_bus_message_open_container(m, 'a', "(ssb)");
|
r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
r = strv_split_colon_pairs(&l, p);
|
for (;;) {
|
||||||
if (r < 0)
|
_cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
|
||||||
return log_error_errno(r, "Failed to parse argument: %m");
|
const char *q = NULL, *source = NULL;
|
||||||
|
|
||||||
STRV_FOREACH_PAIR(source, destination, l) {
|
|
||||||
char *s = *source;
|
|
||||||
bool permissive = false;
|
bool permissive = false;
|
||||||
|
|
||||||
if (s[0] == '-') {
|
r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
q = tuple;
|
||||||
|
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
source = first;
|
||||||
|
if (source[0] == '-') {
|
||||||
permissive = true;
|
permissive = true;
|
||||||
s++;
|
source++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isempty(*destination))
|
if (isempty(second))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Missing argument after ':': %s",
|
"Missing argument after ':': %s",
|
||||||
eq);
|
eq);
|
||||||
|
|
||||||
r = sd_bus_message_append(m, "(ssb)", s, *destination, permissive);
|
r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_message_append(m, "ssb", source, second, permissive);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(m, 'a', "(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *partition = NULL, *mount_options = NULL;
|
||||||
|
|
||||||
|
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
/* Single set of options, applying to the root partition/single filesystem */
|
||||||
|
if (r == 1) {
|
||||||
|
r = sd_bus_message_append(m, "(ss)", "root", partition);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partition_designator_from_string(partition) < 0)
|
||||||
|
return bus_log_create_error(-EINVAL);
|
||||||
|
|
||||||
|
r = sd_bus_message_append(m, "(ss)", partition, mount_options);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_bus_message_close_container(m);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_message_close_container(m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
}
|
}
|
||||||
|
|
|
@ -420,7 +420,7 @@ int dissect_image(
|
||||||
m->verity = root_hash && verity_data;
|
m->verity = root_hash && verity_data;
|
||||||
m->can_verity = !!verity_data;
|
m->can_verity = !!verity_data;
|
||||||
|
|
||||||
options = mount_options_from_part(mount_options, 0);
|
options = mount_options_from_part(mount_options, PARTITION_ROOT);
|
||||||
if (options) {
|
if (options) {
|
||||||
o = strdup(options);
|
o = strdup(options);
|
||||||
if (!o)
|
if (!o)
|
||||||
|
@ -716,7 +716,7 @@ int dissect_image(
|
||||||
if (!n)
|
if (!n)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
options = mount_options_from_part(mount_options, nr);
|
options = mount_options_from_part(mount_options, designator);
|
||||||
if (options) {
|
if (options) {
|
||||||
o = strdup(options);
|
o = strdup(options);
|
||||||
if (!o)
|
if (!o)
|
||||||
|
@ -773,7 +773,7 @@ int dissect_image(
|
||||||
if (!n)
|
if (!n)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
options = mount_options_from_part(mount_options, nr);
|
options = mount_options_from_part(mount_options, PARTITION_XBOOTLDR);
|
||||||
if (options) {
|
if (options) {
|
||||||
o = strdup(options);
|
o = strdup(options);
|
||||||
if (!o)
|
if (!o)
|
||||||
|
@ -827,7 +827,7 @@ int dissect_image(
|
||||||
if (multiple_generic)
|
if (multiple_generic)
|
||||||
return -ENOTUNIQ;
|
return -ENOTUNIQ;
|
||||||
|
|
||||||
options = mount_options_from_part(mount_options, generic_nr);
|
options = mount_options_from_part(mount_options, PARTITION_ROOT);
|
||||||
if (options) {
|
if (options) {
|
||||||
o = strdup(options);
|
o = strdup(options);
|
||||||
if (!o)
|
if (!o)
|
||||||
|
@ -2023,11 +2023,11 @@ MountOptions* mount_options_free_all(MountOptions *options) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* mount_options_from_part(const MountOptions *options, unsigned int partition_number) {
|
const char* mount_options_from_part(const MountOptions *options, int designator) {
|
||||||
MountOptions *m;
|
MountOptions *m;
|
||||||
|
|
||||||
LIST_FOREACH(mount_options, m, (MountOptions *)options)
|
LIST_FOREACH(mount_options, m, (MountOptions *)options)
|
||||||
if (partition_number == m->partition_number && !isempty(m->options))
|
if (designator == m->partition_designator && !isempty(m->options))
|
||||||
return m->options;
|
return m->options;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -87,14 +87,14 @@ struct DissectedImage {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MountOptions {
|
struct MountOptions {
|
||||||
unsigned partition_number;
|
int partition_designator;
|
||||||
char *options;
|
char *options;
|
||||||
LIST_FIELDS(MountOptions, mount_options);
|
LIST_FIELDS(MountOptions, mount_options);
|
||||||
};
|
};
|
||||||
|
|
||||||
MountOptions* mount_options_free_all(MountOptions *options);
|
MountOptions* mount_options_free_all(MountOptions *options);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
|
||||||
const char* mount_options_from_part(const MountOptions *options, unsigned int partition_number);
|
const char* mount_options_from_part(const MountOptions *options, int designator);
|
||||||
|
|
||||||
int probe_filesystem(const char *node, char **ret_fstype);
|
int probe_filesystem(const char *node, char **ret_fstype);
|
||||||
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, const char *verity_data, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret);
|
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, const char *verity_data, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "af-list.h"
|
#include "af-list.h"
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "env-util.h"
|
||||||
#include "errno-list.h"
|
#include "errno-list.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "nsflags.h"
|
#include "nsflags.h"
|
||||||
|
@ -85,6 +86,8 @@ const uint32_t seccomp_local_archs[] = {
|
||||||
SCMP_ARCH_PPC64LE, /* native */
|
SCMP_ARCH_PPC64LE, /* native */
|
||||||
#elif defined(__powerpc__)
|
#elif defined(__powerpc__)
|
||||||
SCMP_ARCH_PPC,
|
SCMP_ARCH_PPC,
|
||||||
|
#elif defined(__riscv) && __riscv_xlen == 64 && defined(SCMP_ARCH_RISCV64)
|
||||||
|
SCMP_ARCH_RISCV64,
|
||||||
#elif defined(__s390x__)
|
#elif defined(__s390x__)
|
||||||
SCMP_ARCH_S390,
|
SCMP_ARCH_S390,
|
||||||
SCMP_ARCH_S390X, /* native */
|
SCMP_ARCH_S390X, /* native */
|
||||||
|
@ -131,6 +134,10 @@ const char* seccomp_arch_to_string(uint32_t c) {
|
||||||
return "ppc64";
|
return "ppc64";
|
||||||
case SCMP_ARCH_PPC64LE:
|
case SCMP_ARCH_PPC64LE:
|
||||||
return "ppc64-le";
|
return "ppc64-le";
|
||||||
|
#ifdef SCMP_ARCH_RISCV64
|
||||||
|
case SCMP_ARCH_RISCV64:
|
||||||
|
return "riscv64";
|
||||||
|
#endif
|
||||||
case SCMP_ARCH_S390:
|
case SCMP_ARCH_S390:
|
||||||
return "s390";
|
return "s390";
|
||||||
case SCMP_ARCH_S390X:
|
case SCMP_ARCH_S390X:
|
||||||
|
@ -176,6 +183,10 @@ int seccomp_arch_from_string(const char *n, uint32_t *ret) {
|
||||||
*ret = SCMP_ARCH_PPC64;
|
*ret = SCMP_ARCH_PPC64;
|
||||||
else if (streq(n, "ppc64-le"))
|
else if (streq(n, "ppc64-le"))
|
||||||
*ret = SCMP_ARCH_PPC64LE;
|
*ret = SCMP_ARCH_PPC64LE;
|
||||||
|
#ifdef SCMP_ARCH_RISCV64
|
||||||
|
else if (streq(n, "riscv64"))
|
||||||
|
*ret = SCMP_ARCH_RISCV64;
|
||||||
|
#endif
|
||||||
else if (streq(n, "s390"))
|
else if (streq(n, "s390"))
|
||||||
*ret = SCMP_ARCH_S390;
|
*ret = SCMP_ARCH_S390;
|
||||||
else if (streq(n, "s390x"))
|
else if (streq(n, "s390x"))
|
||||||
|
@ -224,6 +235,14 @@ int seccomp_init_for_arch(scmp_filter_ctx *ret, uint32_t arch, uint32_t default_
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
#if SCMP_VER_MAJOR >= 3 || (SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR >= 4)
|
||||||
|
if (getenv_bool("SYSTEMD_LOG_SECCOMP") > 0) {
|
||||||
|
r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_LOG, 1);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Failed to enable seccomp event logging: %m");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
*ret = TAKE_PTR(seccomp);
|
*ret = TAKE_PTR(seccomp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1248,7 +1267,13 @@ int seccomp_protect_sysctl(void) {
|
||||||
|
|
||||||
log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch));
|
log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch));
|
||||||
|
|
||||||
if (IN_SET(arch, SCMP_ARCH_X32, SCMP_ARCH_AARCH64))
|
if (IN_SET(arch,
|
||||||
|
SCMP_ARCH_AARCH64,
|
||||||
|
#ifdef SCMP_ARCH_RISCV64
|
||||||
|
SCMP_ARCH_RISCV64,
|
||||||
|
#endif
|
||||||
|
SCMP_ARCH_X32
|
||||||
|
))
|
||||||
/* No _sysctl syscall */
|
/* No _sysctl syscall */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -1332,6 +1357,9 @@ int seccomp_restrict_address_families(Set *address_families, bool allow_list) {
|
||||||
case SCMP_ARCH_MIPS64N32:
|
case SCMP_ARCH_MIPS64N32:
|
||||||
case SCMP_ARCH_MIPSEL64:
|
case SCMP_ARCH_MIPSEL64:
|
||||||
case SCMP_ARCH_MIPS64:
|
case SCMP_ARCH_MIPS64:
|
||||||
|
#ifdef SCMP_ARCH_RISCV64
|
||||||
|
case SCMP_ARCH_RISCV64:
|
||||||
|
#endif
|
||||||
/* These we know we support (i.e. are the ones that do not use socketcall()) */
|
/* These we know we support (i.e. are the ones that do not use socketcall()) */
|
||||||
supported = true;
|
supported = true;
|
||||||
break;
|
break;
|
||||||
|
@ -1569,7 +1597,7 @@ static int add_seccomp_syscall_filter(scmp_filter_ctx seccomp,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For known architectures, check that syscalls are indeed defined or not. */
|
/* For known architectures, check that syscalls are indeed defined or not. */
|
||||||
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
|
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64)
|
||||||
assert_cc(SCMP_SYS(shmget) > 0);
|
assert_cc(SCMP_SYS(shmget) > 0);
|
||||||
assert_cc(SCMP_SYS(shmat) > 0);
|
assert_cc(SCMP_SYS(shmat) > 0);
|
||||||
assert_cc(SCMP_SYS(shmdt) > 0);
|
assert_cc(SCMP_SYS(shmdt) > 0);
|
||||||
|
@ -1614,13 +1642,16 @@ int seccomp_memory_deny_write_execute(void) {
|
||||||
case SCMP_ARCH_X86_64:
|
case SCMP_ARCH_X86_64:
|
||||||
case SCMP_ARCH_X32:
|
case SCMP_ARCH_X32:
|
||||||
case SCMP_ARCH_AARCH64:
|
case SCMP_ARCH_AARCH64:
|
||||||
filter_syscall = SCMP_SYS(mmap); /* amd64, x32 and arm64 have only mmap */
|
#ifdef SCMP_ARCH_RISCV64
|
||||||
|
case SCMP_ARCH_RISCV64:
|
||||||
|
#endif
|
||||||
|
filter_syscall = SCMP_SYS(mmap); /* amd64, x32, arm64 and riscv64 have only mmap */
|
||||||
shmat_syscall = SCMP_SYS(shmat);
|
shmat_syscall = SCMP_SYS(shmat);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Please add more definitions here, if you port systemd to other architectures! */
|
/* Please add more definitions here, if you port systemd to other architectures! */
|
||||||
|
|
||||||
#if !defined(__i386__) && !defined(__x86_64__) && !defined(__powerpc__) && !defined(__powerpc64__) && !defined(__arm__) && !defined(__aarch64__) && !defined(__s390__) && !defined(__s390x__)
|
#if !defined(__i386__) && !defined(__x86_64__) && !defined(__powerpc__) && !defined(__powerpc64__) && !defined(__arm__) && !defined(__aarch64__) && !defined(__s390__) && !defined(__s390x__) && !(defined(__riscv) && __riscv_xlen == 64)
|
||||||
#warning "Consider adding the right mmap() syscall definitions here!"
|
#warning "Consider adding the right mmap() syscall definitions here!"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -5411,24 +5411,56 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
||||||
return 1;
|
return 1;
|
||||||
} else if (streq(name, "MountImages")) {
|
} else if (streq(name, "MountImages")) {
|
||||||
_cleanup_free_ char *paths = NULL;
|
_cleanup_free_ char *paths = NULL;
|
||||||
const char *source, *dest;
|
|
||||||
int ignore_enoent;
|
|
||||||
|
|
||||||
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ssb)");
|
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ssba(ss))");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_parse_error(r);
|
return bus_log_parse_error(r);
|
||||||
|
|
||||||
while ((r = sd_bus_message_read(m, "(ssb)", &source, &dest, &ignore_enoent)) > 0) {
|
for (;;) {
|
||||||
_cleanup_free_ char *str = NULL;
|
_cleanup_free_ char *str = NULL;
|
||||||
|
const char *source, *destination, *partition, *mount_options;
|
||||||
|
int ignore_enoent;
|
||||||
|
|
||||||
if (isempty(source))
|
r = sd_bus_message_enter_container(m, 'r', "ssba(ss)");
|
||||||
continue;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
if (asprintf(&str, "%s%s:%s", ignore_enoent ? "-" : "", source, dest) < 0)
|
r = sd_bus_message_read(m, "ssb", &source, &destination, &ignore_enoent);
|
||||||
|
if (r <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
str = strjoin(ignore_enoent ? "-" : "",
|
||||||
|
source,
|
||||||
|
":",
|
||||||
|
destination);
|
||||||
|
if (!str)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
r = sd_bus_message_enter_container(m, 'a', "(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
while ((r = sd_bus_message_read(m, "(ss)", &partition, &mount_options)) > 0) {
|
||||||
|
_cleanup_free_ char *previous = NULL;
|
||||||
|
|
||||||
|
previous = TAKE_PTR(str);
|
||||||
|
str = strjoin(strempty(previous), previous ? ":" : "", partition, ":", mount_options);
|
||||||
|
if (!str)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
if (!strextend_with_separator(&paths, " ", str, NULL))
|
if (!strextend_with_separator(&paths, " ", str, NULL))
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
r = sd_bus_message_exit_container(m);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_exit_container(m);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_parse_error(r);
|
return bus_log_parse_error(r);
|
||||||
|
|
|
@ -73,6 +73,9 @@ static void test_architecture_table(void) {
|
||||||
"ppc\0"
|
"ppc\0"
|
||||||
"ppc64\0"
|
"ppc64\0"
|
||||||
"ppc64-le\0"
|
"ppc64-le\0"
|
||||||
|
#ifdef SCMP_ARCH_RISCV64
|
||||||
|
"riscv64\0"
|
||||||
|
#endif
|
||||||
"s390\0"
|
"s390\0"
|
||||||
"s390x\0") {
|
"s390x\0") {
|
||||||
uint32_t c;
|
uint32_t c;
|
||||||
|
|
|
@ -128,56 +128,69 @@ umount ${image_dir}/mount
|
||||||
|
|
||||||
systemd-run -t --property RootImage=${image}.gpt --property RootHash=${roothash} /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
|
systemd-run -t --property RootImage=${image}.gpt --property RootHash=${roothash} /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
|
||||||
|
|
||||||
systemd-run -t --property RootImage=${image}.raw --property RootImageOptions="1:ro,noatime 2:ro,dev nosuid,dev" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "nosuid"
|
systemd-run -t --property RootImage=${image}.raw --property RootImageOptions="root:nosuid,dev home:ro,dev ro,noatime" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "nosuid"
|
||||||
systemd-run -t --property RootImage=${image}.gpt --property RootImageOptions="1:ro,noatime 1:ro,dev" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "noatime"
|
systemd-run -t --property RootImage=${image}.gpt --property RootImageOptions="root:ro,noatime root:ro,dev" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "noatime"
|
||||||
|
|
||||||
|
mkdir -p mkdir -p ${image_dir}/result
|
||||||
cat > /run/systemd/system/testservice-50a.service <<EOF
|
cat > /run/systemd/system/testservice-50a.service <<EOF
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart=mount
|
ExecStart=bash -c "mount > /run/result/a"
|
||||||
|
BindPaths=${image_dir}/result:/run/result
|
||||||
|
TemporaryFileSystem=/run
|
||||||
MountAPIVFS=yes
|
MountAPIVFS=yes
|
||||||
RootImage=${image}.raw
|
RootImage=${image}.raw
|
||||||
RootImageOptions=1:ro,noatime,nosuid 2:ro,dev noatime,dev
|
RootImageOptions=root:ro,noatime home:ro,dev relatime,dev
|
||||||
RootImageOptions=nosuid,dev
|
RootImageOptions=nosuid,dev
|
||||||
EOF
|
EOF
|
||||||
systemctl start testservice-50a.service
|
systemctl start testservice-50a.service
|
||||||
journalctl -b -u testservice-50a.service | grep -F "squashfs" | grep -q -F "noatime"
|
grep -F "squashfs" ${image_dir}/result/a | grep -q -F "noatime"
|
||||||
journalctl -b -u testservice-50a.service | grep -F "squashfs" | grep -q -F -v "nosuid"
|
grep -F "squashfs" ${image_dir}/result/a | grep -q -F -v "nosuid"
|
||||||
|
|
||||||
cat > /run/systemd/system/testservice-50b.service <<EOF
|
cat > /run/systemd/system/testservice-50b.service <<EOF
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart=mount
|
ExecStart=bash -c "mount > /run/result/b"
|
||||||
|
BindPaths=${image_dir}/result:/run/result
|
||||||
|
TemporaryFileSystem=/run
|
||||||
MountAPIVFS=yes
|
MountAPIVFS=yes
|
||||||
RootImage=${image}.gpt
|
RootImage=${image}.gpt
|
||||||
RootImageOptions=1:ro,noatime,nosuid 2:ro,dev nosuid,dev
|
RootImageOptions=root:ro,noatime,nosuid home:ro,dev nosuid,dev
|
||||||
RootImageOptions=2:ro,dev nosuid,dev,%%foo
|
RootImageOptions=home:ro,dev nosuid,dev,%%foo
|
||||||
EOF
|
EOF
|
||||||
systemctl start testservice-50b.service
|
systemctl start testservice-50b.service
|
||||||
journalctl -b -u testservice-50b.service | grep -F "squashfs" | grep -q -F "noatime"
|
grep -F "squashfs" ${image_dir}/result/b | grep -q -F "noatime"
|
||||||
|
|
||||||
# Check that specifier escape is applied %%foo -> %foo
|
# Check that specifier escape is applied %%foo -> %foo
|
||||||
busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/testservice_2d50b_2eservice org.freedesktop.systemd1.Service RootImageOptions | grep -F "nosuid,dev,%foo"
|
busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1/unit/testservice_2d50b_2eservice org.freedesktop.systemd1.Service RootImageOptions | grep -F "nosuid,dev,%foo"
|
||||||
|
|
||||||
# Now do some checks with MountImages, both by itself and in combination with RootImage, and as single FS or GPT image
|
# Now do some checks with MountImages, both by itself, with options and in combination with RootImage, and as single FS or GPT image
|
||||||
systemd-run -t --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
|
systemd-run -t --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
|
||||||
systemd-run -t --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
|
systemd-run -t --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
|
||||||
|
systemd-run -t --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2:nosuid,dev" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "nosuid"
|
||||||
|
systemd-run -t --property MountImages="${image}.gpt:/run/img1:root:nosuid ${image}.raw:/run/img2:home:suid" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "nosuid"
|
||||||
systemd-run -t --property MountImages="${image}.raw:/run/img2\:3" /usr/bin/cat /run/img2:3/usr/lib/os-release | grep -q -F "MARKER=1"
|
systemd-run -t --property MountImages="${image}.raw:/run/img2\:3" /usr/bin/cat /run/img2:3/usr/lib/os-release | grep -q -F "MARKER=1"
|
||||||
|
systemd-run -t --property MountImages="${image}.raw:/run/img2\:3:nosuid" --property MountAPIVFS=yes mount | grep -F "squashfs" | grep -q -F "nosuid"
|
||||||
systemd-run -t --property TemporaryFileSystem=/run --property RootImage=${image}.raw --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
|
systemd-run -t --property TemporaryFileSystem=/run --property RootImage=${image}.raw --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
|
||||||
systemd-run -t --property TemporaryFileSystem=/run --property RootImage=${image}.raw --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
|
systemd-run -t --property TemporaryFileSystem=/run --property RootImage=${image}.raw --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img1/usr/lib/os-release | grep -q -F "MARKER=1"
|
||||||
systemd-run -t --property TemporaryFileSystem=/run --property RootImage=${image}.gpt --property RootHash=${roothash} --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
|
systemd-run -t --property TemporaryFileSystem=/run --property RootImage=${image}.gpt --property RootHash=${roothash} --property MountImages="${image}.gpt:/run/img1 ${image}.raw:/run/img2" /usr/bin/cat /run/img2/usr/lib/os-release | grep -q -F "MARKER=1"
|
||||||
cat >/run/systemd/system/testservice-50.service <<EOF
|
cat >/run/systemd/system/testservice-50c.service <<EOF
|
||||||
[Service]
|
[Service]
|
||||||
|
MountAPIVFS=yes
|
||||||
TemporaryFileSystem=/run
|
TemporaryFileSystem=/run
|
||||||
RootImage=${image}.raw
|
RootImage=${image}.raw
|
||||||
MountImages=${image}.gpt:/run/img1
|
MountImages=${image}.gpt:/run/img1:root:noatime:home:relatime
|
||||||
MountImages=${image}.raw:/run/img2\:3
|
MountImages=${image}.raw:/run/img2\:3:nosuid
|
||||||
ExecStart=/usr/bin/cat /run/img1/usr/lib/os-release
|
ExecStart=bash -c "cat /run/img1/usr/lib/os-release > /run/result/c"
|
||||||
ExecStart=/usr/bin/cat /run/img2:3/usr/lib/os-release
|
ExecStart=bash -c "cat /run/img2:3/usr/lib/os-release >> /run/result/c"
|
||||||
|
ExecStart=bash -c "mount >> /run/result/c"
|
||||||
|
BindPaths=${image_dir}/result:/run/result
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
EOF
|
EOF
|
||||||
systemctl start testservice-50.service
|
systemctl start testservice-50c.service
|
||||||
journalctl -b -u testservice-50.service | grep -q -F "MARKER=1"
|
grep -q -F "MARKER=1" ${image_dir}/result/c
|
||||||
|
grep -F "squashfs" ${image_dir}/result/c | grep -q -F "noatime"
|
||||||
|
grep -F "squashfs" ${image_dir}/result/c | grep -q -F -v "nosuid"
|
||||||
|
|
||||||
echo OK > /testok
|
echo OK > /testok
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue