1
0
mirror of https://github.com/systemd/systemd synced 2025-09-30 17:24:46 +02:00

Compare commits

...

14 Commits

Author SHA1 Message Date
Luca Boccassi
1441f2e992
Add padding to sbat section (#38621) 2025-08-19 17:49:07 +01:00
Luca Boccassi
70b7e03ebb sd-stub: use memory proto if available and set kernel memory to RX with NX_COMPAT
When NX_COMPAT gets enabled, firmwares will enforce that executable
memory is either writable or executable.
This needs kernel compatibility, when it will happen the kernel will
have the NX_COMPAT bit set. If it is, set the memory buffer to RO.

Note that this must be undone on failure, as EDK2 in some configurations
overwrites memory ranges that are returned with FreePages() with a
fixed pattern, so if the pages are RO it will crash.

This is only an issue with the new custom PE loader, as LoadImage()
and StartImage() will always do the right thing automatically.

https://microsoft.github.io/mu/WhatAndWhy/enhancedmemoryprotection/
https://www.kraxel.org/blog/2023/12/uefi-nx-linux-boot/

Follow-up for cab9c7b5a42effa8a45611fc6b8556138c869b5f

Fixes https://github.com/systemd/systemd/issues/38545
2025-08-19 17:16:57 +02:00
Luca Boccassi
490aa05ca1 chase: invert CHASE_NO_AUTOFS and only set it where needed
Since c5de7b14ae
file searching implies a new mount api syscall by default,
to trigger automounts.

This is problematic in NSS plugins, as they are dlopen'ed inside
processes by glibc, for two reasons.

First of all, potentially searching on a networked filesystem
automount could lead to nasty surprises, such as the process
responsible for setting up the network filesystem trying to
search on that same filesystem.

More importantly, the new mount api syscall was never part of
the filesystem seccomp filter that we provide by default, and
given mounting/remounting/bind mounting is one of the possible
ways to bypass sandboxing it is very likely not allowed when
custom filters are used in sandboxed processes, if they don't
need to do these operations otherwise.
The filesystem seccomp mask we provide has been updated, however
this only takes effect on the next restart of a service. When
systemd is upgraded via a package upgrade, the new nss plugin is
installed and will be immediately dlopen'ed by glibc when needed,
without waiting for the process to restart, which means the existing
seccomp filter applies, causing the filter to trigger.
Given it's not really possible for any arbitrary program to
predict which NSS modules glibc will load, given programs do not
configure that and instead nsswitch is set up by the sysadmin,
it's impossible to handle at each process level. It's also not
possible to know when it will be triggered, given the plugin
is not linked in each binary tools like need-restart cannot
even pre-emptively restart services that may be affected.

This means in practice, upgrading from systemd << v258 to >= v258
requires a reboot to avoid either subtle or catastrophic system
failures.

By avoiding to trigger automounts in nss-systemd we can avoid
both issues.

userdb drop-ins are searched for in:

/etc/userdb/
/run/userdb/
/run/host/userdb/
/usr/local/lib/userdb/
/usr/lib/userdb/

none of which are supported as automounts anyway.

Note that this happens only when the userdbd service is not running,
as otherwise nss-systemd will go through the varlink IPC, rather than
doing the searches in-process.

So invert CHASE_NO_AUTOFS to CHASE_AUTOFS and set it in the places where
we do want to trigger automounts, like looking for the ESP.

Follow-up for c5de7b14ae
Fixes https://github.com/systemd/systemd/issues/38565
2025-08-19 16:48:13 +02:00
Alexander Bruy
b15ff659b4 hwdb: map FN key on TongFang X4SP4NAL laptops 2025-08-19 13:05:56 +01:00
Luca Boccassi
b1cd38e893
test: also edit /etc/os-release if it's not a symlink when patching /usr/lib/os-release (#38628)
mkosi patches up /etc/os-release to add local IDs and fixup certain
issues, so when tests patch /usr/lib/ on the fly, copy to the version in
/etc/ too to avoid test failures when querying

6370s 10/98 systemd:integration-tests / TEST-07-PID1 FAIL 31.03s exit
status 1
6370s 25/98 systemd:integration-tests / TEST-29-PORTABLE FAIL 12.76s
exit status 1
6370s 33/98 systemd:integration-tests / TEST-43-PRIVATEUSER-UNPRIV FAIL
6.57s exit status 1
6370s 37/98 systemd:integration-tests / TEST-50-DISSECT FAIL 16.97s exit
status 1

This is particularly an issue when running these tests on debian unstable,
where mkosi has to fixup os-release to make it valid and avoid further
breakages:

https://github.com/systemd/mkosi/blob/main/mkosi/distributions/debian.py#L234
2025-08-19 12:32:00 +01:00
Lennart Poettering
265386ba35 importd: accept a single space as SHA256SUMS separator
The SHA256SUMS files provided by https://images.linuxcontainers.org/
are slightly non-conforming, insted of using " *" or "  " as separator
between hash and file name they use " ". Let's accept that too, in the
interest of maximizing compatibility.
2025-08-19 11:49:19 +01:00
Lennart Poettering
de9e6428b5 mountfsd: include polkit allowInteractiveAuthorization field in IDL
Otherwise this option can never be actually used, as the IDL checker
will refuse any attempts to pass it.

Follow-up for: 0261fe571b3e05834b4c7826447ac6e6e434f08e
2025-08-19 11:48:14 +01:00
Lennart Poettering
a294cc182d dissect-image: fix two log messages in mountfsd_mount_directory_fd()
Let's fix some copypasta and make the log messages actually match what
they are about.
2025-08-19 11:47:49 +01:00
Zbigniew Jędrzejewski-Szmek
ee45041da1 ukify: stop appending NUL to merged .sbat section
Our tools will strip trailing NULs, so this is not causing harm, except for
the corner case when the .sbat section is exactly of the maximum size and now
it wouldn't fit because we're one byte short.

But it also is not needed. Sections have an encoded size of the data and the
reader must use that and must be prepared to handle a text section that does
not end in NUL. Appending of the NUL was added in
c3f7501c4d014482b17988d5aed1d88127a50b6e, without any discussion of this
change. Since we didn't insert the NUL before, the tools must have been
prepared to work without it. I think it's better to keep the code clean and
not do this unnecessary step.
2025-08-19 11:50:28 +02:00
Zbigniew Jędrzejewski-Szmek
b4a1854397 sd-boot: pad .sbat section to 1k bytes
Fedora's kernels now ship with a .sbat section:
  kernel,1,Red Hat,kernel-core,6.17.0-0.rc1.250814g0cc53520e68b.20.fc44.x86_64,mailto:secalert@redhat.com
  kernel.fedora,1,Red Hat,kernel-core,6.17.0-0.rc1.250814g0cc53520e68b.20.fc44.x86_64,mailto:secalert@redhat.com
This pushes the combined .sbat section just over its pre-allocated size of 512 bytes:
  File "/usr/bin/ukify", line 1048, in pe_add_sections
    raise PEError(f'Not enough space in existing section {section.name} to append new data')
  PEError: Not enough space in existing section .sbat to append new data

PE sections need to align to 512 bytes, so to make it all fit we pad the .sbat
section with zeros to 1k. Various tools already should strip trailing zeros when
using sbat sections, since ukify always inserts a trailing NUL.

The defines are moved to sbat.h, they are used only in sd-stub and sd-boot.
2025-08-19 11:50:27 +02:00
Zbigniew Jędrzejewski-Szmek
ec1d031f3d ukify: fix insertion of padding in merged sections
The padding was done to expand the new section contents to the expected size of
the new section. And this then would be used for the content in the existing
section. The new section cannot be larger than the old section, but it can be
smaller. If the new section was smaller, then we'd not write enough padding and
the output file would be corrupted.

This was observed in CI when the .sbat section in the stub was padded to 1k.
The UKI with an .sbat section that was merged and was fairly short would hit
this scenario and be corrupted.
2025-08-19 11:08:35 +02:00
Zbigniew Jędrzejewski-Szmek
2ddbbb22db ukify: adjust comments 2025-08-19 10:46:36 +02:00
Zbigniew Jędrzejewski-Szmek
dbd7b16819 ukify: extend error message when section is too small 2025-08-19 10:46:36 +02:00
Zbigniew Jędrzejewski-Szmek
58c2e99012 fundamental/macro: adjust indentation of ifdefs 2025-08-18 09:52:43 +02:00
34 changed files with 279 additions and 91 deletions

View File

@ -2015,6 +2015,13 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnSystem76*:pnPangolin*:pvrpang15*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnT-bao:pnTbookair:*
KEYBOARD_KEY_76=touchpad_toggle # Touchpad toggle
###########################################################
# TongFang
###########################################################
# TongFang GX4 (X4SP4NAL)
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAiStone:pnX4SP4NAL:*
KEYBOARD_KEY_f8=fn
###########################################################
# Toshiba
###########################################################

View File

@ -8,4 +8,7 @@ cat >>"$BUILDROOT/usr/lib/os-release" <<EOF
MARKER=1
PORTABLE_PREFIXES=app0 minimal minimal-app0
EOF
if [ ! -L "$BUILDROOT/etc/os-release" ]; then
cp "$BUILDROOT/usr/lib/os-release" "$BUILDROOT/etc/os-release"
fi
cp "$BUILDROOT/usr/lib/systemd/system/minimal-app0.service" "$BUILDROOT/usr/lib/systemd/system/minimal-app0-foo.service"

View File

@ -8,4 +8,7 @@ cat >>"$BUILDROOT/usr/lib/os-release" <<EOF
MARKER=2
PORTABLE_PREFIXES=app0 minimal minimal-app0
EOF
if [ ! -L "$BUILDROOT/etc/os-release" ]; then
cp "$BUILDROOT/usr/lib/os-release" "$BUILDROOT/etc/os-release"
fi
cp "$BUILDROOT/usr/lib/systemd/system/minimal-app0.service" "$BUILDROOT/usr/lib/systemd/system/minimal-app0-bar.service"

View File

@ -62,6 +62,7 @@ wrap=(
findmnt
getent
getfacl
groups
id
integritysetup
iscsid

View File

@ -83,7 +83,7 @@ static int openat_opath_with_automount(int dir_fd, const char *path, bool automo
/* Pin an inode via O_PATH semantics. Sounds pretty obvious to do this, right? You just do open()
* with O_PATH, and there you go. But uh, it's not that easy. open() via O_PATH does not trigger
* automounts, but we usually want that (except if CHASE_NO_AUTOFS is used). But thankfully there's
* automounts, but we usually want that (when CHASE_AUTOFS is used). But thankfully there's
* a way out: the newer open_tree() call, when specified without OPEN_TREE_CLONE actually is fully
* equivalent to open() with O_PATH except for one thing: it triggers automounts.
*
@ -202,7 +202,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
* -ENOLINK. If CHASE_WARN is also set, a warning describing the unsafe transition is emitted.
* CHASE_WARN cannot be used in PID 1.
*
* 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, path normalization
* 5. Without CHASE_AUTOFS: in this case if an autofs mount point is encountered, path normalization
* is aborted and -EREMOTE is returned. If CHASE_WARN is also set, a warning showing the path of
* the mount point is emitted. CHASE_WARN cannot be used in PID 1.
*/
@ -219,7 +219,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
}
if (!(flags &
(CHASE_AT_RESOLVE_IN_ROOT|CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP|
(CHASE_AT_RESOLVE_IN_ROOT|CHASE_NONEXISTENT|CHASE_AUTOFS|CHASE_SAFE|CHASE_STEP|
CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755|CHASE_PARENT)) &&
!ret_path && ret_fd) {
@ -396,7 +396,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
}
/* Otherwise let's pin it by file descriptor, via O_PATH. */
child = r = openat_opath_with_automount(fd, first, /* automount = */ !FLAGS_SET(flags, CHASE_NO_AUTOFS));
child = r = openat_opath_with_automount(fd, first, /* automount = */ FLAGS_SET(flags, CHASE_AUTOFS));
if (r < 0) {
if (r != -ENOENT)
return r;
@ -435,7 +435,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
unsafe_transition(&st, &st_child))
return log_unsafe_transition(fd, child, path, flags);
if (FLAGS_SET(flags, CHASE_NO_AUTOFS) &&
if (!FLAGS_SET(flags, CHASE_AUTOFS) &&
fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
return log_autofs_mount_point(child, path, flags);
@ -783,7 +783,7 @@ int chase_and_open(
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return xopenat_full(AT_FDCWD, path,
open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0),
@ -822,7 +822,7 @@ int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags
assert(ret_dir);
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
/* Shortcut this call if none of the special features of this call are requested */
d = opendir(path);
if (!d)
@ -858,7 +858,7 @@ int chase_and_stat(const char *path, const char *root, ChaseFlags chase_flags, c
assert(ret_stat);
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(fstatat(AT_FDCWD, path, ret_stat,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));
@ -886,7 +886,7 @@ int chase_and_access(const char *path, const char *root, ChaseFlags chase_flags,
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(faccessat(AT_FDCWD, path, access_mode,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));
@ -992,7 +992,7 @@ int chase_and_openat(
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return xopenat_full(dir_fd, path,
open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0),
@ -1029,7 +1029,7 @@ int chase_and_opendirat(int dir_fd, const char *path, ChaseFlags chase_flags, ch
assert(ret_dir);
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
/* Shortcut this call if none of the special features of this call are requested */
d = opendir(path);
if (!d)
@ -1065,7 +1065,7 @@ int chase_and_statat(int dir_fd, const char *path, ChaseFlags chase_flags, char
assert(ret_stat);
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(fstatat(AT_FDCWD, path, ret_stat,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));
@ -1093,7 +1093,7 @@ int chase_and_accessat(int dir_fd, const char *path, ChaseFlags chase_flags, int
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
(chase_flags & (CHASE_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(faccessat(AT_FDCWD, path, access_mode,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));

View File

@ -6,7 +6,7 @@
typedef enum ChaseFlags {
CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */
CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */
CHASE_NO_AUTOFS = 1 << 2, /* Return -EREMOTE if autofs mount point found */
CHASE_AUTOFS = 1 << 2, /* Trigger automount if autofs mount point found instead of returning -EREMOTE */
CHASE_SAFE = 1 << 3, /* Return -EPERM if we ever traverse from unprivileged to privileged files or directories */
CHASE_TRAIL_SLASH = 1 << 4, /* Any trailing slash will be preserved */
CHASE_STEP = 1 << 5, /* Just execute a single step of the normalization */

View File

@ -15,6 +15,7 @@
#include "pe.h"
#include "proto/device-path.h"
#include "proto/loaded-image.h"
#include "proto/memory-attribute.h"
#include "secure-boot.h"
#include "shim.h"
#include "util.h"
@ -125,6 +126,50 @@ static EFI_STATUS load_via_boot_services(
return log_error_status(err, "Error starting kernel image with shim: %m");
}
static EFI_STATUS kernel_set_nx(EFI_PHYSICAL_ADDRESS addr, uint64_t length) {
EFI_MEMORY_ATTRIBUTE_PROTOCOL *memory_proto;
EFI_STATUS err;
err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_MEMORY_ATTRIBUTE_PROTOCOL), NULL, (void **) &memory_proto);
if (err != EFI_SUCCESS) {
log_debug("No EFI_MEMORY_ATTRIBUTE_PROTOCOL found, skipping NX_COMPAT support.");
return EFI_SUCCESS; /* ignore if firmware lacks support */
}
err = memory_proto->SetMemoryAttributes(memory_proto, addr, length, EFI_MEMORY_RO);
if (err != EFI_SUCCESS)
return log_error_status(err, "Cannot make kernel image read-only: %m");
err = memory_proto->ClearMemoryAttributes(memory_proto, addr, length, EFI_MEMORY_XP);
if (err != EFI_SUCCESS)
return log_error_status(err, "Cannot make kernel image executable: %m");
log_debug("Changed kernel image to read-only for NX_COMPAT support.");
return EFI_SUCCESS;
}
static EFI_STATUS kernel_clear_nx(EFI_PHYSICAL_ADDRESS addr, uint64_t length) {
EFI_MEMORY_ATTRIBUTE_PROTOCOL *memory_proto;
EFI_STATUS err;
err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_MEMORY_ATTRIBUTE_PROTOCOL), NULL, (void **) &memory_proto);
if (err != EFI_SUCCESS) {
log_debug("No EFI_MEMORY_ATTRIBUTE_PROTOCOL found, skipping NX_COMPAT support.");
return EFI_SUCCESS; /* ignore if firmware lacks support */
}
err = memory_proto->SetMemoryAttributes(memory_proto, addr, length, EFI_MEMORY_XP);
if (err != EFI_SUCCESS)
return log_error_status(err, "Cannot make kernel image non-executable: %m");
err = memory_proto->ClearMemoryAttributes(memory_proto, addr, length, EFI_MEMORY_RO);
if (err != EFI_SUCCESS)
return log_error_status(err, "Cannot make kernel image writable: %m");
return EFI_SUCCESS;
}
EFI_STATUS linux_exec(
EFI_HANDLE parent_image,
const char16_t *cmdline,
@ -198,6 +243,16 @@ EFI_STATUS linux_exec(
if (err != EFI_SUCCESS)
return err;
/* As per MSFT requirement, memory pages need to be marked W^X.
* Firmwares will start enforcing this at some point in the near-ish future.
* The kernel needs to mark this as supported explicitly, otherwise it will crash.
* https://microsoft.github.io/mu/WhatAndWhy/enhancedmemoryprotection/
* https://www.kraxel.org/blog/2023/12/uefi-nx-linux-boot/ */
_cleanup_free_ EFI_PHYSICAL_ADDRESS *nx_sections_addrs = NULL;
_cleanup_free_ uint64_t *nx_sections_lengths = NULL;
size_t nx_sections = 0;
bool nx_compat = pe_kernel_check_nx_compat(kernel->iov_base);
const PeSectionHeader *headers;
size_t n_headers;
@ -225,6 +280,20 @@ EFI_STATUS linux_exec(
h->SizeOfRawData);
memzero(loaded_kernel + h->VirtualAddress + h->SizeOfRawData,
h->VirtualSize - h->SizeOfRawData);
/* Not a code section? Nothing to do, leave as-is. */
if (nx_compat && ((h->Characteristics & PE_CODE) || (h->Characteristics & PE_EXECUTE))) {
nx_sections_addrs = xrealloc(nx_sections_addrs, nx_sections * sizeof(EFI_PHYSICAL_ADDRESS), (nx_sections + 1) * sizeof(EFI_PHYSICAL_ADDRESS));
nx_sections_lengths = xrealloc(nx_sections_lengths, nx_sections * sizeof(uint64_t), (nx_sections + 1) * sizeof(uint64_t));
nx_sections_addrs[nx_sections] = POINTER_TO_PHYSICAL_ADDRESS(loaded_kernel + h->VirtualAddress - image_base);
nx_sections_lengths[nx_sections] = h->VirtualSize;
err = kernel_set_nx(nx_sections_addrs[nx_sections], nx_sections_lengths[nx_sections]);
if (err != EFI_SUCCESS)
return err;
++nx_sections;
}
}
_cleanup_free_ KERNEL_FILE_PATH *kernel_file_path = xnew(KERNEL_FILE_PATH, 1);
@ -273,5 +342,11 @@ EFI_STATUS linux_exec(
err = compat_entry(parent_image, ST);
}
/* On failure we'll free the buffers. EDK2 requires the memory buffers to be writable and
* non-executable, as in some configurations it will overwrite them with a fixed pattern, so if the
* attributes are not restored FreePages() will crash. */
for (size_t i = 0; i < nx_sections; i++)
(void) kernel_clear_nx(nx_sections_addrs[i], nx_sections_lengths[i]);
return log_error_status(err, "Error starting kernel image: %m");
}

View File

@ -9,6 +9,7 @@
#define DOS_FILE_MAGIC "MZ"
#define PE_FILE_MAGIC "PE\0\0"
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100
#if defined(__i386__)
# define TARGET_MACHINE_TYPE 0x014CU
@ -555,6 +556,18 @@ EFI_STATUS pe_kernel_check_no_relocation(const void *base) {
return EFI_SUCCESS;
}
bool pe_kernel_check_nx_compat(const void *base) {
const DosFileHeader *dos = ASSERT_PTR(base);
if (!verify_dos(dos))
return false;
const PeFileHeader *pe = (const PeFileHeader *) ((const uint8_t *) base + dos->ExeHeader);
if (!verify_pe(dos, pe, /* allow_compatibility= */ true))
return false;
return pe->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
}
EFI_STATUS pe_section_table_from_base(
const void *base,
const PeSectionHeader **ret_section_table,

View File

@ -3,6 +3,10 @@
#include "efi.h"
/* PE flags in the Characteristics attribute of the optional header indicating executable code */
#define PE_CODE 0x00000020
#define PE_EXECUTE 0x20000000
/* This is the actual PE format of the section header */
typedef struct PeSectionHeader {
uint8_t Name[8];
@ -56,3 +60,5 @@ EFI_STATUS pe_memory_locate_sections(
EFI_STATUS pe_kernel_info(const void *base, uint32_t *ret_entry_point, uint32_t *ret_compat_entry_point, uint64_t *ret_image_base, size_t *ret_size_in_memory);
EFI_STATUS pe_kernel_check_no_relocation(const void *base);
bool pe_kernel_check_nx_compat(const void *base);

View File

@ -0,0 +1,31 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "efi.h"
#define EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \
GUID_DEF(0xf4560cf6, 0x40ec, 0x4b4a, 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89)
#define EFI_MEMORY_RP 0x0000000000002000
#define EFI_MEMORY_XP 0x0000000000004000
#define EFI_MEMORY_RO 0x0000000000020000
struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL;
typedef struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL {
EFI_STATUS (EFIAPI *GetMemoryAttributes)(
struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
EFI_PHYSICAL_ADDRESS BaseAddress,
uint64_t Length,
uint64_t *Attributes);
EFI_STATUS (EFIAPI *SetMemoryAttributes)(
struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
EFI_PHYSICAL_ADDRESS BaseAddress,
uint64_t Length,
uint64_t Attributes);
EFI_STATUS (EFIAPI *ClearMemoryAttributes)(
struct _EFI_MEMORY_ATTRIBUTE_PROTOCOL *This,
EFI_PHYSICAL_ADDRESS BaseAddress,
uint64_t Length,
uint64_t Attributes);
} EFI_MEMORY_ATTRIBUTE_PROTOCOL;

View File

@ -51,7 +51,7 @@ enum {
/* magic string to find in the binary image */
DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION " ####");
DECLARE_SBAT(SBAT_STUB_SECTION_TEXT);
DECLARE_SBAT_PADDED(SBAT_STUB_SECTION_TEXT);
static char16_t* pe_section_to_str16(
EFI_LOADED_IMAGE_PROTOCOL *loaded_image,

View File

@ -343,7 +343,7 @@ static int update_efi_boot_binaries(const char *esp_path, const char *source_pat
assert(esp_path);
assert(source_path);
r = chase_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
r = chase_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &p, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
@ -396,10 +396,10 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
if (!p)
return log_oom();
r = chase(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &source_path, NULL);
r = chase(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &source_path, NULL);
/* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
r = chase(p, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &source_path, NULL);
r = chase(p, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &source_path, NULL);
if (r < 0)
return log_error_errno(r,
"Failed to resolve path %s%s%s: %m",
@ -411,7 +411,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
if (!q)
return log_oom();
r = chase(q, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT, &dest_path, NULL);
r = chase(q, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT|CHASE_AUTOFS, &dest_path, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", q, esp_path);
@ -428,7 +428,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
v = strjoina("/EFI/BOOT/BOOT", e);
ascii_strupper(strrchr(v, '/') + 1);
r = chase(v, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT, &default_dest_path, NULL);
r = chase(v, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT|CHASE_AUTOFS, &default_dest_path, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", v, esp_path);
@ -449,10 +449,10 @@ static int install_binaries(const char *esp_path, const char *arch, bool force)
_cleanup_free_ char *path = NULL;
int r;
r = chase_and_opendir(BOOTLIBDIR, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &path, &d);
r = chase_and_opendir(BOOTLIBDIR, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &path, &d);
/* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
r = chase_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &path, &d);
r = chase_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &path, &d);
if (r == -ENOENT && arg_graceful) {
log_debug("Source directory does not exist, ignoring.");
return 0;
@ -634,7 +634,7 @@ static int install_secure_boot_auto_enroll(const char *esp, X509 *certificate, E
if (r < 0)
return r;
_cleanup_close_ int keys_fd = chase_and_open("loader/keys/auto", esp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, O_DIRECTORY, NULL);
_cleanup_close_ int keys_fd = chase_and_open("loader/keys/auto", esp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, O_DIRECTORY, NULL);
if (keys_fd < 0)
return log_error_errno(keys_fd, "Failed to chase loader/keys/auto in the ESP: %m");
@ -881,7 +881,7 @@ static int install_variables(
uint16_t slot;
int r;
r = chase_and_access(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL);
r = chase_and_access(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, F_OK, NULL);
if (r == -ENOENT)
return 0;
if (r < 0)
@ -1097,7 +1097,7 @@ static int remove_boot_efi(const char *esp_path) {
_cleanup_free_ char *p = NULL;
int r, c = 0;
r = chase_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
r = chase_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &p, &d);
if (r == -ENOENT)
return 0;
if (r < 0)

View File

@ -222,7 +222,7 @@ static int enumerate_binaries(
assert(previous);
assert(is_first);
r = chase_and_opendir(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
r = chase_and_opendir(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, &p, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
@ -693,7 +693,7 @@ static void deref_unlink_file(Hashmap **known_files, const char *fn, const char
return;
if (arg_dry_run) {
r = chase_and_access(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, &path);
r = chase_and_access(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, F_OK, &path);
if (r < 0)
log_info_errno(r, "Unable to determine whether \"%s\" exists, ignoring: %m", fn);
else
@ -701,7 +701,7 @@ static void deref_unlink_file(Hashmap **known_files, const char *fn, const char
return;
}
r = chase_and_unlink(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, 0, &path);
r = chase_and_unlink(fn, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, 0, &path);
if (r >= 0)
log_info("Removed \"%s\"", path);
else if (r != -ENOENT)
@ -709,7 +709,7 @@ static void deref_unlink_file(Hashmap **known_files, const char *fn, const char
_cleanup_free_ char *d = NULL;
if (path_extract_directory(fn, &d) >= 0 && !path_equal(d, "/")) {
r = chase_and_unlink(d, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, AT_REMOVEDIR, NULL);
r = chase_and_unlink(d, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, AT_REMOVEDIR, NULL);
if (r < 0 && !IN_SET(r, -ENOTEMPTY, -ENOENT))
log_warning_errno(r, "Failed to remove directory \"%s\", ignoring: %m", d);
}
@ -801,7 +801,7 @@ static int unlink_entry(const BootConfig *config, const char *root, const char *
if (arg_dry_run)
log_info("Would remove \"%s\"", e->path);
else {
r = chase_and_unlink(e->path, root, CHASE_PROHIBIT_SYMLINKS, 0, NULL);
r = chase_and_unlink(e->path, root, CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS, 0, NULL);
if (r < 0)
return log_error_errno(r, "Failed to remove \"%s\": %m", e->path);
@ -862,7 +862,7 @@ static int cleanup_orphaned_files(
if (r < 0)
return log_error_errno(r, "Failed to count files in %s: %m", root);
dir_fd = chase_and_open(arg_entry_token, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS,
dir_fd = chase_and_open(arg_entry_token, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_AUTOFS,
O_DIRECTORY|O_CLOEXEC, &full);
if (dir_fd == -ENOENT)
return 0;

View File

@ -3079,7 +3079,7 @@ static int setup_exec_directory(
* since they all support the private/ symlink logic at least in some
* configurations, see above. */
r = chase(target, NULL, 0, &target_resolved, NULL);
r = chase(target, NULL, CHASE_AUTOFS, &target_resolved, NULL);
if (r < 0)
goto fail;
@ -3090,7 +3090,7 @@ static int setup_exec_directory(
}
/* /var/lib or friends may be symlinks. So, let's chase them also. */
r = chase(q, NULL, CHASE_NONEXISTENT, &q_resolved, NULL);
r = chase(q, NULL, CHASE_NONEXISTENT|CHASE_AUTOFS, &q_resolved, NULL);
if (r < 0)
goto fail;
@ -3985,7 +3985,7 @@ static int apply_working_directory(
r = chase(wd,
runtime->ephemeral_copy ?: context->root_directory,
CHASE_PREFIX_ROOT|CHASE_AT_RESOLVE_IN_ROOT,
CHASE_PREFIX_ROOT|CHASE_AT_RESOLVE_IN_ROOT|CHASE_AUTOFS,
/* ret_path= */ NULL,
&dfd);
if (r >= 0)

View File

@ -1196,7 +1196,7 @@ static void mount_enter_mounting(Mount *m) {
/* Validate that the path we are overmounting does not contain any symlinks, because if it does, we
* couldn't support that reasonably: the mounts in /proc/self/mountinfo would not be recognizable to
* us anymore. */
fd = chase_and_open_parent(m->where, /* root= */ NULL, CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755, &fn);
fd = chase_and_open_parent(m->where, /* root= */ NULL, CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755|CHASE_AUTOFS, &fn);
if (fd == -EREMCHG) {
r = unit_log_noncanonical_mount_path(UNIT(m), m->where);
goto fail;

View File

@ -1793,7 +1793,7 @@ static int follow_symlink(
* a time by specifying CHASE_STEP. This function returns 0 if we resolved one step, and > 0 if we reached the
* end and already have a fully normalized name. */
r = chase(mount_entry_path(m), root_directory, CHASE_STEP|CHASE_NONEXISTENT, &target, NULL);
r = chase(mount_entry_path(m), root_directory, CHASE_STEP|CHASE_NONEXISTENT|CHASE_AUTOFS, &target, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to chase symlinks '%s': %m", mount_entry_path(m));
if (r > 0) /* Reached the end, nothing more to resolve */
@ -1991,7 +1991,7 @@ static int apply_one_mount(
return log_error_errno(r, "Failed to set label of the source directory %s: %m", mount_entry_source(m));
}
r = chase(mount_entry_source(m), NULL, CHASE_TRAIL_SLASH, &chased, NULL);
r = chase(mount_entry_source(m), NULL, CHASE_TRAIL_SLASH|CHASE_AUTOFS, &chased, NULL);
if (r == -ENOENT && m->ignore) {
log_debug_errno(r, "Path %s does not exist, ignoring.", mount_entry_source(m));
return 0;
@ -3434,7 +3434,7 @@ static int is_extension_overlay(const char *path, int fd) {
assert(path);
if (fd < 0) {
r = chase(path, /* root= */ NULL, CHASE_TRAIL_SLASH|CHASE_MUST_BE_DIRECTORY, /* ret_path= */ NULL, &dfd);
r = chase(path, /* root= */ NULL, CHASE_TRAIL_SLASH|CHASE_MUST_BE_DIRECTORY|CHASE_AUTOFS, /* ret_path= */ NULL, &dfd);
if (r < 0)
return r;
fd = dfd;

View File

@ -5622,7 +5622,7 @@ int service_determine_exec_selinux_label(Service *s, char **ret) {
return -ENODATA;
_cleanup_free_ char *path = NULL;
r = chase(c->path, s->exec_context.root_directory, CHASE_PREFIX_ROOT, &path, NULL);
r = chase(c->path, s->exec_context.root_directory, CHASE_PREFIX_ROOT|CHASE_AUTOFS, &path, NULL);
if (r < 0) {
log_unit_debug_errno(UNIT(s), r, "Failed to resolve service binary '%s', ignoring.", c->path);
return -ENODATA;

View File

@ -421,7 +421,7 @@ assert_cc(sizeof(dummy_t) == 0);
/* Restriction/bug (see below) was fixed in GCC 15 and clang 19. */
#if __GNUC__ >= 15 || (defined(__clang__) && __clang_major__ >= 19)
#define DECLARE_FLEX_ARRAY(type, name) type name[]
# define DECLARE_FLEX_ARRAY(type, name) type name[]
#else
/* Declare a flexible array usable in a union.
* This is essentially a work-around for a pointless constraint in C99
@ -436,17 +436,22 @@ assert_cc(sizeof(dummy_t) == 0);
}
#endif
/* Declares an ELF read-only string section that does not occupy memory at runtime. */
#define DECLARE_NOALLOC_SECTION(name, text) \
asm(".pushsection " name ",\"S\"\n\t" \
".ascii " STRINGIFY(text) "\n\t" \
/* Declare an ELF read-only string section that does not occupy memory at runtime. */
#define DECLARE_NOALLOC_SECTION(name, text) \
asm(".pushsection " name ",\"S\"\n\t" \
".ascii " STRINGIFY(text) "\n\t" \
".popsection\n")
#ifdef SBAT_DISTRO
#define DECLARE_SBAT(text) DECLARE_NOALLOC_SECTION(".sbat", text)
#else
#define DECLARE_SBAT(text)
#endif
/* Similar to DECLARE_NOALLOC_SECTION, but pad the section with extra 512 bytes. After taking alignment into
* account, the section has up to 1024 bytes minus the size of the original content of padding, and this
* extra space can be used to extend the contents. This is intended for the .sbat section. */
#define DECLARE_NOALLOC_SECTION_PADDED(name, text) \
assert_cc(STRLEN(text) <= 512); \
asm(".pushsection " name ",\"S\"\n\t" \
".ascii " STRINGIFY(text) "\n\t" \
".balign 512\n\t" \
".fill 512, 1, 0\n\t" \
".popsection\n")
#define typeof_field(struct_type, member) typeof(((struct_type *) 0)->member)
#define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member)

View File

@ -12,3 +12,11 @@
SBAT_PROJECT "-stub" ",1,The systemd Developers," SBAT_PROJECT "," PROJECT_VERSION "," PROJECT_URL "\n" \
SBAT_PROJECT "-stub" "." SBAT_DISTRO "," STRINGIFY(SBAT_DISTRO_GENERATION) "," SBAT_DISTRO_SUMMARY "," SBAT_DISTRO_PKGNAME "," SBAT_DISTRO_VERSION "," SBAT_DISTRO_URL "\n"
#endif
#ifdef SBAT_DISTRO
# define DECLARE_SBAT(text) DECLARE_NOALLOC_SECTION(".sbat", text)
# define DECLARE_SBAT_PADDED(text) DECLARE_NOALLOC_SECTION_PADDED(".sbat", text)
#else
# define DECLARE_SBAT(text)
# define DECLARE_SBAT_PADDED(text)
#endif

View File

@ -6,6 +6,7 @@
#include "dirent-util.h"
#include "escape.h"
#include "fd-util.h"
#include "hexdecoct.h"
#include "io-util.h"
#include "log.h"
#include "memory-util.h"
@ -333,7 +334,6 @@ int pull_make_verification_jobs(
static int verify_one(PullJob *checksum_job, PullJob *job) {
_cleanup_free_ char *fn = NULL;
const char *line, *p;
int r;
assert(checksum_job);
@ -366,17 +366,23 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
return log_error_errno(SYNTHETIC_ERRNO(ELOOP),
"Cannot verify checksum/signature files via themselves.");
line = strjoina(job->checksum, " *", fn, "\n"); /* string for binary mode */
p = memmem_safe(checksum_job->payload,
checksum_job->payload_size,
line,
strlen(line));
if (!p) {
line = strjoina(job->checksum, " ", fn, "\n"); /* string for text mode */
const char *p = NULL;
FOREACH_STRING(separator,
" *", /* separator for binary mode */
" ", /* separator for text mode */
" " /* non-standard separator used by linuxcontainers.org */) {
_cleanup_free_ char *line = NULL;
line = strjoin(job->checksum, separator, fn, "\n");
if (!line)
return log_oom();
p = memmem_safe(checksum_job->payload,
checksum_job->payload_size,
line,
strlen(line));
if (p)
break;
}
/* Only counts if found at beginning of a line */

View File

@ -2476,7 +2476,7 @@ int device_chase(sd_device *device, const char *path, ChaseFlags flags, char **r
_cleanup_free_ char *resolved = NULL;
_cleanup_close_ int fd = -EBADF;
r = chase(path, /* root = */ NULL, CHASE_NO_AUTOFS | flags, &resolved, ret_fd ? &fd : NULL);
r = chase(path, /* root = */ NULL, flags, &resolved, ret_fd ? &fd : NULL);
if (r < 0)
return r;

View File

@ -91,7 +91,7 @@ static int parse_where(const char *input, char **ret_where) {
assert(ret_where);
if (arg_transport == BUS_TRANSPORT_LOCAL && arg_canonicalize) {
r = chase(input, /* root= */ NULL, CHASE_NONEXISTENT, ret_where, /* ret_fd= */ NULL);
r = chase(input, /* root= */ NULL, CHASE_NONEXISTENT|CHASE_AUTOFS, ret_where, /* ret_fd= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to make path %s absolute: %m", input);
} else {
@ -476,7 +476,7 @@ static int parse_argv(int argc, char *argv[]) {
}
if (arg_transport == BUS_TRANSPORT_LOCAL && arg_canonicalize) {
r = chase(p, /* root= */ NULL, /* flags= */ 0, &arg_mount_what, /* ret_fd= */ NULL);
r = chase(p, /* root= */ NULL, CHASE_AUTOFS, &arg_mount_what, /* ret_fd= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to chase path '%s': %m", p);
} else {
@ -1103,7 +1103,7 @@ static int action_umount(sd_bus *bus, int argc, char **argv) {
return log_oom();
_cleanup_close_ int fd = -EBADF;
r = chase(u, /* root= */ NULL, 0, &p, &fd);
r = chase(u, /* root= */ NULL, CHASE_AUTOFS, &p, &fd);
if (r < 0) {
RET_GATHER(ret, log_error_errno(r, "Failed to chase path '%s': %m", u));
continue;

View File

@ -176,7 +176,7 @@ static int verify_trusted_image_fd_by_path(int fd) {
struct stat stb;
const char *e;
r = chase(s, NULL, CHASE_SAFE, &q, &dir_fd);
r = chase(s, NULL, CHASE_SAFE|CHASE_AUTOFS, &q, &dir_fd);
if (r == -ENOENT)
continue;
if (r < 0) {
@ -194,7 +194,7 @@ static int verify_trusted_image_fd_by_path(int fd) {
if (!filename_is_valid(e))
continue;
r = chaseat(dir_fd, e, CHASE_SAFE, NULL, &inode_fd);
r = chaseat(dir_fd, e, CHASE_SAFE|CHASE_AUTOFS, NULL, &inode_fd);
if (r < 0)
return log_error_errno(r, "Couldn't verify that specified image '%s' is in search path '%s': %m", p, s);

View File

@ -4713,12 +4713,12 @@ int mountfsd_mount_directory(
r = sd_varlink_push_dup_fd(vl, directory_fd);
if (r < 0)
return log_error_errno(r, "Failed to push image fd into varlink connection: %m");
return log_error_errno(r, "Failed to push directory fd into varlink connection: %m");
if (userns_fd >= 0) {
r = sd_varlink_push_dup_fd(vl, userns_fd);
if (r < 0)
return log_error_errno(r, "Failed to push image fd into varlink connection: %m");
return log_error_errno(r, "Failed to push user namespace fd into varlink connection: %m");
}
sd_json_variant *reply = NULL;

View File

@ -371,7 +371,7 @@ static int verify_esp(
/* Non-root user can only check the status, so if an error occurred in the following, it does not cause any
* issues. Let's also, silence the error messages. */
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT, &p, &pfd);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_AUTOFS, &p, &pfd);
if (r < 0)
return log_full_errno((searching && r == -ENOENT) ||
(unprivileged_mode && ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_ERR,
@ -492,7 +492,7 @@ int find_esp_and_warn_at(
"$SYSTEMD_ESP_PATH does not refer to an absolute path, refusing to use it: %s",
path);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT, &p, &fd);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_AUTOFS, &p, &fd);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s: %m", path);
@ -766,7 +766,7 @@ static int verify_xbootldr(
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(path);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT, &p, &pfd);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_AUTOFS, &p, &pfd);
if (r < 0)
return log_full_errno((searching && r == -ENOENT) ||
(unprivileged_mode && ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_ERR,
@ -844,7 +844,7 @@ int find_xbootldr_and_warn_at(
"$SYSTEMD_XBOOTLDR_PATH does not refer to an absolute path, refusing to use it: %s",
path);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT, &p, &fd);
r = chaseat(rfd, path, CHASE_AT_RESOLVE_IN_ROOT|CHASE_AUTOFS, &p, &fd);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s: %m", p);

View File

@ -105,6 +105,7 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_DEFINE_INPUT(parentFileDescriptor, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Name of the directory to create."),
SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, 0),
VARLINK_DEFINE_POLKIT_INPUT,
SD_VARLINK_FIELD_COMMENT("File descriptor referencing the newly created directory."),
SD_VARLINK_DEFINE_OUTPUT(directoryFileDescriptor, SD_VARLINK_INT, 0));

View File

@ -660,7 +660,7 @@ int resource_resolve_path(
_cleanup_free_ char *resolved = NULL;
struct stat st;
r = chase(rr->path, root, CHASE_PREFIX_ROOT, &resolved, &fd);
r = chase(rr->path, root, CHASE_PREFIX_ROOT|CHASE_AUTOFS, &resolved, &fd);
if (r < 0)
return log_error_errno(r, "Failed to resolve '%s': %m", rr->path);
@ -697,7 +697,7 @@ int resource_resolve_path(
} else if (RESOURCE_IS_FILESYSTEM(rr->type)) {
_cleanup_free_ char *resolved = NULL, *relative_to = NULL;
ChaseFlags chase_flags = CHASE_NONEXISTENT | CHASE_PREFIX_ROOT;
ChaseFlags chase_flags = CHASE_NONEXISTENT | CHASE_PREFIX_ROOT | CHASE_AUTOFS;
if (rr->path_relative_to == PATH_RELATIVE_TO_EXPLICIT) {
assert(relative_to_directory);

View File

@ -1498,7 +1498,7 @@ int transfer_install_instance(
assert_not_reached();
if (resolve_link_path && root) {
r = chase(link_path, root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved, NULL);
r = chase(link_path, root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT|CHASE_AUTOFS, &resolved, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve current symlink path '%s': %m", link_path);

View File

@ -1557,7 +1557,7 @@ static int verb_components(int argc, char **argv, void *userdata) {
_cleanup_closedir_ DIR *d = NULL;
_cleanup_free_ char *p = NULL;
r = chase_and_opendir(*i, arg_root, CHASE_PREFIX_ROOT, &p, &d);
r = chase_and_opendir(*i, arg_root, CHASE_PREFIX_ROOT|CHASE_AUTOFS, &p, &d);
if (r == -ENOENT)
continue;
if (r < 0)

View File

@ -24,7 +24,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "prefix-root", no_argument, NULL, CHASE_PREFIX_ROOT },
{ "nonexistent", no_argument, NULL, CHASE_NONEXISTENT },
{ "no_autofs", no_argument, NULL, CHASE_NO_AUTOFS },
{ "autofs", no_argument, NULL, CHASE_AUTOFS },
{ "safe", no_argument, NULL, CHASE_SAFE },
{ "trail-slash", no_argument, NULL, CHASE_TRAIL_SLASH },
{ "step", no_argument, NULL, CHASE_STEP },
@ -60,7 +60,7 @@ static int parse_argv(int argc, char *argv[]) {
case CHASE_PREFIX_ROOT:
case CHASE_NONEXISTENT:
case CHASE_NO_AUTOFS:
case CHASE_AUTOFS:
case CHASE_SAFE:
case CHASE_TRAIL_SLASH:
case CHASE_STEP:

View File

@ -1082,7 +1082,7 @@ static int path_open_parent_safe(const char *path, bool allow_failure) {
path,
allow_failure ? ", ignoring" : "");
r = chase(dn, arg_root, allow_failure ? CHASE_SAFE : CHASE_SAFE|CHASE_WARN, NULL, &fd);
r = chase(dn, arg_root, allow_failure ? CHASE_SAFE|CHASE_AUTOFS : CHASE_SAFE|CHASE_WARN|CHASE_AUTOFS, NULL, &fd);
if (r == -ENOLINK) /* Unsafe symlink: already covered by CHASE_WARN */
return r;
if (r < 0)
@ -1107,7 +1107,7 @@ static int path_open_safe(const char *path) {
if (!path_is_normalized(path))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to open invalid path '%s'.", path);
r = chase(path, arg_root, CHASE_SAFE|CHASE_WARN|CHASE_NOFOLLOW, NULL, &fd);
r = chase(path, arg_root, CHASE_SAFE|CHASE_WARN|CHASE_NOFOLLOW|CHASE_AUTOFS, NULL, &fd);
if (r == -ENOLINK)
return r; /* Unsafe symlink: already covered by CHASE_WARN */
if (r < 0)
@ -2162,7 +2162,7 @@ static int empty_directory(
assert(i);
assert(i->type == EMPTY_DIRECTORY);
r = chase(path, arg_root, CHASE_SAFE|CHASE_WARN, NULL, &fd);
r = chase(path, arg_root, CHASE_SAFE|CHASE_WARN|CHASE_AUTOFS, NULL, &fd);
if (r == -ENOLINK) /* Unsafe symlink: already covered by CHASE_WARN */
return r;
if (r == -ENOENT) {
@ -2406,7 +2406,7 @@ static int create_symlink(Context *c, Item *i) {
assert(i);
if (i->ignore_if_target_missing) {
r = chase(i->argument, arg_root, CHASE_SAFE|CHASE_PREFIX_ROOT|CHASE_NOFOLLOW, /* ret_path = */ NULL, /* ret_fd = */ NULL);
r = chase(i->argument, arg_root, CHASE_SAFE|CHASE_PREFIX_ROOT|CHASE_NOFOLLOW|CHASE_AUTOFS, /* ret_path = */ NULL, /* ret_fd = */ NULL);
if (r == -ENOENT) {
/* Silently skip over lines where the source file is missing. */
log_info("Symlink source path '%s/%s' does not exist, skipping line.",
@ -3232,7 +3232,7 @@ static int process_item(
path = _path;
}
r = chase(path, arg_root, CHASE_NO_AUTOFS|CHASE_NONEXISTENT|CHASE_WARN, NULL, NULL);
r = chase(path, arg_root, CHASE_NONEXISTENT|CHASE_WARN|CHASE_AUTOFS, NULL, NULL);
if (r == -EREMOTE) {
log_notice_errno(r, "Skipping %s", i->path); /* We log the configured path, to not confuse the user. */
return 0;

View File

@ -943,10 +943,10 @@ def pe_add_sections(opts: UkifyConfig, uki: UKI, output: str) -> None:
pe.FILE_HEADER.NumberOfSymbols = 0
pe.FILE_HEADER.IMAGE_FILE_LOCAL_SYMS_STRIPPED = True
# Old stubs might have been stripped, leading to unaligned raw data values, so let's fix them up here.
# pylint thinks that Structure doesn't have various members that it has…
# pylint: disable=no-member
# Old stubs might have been stripped, leading to unaligned raw data values, so let's fix them up here.
for i, section in enumerate(pe.sections):
oldp = section.PointerToRawData
oldsz = section.SizeOfRawData
@ -1045,16 +1045,18 @@ def pe_add_sections(opts: UkifyConfig, uki: UKI, output: str) -> None:
for i, s in enumerate(pe.sections[:n_original_sections]):
if pe_strip_section_name(s.Name) == section.name and section.name != '.dtbauto':
if new_section.Misc_VirtualSize > s.SizeOfRawData:
raise PEError(f'Not enough space in existing section {section.name} to append new data')
raise PEError(
f'Not enough space in existing section {section.name} to append new data'
f' (need {new_section.Misc_VirtualSize}, have {s.SizeOfRawData})'
)
padding = bytes(new_section.SizeOfRawData - new_section.Misc_VirtualSize)
padding = bytes(s.SizeOfRawData - new_section.Misc_VirtualSize)
pe.__data__ = (
pe.__data__[: s.PointerToRawData]
+ data
+ padding
+ pe.__data__[pe.sections[i + 1].PointerToRawData :]
)
s.SizeOfRawData = new_section.SizeOfRawData
s.Misc_VirtualSize = new_section.Misc_VirtualSize
break
else:
@ -1148,10 +1150,12 @@ def merge_sbat(input_pe: list[Path], input_text: list[str]) -> str:
continue
sbat += split[1:]
return (
'sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md\n'
+ '\n'.join(sbat)
+ '\n\x00'
return '\n'.join(
(
'sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md',
*sbat,
'', # an empty line so that we end up with a newline at the end
)
)
@ -1415,11 +1419,11 @@ def make_uki(opts: UkifyConfig) -> None:
for section in opts.sections:
uki.add_section(section)
# Don't add a sbat section to profile PE binaries.
# Don't add an .sbat section to profile PE binaries.
if (opts.join_profiles or not opts.profile) and not opts.pcrsig:
if linux is not None:
# Merge the .sbat sections from stub, kernel and parameter, so that revocation can be done on
# either.
# Merge the .sbat sections from stub, kernel, and parameter, so
# that revocation can be done on either.
input_pes = [opts.stub, linux]
if not opts.sbat:
opts.sbat = [STUB_SBAT]

View File

@ -89,6 +89,11 @@ prepare_root() {
echo "VERSION=1.2.3"
} >"$root/usr/lib/os-release"
if [[ -e $root/etc/os-release ]] && [[ ! -L $root/etc/os-release ]]; then
mv "$root/etc/os-release" "$root/etc/os-release.orig"
cp "$root/usr/lib/os-release" "$root/etc/os-release"
fi
prepend_trap "cleanup_os_release ${root@Q}"
}
@ -103,6 +108,11 @@ cleanup_os_release() {
# shellcheck disable=SC2317 # It is not unreachable, used in a trap couple lines above.
mv "$root/usr/lib/os-release.orig" "$root/usr/lib/os-release"
fi
# shellcheck disable=SC2317 # It is not unreachable, used in a trap couple lines above.
if [[ -e $root/etc/os-release.orig ]]; then
# shellcheck disable=SC2317 # It is not unreachable, used in a trap couple lines above.
mv "$root/etc/os-release.orig" "$root/etc/os-release"
fi
}
prepare_extension_image() {

View File

@ -46,3 +46,18 @@ userdbctl user 65534 -j | userdbctl -F- user | cmp - <(userdbctl user 65534)
userdbctl group root -j | userdbctl -F- group | cmp - <(userdbctl group root)
userdbctl group systemd-network -j | userdbctl -F- group | cmp - <(userdbctl group systemd-network)
userdbctl group 65534 -j | userdbctl -F- group | cmp - <(userdbctl group 65534)
# Ensure NSS doesn't try to automount via open_tree
if [[ ! -v ASAN_OPTIONS ]]; then
systemctl stop systemd-userdbd.socket systemd-userdbd.service
set +o pipefail
systemd-run -q -t --property SystemCallFilter=~open_tree id definitelynotarealuser | grep -q "no such user"
systemd-run -q -t --property SystemCallFilter=~open_tree id --groups definitelynotarealuser | grep -q "no such user"
systemd-run -q -t --property SystemCallFilter=~open_tree groups definitelynotarealuser | grep -q "no such user"
set -o pipefail
# getent shows no output when the entry is not found, but exists with 2, while sd-run crashing will exit
# with 1
assert_rc 2 systemd-run -q -t --property SystemCallFilter=~open_tree getent passwd definitelynotarealuser
assert_rc 2 systemd-run -q -t --property SystemCallFilter=~open_tree getent group definitelynotarealgroup
systemctl start systemd-userdbd.socket systemd-userdbd.service
fi