New upstream version 252.2

This commit is contained in:
Luca Boccassi 2022-11-28 22:25:21 +00:00
parent b7785f44d2
commit c1e08e516e
49 changed files with 552 additions and 476 deletions

1
docs/CNAME Normal file
View File

@ -0,0 +1 @@
systemd.io

View File

@ -73,13 +73,9 @@ All tools:
(relevant in particular for the system manager and `systemd-hostnamed`). (relevant in particular for the system manager and `systemd-hostnamed`).
Must be a valid hostname (either a single label or a FQDN). Must be a valid hostname (either a single label or a FQDN).
* `$SYSTEMD_IN_INITRD=[auto|lenient|0|1]` — if set, specifies initrd detection * `$SYSTEMD_IN_INITRD` — takes a boolean. If set, overrides initrd detection.
method. Defaults to `auto`. Behavior is defined as follows: This is useful for debugging and testing initrd-only programs in the main
`auto`: Checks if `/etc/initrd-release` exists, and a temporary fs is mounted system.
on `/`. If both conditions meet, then it's in initrd.
`lenient`: Similar to `auto`, but the rootfs check is skipped.
`0|1`: Simply overrides initrd detection. This is useful for debugging and
testing initrd-only programs in the main system.
* `$SYSTEMD_BUS_TIMEOUT=SECS` — specifies the maximum time to wait for method call * `$SYSTEMD_BUS_TIMEOUT=SECS` — specifies the maximum time to wait for method call
completion. If no time unit is specified, assumes seconds. The usual other units completion. If no time unit is specified, assumes seconds. The usual other units

View File

@ -1474,11 +1474,14 @@ if want_tpm2 != 'false' and not skip_deps
tpm2 = dependency('tss2-esys tss2-rc tss2-mu', tpm2 = dependency('tss2-esys tss2-rc tss2-mu',
required : want_tpm2 == 'true') required : want_tpm2 == 'true')
have = tpm2.found() have = tpm2.found()
have_esys3 = tpm2.version().version_compare('>= 3.0.0')
else else
have = false have = false
have_esys3 = false
tpm2 = [] tpm2 = []
endif endif
conf.set10('HAVE_TPM2', have) conf.set10('HAVE_TPM2', have)
conf.set10('HAVE_TSS2_ESYS3', have_esys3)
want_elfutils = get_option('elfutils') want_elfutils = get_option('elfutils')
if want_elfutils != 'false' and not skip_deps if want_elfutils != 'false' and not skip_deps
@ -3838,7 +3841,7 @@ exe = custom_target(
install_dir : bindir) install_dir : bindir)
public_programs += exe public_programs += exe
if want_tests != 'false' if want_tests != 'false' and want_kernel_install
test('test-kernel-install', test('test-kernel-install',
test_kernel_install_sh, test_kernel_install_sh,
args : [exe.full_path(), loaderentry_install]) args : [exe.full_path(), loaderentry_install])

View File

@ -174,12 +174,35 @@ int fd_cloexec(int fd, bool cloexec) {
return RET_NERRNO(fcntl(fd, F_SETFD, nflags)); return RET_NERRNO(fcntl(fd, F_SETFD, nflags));
} }
int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec) {
int ret = 0, r;
assert(n_fds == 0 || fds);
for (size_t i = 0; i < n_fds; i++) {
if (fds[i] < 0) /* Skip gracefully over already invalidated fds */
continue;
r = fd_cloexec(fds[i], cloexec);
if (r < 0 && ret >= 0) /* Continue going, but return first error */
ret = r;
else
ret = 1; /* report if we did anything */
}
return ret;
}
_pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) { _pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) {
assert(n_fdset == 0 || fdset); assert(n_fdset == 0 || fdset);
for (size_t i = 0; i < n_fdset; i++) for (size_t i = 0; i < n_fdset; i++) {
if (fdset[i] < 0)
continue;
if (fdset[i] == fd) if (fdset[i] == fd)
return true; return true;
}
return false; return false;
} }
@ -252,6 +275,10 @@ static int close_all_fds_special_case(const int except[], size_t n_except) {
if (!have_close_range) if (!have_close_range)
return 0; return 0;
if (n_except == 1 && except[0] < 0) /* Minor optimization: if we only got one fd, and it's invalid,
* we got none */
n_except = 0;
switch (n_except) { switch (n_except) {
case 0: case 0:

View File

@ -56,6 +56,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(DIR*, closedir, NULL);
int fd_nonblock(int fd, bool nonblock); int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec); int fd_cloexec(int fd, bool cloexec);
int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec);
int get_max_fd(void); int get_max_fd(void);

View File

@ -1372,6 +1372,14 @@ int safe_fork_full(
} }
} }
if (flags & FORK_CLOEXEC_OFF) {
r = fd_cloexec_many(except_fds, n_except_fds, false);
if (r < 0) {
log_full_errno(prio, r, "Failed to turn off O_CLOEXEC on file descriptors: %m");
_exit(EXIT_FAILURE);
}
}
/* When we were asked to reopen the logs, do so again now */ /* When we were asked to reopen the logs, do so again now */
if (flags & FORK_REOPEN_LOG) { if (flags & FORK_REOPEN_LOG) {
log_open(); log_open();

View File

@ -150,6 +150,7 @@ typedef enum ForkFlags {
FORK_STDOUT_TO_STDERR = 1 << 11, /* Make stdout a copy of stderr */ FORK_STDOUT_TO_STDERR = 1 << 11, /* Make stdout a copy of stderr */
FORK_FLUSH_STDIO = 1 << 12, /* fflush() stdout (and stderr) before forking */ FORK_FLUSH_STDIO = 1 << 12, /* fflush() stdout (and stderr) before forking */
FORK_NEW_USERNS = 1 << 13, /* Run child in its own user namespace */ FORK_NEW_USERNS = 1 << 13, /* Run child in its own user namespace */
FORK_CLOEXEC_OFF = 1 << 14, /* In the child: turn off O_CLOEXEC on all fds in except_fds[] */
} ForkFlags; } ForkFlags;
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid); int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);

View File

@ -721,7 +721,7 @@ int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
} }
if (!m) { if (!m) {
m = new0(char, 1); m = new0(char, 2);
if (!m) if (!m)
return -ENOMEM; return -ENOMEM;
n = 1; n = 1;
@ -730,11 +730,9 @@ int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
m[n] = '\0'; m[n] = '\0';
assert(n > 0); assert(n > 0);
*ret = m; *ret = TAKE_PTR(m);
*ret_size = n - 1; *ret_size = n - 1;
m = NULL;
return 0; return 0;
} }

View File

@ -45,7 +45,7 @@ static inline int strv_extend(char ***l, const char *value) {
return strv_extend_with_size(l, NULL, value); return strv_extend_with_size(l, NULL, value);
} }
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); int strv_extendf(char ***l, const char *format, ...) _printf_(2,3);
int strv_extend_front(char ***l, const char *value); int strv_extend_front(char ***l, const char *value);
int strv_push_with_size(char ***l, size_t *n, char *value); int strv_push_with_size(char ***l, size_t *n, char *value);

View File

@ -52,59 +52,25 @@ int prot_from_flags(int flags) {
bool in_initrd(void) { bool in_initrd(void) {
int r; int r;
const char *e;
bool lenient = false;
if (saved_in_initrd >= 0) if (saved_in_initrd >= 0)
return saved_in_initrd; return saved_in_initrd;
/* We have two checks here: /* If /etc/initrd-release exists, we're in an initrd.
* * This can be overridden by setting SYSTEMD_IN_INITRD=0|1.
* 1. the flag file /etc/initrd-release must exist
* 2. the root file system must be a memory file system
*
* The second check is extra paranoia, since misdetecting an
* initrd can have bad consequences due the initrd
* emptying when transititioning to the main systemd.
*
* If env var $SYSTEMD_IN_INITRD is not set or set to "auto",
* both checks are used. If it's set to "lenient", only check
* 1 is used. If set to a boolean value, then the boolean
* value is returned.
*/ */
e = secure_getenv("SYSTEMD_IN_INITRD"); r = getenv_bool_secure("SYSTEMD_IN_INITRD");
if (e) { if (r < 0 && r != -ENXIO)
if (streq(e, "lenient")) log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
lenient = true;
else if (!streq(e, "auto")) {
r = parse_boolean(e);
if (r >= 0) {
saved_in_initrd = r > 0;
return saved_in_initrd;
}
log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
}
}
if (!lenient) {
r = path_is_temporary_fs("/");
if (r < 0)
log_debug_errno(r, "Couldn't determine if / is a temporary file system: %m");
if (r >= 0)
saved_in_initrd = r > 0; saved_in_initrd = r > 0;
} else {
r = access("/etc/initrd-release", F_OK);
r = access("/etc/initrd-release", F_OK); if (r < 0 && errno != ENOENT)
if (r >= 0) { log_debug_errno(r, "Failed to check if /etc/initrd-release exists, assuming it does not: %m");
if (saved_in_initrd == 0) saved_in_initrd = r >= 0;
log_debug("/etc/initrd-release exists, but it's not an initrd.");
else
saved_in_initrd = 1;
} else {
if (errno != ENOENT)
log_debug_errno(errno, "Failed to test if /etc/initrd-release exists: %m");
saved_in_initrd = 0;
} }
return saved_in_initrd; return saved_in_initrd;

View File

@ -585,12 +585,16 @@ static int print_efi_option(uint16_t id, int *n_printed, bool in_order) {
assert(n_printed); assert(n_printed);
r = efi_get_boot_option(id, &title, &partition, &path, &active); r = efi_get_boot_option(id, &title, &partition, &path, &active);
if (r == -ENOENT) {
log_debug_errno(r, "Boot option 0x%04X referenced but missing, ignoring: %m", id);
return 0;
}
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to read boot option %u: %m", id); return log_error_errno(r, "Failed to read boot option 0x%04X: %m", id);
/* print only configured entries with partition information */ /* print only configured entries with partition information */
if (!path || sd_id128_is_null(partition)) { if (!path || sd_id128_is_null(partition)) {
log_debug("Ignoring boot entry %u without partition information.", id); log_debug("Ignoring boot entry 0x%04X without partition information.", id);
return 0; return 0;
} }

View File

@ -471,7 +471,6 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
_cleanup_free_ char16_t *device_part_uuid = NULL; _cleanup_free_ char16_t *device_part_uuid = NULL;
assert(config); assert(config);
assert(loaded_image_path);
clear_screen(COLOR_NORMAL); clear_screen(COLOR_NORMAL);
console_query_mode(&x_max, &y_max); console_query_mode(&x_max, &y_max);
@ -619,7 +618,6 @@ static bool menu_run(
assert(config); assert(config);
assert(chosen_entry); assert(chosen_entry);
assert(loaded_image_path);
EFI_STATUS err; EFI_STATUS err;
UINTN visible_max = 0; UINTN visible_max = 0;
@ -1478,7 +1476,7 @@ static void config_entry_add_type1(
entry->loader = xstra_to_path(value); entry->loader = xstra_to_path(value);
/* do not add an entry for ourselves */ /* do not add an entry for ourselves */
if (loaded_image_path && strcaseeq16(entry->loader, loaded_image_path)) { if (strcaseeq16(entry->loader, loaded_image_path)) {
entry->type = LOADER_UNDEFINED; entry->type = LOADER_UNDEFINED;
break; break;
} }
@ -1908,12 +1906,11 @@ static ConfigEntry *config_entry_add_loader_auto(
assert(root_dir); assert(root_dir);
assert(id); assert(id);
assert(title); assert(title);
assert(loader || loaded_image_path);
if (!config->auto_entries) if (!config->auto_entries)
return NULL; return NULL;
if (loaded_image_path) { if (!loader) {
loader = L"\\EFI\\BOOT\\BOOT" EFI_MACHINE_TYPE_NAME ".efi"; loader = L"\\EFI\\BOOT\\BOOT" EFI_MACHINE_TYPE_NAME ".efi";
/* We are trying to add the default EFI loader here, /* We are trying to add the default EFI loader here,
@ -2562,7 +2559,6 @@ static void export_variables(
char16_t uuid[37]; char16_t uuid[37];
assert(loaded_image); assert(loaded_image);
assert(loaded_image_path);
efivar_set_time_usec(LOADER_GUID, L"LoaderTimeInitUSec", init_usec); efivar_set_time_usec(LOADER_GUID, L"LoaderTimeInitUSec", init_usec);
efivar_set(LOADER_GUID, L"LoaderInfo", L"systemd-boot " GIT_VERSION, 0); efivar_set(LOADER_GUID, L"LoaderInfo", L"systemd-boot " GIT_VERSION, 0);
@ -2591,7 +2587,6 @@ static void config_load_all_entries(
assert(config); assert(config);
assert(loaded_image); assert(loaded_image);
assert(loaded_image_path);
assert(root_dir); assert(root_dir);
config_load_defaults(config, root_dir); config_load_defaults(config, root_dir);
@ -2650,7 +2645,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
EFI_LOADED_IMAGE_PROTOCOL *loaded_image; EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
_cleanup_(file_closep) EFI_FILE *root_dir = NULL; _cleanup_(file_closep) EFI_FILE *root_dir = NULL;
_cleanup_(config_free) Config config = {}; _cleanup_(config_free) Config config = {};
char16_t *loaded_image_path; _cleanup_free_ char16_t *loaded_image_path = NULL;
EFI_STATUS err; EFI_STATUS err;
uint64_t init_usec; uint64_t init_usec;
bool menu = false; bool menu = false;
@ -2676,9 +2671,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
if (err != EFI_SUCCESS) if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err); return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
err = device_path_to_str(loaded_image->FilePath, &loaded_image_path); (void) device_path_to_str(loaded_image->FilePath, &loaded_image_path);
if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Error getting loaded image path: %m");
export_variables(loaded_image, loaded_image_path, init_usec); export_variables(loaded_image, loaded_image_path, init_usec);

View File

@ -51,25 +51,23 @@ static EFI_STATUS load_one_driver(
} }
EFI_STATUS reconnect_all_drivers(void) { EFI_STATUS reconnect_all_drivers(void) {
_cleanup_free_ EFI_HANDLE *handles = NULL; _cleanup_free_ EFI_HANDLE *handles = NULL;
UINTN n_handles = 0; size_t n_handles = 0;
EFI_STATUS err; EFI_STATUS err;
/* Reconnects all handles, so that any loaded drivers can take effect. */ /* Reconnects all handles, so that any loaded drivers can take effect. */
err = BS->LocateHandleBuffer(AllHandles, NULL, NULL, &n_handles, &handles); err = BS->LocateHandleBuffer(AllHandles, NULL, NULL, &n_handles, &handles);
if (err != EFI_SUCCESS) if (err != EFI_SUCCESS)
return log_error_status_stall(err, L"Failed to get list of handles: %r", err); return log_error_status_stall(err, L"Failed to get list of handles: %r", err);
for (UINTN i = 0; i < n_handles; i++) { for (size_t i = 0; i < n_handles; i++)
err = BS->ConnectController(handles[i], NULL, NULL, true); /* Some firmware gives us some bogus handles (or they might become bad due to
if (err == EFI_NOT_FOUND) /* No drivers for this handle */ * reconnecting everything). Security policy may also prevent us from doing so too.
continue; * There is nothing we can realistically do on errors anyways, so just ignore them. */
if (err != EFI_SUCCESS) (void) BS->ConnectController(handles[i], NULL, NULL, true);
log_error_status_stall(err, L"Failed to reconnect handle %" PRIuN L", ignoring: %r", i, err);
}
return EFI_SUCCESS; return EFI_SUCCESS;
} }
EFI_STATUS load_drivers( EFI_STATUS load_drivers(

View File

@ -20,35 +20,26 @@
#define STUB_PAYLOAD_GUID \ #define STUB_PAYLOAD_GUID \
{ 0x55c5d1f8, 0x04cd, 0x46b5, { 0x8a, 0x20, 0xe5, 0x6c, 0xbb, 0x30, 0x52, 0xd0 } } { 0x55c5d1f8, 0x04cd, 0x46b5, { 0x8a, 0x20, 0xe5, 0x6c, 0xbb, 0x30, 0x52, 0xd0 } }
static EFIAPI EFI_STATUS security_hook( typedef struct {
const SecurityOverride *this, uint32_t authentication_status, const EFI_DEVICE_PATH *file) { const void *addr;
size_t len;
const EFI_DEVICE_PATH *device_path;
} ValidationContext;
assert(this); static bool validate_payload(
assert(this->hook == security_hook); const void *ctx, const EFI_DEVICE_PATH *device_path, const void *file_buffer, size_t file_size) {
if (file == this->payload_device_path) const ValidationContext *payload = ASSERT_PTR(ctx);
return EFI_SUCCESS;
return this->original_security->FileAuthenticationState( if (device_path != payload->device_path)
this->original_security, authentication_status, file); return false;
}
static EFIAPI EFI_STATUS security2_hook( /* Security arch (1) protocol does not provide a file buffer. Instead we are supposed to fetch the payload
const SecurityOverride *this, * ourselves, which is not needed as we already have everything in memory and the device paths match. */
const EFI_DEVICE_PATH *device_path, if (file_buffer && (file_buffer != payload->addr || file_size != payload->len))
void *file_buffer, return false;
size_t file_size,
BOOLEAN boot_policy) {
assert(this); return true;
assert(this->hook == security2_hook);
if (file_buffer == this->payload && file_size == this->payload_len &&
device_path == this->payload_device_path)
return EFI_SUCCESS;
return this->original_security2->FileAuthentication(
this->original_security2, device_path, file_buffer, file_size, boot_policy);
} }
static EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len, EFI_HANDLE *ret_image) { static EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len, EFI_HANDLE *ret_image) {
@ -79,19 +70,13 @@ static EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len,
/* We want to support unsigned kernel images as payload, which is safe to do under secure boot /* We want to support unsigned kernel images as payload, which is safe to do under secure boot
* because it is embedded in this stub loader (and since it is already running it must be trusted). */ * because it is embedded in this stub loader (and since it is already running it must be trusted). */
SecurityOverride security_override = { install_security_override(
.hook = security_hook, validate_payload,
.payload = source, &(ValidationContext) {
.payload_len = len, .addr = source,
.payload_device_path = &payload_device_path.payload.Header, .len = len,
}, security2_override = { .device_path = &payload_device_path.payload.Header,
.hook = security2_hook, });
.payload = source,
.payload_len = len,
.payload_device_path = &payload_device_path.payload.Header,
};
install_security_override(&security_override, &security2_override);
EFI_STATUS ret = BS->LoadImage( EFI_STATUS ret = BS->LoadImage(
/*BootPolicy=*/false, /*BootPolicy=*/false,
@ -101,7 +86,7 @@ static EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len,
len, len,
ret_image); ret_image);
uninstall_security_override(&security_override, &security2_override); uninstall_security_override();
return ret; return ret;
} }

View File

@ -127,69 +127,91 @@ out_deallocate:
return err; return err;
} }
static EFI_STATUS install_security_override_one(EFI_GUID guid, SecurityOverride *override) { static struct SecurityOverride {
EFI_STATUS err; EFI_SECURITY_ARCH_PROTOCOL *security;
EFI_SECURITY2_ARCH_PROTOCOL *security2;
EFI_SECURITY_FILE_AUTHENTICATION_STATE original_hook;
EFI_SECURITY2_FILE_AUTHENTICATION original_hook2;
assert(override); security_validator_t validator;
const void *validator_ctx;
} security_override;
_cleanup_free_ EFI_HANDLE *handles = NULL; static EFIAPI EFI_STATUS security_hook(
size_t n_handles = 0; const EFI_SECURITY_ARCH_PROTOCOL *this,
uint32_t authentication_status,
const EFI_DEVICE_PATH *file) {
err = BS->LocateHandleBuffer(ByProtocol, &guid, NULL, &n_handles, &handles); assert(security_override.validator);
if (err != EFI_SUCCESS) assert(security_override.security);
/* No security arch protocol around? */ assert(security_override.original_hook);
return err;
/* There should only ever be one security arch protocol instance, but let's be paranoid here. */ if (security_override.validator(security_override.validator_ctx, file, NULL, 0))
assert(n_handles == 1); return EFI_SUCCESS;
void *security = NULL; return security_override.original_hook(security_override.security, authentication_status, file);
err = BS->LocateProtocol(&guid, NULL, &security);
if (err != EFI_SUCCESS)
return log_error_status_stall(err, u"Error getting security arch protocol: %r", err);
err = BS->ReinstallProtocolInterface(handles[0], &guid, security, override);
if (err != EFI_SUCCESS)
return log_error_status_stall(err, u"Error overriding security arch protocol: %r", err);
override->original = security;
override->original_handle = handles[0];
return EFI_SUCCESS;
} }
/* This replaces the platform provided security arch protocols (defined in the UEFI Platform Initialization static EFIAPI EFI_STATUS security2_hook(
* Specification) with the provided override instances. If not running in secure boot or the protocols are const EFI_SECURITY2_ARCH_PROTOCOL *this,
* not available nothing happens. The override instances are provided with the necessary info to undo this const EFI_DEVICE_PATH *device_path,
* in uninstall_security_override(). */ void *file_buffer,
void install_security_override(SecurityOverride *override, SecurityOverride *override2) { size_t file_size,
assert(override); BOOLEAN boot_policy) {
assert(override2);
assert(security_override.validator);
assert(security_override.security2);
assert(security_override.original_hook2);
if (security_override.validator(security_override.validator_ctx, device_path, file_buffer, file_size))
return EFI_SUCCESS;
return security_override.original_hook2(
security_override.security2, device_path, file_buffer, file_size, boot_policy);
}
/* This replaces the platform provided security arch protocols hooks (defined in the UEFI Platform
* Initialization Specification) with our own that uses the given validator to decide if a image is to be
* trusted. If not running in secure boot or the protocols are not available nothing happens. The override
* must be removed with uninstall_security_override() after LoadImage() has been called.
*
* This is a hack as we do not own the security protocol instances and modifying them is not an official part
* of their spec. But there is little else we can do to circumvent secure boot short of implementing our own
* PE loader. We could replace the firmware instances with our own instance using
* ReinstallProtocolInterface(), but some firmware will still use the old ones. */
void install_security_override(security_validator_t validator, const void *validator_ctx) {
EFI_STATUS err;
assert(validator);
if (!secure_boot_enabled()) if (!secure_boot_enabled())
return; return;
(void) install_security_override_one((EFI_GUID) EFI_SECURITY_ARCH_PROTOCOL_GUID, override); security_override = (struct SecurityOverride) {
(void) install_security_override_one((EFI_GUID) EFI_SECURITY2_ARCH_PROTOCOL_GUID, override2); .validator = validator,
.validator_ctx = validator_ctx,
};
EFI_SECURITY_ARCH_PROTOCOL *security = NULL;
err = BS->LocateProtocol(&(EFI_GUID) EFI_SECURITY_ARCH_PROTOCOL_GUID, NULL, (void **) &security);
if (err == EFI_SUCCESS) {
security_override.security = security;
security_override.original_hook = security->FileAuthenticationState;
security->FileAuthenticationState = security_hook;
}
EFI_SECURITY2_ARCH_PROTOCOL *security2 = NULL;
err = BS->LocateProtocol(&(EFI_GUID) EFI_SECURITY2_ARCH_PROTOCOL_GUID, NULL, (void **) &security2);
if (err == EFI_SUCCESS) {
security_override.security2 = security2;
security_override.original_hook2 = security2->FileAuthentication;
security2->FileAuthentication = security2_hook;
}
} }
void uninstall_security_override(SecurityOverride *override, SecurityOverride *override2) { void uninstall_security_override(void) {
assert(override); if (security_override.original_hook)
assert(override2); security_override.security->FileAuthenticationState = security_override.original_hook;
if (security_override.original_hook2)
/* We use assert_se here to guarantee the system is not in a weird state in the unlikely case of an security_override.security2->FileAuthentication = security_override.original_hook2;
* error restoring the original protocols. */
if (override->original_handle)
assert_se(BS->ReinstallProtocolInterface(
override->original_handle,
&(EFI_GUID) EFI_SECURITY_ARCH_PROTOCOL_GUID,
override,
override->original) == EFI_SUCCESS);
if (override2->original_handle)
assert_se(BS->ReinstallProtocolInterface(
override2->original_handle,
&(EFI_GUID) EFI_SECURITY2_ARCH_PROTOCOL_GUID,
override2,
override2->original) == EFI_SUCCESS);
} }

View File

@ -17,23 +17,11 @@ SecureBootMode secure_boot_mode(void);
EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path); EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path);
typedef struct { typedef bool (*security_validator_t)(
void *hook; const void *ctx,
const EFI_DEVICE_PATH *device_path,
const void *file_buffer,
size_t file_size);
/* End of EFI_SECURITY_ARCH(2)_PROTOCOL. The rest is our own protocol instance data. */ void install_security_override(security_validator_t validator, const void *validator_ctx);
void uninstall_security_override(void);
EFI_HANDLE original_handle;
union {
void *original;
EFI_SECURITY_ARCH_PROTOCOL *original_security;
EFI_SECURITY2_ARCH_PROTOCOL *original_security2;
};
/* Used by the stub to identify the embedded image. */
const void *payload;
size_t payload_len;
const EFI_DEVICE_PATH *payload_device_path;
} SecurityOverride;
void install_security_override(SecurityOverride *override, SecurityOverride *override2);
void uninstall_security_override(SecurityOverride *override, SecurityOverride *override2);

View File

@ -23,7 +23,7 @@
#endif #endif
struct ShimLock { struct ShimLock {
EFI_STATUS __sysv_abi__ (*shim_verify) (void *buffer, uint32_t size); EFI_STATUS __sysv_abi__ (*shim_verify) (const void *buffer, uint32_t size);
/* context is actually a struct for the PE header, but it isn't needed so void is sufficient just do define the interface /* context is actually a struct for the PE header, but it isn't needed so void is sufficient just do define the interface
* see shim.c/shim.h and PeHeader.h in the github shim repo */ * see shim.c/shim.h and PeHeader.h in the github shim repo */
@ -41,79 +41,45 @@ bool shim_loaded(void) {
return BS->LocateProtocol((EFI_GUID*) SHIM_LOCK_GUID, NULL, (void**) &shim_lock) == EFI_SUCCESS; return BS->LocateProtocol((EFI_GUID*) SHIM_LOCK_GUID, NULL, (void**) &shim_lock) == EFI_SUCCESS;
} }
static bool shim_validate(void *data, uint32_t size) { static bool shim_validate(
struct ShimLock *shim_lock; const void *ctx, const EFI_DEVICE_PATH *device_path, const void *file_buffer, size_t file_size) {
if (!data)
return false;
if (BS->LocateProtocol((EFI_GUID*) SHIM_LOCK_GUID, NULL, (void**) &shim_lock) != EFI_SUCCESS)
return false;
if (!shim_lock)
return false;
return shim_lock->shim_verify(data, size) == EFI_SUCCESS;
}
static EFIAPI EFI_STATUS security2_hook(
const SecurityOverride *this,
const EFI_DEVICE_PATH *device_path,
void *file_buffer,
UINTN file_size,
BOOLEAN boot_policy) {
assert(this);
assert(this->hook == security2_hook);
if (shim_validate(file_buffer, file_size))
return EFI_SUCCESS;
return this->original_security2->FileAuthentication(
this->original_security2, device_path, file_buffer, file_size, boot_policy);
}
static EFIAPI EFI_STATUS security_hook(
const SecurityOverride *this,
uint32_t authentication_status,
const EFI_DEVICE_PATH *device_path) {
EFI_STATUS err; EFI_STATUS err;
_cleanup_free_ char *file_buffer_owned = NULL;
assert(this); if (!file_buffer) {
assert(this->hook == security_hook); if (!device_path)
return false;
if (!device_path) EFI_HANDLE device_handle;
return this->original_security->FileAuthenticationState( EFI_DEVICE_PATH *file_dp = (EFI_DEVICE_PATH *) device_path;
this->original_security, authentication_status, device_path); err = BS->LocateDevicePath(&FileSystemProtocol, &file_dp, &device_handle);
if (err != EFI_SUCCESS)
return false;
EFI_HANDLE device_handle; _cleanup_(file_closep) EFI_FILE *root = NULL;
EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *) device_path; err = open_volume(device_handle, &root);
err = BS->LocateDevicePath(&FileSystemProtocol, &dp, &device_handle); if (err != EFI_SUCCESS)
return false;
_cleanup_free_ char16_t *dp_str = NULL;
err = device_path_to_str(file_dp, &dp_str);
if (err != EFI_SUCCESS)
return false;
err = file_read(root, dp_str, 0, 0, &file_buffer_owned, &file_size);
if (err != EFI_SUCCESS)
return false;
file_buffer = file_buffer_owned;
}
struct ShimLock *shim_lock;
err = BS->LocateProtocol((EFI_GUID *) SHIM_LOCK_GUID, NULL, (void **) &shim_lock);
if (err != EFI_SUCCESS) if (err != EFI_SUCCESS)
return err; return false;
_cleanup_(file_closep) EFI_FILE *root = NULL; return shim_lock->shim_verify(file_buffer, file_size) == EFI_SUCCESS;
err = open_volume(device_handle, &root);
if (err != EFI_SUCCESS)
return err;
_cleanup_free_ char16_t *dp_str = NULL;
err = device_path_to_str(dp, &dp_str);
if (err != EFI_SUCCESS)
return err;
char *file_buffer;
size_t file_size;
err = file_read(root, dp_str, 0, 0, &file_buffer, &file_size);
if (err != EFI_SUCCESS)
return err;
if (shim_validate(file_buffer, file_size))
return EFI_SUCCESS;
return this->original_security->FileAuthenticationState(
this->original_security, authentication_status, device_path);
} }
EFI_STATUS shim_load_image(EFI_HANDLE parent, const EFI_DEVICE_PATH *device_path, EFI_HANDLE *ret_image) { EFI_STATUS shim_load_image(EFI_HANDLE parent, const EFI_DEVICE_PATH *device_path, EFI_HANDLE *ret_image) {
@ -122,20 +88,14 @@ EFI_STATUS shim_load_image(EFI_HANDLE parent, const EFI_DEVICE_PATH *device_path
bool have_shim = shim_loaded(); bool have_shim = shim_loaded();
SecurityOverride security_override = {
.hook = security_hook,
}, security2_override = {
.hook = security2_hook,
};
if (have_shim) if (have_shim)
install_security_override(&security_override, &security2_override); install_security_override(shim_validate, NULL);
EFI_STATUS ret = BS->LoadImage( EFI_STATUS ret = BS->LoadImage(
/*BootPolicy=*/false, parent, (EFI_DEVICE_PATH *) device_path, NULL, 0, ret_image); /*BootPolicy=*/false, parent, (EFI_DEVICE_PATH *) device_path, NULL, 0, ret_image);
if (have_shim) if (have_shim)
uninstall_security_override(&security_override, &security2_override); uninstall_security_override();
return ret; return ret;
} }

View File

@ -772,19 +772,51 @@ EFI_STATUS make_file_device_path(EFI_HANDLE device, const char16_t *file, EFI_DE
EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret) { EFI_STATUS device_path_to_str(const EFI_DEVICE_PATH *dp, char16_t **ret) {
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *dp_to_text; EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *dp_to_text;
EFI_STATUS err; EFI_STATUS err;
_cleanup_free_ char16_t *str = NULL;
assert(dp); assert(dp);
assert(ret); assert(ret);
err = BS->LocateProtocol(&(EFI_GUID) EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID, NULL, (void **) &dp_to_text); err = BS->LocateProtocol(&(EFI_GUID) EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID, NULL, (void **) &dp_to_text);
if (err != EFI_SUCCESS) if (err != EFI_SUCCESS) {
return err; /* If the device path to text protocol is not available we can still do a best-effort attempt
* to convert it ourselves if we are given filepath-only device path. */
char16_t *str = dp_to_text->ConvertDevicePathToText(dp, false, false); size_t size = 0;
for (const EFI_DEVICE_PATH *node = dp; !IsDevicePathEnd(node);
node = NextDevicePathNode(node)) {
if (DevicePathType(node) != MEDIA_DEVICE_PATH ||
DevicePathSubType(node) != MEDIA_FILEPATH_DP)
return err;
size_t path_size = DevicePathNodeLength(node);
if (path_size <= offsetof(FILEPATH_DEVICE_PATH, PathName) || path_size % sizeof(char16_t))
return EFI_INVALID_PARAMETER;
path_size -= offsetof(FILEPATH_DEVICE_PATH, PathName);
_cleanup_free_ char16_t *old = str;
str = xmalloc(size + path_size);
if (old) {
memcpy(str, old, size);
str[size / sizeof(char16_t) - 1] = '\\';
}
memcpy(str + (size / sizeof(char16_t)),
((uint8_t *) node) + offsetof(FILEPATH_DEVICE_PATH, PathName),
path_size);
size += path_size;
}
*ret = TAKE_PTR(str);
return EFI_SUCCESS;
}
str = dp_to_text->ConvertDevicePathToText(dp, false, false);
if (!str) if (!str)
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
*ret = str; *ret = TAKE_PTR(str);
return EFI_SUCCESS; return EFI_SUCCESS;
} }

View File

@ -897,7 +897,7 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
} }
_cleanup_free_ void *sig = malloc(ss); _cleanup_free_ void *sig = malloc(ss);
if (!ss) { if (!sig) {
r = log_oom(); r = log_oom();
goto finish; goto finish;
} }

View File

@ -113,9 +113,9 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
if (r >= 0) { if (r >= 0) {
if (type == SELINUX_AVC) if (type == SELINUX_AVC)
audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0); audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, getuid());
else if (type == SELINUX_ERROR) else if (type == SELINUX_ERROR)
audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_SELINUX_ERR, buf, NULL, NULL, NULL, 0); audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_SELINUX_ERR, buf, NULL, NULL, NULL, getuid());
return 0; return 0;
} }

View File

@ -948,11 +948,11 @@ static int activation_details_timer_append_env(ActivationDetails *details, char
if (!dual_timestamp_is_set(&t->last_trigger)) if (!dual_timestamp_is_set(&t->last_trigger))
return 0; return 0;
r = strv_extendf(strv, "TRIGGER_TIMER_REALTIME_USEC=%" USEC_FMT, t->last_trigger.realtime); r = strv_extendf(strv, "TRIGGER_TIMER_REALTIME_USEC=" USEC_FMT, t->last_trigger.realtime);
if (r < 0) if (r < 0)
return r; return r;
r = strv_extendf(strv, "TRIGGER_TIMER_MONOTONIC_USEC=%" USEC_FMT, t->last_trigger.monotonic); r = strv_extendf(strv, "TRIGGER_TIMER_MONOTONIC_USEC=" USEC_FMT, t->last_trigger.monotonic);
if (r < 0) if (r < 0)
return r; return r;
@ -974,7 +974,7 @@ static int activation_details_timer_append_pair(ActivationDetails *details, char
if (r < 0) if (r < 0)
return r; return r;
r = strv_extendf(strv, "%" USEC_FMT, t->last_trigger.realtime); r = strv_extendf(strv, USEC_FMT, t->last_trigger.realtime);
if (r < 0) if (r < 0)
return r; return r;
@ -982,7 +982,7 @@ static int activation_details_timer_append_pair(ActivationDetails *details, char
if (r < 0) if (r < 0)
return r; return r;
r = strv_extendf(strv, "%" USEC_FMT, t->last_trigger.monotonic); r = strv_extendf(strv, USEC_FMT, t->last_trigger.monotonic);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -55,7 +55,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
size_t sw_alloc = MAX(h->sw_alloc, 1u); size_t sw_alloc = MAX(h->sw_alloc, 1u);
buf2 = malloc(sw_alloc); buf2 = malloc(sw_alloc);
if (!buf) { if (!buf2) {
log_oom(); log_oom();
return 0; return 0;
} }

View File

@ -158,7 +158,6 @@ static void test_skip_one(void (*setup)(void)) {
*/ */
assert_ret(sd_journal_open_directory(&j, t, 0)); assert_ret(sd_journal_open_directory(&j, t, 0));
assert_ret(sd_journal_seek_head(j)); assert_ret(sd_journal_seek_head(j));
assert_ret(sd_journal_previous(j) == 0);
assert_ret(sd_journal_next(j)); assert_ret(sd_journal_next(j));
test_check_numbers_down(j, 4); test_check_numbers_down(j, 4);
sd_journal_close(j); sd_journal_close(j);
@ -167,7 +166,6 @@ static void test_skip_one(void (*setup)(void)) {
*/ */
assert_ret(sd_journal_open_directory(&j, t, 0)); assert_ret(sd_journal_open_directory(&j, t, 0));
assert_ret(sd_journal_seek_tail(j)); assert_ret(sd_journal_seek_tail(j));
assert_ret(sd_journal_next(j) == 0);
assert_ret(sd_journal_previous(j)); assert_ret(sd_journal_previous(j));
test_check_numbers_up(j, 4); test_check_numbers_up(j, 4);
sd_journal_close(j); sd_journal_close(j);
@ -176,7 +174,6 @@ static void test_skip_one(void (*setup)(void)) {
*/ */
assert_ret(sd_journal_open_directory(&j, t, 0)); assert_ret(sd_journal_open_directory(&j, t, 0));
assert_ret(sd_journal_seek_tail(j)); assert_ret(sd_journal_seek_tail(j));
assert_ret(sd_journal_next(j) == 0);
assert_ret(r = sd_journal_previous_skip(j, 4)); assert_ret(r = sd_journal_previous_skip(j, 4));
assert_se(r == 4); assert_se(r == 4);
test_check_numbers_down(j, 4); test_check_numbers_down(j, 4);
@ -186,7 +183,6 @@ static void test_skip_one(void (*setup)(void)) {
*/ */
assert_ret(sd_journal_open_directory(&j, t, 0)); assert_ret(sd_journal_open_directory(&j, t, 0));
assert_ret(sd_journal_seek_head(j)); assert_ret(sd_journal_seek_head(j));
assert_ret(sd_journal_previous(j) == 0);
assert_ret(r = sd_journal_next_skip(j, 4)); assert_ret(r = sd_journal_next_skip(j, 4));
assert_se(r == 4); assert_se(r == 4);
test_check_numbers_up(j, 4); test_check_numbers_up(j, 4);

View File

@ -158,8 +158,9 @@ if [ -z "$MACHINE_ID" ] && [ -f /etc/machine-info ]; then
[ -n "$MACHINE_ID" ] && \ [ -n "$MACHINE_ID" ] && \
log_verbose "machine-id $MACHINE_ID acquired from /etc/machine-info" log_verbose "machine-id $MACHINE_ID acquired from /etc/machine-info"
fi fi
if [ -z "$MACHINE_ID" ] && [ -f /etc/machine-id ]; then if [ -z "$MACHINE_ID" ] && [ -s /etc/machine-id ]; then
read -r MACHINE_ID </etc/machine-id read -r MACHINE_ID </etc/machine-id
[ "$MACHINE_ID" = "uninitialized" ] && unset MACHINE_ID
[ -n "$MACHINE_ID" ] && \ [ -n "$MACHINE_ID" ] && \
log_verbose "machine-id $MACHINE_ID acquired from /etc/machine-id" log_verbose "machine-id $MACHINE_ID acquired from /etc/machine-id"
fi fi

View File

@ -3529,7 +3529,7 @@ static int bus_add_match_full(
s); s);
if (r < 0) if (r < 0)
return r; goto finish;
/* Make the slot of the match call floating now. We need the reference, but we don't /* Make the slot of the match call floating now. We need the reference, but we don't
* want that this match pins the bus object, hence we first create it non-floating, but * want that this match pins the bus object, hence we first create it non-floating, but

View File

@ -606,9 +606,9 @@ static int find_location_for_match(
/* FIXME: missing: find by monotonic */ /* FIXME: missing: find by monotonic */
if (j->current_location.type == LOCATION_HEAD) if (j->current_location.type == LOCATION_HEAD)
return direction == DIRECTION_DOWN ? journal_file_next_entry_for_data(f, d, DIRECTION_DOWN, ret, offset) : 0; return journal_file_next_entry_for_data(f, d, DIRECTION_DOWN, ret, offset);
if (j->current_location.type == LOCATION_TAIL) if (j->current_location.type == LOCATION_TAIL)
return direction == DIRECTION_UP ? journal_file_next_entry_for_data(f, d, DIRECTION_UP, ret, offset) : 0; return journal_file_next_entry_for_data(f, d, DIRECTION_UP, ret, offset);
if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id)) if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
return journal_file_move_to_entry_by_seqnum_for_data(f, d, j->current_location.seqnum, direction, ret, offset); return journal_file_move_to_entry_by_seqnum_for_data(f, d, j->current_location.seqnum, direction, ret, offset);
if (j->current_location.monotonic_set) { if (j->current_location.monotonic_set) {
@ -701,9 +701,9 @@ static int find_location_with_matches(
/* No matches is simple */ /* No matches is simple */
if (j->current_location.type == LOCATION_HEAD) if (j->current_location.type == LOCATION_HEAD)
return direction == DIRECTION_DOWN ? journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset) : 0; return journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset);
if (j->current_location.type == LOCATION_TAIL) if (j->current_location.type == LOCATION_TAIL)
return direction == DIRECTION_UP ? journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset) : 0; return journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset);
if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id)) if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id))
return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset); return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset);
if (j->current_location.monotonic_set) { if (j->current_location.monotonic_set) {

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/if_arp.h> #include <net/if.h> /* IFF_LOOPBACK */
#include <net/if_arp.h> /* ARPHRD_ETHER */
#include "sd-dhcp-client.h" #include "sd-dhcp-client.h"
#include "sd-ipv4acd.h" #include "sd-ipv4acd.h"

View File

@ -1178,7 +1178,7 @@ static int link_get_network(Link *link, Network **ret) {
return -ENOENT; return -ENOENT;
} }
static int link_reconfigure_impl(Link *link, bool force) { int link_reconfigure_impl(Link *link, bool force) {
Network *network = NULL; Network *network = NULL;
NetDev *netdev = NULL; NetDev *netdev = NULL;
int r; int r;

View File

@ -234,6 +234,7 @@ int link_stop_engines(Link *link, bool may_keep_dhcp);
const char* link_state_to_string(LinkState s) _const_; const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_; LinkState link_state_from_string(const char *s) _pure_;
int link_reconfigure_impl(Link *link, bool force);
int link_reconfigure(Link *link, bool force); int link_reconfigure(Link *link, bool force);
int link_reconfigure_after_sleep(Link *link); int link_reconfigure_after_sleep(Link *link);

View File

@ -269,6 +269,18 @@ int manager_genl_process_nl80211_mlme(sd_netlink *genl, sd_netlink_message *mess
if (link->wlan_iftype == NL80211_IFTYPE_STATION && link->ssid) if (link->wlan_iftype == NL80211_IFTYPE_STATION && link->ssid)
log_link_info(link, "Connected WiFi access point: %s (%s)", log_link_info(link, "Connected WiFi access point: %s (%s)",
link->ssid, ETHER_ADDR_TO_STR(&link->bssid)); link->ssid, ETHER_ADDR_TO_STR(&link->bssid));
/* Sometimes, RTM_NEWLINK message with carrier is received earlier than NL80211_CMD_CONNECT.
* To make SSID= or other WiFi related settings in [Match] section work, let's try to
* reconfigure the interface. */
if (link->ssid && link_has_carrier(link)) {
r = link_reconfigure_impl(link, /* force = */ false);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to reconfigure interface: %m");
link_enter_failed(link);
return 0;
}
}
break; break;
} }
case NL80211_CMD_DISCONNECT: case NL80211_CMD_DISCONNECT:

View File

@ -88,6 +88,7 @@ static int add_syscall_filters(
{ 0, "sched_getparam" }, { 0, "sched_getparam" },
{ 0, "sched_getscheduler" }, { 0, "sched_getscheduler" },
{ 0, "sched_rr_get_interval" }, { 0, "sched_rr_get_interval" },
{ 0, "sched_rr_get_interval_time64" },
{ 0, "sched_yield" }, { 0, "sched_yield" },
{ 0, "seccomp" }, { 0, "seccomp" },
{ 0, "sendfile" }, { 0, "sendfile" },

View File

@ -164,7 +164,7 @@ int oomd_fetch_cgroup_oom_preference(OomdCGroupContext *ctx, const char *prefix)
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to get owner/group from %s: %m", ctx->path); return log_debug_errno(r, "Failed to get owner/group from %s: %m", ctx->path);
if (uid == prefix_uid) { if (uid == prefix_uid || uid == 0) {
/* Ignore most errors when reading the xattr since it is usually unset and cgroup xattrs are only used /* Ignore most errors when reading the xattr since it is usually unset and cgroup xattrs are only used
* as an optional feature of systemd-oomd (and the system might not even support them). */ * as an optional feature of systemd-oomd (and the system might not even support them). */
r = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, ctx->path, "user.oomd_avoid"); r = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, ctx->path, "user.oomd_avoid");

View File

@ -475,9 +475,9 @@ static void test_oomd_fetch_cgroup_oom_preference(void) {
/* Assert that avoid/omit are not set if the cgroup and prefix are not /* Assert that avoid/omit are not set if the cgroup and prefix are not
* owned by the same user.*/ * owned by the same user.*/
if (test_xattrs && !empty_or_root(ctx->path)) { if (test_xattrs && !empty_or_root(cgroup)) {
ctx = oomd_cgroup_context_free(ctx); ctx = oomd_cgroup_context_free(ctx);
assert_se(cg_set_access(SYSTEMD_CGROUP_CONTROLLER, cgroup, 65534, 0) >= 0); assert_se(cg_set_access(SYSTEMD_CGROUP_CONTROLLER, cgroup, 61183, 0) >= 0);
assert_se(oomd_cgroup_context_acquire(cgroup, &ctx) == 0); assert_se(oomd_cgroup_context_acquire(cgroup, &ctx) == 0);
assert_se(oomd_fetch_cgroup_oom_preference(ctx, NULL) == 0); assert_se(oomd_fetch_cgroup_oom_preference(ctx, NULL) == 0);

View File

@ -4387,13 +4387,15 @@ static int context_write_partition_table(
log_info("Wiped block device."); log_info("Wiped block device.");
r = context_discard_range(context, 0, context->total); if (arg_discard) {
if (r == -EOPNOTSUPP) r = context_discard_range(context, 0, context->total);
log_info("Storage does not support discard, not discarding entire block device data."); if (r == -EOPNOTSUPP)
else if (r < 0) log_info("Storage does not support discard, not discarding entire block device data.");
return log_error_errno(r, "Failed to discard entire block device: %m"); else if (r < 0)
else if (r > 0) return log_error_errno(r, "Failed to discard entire block device: %m");
log_info("Discarded entire block device."); else if (r > 0)
log_info("Discarded entire block device.");
}
} }
r = fdisk_get_partitions(context->fdisk_context, &original_table); r = fdisk_get_partitions(context->fdisk_context, &original_table);

View File

@ -1131,7 +1131,7 @@ static int attach_unit_file(
(void) mkdir_parents(where, 0755); (void) mkdir_parents(where, 0755);
if (mkdir(where, 0755) < 0) { if (mkdir(where, 0755) < 0) {
if (errno != EEXIST) if (errno != EEXIST)
return -errno; return log_debug_errno(errno, "Failed to create attach directory %s: %m", where);
} else } else
(void) portable_changes_add(changes, n_changes, PORTABLE_MKDIR, where, NULL); (void) portable_changes_add(changes, n_changes, PORTABLE_MKDIR, where, NULL);
@ -1145,7 +1145,7 @@ static int attach_unit_file(
if (mkdir(dropin_dir, 0755) < 0) { if (mkdir(dropin_dir, 0755) < 0) {
if (errno != EEXIST) if (errno != EEXIST)
return -errno; return log_debug_errno(errno, "Failed to create drop-in directory %s: %m", dropin_dir);
} else } else
(void) portable_changes_add(changes, n_changes, PORTABLE_MKDIR, dropin_dir, NULL); (void) portable_changes_add(changes, n_changes, PORTABLE_MKDIR, dropin_dir, NULL);
@ -1392,7 +1392,7 @@ int portable_attach(
r = attach_unit_file(&paths, image->path, image->type, extension_images, r = attach_unit_file(&paths, image->path, image->type, extension_images,
item, profile, flags, changes, n_changes); item, profile, flags, changes, n_changes);
if (r < 0) if (r < 0)
return r; return sd_bus_error_set_errnof(error, r, "Failed to attach unit '%s': %m", item->name);
} }
/* We don't care too much for the image symlink, it's just a convenience thing, it's not necessary for proper /* We don't care too much for the image symlink, it's just a convenience thing, it's not necessary for proper

View File

@ -424,7 +424,7 @@ static int dns_scope_socket(
return r; return r;
} }
if (s->link) { if (ifindex != 0) {
r = socket_set_unicast_if(fd, sa.sa.sa_family, ifindex); r = socket_set_unicast_if(fd, sa.sa.sa_family, ifindex);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -648,6 +648,11 @@ int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeature
int dns_server_ifindex(const DnsServer *s) { int dns_server_ifindex(const DnsServer *s) {
assert(s); assert(s);
/* For loopback addresses, go via the loopback interface, regardless which interface this is linked
* to. */
if (in_addr_is_localhost(s->family, &s->address))
return LOOPBACK_IFINDEX;
/* The link ifindex always takes precedence */ /* The link ifindex always takes precedence */
if (s->link) if (s->link)
return s->link->ifindex; return s->link->ifindex;

View File

@ -14,6 +14,19 @@
#include "resolved-dnstls.h" #include "resolved-dnstls.h"
#include "resolved-manager.h" #include "resolved-manager.h"
static char *dnstls_error_string(int ssl_error, char *buf, size_t count) {
assert(buf || count == 0);
if (ssl_error == SSL_ERROR_SSL)
ERR_error_string_n(ERR_get_error(), buf, count);
else
snprintf(buf, count, "SSL_get_error()=%d", ssl_error);
return buf;
}
#define DNSTLS_ERROR_BUFSIZE 256
#define DNSTLS_ERROR_STRING(error) \
dnstls_error_string((error), (char[DNSTLS_ERROR_BUFSIZE]){}, DNSTLS_ERROR_BUFSIZE)
static int dnstls_flush_write_buffer(DnsStream *stream) { static int dnstls_flush_write_buffer(DnsStream *stream) {
ssize_t ss; ssize_t ss;
@ -97,26 +110,18 @@ int dnstls_stream_connect_tls(DnsStream *stream, DnsServer *server) {
if (server->server_name) { if (server->server_name) {
r = SSL_set_tlsext_host_name(s, server->server_name); r = SSL_set_tlsext_host_name(s, server->server_name);
if (r <= 0) { if (r <= 0)
char errbuf[256]; return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to set server name: %s", DNSTLS_ERROR_STRING(SSL_ERROR_SSL));
error = ERR_get_error();
ERR_error_string_n(error, errbuf, sizeof(errbuf));
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to set server name: %s", errbuf);
}
} }
ERR_clear_error(); ERR_clear_error();
stream->dnstls_data.handshake = SSL_do_handshake(s); stream->dnstls_data.handshake = SSL_do_handshake(s);
if (stream->dnstls_data.handshake <= 0) { if (stream->dnstls_data.handshake <= 0) {
error = SSL_get_error(s, stream->dnstls_data.handshake); error = SSL_get_error(s, stream->dnstls_data.handshake);
if (!IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE)) { if (!IN_SET(error, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE))
char errbuf[256];
ERR_error_string_n(error, errbuf, sizeof(errbuf));
return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED), return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED),
"Failed to invoke SSL_do_handshake: %s", errbuf); "Failed to invoke SSL_do_handshake: %s", DNSTLS_ERROR_STRING(error));
}
} }
stream->encrypted = true; stream->encrypted = true;
@ -177,12 +182,8 @@ int dnstls_stream_on_io(DnsStream *stream, uint32_t revents) {
} else if (error == SSL_ERROR_SYSCALL) { } else if (error == SSL_ERROR_SYSCALL) {
if (errno > 0) if (errno > 0)
log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m"); log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m");
} else { } else
char errbuf[256]; log_debug("Failed to invoke SSL_shutdown, ignoring: %s", DNSTLS_ERROR_STRING(error));
ERR_error_string_n(error, errbuf, sizeof(errbuf));
log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf);
}
} }
stream->dnstls_events = 0; stream->dnstls_events = 0;
@ -206,14 +207,10 @@ int dnstls_stream_on_io(DnsStream *stream, uint32_t revents) {
return r; return r;
return -EAGAIN; return -EAGAIN;
} else { } else
char errbuf[256];
ERR_error_string_n(error, errbuf, sizeof(errbuf));
return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED), return log_debug_errno(SYNTHETIC_ERRNO(ECONNREFUSED),
"Failed to invoke SSL_do_handshake: %s", "Failed to invoke SSL_do_handshake: %s",
errbuf); DNSTLS_ERROR_STRING(error));
}
} }
stream->dnstls_events = 0; stream->dnstls_events = 0;
@ -275,12 +272,8 @@ int dnstls_stream_shutdown(DnsStream *stream, int error) {
} else if (ssl_error == SSL_ERROR_SYSCALL) { } else if (ssl_error == SSL_ERROR_SYSCALL) {
if (errno > 0) if (errno > 0)
log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m"); log_debug_errno(errno, "Failed to invoke SSL_shutdown, ignoring: %m");
} else { } else
char errbuf[256]; log_debug("Failed to invoke SSL_shutdown, ignoring: %s", DNSTLS_ERROR_STRING(ssl_error));
ERR_error_string_n(ssl_error, errbuf, sizeof(errbuf));
log_debug("Failed to invoke SSL_shutdown, ignoring: %s", errbuf);
}
} }
stream->dnstls_events = 0; stream->dnstls_events = 0;
@ -307,10 +300,7 @@ static ssize_t dnstls_stream_write(DnsStream *stream, const char *buf, size_t co
stream->dnstls_events = 0; stream->dnstls_events = 0;
ss = 0; ss = 0;
} else { } else {
char errbuf[256]; log_debug("Failed to invoke SSL_write: %s", DNSTLS_ERROR_STRING(error));
ERR_error_string_n(error, errbuf, sizeof(errbuf));
log_debug("Failed to invoke SSL_write: %s", errbuf);
stream->dnstls_events = 0; stream->dnstls_events = 0;
ss = -EPIPE; ss = -EPIPE;
} }
@ -375,10 +365,7 @@ ssize_t dnstls_stream_read(DnsStream *stream, void *buf, size_t count) {
stream->dnstls_events = 0; stream->dnstls_events = 0;
ss = 0; ss = 0;
} else { } else {
char errbuf[256]; log_debug("Failed to invoke SSL_read: %s", DNSTLS_ERROR_STRING(error));
ERR_error_string_n(error, errbuf, sizeof(errbuf));
log_debug("Failed to invoke SSL_read: %s", errbuf);
stream->dnstls_events = 0; stream->dnstls_events = 0;
ss = -EPIPE; ss = -EPIPE;
} }

View File

@ -994,6 +994,12 @@ static int boot_config_find(const BootConfig *config, const char *id) {
if (!id) if (!id)
return -1; return -1;
if (id[0] == '@') {
if (!strcaseeq(id, "@saved"))
return -1;
id = config->entry_selected;
}
for (size_t i = 0; i < config->n_entries; i++) for (size_t i = 0; i < config->n_entries; i++)
if (fnmatch(id, config->entries[i].id, FNM_CASEFOLD) == 0) if (fnmatch(id, config->entries[i].id, FNM_CASEFOLD) == 0)
return i; return i;

View File

@ -1010,19 +1010,13 @@ static int dissect_image(
log_debug("No root partition found of the native architecture, falling back to a root " log_debug("No root partition found of the native architecture, falling back to a root "
"partition of the secondary architecture."); "partition of the secondary architecture.");
m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_SECONDARY]; m->partitions[PARTITION_ROOT] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_SECONDARY]);
zero(m->partitions[PARTITION_ROOT_SECONDARY]); m->partitions[PARTITION_ROOT_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY]; m->partitions[PARTITION_ROOT_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG]);
zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
m->partitions[PARTITION_ROOT_VERITY_SIG] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG];
zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG]);
m->partitions[PARTITION_USR] = m->partitions[PARTITION_USR_SECONDARY]; m->partitions[PARTITION_USR] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY]);
zero(m->partitions[PARTITION_USR_SECONDARY]); m->partitions[PARTITION_USR_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_SECONDARY_VERITY]; m->partitions[PARTITION_USR_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
zero(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG];
zero(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
m->partitions[PARTITION_ROOT_OTHER].found = false; m->partitions[PARTITION_ROOT_OTHER].found = false;
m->partitions[PARTITION_ROOT_OTHER_VERITY].found = false; m->partitions[PARTITION_ROOT_OTHER_VERITY].found = false;
@ -1044,19 +1038,13 @@ static int dissect_image(
"falling back to a root partition of a non-native architecture (%s).", "falling back to a root partition of a non-native architecture (%s).",
architecture_to_string(m->partitions[PARTITION_ROOT_OTHER].architecture)); architecture_to_string(m->partitions[PARTITION_ROOT_OTHER].architecture));
m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_OTHER]; m->partitions[PARTITION_ROOT] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_OTHER]);
zero(m->partitions[PARTITION_ROOT_OTHER]); m->partitions[PARTITION_ROOT_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_OTHER_VERITY]);
m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_OTHER_VERITY]; m->partitions[PARTITION_ROOT_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_OTHER_VERITY_SIG]);
zero(m->partitions[PARTITION_ROOT_OTHER_VERITY]);
m->partitions[PARTITION_ROOT_VERITY_SIG] = m->partitions[PARTITION_ROOT_OTHER_VERITY_SIG];
zero(m->partitions[PARTITION_ROOT_OTHER_VERITY_SIG]);
m->partitions[PARTITION_USR] = m->partitions[PARTITION_USR_OTHER]; m->partitions[PARTITION_USR] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER]);
zero(m->partitions[PARTITION_USR_OTHER]); m->partitions[PARTITION_USR_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER_VERITY]);
m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_OTHER_VERITY]; m->partitions[PARTITION_USR_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER_VERITY_SIG]);
zero(m->partitions[PARTITION_USR_OTHER_VERITY]);
m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_OTHER_VERITY_SIG];
zero(m->partitions[PARTITION_USR_OTHER_VERITY_SIG]);
} }
/* Hmm, we found a signature partition but no Verity data? Something is off. */ /* Hmm, we found a signature partition but no Verity data? Something is off. */
@ -1083,12 +1071,9 @@ static int dissect_image(
"partition of the secondary architecture."); "partition of the secondary architecture.");
/* Upgrade secondary arch to primary */ /* Upgrade secondary arch to primary */
m->partitions[PARTITION_USR] = m->partitions[PARTITION_USR_SECONDARY]; m->partitions[PARTITION_USR] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY]);
zero(m->partitions[PARTITION_USR_SECONDARY]); m->partitions[PARTITION_USR_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_SECONDARY_VERITY]; m->partitions[PARTITION_USR_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
zero(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG];
zero(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
m->partitions[PARTITION_USR_OTHER].found = false; m->partitions[PARTITION_USR_OTHER].found = false;
m->partitions[PARTITION_USR_OTHER_VERITY].found = false; m->partitions[PARTITION_USR_OTHER_VERITY].found = false;
@ -1105,12 +1090,9 @@ static int dissect_image(
architecture_to_string(m->partitions[PARTITION_ROOT_OTHER].architecture)); architecture_to_string(m->partitions[PARTITION_ROOT_OTHER].architecture));
/* Upgrade other arch to primary */ /* Upgrade other arch to primary */
m->partitions[PARTITION_USR] = m->partitions[PARTITION_USR_OTHER]; m->partitions[PARTITION_USR] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER]);
zero(m->partitions[PARTITION_USR_OTHER]); m->partitions[PARTITION_USR_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER_VERITY]);
m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_OTHER_VERITY]; m->partitions[PARTITION_USR_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER_VERITY_SIG]);
zero(m->partitions[PARTITION_USR_OTHER_VERITY]);
m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_OTHER_VERITY_SIG];
zero(m->partitions[PARTITION_USR_OTHER_VERITY_SIG]);
} }
/* Hmm, we found a signature partition but no Verity data? Something is off. */ /* Hmm, we found a signature partition but no Verity data? Something is off. */
@ -1327,11 +1309,11 @@ static int is_loop_device(const char *path) {
return true; return true;
} }
static int run_fsck(const char *node, const char *fstype) { static int run_fsck(int node_fd, const char *fstype) {
int r, exit_status; int r, exit_status;
pid_t pid; pid_t pid;
assert(node); assert(node_fd >= 0);
assert(fstype); assert(fstype);
r = fsck_exists_for_fstype(fstype); r = fsck_exists_for_fstype(fstype);
@ -1340,16 +1322,20 @@ static int run_fsck(const char *node, const char *fstype) {
return 0; return 0;
} }
if (r == 0) { if (r == 0) {
log_debug("Not checking partition %s, as fsck for %s does not exist.", node, fstype); log_debug("Not checking partition %s, as fsck for %s does not exist.", FORMAT_PROC_FD_PATH(node_fd), fstype);
return 0; return 0;
} }
r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_NULL_STDIO, &pid); r = safe_fork_full(
"(fsck)",
&node_fd, 1, /* Leave the node fd open */
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_NULL_STDIO|FORK_CLOEXEC_OFF,
&pid);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to fork off fsck: %m"); return log_debug_errno(r, "Failed to fork off fsck: %m");
if (r == 0) { if (r == 0) {
/* Child */ /* Child */
execl("/sbin/fsck", "/sbin/fsck", "-aT", node, NULL); execl("/sbin/fsck", "/sbin/fsck", "-aT", FORMAT_PROC_FD_PATH(node_fd), NULL);
log_open(); log_open();
log_debug_errno(errno, "Failed to execl() fsck: %m"); log_debug_errno(errno, "Failed to execl() fsck: %m");
_exit(FSCK_OPERATIONAL_ERROR); _exit(FSCK_OPERATIONAL_ERROR);
@ -1439,7 +1425,7 @@ static int mount_partition(
rw = m->rw && !(flags & DISSECT_IMAGE_MOUNT_READ_ONLY); rw = m->rw && !(flags & DISSECT_IMAGE_MOUNT_READ_ONLY);
if (FLAGS_SET(flags, DISSECT_IMAGE_FSCK) && rw) { if (FLAGS_SET(flags, DISSECT_IMAGE_FSCK) && rw) {
r = run_fsck(node, fstype); r = run_fsck(m->mount_node_fd, fstype);
if (r < 0) if (r < 0)
return r; return r;
} }

View File

@ -40,6 +40,12 @@ struct DissectedPartition {
.architecture = _ARCHITECTURE_INVALID, \ .architecture = _ARCHITECTURE_INVALID, \
.mount_node_fd = -1, \ .mount_node_fd = -1, \
}) })
#define TAKE_PARTITION(p) \
({ \
DissectedPartition *_pp = &(p), _p = *_pp; \
*_pp = DISSECTED_PARTITION_NULL; \
_p; \
})
typedef enum PartitionDesignator { typedef enum PartitionDesignator {
PARTITION_ROOT, PARTITION_ROOT,

View File

@ -165,59 +165,65 @@ static int verify_esp_udev(
r = sd_device_get_devname(d, &node); r = sd_device_get_devname(d, &node);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device node: %m"); return log_device_error_errno(d, r, "Failed to get device node: %m");
r = sd_device_get_property_value(d, "ID_FS_TYPE", &v); r = sd_device_get_property_value(d, "ID_FS_TYPE", &v);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device property: %m"); return log_device_error_errno(d, r, "Failed to get device property: %m");
if (!streq(v, "vfat")) if (!streq(v, "vfat"))
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, return log_device_full_errno(d,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), searching ? LOG_DEBUG : LOG_ERR,
"File system \"%s\" is not FAT.", node ); SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"File system \"%s\" is not FAT.", node );
r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v); r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device property: %m"); return log_device_full_errno(d,
searching && r == -ENOENT ? LOG_DEBUG : LOG_ERR,
searching && r == -ENOENT ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : r,
"Failed to get device property: %m");
if (!streq(v, "gpt")) if (!streq(v, "gpt"))
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, return log_device_full_errno(d,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), searching ? LOG_DEBUG : LOG_ERR,
"File system \"%s\" is not on a GPT partition table.", node); SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"File system \"%s\" is not on a GPT partition table.", node);
r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v); r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device property: %m"); return log_device_error_errno(d, r, "Failed to get device property: %m");
if (sd_id128_string_equal(v, SD_GPT_ESP) <= 0) if (sd_id128_string_equal(v, SD_GPT_ESP) <= 0)
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, return log_device_full_errno(d,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), searching ? LOG_DEBUG : LOG_ERR,
"File system \"%s\" has wrong type for an EFI System Partition (ESP).", node); SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v); r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device property: %m"); return log_device_error_errno(d, r, "Failed to get device property: %m");
r = sd_id128_from_string(v, &uuid); r = sd_id128_from_string(v, &uuid);
if (r < 0) if (r < 0)
return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v); return log_device_error_errno(d, r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
r = sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &v); r = sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &v);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device property: %m"); return log_device_error_errno(d, r, "Failed to get device property: %m");
r = safe_atou32(v, &part); r = safe_atou32(v, &part);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field."); return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_NUMBER field.");
r = sd_device_get_property_value(d, "ID_PART_ENTRY_OFFSET", &v); r = sd_device_get_property_value(d, "ID_PART_ENTRY_OFFSET", &v);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device property: %m"); return log_device_error_errno(d, r, "Failed to get device property: %m");
r = safe_atou64(v, &pstart); r = safe_atou64(v, &pstart);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field."); return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_OFFSET field.");
r = sd_device_get_property_value(d, "ID_PART_ENTRY_SIZE", &v); r = sd_device_get_property_value(d, "ID_PART_ENTRY_SIZE", &v);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device property: %m"); return log_device_error_errno(d, r, "Failed to get device property: %m");
r = safe_atou64(v, &psize); r = safe_atou64(v, &psize);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field."); return log_device_error_errno(d, r, "Failed to parse PART_ENTRY_SIZE field.");
if (ret_part) if (ret_part)
*ret_part = part; *ret_part = part;
@ -572,10 +578,11 @@ static int verify_xbootldr_blkid(
else if (r != 0) else if (r != 0)
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe file system: %m", node); return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe file system: %m", node);
errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &type, NULL); r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &type, NULL);
if (r != 0) if (r != 0)
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "%s: Failed to probe PART_ENTRY_SCHEME: %m", node); return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(EIO),
"%s: Failed to probe PART_ENTRY_SCHEME: %m", node);
if (streq(type, "gpt")) { if (streq(type, "gpt")) {
errno = 0; errno = 0;
@ -634,11 +641,14 @@ static int verify_xbootldr_udev(
r = sd_device_get_devname(d, &node); r = sd_device_get_devname(d, &node);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device node: %m"); return log_device_error_errno(d, r, "Failed to get device node: %m");
r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &type); r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &type);
if (r < 0) if (r < 0)
return log_device_error_errno(d, r, "Failed to query ID_PART_ENTRY_SCHEME: %m"); return log_device_full_errno(d,
searching && r == -ENOENT ? LOG_DEBUG : LOG_ERR,
searching && r == -ENOENT ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : r,
"Failed to query ID_PART_ENTRY_SCHEME: %m");
if (streq(type, "gpt")) { if (streq(type, "gpt")) {

View File

@ -32,7 +32,6 @@ int switch_root(const char *new_root,
_cleanup_free_ char *resolved_old_root_after = NULL; _cleanup_free_ char *resolved_old_root_after = NULL;
_cleanup_close_ int old_root_fd = -1; _cleanup_close_ int old_root_fd = -1;
bool old_root_remove;
int r; int r;
assert(new_root); assert(new_root);
@ -42,12 +41,16 @@ int switch_root(const char *new_root,
return 0; return 0;
/* Check if we shall remove the contents of the old root */ /* Check if we shall remove the contents of the old root */
old_root_remove = in_initrd(); old_root_fd = open("/", O_RDONLY | O_CLOEXEC | O_DIRECTORY);
if (old_root_remove) { if (old_root_fd < 0)
old_root_fd = open("/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY|O_DIRECTORY); return log_error_errno(errno, "Failed to open root directory: %m");
if (old_root_fd < 0) r = fd_is_temporary_fs(old_root_fd);
return log_error_errno(errno, "Failed to open root directory: %m"); if (r < 0)
} return log_error_errno(r, "Failed to stat root directory: %m");
if (r > 0)
log_debug("Root directory is on tmpfs, will do cleanup later.");
else
old_root_fd = safe_close(old_root_fd);
/* Determine where we shall place the old root after the transition */ /* Determine where we shall place the old root after the transition */
r = chase_symlinks(old_root_after, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved_old_root_after, NULL); r = chase_symlinks(old_root_after, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved_old_root_after, NULL);
@ -117,9 +120,8 @@ int switch_root(const char *new_root,
struct stat rb; struct stat rb;
if (fstat(old_root_fd, &rb) < 0) if (fstat(old_root_fd, &rb) < 0)
log_warning_errno(errno, "Failed to stat old root directory, leaving: %m"); return log_error_errno(errno, "Failed to stat old root directory: %m");
else (void) rm_rf_children(TAKE_FD(old_root_fd), 0, &rb); /* takes possession of the dir fd, even on failure */
(void) rm_rf_children(TAKE_FD(old_root_fd), 0, &rb); /* takes possession of the dir fd, even on failure */
} }
return 0; return 0;

View File

@ -152,8 +152,19 @@ int tpm2_context_init(const char *device, struct tpm2_context *ret) {
if (r < 0) if (r < 0)
return log_error_errno(r, "TPM2 support not installed: %m"); return log_error_errno(r, "TPM2 support not installed: %m");
if (!device) if (!device) {
device = secure_getenv("SYSTEMD_TPM2_DEVICE"); device = secure_getenv("SYSTEMD_TPM2_DEVICE");
if (device)
/* Setting the env var to an empty string forces tpm2-tss' own device picking
* logic to be used. */
device = empty_to_null(device);
else
/* If nothing was specified explicitly, we'll use a hardcoded default: the "device" tcti
* driver and the "/dev/tpmrm0" device. We do this since on some distributions the tpm2-abrmd
* might be used and we really don't want that, since it is a system service and that creates
* various ordering issues/deadlocks during early boot. */
device = "device:/dev/tpmrm0";
}
if (device) { if (device) {
const char *param, *driver, *fn; const char *param, *driver, *fn;
@ -163,15 +174,27 @@ int tpm2_context_init(const char *device, struct tpm2_context *ret) {
param = strchr(device, ':'); param = strchr(device, ':');
if (param) { if (param) {
/* Syntax #1: Pair of driver string and arbitrary parameter */
driver = strndupa_safe(device, param - device); driver = strndupa_safe(device, param - device);
if (isempty(driver))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 driver name is empty, refusing.");
param++; param++;
} else { } else if (path_is_absolute(device) && path_is_valid(device)) {
/* Syntax #2: TPM device node */
driver = "device"; driver = "device";
param = device; param = device;
} } else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid TPM2 driver string, refusing.");
log_debug("Using TPM2 TCTI driver '%s' with device '%s'.", driver, param);
fn = strjoina("libtss2-tcti-", driver, ".so.0"); fn = strjoina("libtss2-tcti-", driver, ".so.0");
/* Better safe than sorry, let's refuse strings that cannot possibly be valid driver early, before going to disk. */
if (!filename_is_valid(fn))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "TPM2 driver name '%s' not valid, refusing.", driver);
dl = dlopen(fn, RTLD_NOW); dl = dlopen(fn, RTLD_NOW);
if (!dl) if (!dl)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to load %s: %s", fn, dlerror()); return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to load %s: %s", fn, dlerror());
@ -1094,7 +1117,13 @@ static int tpm2_make_policy_session(
ESYS_TR_NONE, ESYS_TR_NONE,
NULL, NULL,
&pubkey_tpm2, &pubkey_tpm2,
#if HAVE_TSS2_ESYS3
/* tpm2-tss >= 3.0.0 requires a ESYS_TR_RH_* constant specifying the requested
* hierarchy, older versions need TPM2_RH_* instead. */
ESYS_TR_RH_OWNER,
#else
TPM2_RH_OWNER, TPM2_RH_OWNER,
#endif
&pubkey_handle); &pubkey_handle);
if (rc != TSS2_RC_SUCCESS) { if (rc != TSS2_RC_SUCCESS) {
r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),

View File

@ -642,9 +642,46 @@ static int device_is_power_sink(sd_device *device) {
return found_sink || !found_source; return found_sink || !found_source;
} }
static bool battery_is_discharging(sd_device *d) {
const char *val;
int r;
assert(d);
r = sd_device_get_sysattr_value(d, "scope", &val);
if (r < 0) {
if (r != -ENOENT)
log_device_debug_errno(d, r, "Failed to read 'scope' sysfs attribute, ignoring: %m");
} else if (streq(val, "Device")) {
log_device_debug(d, "The power supply is a device battery, ignoring device.");
return false;
}
r = device_get_sysattr_bool(d, "present");
if (r < 0)
log_device_debug_errno(d, r, "Failed to read 'present' sysfs attribute, assuming the battery is present: %m");
else if (r == 0) {
log_device_debug(d, "The battery is not present, ignoring the power supply.");
return false;
}
/* Possible values: "Unknown", "Charging", "Discharging", "Not charging", "Full" */
r = sd_device_get_sysattr_value(d, "status", &val);
if (r < 0) {
log_device_debug_errno(d, r, "Failed to read 'status' sysfs attribute, assuming the battery is discharging: %m");
return true;
}
if (!streq(val, "Discharging")) {
log_device_debug(d, "The battery status is '%s', assuming the battery is not used as a power source of this machine.", val);
return false;
}
return true;
}
int on_ac_power(void) { int on_ac_power(void) {
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
bool found_ac_online = false, found_battery = false; bool found_ac_online = false, found_discharging_battery = false;
sd_device *d; sd_device *d;
int r; int r;
@ -686,17 +723,10 @@ int on_ac_power(void) {
} }
if (streq(val, "Battery")) { if (streq(val, "Battery")) {
r = sd_device_get_sysattr_value(d, "scope", &val); if (battery_is_discharging(d)) {
if (r < 0) { found_discharging_battery = true;
if (r != -ENOENT) log_device_debug(d, "The power supply is a battery and currently discharging.");
log_device_debug_errno(d, r, "Failed to read 'scope' sysfs attribute, ignoring: %m");
} else if (streq(val, "Device")) {
log_device_debug(d, "The power supply is a device battery, ignoring device.");
continue;
} }
found_battery = true;
log_device_debug(d, "The power supply is battery.");
continue; continue;
} }
@ -713,11 +743,11 @@ int on_ac_power(void) {
if (found_ac_online) { if (found_ac_online) {
log_debug("Found at least one online non-battery power supply, system is running on AC."); log_debug("Found at least one online non-battery power supply, system is running on AC.");
return true; return true;
} else if (found_battery) { } else if (found_discharging_battery) {
log_debug("Found battery and no online power sources, assuming system is running from battery."); log_debug("Found at least one discharging battery and no online power sources, assuming system is running from battery.");
return false; return false;
} else { } else {
log_debug("No power supply reported online and no battery, assuming system is running on AC."); log_debug("No power supply reported online and no discharging battery found, assuming system is running on AC.");
return true; return true;
} }
} }

View File

@ -2207,9 +2207,10 @@ int verb_show(int argc, char *argv[], void *userdata) {
if (!arg_states && !arg_types) { if (!arg_states && !arg_types) {
if (show_mode == SYSTEMCTL_SHOW_PROPERTIES) if (show_mode == SYSTEMCTL_SHOW_PROPERTIES)
r = show_one(bus, "/org/freedesktop/systemd1", NULL, show_mode, &new_line, &ellipsized); /* systemctl show --all → show properties of the manager */
else return show_one(bus, "/org/freedesktop/systemd1", NULL, show_mode, &new_line, &ellipsized);
r = show_system_status(bus);
r = show_system_status(bus);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -622,7 +622,8 @@ tests += [
[files('test-journal-importer.c')], [files('test-journal-importer.c')],
[files('test-utmp.c')], [files('test-utmp.c'),
[], [], [], 'ENABLE_UTMP'],
[files('test-udev.c'), [files('test-udev.c'),
[libudevd_core, [libudevd_core,

View File

@ -961,22 +961,34 @@ shortcut:
return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, 0); return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, 0);
} }
static int path_open_parent_safe(const char *path) { static int path_open_parent_safe(const char *path, bool allow_failure) {
_cleanup_free_ char *dn = NULL; _cleanup_free_ char *dn = NULL;
int r, fd; int r, fd;
if (!path_is_normalized(path)) if (!path_is_normalized(path))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to open parent of '%s': path not normalized.", path); return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
SYNTHETIC_ERRNO(EINVAL),
"Failed to open parent of '%s': path not normalized%s.",
path,
allow_failure ? ", ignoring" : "");
r = path_extract_directory(path, &dn); r = path_extract_directory(path, &dn);
if (r < 0) if (r < 0)
return log_error_errno(r, "Unable to determine parent directory of '%s': %m", path); return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
r,
"Unable to determine parent directory of '%s'%s: %m",
path,
allow_failure ? ", ignoring" : "");
r = chase_symlinks(dn, arg_root, CHASE_SAFE|CHASE_WARN, NULL, &fd); r = chase_symlinks(dn, arg_root, allow_failure ? CHASE_SAFE : CHASE_SAFE|CHASE_WARN, NULL, &fd);
if (r == -ENOLINK) /* Unsafe symlink: already covered by CHASE_WARN */ if (r == -ENOLINK) /* Unsafe symlink: already covered by CHASE_WARN */
return r; return r;
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to open path '%s': %m", dn); return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
r,
"Failed to open path '%s'%s: %m",
dn,
allow_failure ? ", ignoring" : "");
return fd; return fd;
} }
@ -1431,7 +1443,7 @@ static int write_one_file(Item *i, const char *path, CreationMode creation) {
/* Validate the path and keep the fd on the directory for opening the file so we're sure that it /* Validate the path and keep the fd on the directory for opening the file so we're sure that it
* can't be changed behind our back. */ * can't be changed behind our back. */
dir_fd = path_open_parent_safe(path); dir_fd = path_open_parent_safe(path, i->allow_failure);
if (dir_fd < 0) if (dir_fd < 0)
return dir_fd; return dir_fd;
@ -1481,7 +1493,7 @@ static int create_file(Item *i, const char *path) {
/* Validate the path and keep the fd on the directory for opening the file so we're sure that it /* Validate the path and keep the fd on the directory for opening the file so we're sure that it
* can't be changed behind our back. */ * can't be changed behind our back. */
dir_fd = path_open_parent_safe(path); dir_fd = path_open_parent_safe(path, i->allow_failure);
if (dir_fd < 0) if (dir_fd < 0)
return dir_fd; return dir_fd;
@ -1549,7 +1561,7 @@ static int truncate_file(Item *i, const char *path) {
/* Validate the path and keep the fd on the directory for opening the file so we're sure that it /* Validate the path and keep the fd on the directory for opening the file so we're sure that it
* can't be changed behind our back. */ * can't be changed behind our back. */
dir_fd = path_open_parent_safe(path); dir_fd = path_open_parent_safe(path, i->allow_failure);
if (dir_fd < 0) if (dir_fd < 0)
return dir_fd; return dir_fd;
@ -1628,7 +1640,7 @@ static int copy_files(Item *i) {
/* Validate the path and use the returned directory fd for copying the target so we're sure that the /* Validate the path and use the returned directory fd for copying the target so we're sure that the
* path can't be changed behind our back. */ * path can't be changed behind our back. */
dfd = path_open_parent_safe(i->path); dfd = path_open_parent_safe(i->path, i->allow_failure);
if (dfd < 0) if (dfd < 0)
return dfd; return dfd;
@ -1664,6 +1676,7 @@ static int create_directory_or_subvolume(
const char *path, const char *path,
mode_t mode, mode_t mode,
bool subvol, bool subvol,
bool allow_failure,
struct stat *ret_st, struct stat *ret_st,
CreationMode *ret_creation) { CreationMode *ret_creation) {
@ -1679,7 +1692,7 @@ static int create_directory_or_subvolume(
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to extract filename from path '%s': %m", path); return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
pfd = path_open_parent_safe(path); pfd = path_open_parent_safe(path, allow_failure);
if (pfd < 0) if (pfd < 0)
return pfd; return pfd;
@ -1720,7 +1733,11 @@ static int create_directory_or_subvolume(
/* Then look at the original error */ /* Then look at the original error */
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", path); return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
r,
"Failed to create directory or subvolume \"%s\"%s: %m",
path,
allow_failure ? ", ignoring" : "");
return log_error_errno(errno, "Failed to open directory/subvolume we just created '%s': %m", path); return log_error_errno(errno, "Failed to open directory/subvolume we just created '%s': %m", path);
} }
@ -1748,7 +1765,7 @@ static int create_directory(Item *i, const char *path) {
assert(i); assert(i);
assert(IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY)); assert(IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY));
fd = create_directory_or_subvolume(path, i->mode, /* subvol= */ false, &st, &creation); fd = create_directory_or_subvolume(path, i->mode, /* subvol= */ false, i->allow_failure, &st, &creation);
if (fd == -EEXIST) if (fd == -EEXIST)
return 0; return 0;
if (fd < 0) if (fd < 0)
@ -1766,7 +1783,7 @@ static int create_subvolume(Item *i, const char *path) {
assert(i); assert(i);
assert(IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)); assert(IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA));
fd = create_directory_or_subvolume(path, i->mode, /* subvol = */ true, &st, &creation); fd = create_directory_or_subvolume(path, i->mode, /* subvol = */ true, i->allow_failure, &st, &creation);
if (fd == -EEXIST) if (fd == -EEXIST)
return 0; return 0;
if (fd < 0) if (fd < 0)
@ -1845,7 +1862,7 @@ static int create_device(Item *i, mode_t file_type) {
/* Validate the path and use the returned directory fd for copying the target so we're sure that the /* Validate the path and use the returned directory fd for copying the target so we're sure that the
* path can't be changed behind our back. */ * path can't be changed behind our back. */
dfd = path_open_parent_safe(i->path); dfd = path_open_parent_safe(i->path, i->allow_failure);
if (dfd < 0) if (dfd < 0)
return dfd; return dfd;
@ -1947,7 +1964,7 @@ static int create_fifo(Item *i) {
if (r == O_DIRECTORY) if (r == O_DIRECTORY)
return log_error_errno(SYNTHETIC_ERRNO(EISDIR), "Cannot open path '%s' for creating FIFO, is a directory.", i->path); return log_error_errno(SYNTHETIC_ERRNO(EISDIR), "Cannot open path '%s' for creating FIFO, is a directory.", i->path);
pfd = path_open_parent_safe(i->path); pfd = path_open_parent_safe(i->path, i->allow_failure);
if (pfd < 0) if (pfd < 0)
return pfd; return pfd;
@ -2032,7 +2049,7 @@ static int create_symlink(Item *i) {
if (r == O_DIRECTORY) if (r == O_DIRECTORY)
return log_error_errno(SYNTHETIC_ERRNO(EISDIR), "Cannot open path '%s' for creating FIFO, is a directory.", i->path); return log_error_errno(SYNTHETIC_ERRNO(EISDIR), "Cannot open path '%s' for creating FIFO, is a directory.", i->path);
pfd = path_open_parent_safe(i->path); pfd = path_open_parent_safe(i->path, i->allow_failure);
if (pfd < 0) if (pfd < 0)
return pfd; return pfd;

View File

@ -120,14 +120,14 @@ static int find_gpt_root(sd_device *dev, blkid_probe pr, bool test) {
#if defined(SD_GPT_ROOT_NATIVE) && ENABLE_EFI #if defined(SD_GPT_ROOT_NATIVE) && ENABLE_EFI
_cleanup_free_ char *root_id = NULL, *root_label = NULL; _cleanup_free_ char *root_id = NULL, *root_label = NULL;
bool found_esp = false; bool found_esp_or_xbootldr = false;
int r; int r;
assert(pr); assert(pr);
/* Iterate through the partitions on this disk, and see if the /* Iterate through the partitions on this disk, and see if the UEFI ESP or XBOOTLDR partition we
* EFI ESP we booted from is on it. If so, find the first root * booted from is on it. If so, find the first root disk, and add a property indicating its partition
* disk, and add a property indicating its partition UUID. */ * UUID. */
errno = 0; errno = 0;
blkid_partlist pl = blkid_probe_get_partitions(pr); blkid_partlist pl = blkid_probe_get_partitions(pr);
@ -157,21 +157,20 @@ static int find_gpt_root(sd_device *dev, blkid_probe pr, bool test) {
if (sd_id128_from_string(stype, &type) < 0) if (sd_id128_from_string(stype, &type) < 0)
continue; continue;
if (sd_id128_equal(type, SD_GPT_ESP)) { if (sd_id128_in_set(type, SD_GPT_ESP, SD_GPT_XBOOTLDR)) {
sd_id128_t id, esp; sd_id128_t id, esp_or_xbootldr;
/* We found an ESP, let's see if it matches /* We found an ESP or XBOOTLDR, let's see if it matches the ESP/XBOOTLDR we booted from. */
* the ESP we booted from. */
if (sd_id128_from_string(sid, &id) < 0) if (sd_id128_from_string(sid, &id) < 0)
continue; continue;
r = efi_loader_get_device_part_uuid(&esp); r = efi_loader_get_device_part_uuid(&esp_or_xbootldr);
if (r < 0) if (r < 0)
return r; return r;
if (sd_id128_equal(id, esp)) if (sd_id128_equal(id, esp_or_xbootldr))
found_esp = true; found_esp_or_xbootldr = true;
} else if (sd_id128_equal(type, SD_GPT_ROOT_NATIVE)) { } else if (sd_id128_equal(type, SD_GPT_ROOT_NATIVE)) {
unsigned long long flags; unsigned long long flags;
@ -195,9 +194,9 @@ static int find_gpt_root(sd_device *dev, blkid_probe pr, bool test) {
} }
} }
/* We found the ESP on this disk, and also found a root /* We found the ESP/XBOOTLDR on this disk, and also found a root partition, nice! Let's export its
* partition, nice! Let's export its UUID */ * UUID */
if (found_esp && root_id) if (found_esp_or_xbootldr && root_id)
udev_builtin_add_property(dev, test, "ID_PART_GPT_AUTO_ROOT_UUID", root_id); udev_builtin_add_property(dev, test, "ID_PART_GPT_AUTO_ROOT_UUID", root_id);
#endif #endif