1
0
mirror of https://github.com/systemd/systemd synced 2025-09-22 21:34:46 +02:00

Compare commits

...

17 Commits

Author SHA1 Message Date
Daan De Meyer
45204921be
Merge pull request #16104 from ssahani/dhcpv6-iaid
networkctl: Display DHCPv6 IAID
2020-06-09 21:18:28 +02:00
YmrDtnJu
2ffadd3cee AppArmor: Support for loading a set of pre-compiled profiles at startup time
Let systemd load a set of pre-compiled AppArmor profile files from a policy
cache at /etc/apparmor/earlypolicy. Maintenance of that policy cache must be
done outside of systemd.

After successfully loading the profiles systemd will attempt to change to a
profile named systemd.

If systemd is already confined in a profile, it will not load any profile files
and will not attempt to change it's profile.

If anything goes wrong, systemd will only log failures. It will not fail to
start.
2020-06-09 20:27:47 +02:00
Lennart Poettering
d689f0f20a
Merge pull request #16058 from Werkov/fix-memory-protection-default
Fix memory protection default setting
2020-06-09 20:02:53 +02:00
Lennart Poettering
4f4f37b20d
Merge pull request #16046 from bluca/dissect_squashfs_verity
dissect: single-filesystem verity images with external hashdevice
2020-06-09 19:52:21 +02:00
Yigal Korman
2233c2703c man: udevadm: mention non-zero exit code on settle
'udevadm settle --timeout=XY' will return 1 in case the timeout was
reached and the event queue was not empty.
The manpage should mention it.
2020-06-09 17:31:49 +02:00
Yu Watanabe
60b316b1e9 test-network: wait 2min for the bridge being in configured state
On some CIs, it may takes more than 40 seconds.

Hopefully fixes #16105.
2020-06-09 17:19:22 +02:00
Chris Down
69876f94ab doc: Try to clarify automount dependency confusion
Arch recently upgraded systemd to 245.6. Shortly afterwards, users began
reporting[0] that systemd detected an ordering cycle, and they were
unable to log in. The reason they were unable to log in was because of
ordering cycle resolution:

    [...]
    systemd[1]: sysinit.target: Job systemd-tmpfiles-setup.service/start deleted to break ordering cycle starting with sysinit.target/start
    systemd[1]: sysinit.target: Job systemd-update-done.service/start deleted to break ordering cycle starting with sysinit.target/start
    systemd[1]: sysinit.target: Job systemd-journal-catalog-update.service/start deleted to break ordering cycle starting with sysinit.target/start
    systemd[1]: sysinit.target: Job local-fs.target/start deleted to break ordering cycle starting with sysinit.target/start
    systemd[1]: sysinit.target: Job systemd-tmpfiles-setup.service/start deleted to break ordering cycle starting with sysinit.target/start
    [...]

Whether the resolution did the right thing here or not is a longer-term
discussion, but in the interim we should at least make this distinction
between automount dependencies and mount dependencies clearer in the
documentation, so that users and distribution maintainers know what's
acceptable. In this case Arch actually backed out b3d7aef5 entirely and
released a new version due to the confusion.

Also see https://github.com/systemd/systemd-stable/issues/69.

0: https://bugs.archlinux.org/task/66908
2020-06-09 17:13:59 +02:00
Michał Bartoszkiewicz
fa0e23c900 docs: use bool in varlink interface definition
Boolean type in varlink is named bool, not boolean.
2020-06-09 17:11:38 +02:00
Luca Boccassi
e7cbe5cb9e dissect: support single-filesystem verity images with external verity hash
dm-verity support in dissect-image at the moment is restricted to GPT
volumes.
If the image a single-filesystem type without a partition table (eg: squashfs)
and a roothash/verity file are passed, set the verity flag and mark as
read-only.
2020-06-09 12:19:21 +01:00
Susant Sahani
331ee15f18 networkctl: DHCPv6 - display IAID 2020-06-09 19:58:36 +09:00
Susant Sahani
01dd138031 sd-network: Introduce API to get DHCPv6 IAID 2020-06-09 19:58:36 +09:00
Susant Sahani
18d8a2cf30 network: DHCPv6 - export IAID to state file 2020-06-09 19:58:31 +09:00
Susant Sahani
d69d4038ec dhcp6: Provide method to access IAID 2020-06-09 19:57:38 +09:00
Luca Boccassi
b1806441bb dissect-image: wait for udev for single filesystem images too
Single filesystem images are mounted from the /dev/block/X:Y symlink
rather than /dev/loopZ, so we need to wait for udev to create it or
mounting will be racy and occasionally fail.
2020-06-08 13:06:53 +01:00
Michal Koutný
53aa85af24 cgroup: Allow empty assignments of Memory{Low,Min}=
Currently, an empty assignment of Memory{Low,Min}= directives would be
interpretted as setting it to global default, i.e. zero. However, if we
set a runtime protection value on a unit that inherits parent's
DefaultMemory{Low,Min}=, it is not possible to revert it back to the
state where the DefaultMemory{Low,Min}= is propagated from parent
slice(s).

This patch changes the semantics of the empty assignments to explicitly
nullify any value set by the user previously. Since DBus API uses
uint64_t where 0 is a valid configuration, the patch modifies DBus API
by exploiting the variant type of property value to pass the NULL value.
2020-06-02 18:59:47 +02:00
Michal Koutný
db2b8d2e28 cgroup: Make empty assignments reset to default
When MemoryLow= or MemoryMin= is set, it is interpretted as setting the
values to infinity. This is inconsistent with the default initialization
to 0.
It'd be nice to interpret the empty assignment as fallback to
DefaultMemory* of parent slice, however, current DBus API cannot convey
such a NULL value, so stick to simply interpretting that as hard-wired
default.
2020-06-02 18:59:47 +02:00
Michal Koutný
21c8397694 tests: Fix description of test units
Corrected reference to non-existent unit.
2020-06-02 18:59:47 +02:00
33 changed files with 586 additions and 165 deletions

View File

@ -160,7 +160,7 @@ method GetUserRecord(
service : string
) -> (
record : object,
incomplete : boolean
incomplete : bool
)
method GetGroupRecord(
@ -169,7 +169,7 @@ method GetGroupRecord(
service : string
) -> (
record : object,
incomplete : boolean
incomplete : bool
)
method GetMemberships(

View File

@ -302,6 +302,10 @@
hash partitions are set up if the root hash for them is specified using the <option>--root-hash=</option>
option.</para>
<para>Single file system images (i.e. file systems without a surrounding partition table) can be opened using
dm-verity if the integrity data is passed using the <option>--root-hash=</option> and
<option>--verity-data=</option> options.</para>
<para>Any other partitions, such as foreign partitions or swap partitions are not mounted. May not be specified
together with <option>--directory=</option>, <option>--template=</option>.</para></listitem>
</varlistentry>
@ -390,8 +394,20 @@
project='man-pages'><refentrytitle>xattr</refentrytitle><manvolnum>7</manvolnum></citerefentry>), then the root
hash is read from it, also as formatted hexadecimal characters. If the extended file attribute is not found (or
is not supported by the underlying file system), but a file with the <filename>.roothash</filename> suffix is
found next to the image file, bearing otherwise the same name, the root hash is read from it and automatically
used, also as formatted hexadecimal characters.</para></listitem>
found next to the image file, bearing otherwise the same name (except if the image has the
<filename>.raw</filename> suffix, in which case the root hash file must not have it in its name), the root hash
is read from it and automatically used, also as formatted hexadecimal characters.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--verity-data=</option></term>
<listitem><para>Takes the path to a data integrity (dm-verity) file. This option enables data integrity checks
using dm-verity, if a root-hash is passed and if the used image itself does not contains the integrity data.
The integrity data must be matched by the root hash. If this option is not specified, but a file with the
<filename>.verity</filename> suffix is found next to the image file, bearing otherwise the same name (except if
the image has the <filename>.raw</filename> suffix, in which case the verity data file must not have it in its name),
the verity data is read from it and automatically used.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -57,6 +57,12 @@
<para>Automount units may be used to implement on-demand mounting
as well as parallelized mounting of file systems.</para>
<para>Note that automount units are separate from the mount itself, so you
should not set <varname>After=</varname> or <varname>Requires=</varname>
for mount dependencies here. For example, you should not set
<varname>After=network-online.target</varname> or similar on network
filesystems. Doing so may result in an ordering cycle.</para>
</refsect1>
<refsect1>

View File

@ -359,7 +359,9 @@
<para>Maximum number of seconds to wait for the event
queue to become empty. The default value is 120 seconds. A
value of 0 will check if the queue is empty and always
return immediately.</para>
return immediately. A non-zero value will return an exit
code of 0 if queue became empty before timeout was reached,
non-zero otherwise.</para>
</listitem>
</varlistentry>
<varlistentry>

View File

@ -929,6 +929,7 @@ conf.set10('HAVE_SELINUX', have)
want_apparmor = get_option('apparmor')
if want_apparmor != 'false' and not skip_deps
libapparmor = dependency('libapparmor',
version : '>= 2.13',
required : want_apparmor == 'true')
have = libapparmor.found()
else

100
src/core/apparmor-setup.c Normal file
View File

@ -0,0 +1,100 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
#if HAVE_APPARMOR
# include <sys/apparmor.h>
#endif
#include <unistd.h>
#include "apparmor-setup.h"
#include "apparmor-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
#include "macro.h"
#include "string-util.h"
#include "strv.h"
#if HAVE_APPARMOR
DEFINE_TRIVIAL_CLEANUP_FUNC(aa_policy_cache *, aa_policy_cache_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(aa_features *, aa_features_unref);
#endif
int mac_apparmor_setup(void) {
#if HAVE_APPARMOR
int r;
_cleanup_(aa_policy_cache_unrefp) aa_policy_cache *policy_cache = NULL;
_cleanup_(aa_features_unrefp) aa_features *features = NULL;
const char *current_file;
_cleanup_free_ char *current_profile = NULL, *cache_dir_path = NULL;
if (!mac_apparmor_use()) {
log_debug("AppArmor either not supported by the kernel or disabled.");
return 0;
}
/* To enable LSM stacking a patch to the kernel is proposed to create a
* per-LSM subdirectory to distinguish between the LSMs. Therefore, we
* read the file from the LSM specific directory first and only if that
* fails the one from the generic directory.
*/
FOREACH_STRING(current_file, "/proc/self/attr/apparmor/current", "/proc/self/attr/current") {
r = read_one_line_file(current_file, &current_profile);
if (r == -ENOENT)
continue;
else if (r < 0)
log_warning_errno(r, "Failed to read current AppArmor profile from file %s, ignoring: %m", current_file);
else
break;
}
if (!current_profile) {
log_warning("Failed to get the current AppArmor profile of systemd from /proc/self/attr/apparmor/current or /proc/self/attr/current, ignoring.");
return 0;
}
if (!streq(current_profile, "unconfined")) {
log_debug("We are already confined in an AppArmor profile.");
return 0;
}
r = aa_features_new_from_kernel(&features);
if (r < 0) {
log_warning_errno(errno, "Failed to get the AppArmor feature set from the kernel, ignoring: %m");
return 0;
}
cache_dir_path = aa_policy_cache_dir_path_preview(features, AT_FDCWD, "/etc/apparmor/earlypolicy");
if (!cache_dir_path) {
log_debug_errno(errno, "Failed to get the path of the early AppArmor policy cache directory.");
return 0;
}
/* aa_policy_cache_new will internally use the same path as aa_policy_cache_dir_path_preview has returned. */
r = aa_policy_cache_new(&policy_cache, features, AT_FDCWD, "/etc/apparmor/earlypolicy", 0);
if (r < 0) {
if (errno == ENOENT) {
log_debug_errno(errno, "The early AppArmor policy cache directory %s does not exist.", cache_dir_path);
return 0;
}
log_warning_errno(errno, "Failed to create a new AppArmor policy cache, ignoring: %m");
return 0;
}
r = aa_policy_cache_replace_all(policy_cache, NULL);
if (r < 0) {
log_warning_errno(errno, "Failed to load the profiles from the early AppArmor policy cache directory %s, ignoring: %m", cache_dir_path);
return 0;
}
log_info("Successfully loaded all binary profiles from AppArmor early policy cache at %s.", cache_dir_path);
r = aa_change_profile("systemd");
if (r < 0) {
if (errno == ENOENT)
log_debug_errno(errno, "Failed to change to AppArmor profile 'systemd'. Please ensure that one of the binary profile files in policy cache directory %s contains a profile with that name.", cache_dir_path);
else
log_error_errno(errno, "Failed to change to AppArmor profile 'systemd': %m");
return 0;
}
log_info("Changed to AppArmor profile systemd.");
#endif
return 0;
}

View File

@ -0,0 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
int mac_apparmor_setup(void);

View File

@ -707,14 +707,112 @@ static int bus_cgroup_set_boolean(
return 1; \
}
#define BUS_DEFINE_SET_CGROUP_PROTECTION(function, mask, scale) \
static int bus_cgroup_set_##function( \
Unit *u, \
const char *name, \
uint64_t *p, \
bool *s, \
sd_bus_message *message, \
UnitWriteFlags flags, \
sd_bus_error *error) { \
\
uint64_t v = CGROUP_LIMIT_MIN; \
bool nonempty = true; \
char type; \
int r; \
\
assert(p); \
assert(s); \
\
r = sd_bus_message_peek_type(message, &type, NULL); \
if (r < 0) \
return r; \
if (type == SD_BUS_TYPE_BOOLEAN) { \
r = sd_bus_message_read(message, "b", &nonempty); \
if (r < 0) \
return r; \
/* Bool is used to denote empty value only */ \
if (nonempty) \
return -EINVAL; \
} else if (type != SD_BUS_TYPE_UINT64) { \
return -EINVAL; \
} else { \
r = sd_bus_message_read(message, "t", &v); \
if (r < 0) \
return r; \
} \
\
if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
*p = v; \
unit_invalidate_cgroup(u, mask); \
if (!nonempty) { \
*s = false; \
unit_write_settingf(u, flags, name, \
"%s=", name); \
} else if (v == CGROUP_LIMIT_MAX) { \
*s = true; \
unit_write_settingf(u, flags, name, \
"%s=infinity", name); \
} else { \
*s = true; \
unit_write_settingf(u, flags, name, \
"%s=%" PRIu64, name, v); \
} \
} \
\
return 1; \
} \
static int bus_cgroup_set_##function##_scale( \
Unit *u, \
const char *name, \
uint64_t *p, \
bool *s, \
sd_bus_message *message, \
UnitWriteFlags flags, \
sd_bus_error *error) { \
\
uint64_t v; \
uint32_t raw; \
int r; \
\
assert(p); \
assert(s); \
\
r = sd_bus_message_read(message, "u", &raw); \
if (r < 0) \
return r; \
\
v = scale(raw, UINT32_MAX); \
if (v >= UINT64_MAX) \
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, \
"Value specified in %s is out of range", name); \
\
if (!UNIT_WRITE_FLAGS_NOOP(flags)) { \
*p = v; \
unit_invalidate_cgroup(u, mask); \
\
/* Prepare to chop off suffix */ \
assert_se(endswith(name, "Scale")); \
\
uint32_t scaled = DIV_ROUND_UP((uint64_t) raw * 1000, (uint64_t) UINT32_MAX); \
unit_write_settingf(u, flags, name, "%.*s=%" PRIu32 ".%" PRIu32 "%%", \
(int)(strlen(name) - strlen("Scale")), name, \
scaled / 10, scaled % 10); \
} \
\
*s = true; \
return 1; \
}
DISABLE_WARNING_TYPE_LIMITS;
BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_weight, CGROUP_MASK_CPU, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_shares, CGROUP_MASK_CPU, CGROUP_CPU_SHARES_IS_OK, CGROUP_CPU_SHARES_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(io_weight, CGROUP_MASK_IO, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(blockio_weight, CGROUP_MASK_BLKIO, CGROUP_BLKIO_WEIGHT_IS_OK, CGROUP_BLKIO_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_LIMIT(memory, CGROUP_MASK_MEMORY, physical_memory_scale, 1);
BUS_DEFINE_SET_CGROUP_LIMIT(memory_protection, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
BUS_DEFINE_SET_CGROUP_LIMIT(swap, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
BUS_DEFINE_SET_CGROUP_PROTECTION(memory_protection, CGROUP_MASK_MEMORY, physical_memory_scale);
REENABLE_WARNING;
static int bus_cgroup_set_tasks_max(
@ -840,33 +938,17 @@ int bus_cgroup_set_property(
if (streq(name, "MemoryAccounting"))
return bus_cgroup_set_boolean(u, name, &c->memory_accounting, CGROUP_MASK_MEMORY, message, flags, error);
if (streq(name, "MemoryMin")) {
r = bus_cgroup_set_memory_protection(u, name, &c->memory_min, message, flags, error);
if (r > 0)
c->memory_min_set = true;
return r;
}
if (streq(name, "MemoryMin"))
return bus_cgroup_set_memory_protection(u, name, &c->memory_min, &c->memory_min_set, message, flags, error);
if (streq(name, "MemoryLow")) {
r = bus_cgroup_set_memory_protection(u, name, &c->memory_low, message, flags, error);
if (r > 0)
c->memory_low_set = true;
return r;
}
if (streq(name, "MemoryLow"))
return bus_cgroup_set_memory_protection(u, name, &c->memory_low, &c->memory_low_set, message, flags, error);
if (streq(name, "DefaultMemoryMin")) {
r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, message, flags, error);
if (r > 0)
c->default_memory_min_set = true;
return r;
}
if (streq(name, "DefaultMemoryMin"))
return bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, &c->default_memory_min_set, message, flags, error);
if (streq(name, "DefaultMemoryLow")) {
r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, message, flags, error);
if (r > 0)
c->default_memory_low_set = true;
return r;
}
if (streq(name, "DefaultMemoryLow"))
return bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, &c->default_memory_low_set, message, flags, error);
if (streq(name, "MemoryHigh"))
return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, error);
@ -880,33 +962,17 @@ int bus_cgroup_set_property(
if (streq(name, "MemoryLimit"))
return bus_cgroup_set_memory(u, name, &c->memory_limit, message, flags, error);
if (streq(name, "MemoryMinScale")) {
r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, error);
if (r > 0)
c->memory_min_set = true;
return r;
}
if (streq(name, "MemoryMinScale"))
return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, &c->memory_min_set, message, flags, error);
if (streq(name, "MemoryLowScale")) {
r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, message, flags, error);
if (r > 0)
c->memory_low_set = true;
return r;
}
if (streq(name, "MemoryLowScale"))
return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, &c->memory_low_set, message, flags, error);
if (streq(name, "DefaultMemoryMinScale")) {
r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, message, flags, error);
if (r > 0)
c->default_memory_min_set = true;
return r;
}
if (streq(name, "DefaultMemoryMinScale"))
return bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, &c->default_memory_min_set, message, flags, error);
if (streq(name, "DefaultMemoryLowScale")) {
r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, message, flags, error);
if (r > 0)
c->default_memory_low_set = true;
return r;
}
if (streq(name, "DefaultMemoryLowScale"))
return bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, &c->default_memory_low_set, message, flags, error);
if (streq(name, "MemoryHighScale"))
return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, error);

View File

@ -3372,6 +3372,12 @@ int config_parse_memory_limit(
uint64_t bytes = CGROUP_LIMIT_MAX;
int r;
if (STR_IN_SET(lvalue, "DefaultMemoryLow",
"DefaultMemoryMin",
"MemoryLow",
"MemoryMin"))
bytes = CGROUP_LIMIT_MIN;
if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
r = parse_permille(rvalue);
@ -3391,24 +3397,20 @@ int config_parse_memory_limit(
}
}
/* Keep Memory{Low,Min} unset with empty assignment so that we fall back to DefaultMemory* which in
* contrast means zeroing the property. */
if (streq(lvalue, "DefaultMemoryLow")) {
c->default_memory_low = bytes;
c->default_memory_low_set = true;
if (isempty(rvalue))
c->default_memory_low = CGROUP_LIMIT_MIN;
else
c->default_memory_low = bytes;
} else if (streq(lvalue, "DefaultMemoryMin")) {
c->default_memory_min = bytes;
c->default_memory_min_set = true;
if (isempty(rvalue))
c->default_memory_min = CGROUP_LIMIT_MIN;
else
c->default_memory_min = bytes;
} else if (streq(lvalue, "MemoryMin")) {
c->memory_min = bytes;
c->memory_min_set = true;
c->memory_min_set = !isempty(rvalue);
} else if (streq(lvalue, "MemoryLow")) {
c->memory_low = bytes;
c->memory_low_set = true;
c->memory_low_set = !isempty(rvalue);
} else if (streq(lvalue, "MemoryHigh"))
c->memory_high = bytes;
else if (streq(lvalue, "MemoryMax"))

View File

@ -19,6 +19,7 @@
#include "sd-messages.h"
#include "alloc-util.h"
#include "apparmor-setup.h"
#include "architecture.h"
#include "build.h"
#include "bus-error.h"
@ -2366,6 +2367,12 @@ static int initialize_security(
return r;
}
r = mac_apparmor_setup();
if (r < 0) {
*ret_error_message = "Failed to load AppArmor policy";
return r;
}
r = ima_setup();
if (r < 0) {
*ret_error_message = "Failed to load IMA policy";

View File

@ -12,6 +12,8 @@ libcore_shared_sources = '''
'''.split()
libcore_sources = '''
apparmor-setup.c
apparmor-setup.h
audit-fd.c
audit-fd.h
automount.c

View File

@ -1264,6 +1264,7 @@ int setup_namespace(
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
_cleanup_free_ void *root_hash = NULL;
_cleanup_free_ char *verity_data = NULL;
MountEntry *m = NULL, *mounts = NULL;
size_t n_mounts, root_hash_size = 0;
bool require_prefix = false;
@ -1294,15 +1295,16 @@ int setup_namespace(
if (r < 0)
return log_debug_errno(r, "Failed to create loop device for root image: %m");
r = root_hash_load(root_image, &root_hash, &root_hash_size);
r = verity_metadata_load(root_image, &root_hash, &root_hash_size, &verity_data);
if (r < 0)
return log_debug_errno(r, "Failed to load root hash: %m");
dissect_image_flags |= verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
r = dissect_image(loop_device->fd, root_hash, root_hash_size, dissect_image_flags, &dissected_image);
r = dissect_image(loop_device->fd, root_hash, root_hash_size, verity_data, dissect_image_flags, &dissected_image);
if (r < 0)
return log_debug_errno(r, "Failed to dissect image: %m");
r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, dissect_image_flags, &decrypted_image);
r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, verity_data, dissect_image_flags, &decrypted_image);
if (r < 0)
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
}

View File

@ -12,6 +12,7 @@
#include "loop-util.h"
#include "main-func.h"
#include "parse-util.h"
#include "path-util.h"
#include "string-util.h"
#include "strv.h"
#include "user-util.h"
@ -25,21 +26,25 @@ static const char *arg_image = NULL;
static const char *arg_path = NULL;
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK;
static void *arg_root_hash = NULL;
static char *arg_verity_data = NULL;
static size_t arg_root_hash_size = 0;
STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
STATIC_DESTRUCTOR_REGISTER(arg_verity_data, freep);
static void help(void) {
printf("%s [OPTIONS...] IMAGE\n"
"%s [OPTIONS...] --mount IMAGE PATH\n"
"Dissect a file system OS image.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -m --mount Mount the image to the specified directory\n"
" -r --read-only Mount read-only\n"
" --fsck=BOOL Run fsck before mounting\n"
" --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n"
" --root-hash=HASH Specify root hash for verity\n",
" -h --help Show this help\n"
" --version Show package version\n"
" -m --mount Mount the image to the specified directory\n"
" -r --read-only Mount read-only\n"
" --fsck=BOOL Run fsck before mounting\n"
" --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n"
" --root-hash=HASH Specify root hash for verity\n"
" --verity-data=PATH Specify data file with hash tree for verity if it is\n"
" not embedded in IMAGE\n",
program_invocation_short_name,
program_invocation_short_name);
}
@ -51,16 +56,18 @@ static int parse_argv(int argc, char *argv[]) {
ARG_DISCARD,
ARG_ROOT_HASH,
ARG_FSCK,
ARG_VERITY_DATA,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "mount", no_argument, NULL, 'm' },
{ "read-only", no_argument, NULL, 'r' },
{ "discard", required_argument, NULL, ARG_DISCARD },
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
{ "fsck", required_argument, NULL, ARG_FSCK },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "mount", no_argument, NULL, 'm' },
{ "read-only", no_argument, NULL, 'r' },
{ "discard", required_argument, NULL, ARG_DISCARD },
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
{ "fsck", required_argument, NULL, ARG_FSCK },
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
{}
};
@ -127,6 +134,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
case ARG_VERITY_DATA:
r = parse_path_argument_and_warn(optarg, false, &arg_verity_data);
if (r < 0)
return r;
break;
case ARG_FSCK:
r = parse_boolean(optarg);
if (r < 0)
@ -188,13 +201,13 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to set up loopback device: %m");
if (!arg_root_hash) {
r = root_hash_load(arg_image, &arg_root_hash, &arg_root_hash_size);
if (r < 0)
return log_error_errno(r, "Failed to read root hash file for %s: %m", arg_image);
}
r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
arg_verity_data ? NULL : &arg_verity_data);
if (r < 0)
return log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
arg_flags |= arg_verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
r = dissect_image_and_warn(d->fd, arg_image, arg_root_hash, arg_root_hash_size, arg_flags, &m);
r = dissect_image_and_warn(d->fd, arg_image, arg_root_hash, arg_root_hash_size, arg_verity_data, arg_flags, &m);
if (r < 0)
return r;
@ -205,7 +218,6 @@ static int run(int argc, char *argv[]) {
for (i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) {
DissectedPartition *p = m->partitions + i;
int k;
if (!p->found)
continue;
@ -223,9 +235,8 @@ static int run(int argc, char *argv[]) {
if (p->architecture != _ARCHITECTURE_INVALID)
printf(" for %s", architecture_to_string(p->architecture));
k = PARTITION_VERITY_OF(i);
if (k >= 0)
printf(" %s verity", m->partitions[k].found ? "with" : "without");
if (dissected_image_can_do_verity(m, i))
printf(" %s verity", dissected_image_has_verity(m, i) ? "with" : "without");
if (p->partno >= 0)
printf(" on partition #%i", p->partno);
@ -268,7 +279,7 @@ static int run(int argc, char *argv[]) {
}
case ACTION_MOUNT:
r = dissected_image_decrypt_interactively(m, NULL, arg_root_hash, arg_root_hash_size, arg_flags, &di);
r = dissected_image_decrypt_interactively(m, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, arg_flags, &di);
if (r < 0)
return r;

View File

@ -665,7 +665,7 @@ static int enumerate_partitions(dev_t devnum) {
if (r <= 0)
return r;
r = dissect_image(fd, NULL, 0, DISSECT_IMAGE_GPT_ONLY|DISSECT_IMAGE_NO_UDEV, &m);
r = dissect_image(fd, NULL, 0, NULL, DISSECT_IMAGE_GPT_ONLY|DISSECT_IMAGE_NO_UDEV, &m);
if (r == -ENOPKG) {
log_debug_errno(r, "No suitable partition table found, ignoring.");
return 0;

View File

@ -342,6 +342,18 @@ int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
return 0;
}
int sd_dhcp6_client_get_iaid(sd_dhcp6_client *client, uint32_t *iaid) {
assert_return(client, -EINVAL);
assert_return(iaid, -EINVAL);
if (!client->iaid_set)
return -ENODATA;
*iaid = be32toh(client->ia_na.ia_na.id);
return 0;
}
int sd_dhcp6_client_set_fqdn(
sd_dhcp6_client *client,
const char *fqdn) {

View File

@ -172,6 +172,10 @@ _public_ int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **clie
return network_link_get_string(ifindex, "DHCP4_CLIENT_ID", client_id);
}
_public_ int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **iaid) {
return network_link_get_string(ifindex, "DHCP6_CLIENT_IAID", iaid);
}
_public_ int sd_network_link_get_required_for_online(int ifindex) {
_cleanup_free_ char *s = NULL;
int r;

View File

@ -1381,7 +1381,7 @@ static int link_status_one(
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL,
**pop3_server = NULL, **smtp_server = NULL, **lpr_server = NULL;
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
_cleanup_free_ char *t = NULL, *network = NULL, *client_id = NULL;
_cleanup_free_ char *t = NULL, *network = NULL, *client_id = NULL, *iaid = NULL;
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
const char *on_color_operational, *off_color_operational,
*on_color_setup, *off_color_setup;
@ -2083,6 +2083,16 @@ static int link_status_one(
return table_log_add_error(r);
}
r = sd_network_link_get_dhcp6_client_iaid_string(info->ifindex, &iaid);
if (r >= 0) {
r = table_add_many(table,
TABLE_EMPTY,
TABLE_STRING, "DHCP6 Client IAID:",
TABLE_STRING, iaid);
if (r < 0)
return table_log_add_error(r);
}
r = dump_lldp_neighbors(table, "Connected To:", info->ifindex);
if (r < 0)
return r;

View File

@ -4086,8 +4086,9 @@ int link_save(Link *link) {
const char *admin_state, *oper_state, *carrier_state, *address_state;
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
Address *a;
uint32_t iaid;
Route *route;
Address *a;
Iterator i;
int r;
@ -4420,6 +4421,10 @@ int link_save(Link *link) {
}
}
r = sd_dhcp6_client_get_iaid(link->dhcp6_client, &iaid);
if (r >= 0)
fprintf(f, "DHCP6_CLIENT_IAID=0x%x\n", iaid);
r = fflush_and_check(f);
if (r < 0)
goto fail;

View File

@ -199,6 +199,7 @@ static bool arg_use_cgns = true;
static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS;
static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_TMPFS_TMP;
static void *arg_root_hash = NULL;
static char *arg_verity_data = NULL;
static size_t arg_root_hash_size = 0;
static char **arg_syscall_whitelist = NULL;
static char **arg_syscall_blacklist = NULL;
@ -242,6 +243,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_property_message, sd_bus_message_unrefp);
STATIC_DESTRUCTOR_REGISTER(arg_parameters, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
STATIC_DESTRUCTOR_REGISTER(arg_verity_data, freep);
STATIC_DESTRUCTOR_REGISTER(arg_syscall_whitelist, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_syscall_blacklist, strv_freep);
#if HAVE_SECCOMP
@ -303,6 +305,7 @@ static int help(void) {
" --read-only Mount the root directory read-only\n"
" --volatile[=MODE] Run the system in volatile mode\n"
" --root-hash=HASH Specify verity root hash for root disk image\n"
" --verity-data=PATH Specify hash device for verity\n"
" --pivot-root=PATH[:PATH]\n"
" Pivot root to given directory in the container\n\n"
"%3$sExecution:%4$s\n"
@ -663,6 +666,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_PIPE,
ARG_OCI_BUNDLE,
ARG_NO_PAGER,
ARG_VERITY_DATA,
};
static const struct option options[] = {
@ -728,6 +732,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "pipe", no_argument, NULL, ARG_PIPE },
{ "oci-bundle", required_argument, NULL, ARG_OCI_BUNDLE },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
{}
};
@ -1316,6 +1321,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
case ARG_VERITY_DATA:
r = parse_path_argument_and_warn(optarg, false, &arg_verity_data);
if (r < 0)
return r;
break;
case ARG_SYSTEM_CALL_FILTER: {
bool negative;
const char *items;
@ -5080,6 +5091,7 @@ static int run(int argc, char *argv[]) {
}
} else {
DissectImageFlags dissect_image_flags = DISSECT_IMAGE_REQUIRE_ROOT | DISSECT_IMAGE_RELAX_VAR_CHECK;
assert(arg_image);
assert(!arg_template);
@ -5129,13 +5141,13 @@ static int run(int argc, char *argv[]) {
goto finish;
}
if (!arg_root_hash) {
r = root_hash_load(arg_image, &arg_root_hash, &arg_root_hash_size);
if (r < 0) {
log_error_errno(r, "Failed to load root hash file for %s: %m", arg_image);
goto finish;
}
r = verity_metadata_load(arg_image, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
arg_verity_data ? NULL : &arg_verity_data);
if (r < 0) {
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
goto finish;
}
dissect_image_flags |= arg_verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
}
if (!mkdtemp(tmprootdir)) {
@ -5161,7 +5173,8 @@ static int run(int argc, char *argv[]) {
loop->fd,
arg_image,
arg_root_hash, arg_root_hash_size,
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK,
arg_verity_data,
dissect_image_flags,
&dissected_image);
if (r == -ENOPKG) {
/* dissected_image_and_warn() already printed a brief error message. Extend on that with more details */
@ -5179,7 +5192,7 @@ static int run(int argc, char *argv[]) {
if (!arg_root_hash && dissected_image->can_verity)
log_notice("Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking.", arg_image);
r = dissected_image_decrypt_interactively(dissected_image, NULL, arg_root_hash, arg_root_hash_size, 0, &decrypted_image);
r = dissected_image_decrypt_interactively(dissected_image, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, 0, &decrypted_image);
if (r < 0)
goto finish;

View File

@ -380,7 +380,7 @@ static int portable_extract_by_path(
if (r < 0)
return log_debug_errno(r, "Failed to create temporary directory: %m");
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
r = dissect_image(d->fd, NULL, 0, NULL, DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
if (r == -ENOPKG)
sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Couldn't identify a suitable partition table or file system in '%s'.", path);
else if (r == -EADDRNOTAVAIL)

View File

@ -489,7 +489,22 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
"MemoryLimit",
"TasksMax")) {
if (isempty(eq) || streq(eq, "infinity")) {
if (streq(eq, "infinity")) {
r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
if (r < 0)
return bus_log_create_error(r);
return 1;
} else if (isempty(eq) && STR_IN_SET(field, "DefaultMemoryLow",
"DefaultMemoryMin",
"MemoryLow",
"MemoryMin")) {
/* We can't use CGROUP_LIMIT_MIN nor CGROUP_LIMIT_MAX to convey the empty assignment
* so marshall specially as a boolean. */
r = sd_bus_message_append(m, "(sv)", field, "b", 0);
if (r < 0)
return bus_log_create_error(r);
return 1;
} else if (isempty(eq)) {
r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
if (r < 0)
return bus_log_create_error(r);

View File

@ -307,6 +307,7 @@ int dissect_image(
int fd,
const void *root_hash,
size_t root_hash_size,
const char *verity_data,
DissectImageFlags flags,
DissectedImage **ret) {
@ -329,6 +330,7 @@ int dissect_image(
assert(fd >= 0);
assert(ret);
assert(root_hash || root_hash_size == 0);
assert(!((flags & DISSECT_IMAGE_GPT_ONLY) && (flags & DISSECT_IMAGE_NO_PARTITION_TABLE)));
/* Probes a disk image, and returns information about what it found in *ret.
*
@ -391,8 +393,9 @@ int dissect_image(
if (r < 0)
return r;
if (!(flags & DISSECT_IMAGE_GPT_ONLY) &&
(flags & DISSECT_IMAGE_REQUIRE_ROOT)) {
if ((!(flags & DISSECT_IMAGE_GPT_ONLY) &&
(flags & DISSECT_IMAGE_REQUIRE_ROOT)) ||
(flags & DISSECT_IMAGE_NO_PARTITION_TABLE)) {
const char *usage = NULL;
(void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
@ -413,9 +416,13 @@ int dissect_image(
if (r < 0)
return r;
m->single_file_system = true;
m->verity = root_hash && verity_data;
m->can_verity = !!verity_data;
m->partitions[PARTITION_ROOT] = (DissectedPartition) {
.found = true,
.rw = true,
.rw = !m->verity,
.partno = -1,
.architecture = _ARCHITECTURE_INVALID,
.fstype = TAKE_PTR(t),
@ -424,11 +431,11 @@ int dissect_image(
m->encrypted = streq_ptr(fstype, "crypto_LUKS");
if (!streq(usage, "filesystem")) {
r = loop_wait_for_partitions_to_appear(fd, d, 0, flags, &e);
if (r < 0)
return r;
}
/* Even on a single partition we need to wait for udev to create the
* /dev/block/X:Y symlink to /dev/loopZ */
r = loop_wait_for_partitions_to_appear(fd, d, 0, flags, &e);
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return 0;
@ -1215,6 +1222,7 @@ static int verity_partition(
DissectedPartition *v,
const void *root_hash,
size_t root_hash_size,
const char *verity_data,
DissectImageFlags flags,
DecryptedImage *d) {
@ -1223,18 +1231,20 @@ static int verity_partition(
int r;
assert(m);
assert(v);
assert(v || verity_data);
if (!root_hash)
return 0;
if (!m->found || !m->node || !m->fstype)
return 0;
if (!v->found || !v->node || !v->fstype)
return 0;
if (!verity_data) {
if (!v->found || !v->node || !v->fstype)
return 0;
if (!streq(v->fstype, "DM_verity_hash"))
return 0;
if (!streq(v->fstype, "DM_verity_hash"))
return 0;
}
r = make_dm_name_and_node(m->node, "-verity", &name, &node);
if (r < 0)
@ -1243,7 +1253,7 @@ static int verity_partition(
if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
return -ENOMEM;
r = crypt_init(&cd, v->node);
r = crypt_init(&cd, verity_data ?: v->node);
if (r < 0)
return r;
@ -1276,6 +1286,7 @@ int dissected_image_decrypt(
const char *passphrase,
const void *root_hash,
size_t root_hash_size,
const char *verity_data,
DissectImageFlags flags,
DecryptedImage **ret) {
@ -1322,7 +1333,7 @@ int dissected_image_decrypt(
k = PARTITION_VERITY_OF(i);
if (k >= 0) {
r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, flags, d);
r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, verity_data, flags, d);
if (r < 0)
return r;
}
@ -1347,6 +1358,7 @@ int dissected_image_decrypt_interactively(
const char *passphrase,
const void *root_hash,
size_t root_hash_size,
const char *verity_data,
DissectImageFlags flags,
DecryptedImage **ret) {
@ -1357,7 +1369,7 @@ int dissected_image_decrypt_interactively(
n--;
for (;;) {
r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, flags, ret);
r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, verity_data, flags, ret);
if (r >= 0)
return r;
if (r == -EKEYREJECTED)
@ -1409,56 +1421,85 @@ int decrypted_image_relinquish(DecryptedImage *d) {
return 0;
}
int root_hash_load(const char *image, void **ret, size_t *ret_size) {
_cleanup_free_ char *text = NULL;
_cleanup_free_ void *k = NULL;
size_t l;
int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) {
_cleanup_free_ char *verity_filename = NULL;
_cleanup_free_ void *roothash_decoded = NULL;
size_t roothash_decoded_size = 0;
int r;
assert(image);
assert(ret);
assert(ret_size);
if (is_device_path(image)) {
/* If we are asked to load the root hash for a device node, exit early */
*ret = NULL;
*ret_size = 0;
if (ret_roothash)
*ret_roothash = NULL;
if (ret_roothash_size)
*ret_roothash_size = 0;
if (ret_verity_data)
*ret_verity_data = NULL;
return 0;
}
r = getxattr_malloc(image, "user.verity.roothash", &text, true);
if (r < 0) {
char *fn, *e, *n;
if (ret_verity_data) {
char *e;
if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
return r;
fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
n = stpcpy(fn, image);
e = endswith(fn, ".raw");
verity_filename = new(char, strlen(image) + STRLEN(".verity") + 1);
if (!verity_filename)
return -ENOMEM;
strcpy(verity_filename, image);
e = endswith(verity_filename, ".raw");
if (e)
n = e;
strcpy(e, ".verity");
else
strcat(verity_filename, ".verity");
strcpy(n, ".roothash");
r = read_one_line_file(fn, &text);
if (r == -ENOENT) {
*ret = NULL;
*ret_size = 0;
return 0;
r = access(verity_filename, F_OK);
if (r < 0) {
if (errno != ENOENT)
return -errno;
verity_filename = mfree(verity_filename);
}
if (r < 0)
return r;
}
r = unhexmem(text, strlen(text), &k, &l);
if (r < 0)
return r;
if (l < sizeof(sd_id128_t))
return -EINVAL;
if (ret_roothash) {
_cleanup_free_ char *text = NULL;
assert(ret_roothash_size);
*ret = TAKE_PTR(k);
*ret_size = l;
r = getxattr_malloc(image, "user.verity.roothash", &text, true);
if (r < 0) {
char *fn, *e, *n;
if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
return r;
fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
n = stpcpy(fn, image);
e = endswith(fn, ".raw");
if (e)
n = e;
strcpy(n, ".roothash");
r = read_one_line_file(fn, &text);
if (r < 0 && r != -ENOENT)
return r;
}
if (text) {
r = unhexmem(text, strlen(text), &roothash_decoded, &roothash_decoded_size);
if (r < 0)
return r;
if (roothash_decoded_size < sizeof(sd_id128_t))
return -EINVAL;
}
}
if (ret_roothash) {
*ret_roothash = TAKE_PTR(roothash_decoded);
*ret_roothash_size = roothash_decoded_size;
}
if (ret_verity_data)
*ret_verity_data = TAKE_PTR(verity_filename);
return 1;
}
@ -1617,6 +1658,7 @@ int dissect_image_and_warn(
const char *name,
const void *root_hash,
size_t root_hash_size,
const char *verity_data,
DissectImageFlags flags,
DissectedImage **ret) {
@ -1631,7 +1673,7 @@ int dissect_image_and_warn(
name = buffer;
}
r = dissect_image(fd, root_hash, root_hash_size, flags, ret);
r = dissect_image(fd, root_hash, root_hash_size, verity_data, flags, ret);
switch (r) {
@ -1661,6 +1703,23 @@ int dissect_image_and_warn(
}
}
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator) {
if (image->single_file_system)
return partition_designator == PARTITION_ROOT && image->can_verity;
return PARTITION_VERITY_OF(partition_designator) >= 0;
}
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator) {
int k;
if (image->single_file_system)
return partition_designator == PARTITION_ROOT && image->verity;
k = PARTITION_VERITY_OF(partition_designator);
return k >= 0 && image->partitions[k].found;
}
static const char *const partition_designator_table[] = {
[PARTITION_ROOT] = "root",
[PARTITION_ROOT_SECONDARY] = "root-secondary",

View File

@ -63,12 +63,14 @@ typedef enum DissectImageFlags {
DISSECT_IMAGE_NO_UDEV = 1 << 9, /* Don't wait for udev initializing things */
DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
DISSECT_IMAGE_FSCK = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
DISSECT_IMAGE_NO_PARTITION_TABLE = 1 << 12, /* Only recognize single file system images */
} DissectImageFlags;
struct DissectedImage {
bool encrypted:1;
bool verity:1; /* verity available and usable */
bool can_verity:1; /* verity available, but not necessarily used */
bool single_file_system:1; /* MBR/GPT or single file system */
DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX];
@ -79,14 +81,14 @@ struct DissectedImage {
};
int probe_filesystem(const char *node, char **ret_fstype);
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret);
int dissect_image_and_warn(int fd, const char *name, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret);
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, const char *verity_data, DissectImageFlags flags, DissectedImage **ret);
int dissect_image_and_warn(int fd, const char *name, const void *root_hash, size_t root_hash_size, const char *verity_data, DissectImageFlags flags, DissectedImage **ret);
DissectedImage* dissected_image_unref(DissectedImage *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret);
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret);
int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, DissectImageFlags flags, DecryptedImage **ret);
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, DissectImageFlags flags, DecryptedImage **ret);
int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, DissectImageFlags flags);
int dissected_image_acquire_metadata(DissectedImage *m);
@ -98,4 +100,6 @@ int decrypted_image_relinquish(DecryptedImage *d);
const char* partition_designator_to_string(int i) _const_;
int partition_designator_from_string(const char *name) _pure_;
int root_hash_load(const char *image, void **ret, size_t *ret_size);
int verity_metadata_load(const char *image, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data);
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);

View File

@ -1171,7 +1171,7 @@ int image_read_metadata(Image *i) {
if (r < 0)
return r;
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
r = dissect_image(d->fd, NULL, 0, NULL, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
if (r < 0)
return r;

View File

@ -110,6 +110,9 @@ int sd_dhcp6_client_set_duid_llt(
int sd_dhcp6_client_set_iaid(
sd_dhcp6_client *client,
uint32_t iaid);
int sd_dhcp6_client_get_iaid(
sd_dhcp6_client *client,
uint32_t *iaid);
int sd_dhcp6_client_set_fqdn(
sd_dhcp6_client *client,
const char *fqdn);

View File

@ -191,6 +191,9 @@ int sd_network_link_get_timezone(int ifindex, char **timezone);
/* Get DHCPv4 client id for a given link. */
int sd_network_link_get_dhcp4_client_id_string(int ifindex, char **client_id);
/* Get DHCPv6 client IAID for a given link. */
int sd_network_link_get_dhcp6_client_iaid_string(int ifindex, char **iaid);
/* Monitor object */
typedef struct sd_network_monitor sd_network_monitor;

View File

@ -72,7 +72,7 @@ static int test_default_memory_low(void) {
*
* 3. dml-discard.slice sets DefaultMemoryLow= with no rvalue. As such,
* dml-discard-empty.service should end up with a value of 0.
* dml-discard-explicit-ml.service sets MemoryLow=70, and as such should have that override the
* dml-discard-set-ml.service sets MemoryLow=15, and as such should have that override the
* reset DefaultMemoryLow value. dml-discard.slice should still have an eventual memory.low of 50.
*
*

View File

@ -28,7 +28,7 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
r = dissect_image(d->fd, NULL, 0, NULL, DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_RELAX_VAR_CHECK, &m);
if (r < 0) {
log_error_errno(r, "Failed to dissect image: %m");
return EXIT_FAILURE;

View File

@ -0,0 +1 @@
../TEST-01-BASIC/Makefile

34
test/TEST-50-DISSECT/test.sh Executable file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env bash
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh
set -e
TEST_DESCRIPTION="test systemd-dissect"
IMAGE_NAME="dissect"
TEST_NO_NSPAWN=1
. $TEST_BASE_DIR/test-functions
command -v mksquashfs >/dev/null 2>&1 || exit 0
command -v veritysetup >/dev/null 2>&1 || exit 0
# Need loop devices for systemd-dissect
test_create_image() {
create_empty_image_rootdir
# Create what will eventually be our root filesystem onto an overlay
# If some pieces are missing from the host, skip rather than fail
(
LOG_LEVEL=5
setup_basic_environment
mask_supporting_services
instmods loop =block
instmods squashfs =squashfs
instmods dm_verity =md
generate_module_dependencies
inst_binary mksquashfs
inst_binary veritysetup
)
}
do_test "$@" 50

View File

@ -2797,7 +2797,8 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
with self.subTest(test=test):
if test == 'no-slave':
# bridge has no slaves; it's up but *might* not have carrier
self.wait_online(['bridge99:no-carrier'])
# It may take very long time that the interface become configured state.
self.wait_online(['bridge99:no-carrier'], timeout='2m')
# due to a bug in the kernel, newly-created bridges are brought up
# *with* carrier, unless they have had any setting changed; e.g.
# their mac set, priority set, etc. Then, they will lose carrier

View File

@ -0,0 +1,7 @@
[Unit]
Description=TEST-50-DISSECT
[Service]
ExecStartPre=rm -f /failed /testok
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
Type=oneshot

31
test/units/testsuite-50.sh Executable file
View File

@ -0,0 +1,31 @@
#!/usr/bin/env bash
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh
set -ex
set -o pipefail
cd /tmp
image=$(mktemp -d -t -p /tmp tmp.XXXXXX)
if [ -z "${image}" ] || [ ! -d "${image}" ]; then
echo "Could not create temporary directory with mktemp under /tmp"
exit 1
fi
mkdir -p ${image}/usr/lib ${image}/etc
cp /usr/lib/os-release ${image}/usr/lib/
cp /etc/machine-id /etc/os-release ${image}/etc/
mksquashfs ${image} ${image}.raw
veritysetup format ${image}.raw ${image}.verity | grep '^Root hash:' | cut -f2 | tr -d '\n' > ${image}.roothash
/usr/lib/systemd/systemd-dissect ${image}.raw | grep -q -F "Found read-only 'root' partition of type squashfs with verity"
/usr/lib/systemd/systemd-dissect ${image}.raw | grep -q -F -f /usr/lib/os-release
mv ${image}.verity ${image}.fooverity
mv ${image}.roothash ${image}.foohash
/usr/lib/systemd/systemd-dissect ${image}.raw --root-hash=`cat ${image}.foohash` --verity-data=${image}.fooverity | grep -q -F "Found read-only 'root' partition of type squashfs with verity"
/usr/lib/systemd/systemd-dissect ${image}.raw --root-hash=`cat ${image}.foohash` --verity-data=${image}.fooverity | grep -q -F -f /usr/lib/os-release
echo OK > /testok
exit 0