summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/HACKING.md40
-rw-r--r--hwdb.d/70-analyzers.hwdb15
-rwxr-xr-xhwdb.d/parse_hwdb.py10
-rw-r--r--rules.d/50-udev-default.rules.in1
-rw-r--r--src/backlight/backlight.c12
-rw-r--r--src/boot/efi/boot.c180
-rw-r--r--src/boot/efi/console.c4
-rw-r--r--src/boot/efi/cpio.c2
-rw-r--r--src/boot/efi/devicetree.c2
-rw-r--r--src/boot/efi/drivers.c2
-rw-r--r--src/boot/efi/fuzz-bcd.c3
-rw-r--r--src/boot/efi/pe.c2
-rw-r--r--src/boot/efi/random-seed.c2
-rw-r--r--src/boot/efi/stub.c3
-rw-r--r--src/boot/efi/util.c21
-rw-r--r--src/boot/efi/util.h16
-rwxr-xr-xsrc/partition/test-repart.sh8
-rw-r--r--src/random-seed/random-seed.c26
-rw-r--r--src/resolve/resolved-dns-dnssec.c2
-rw-r--r--src/test/meson.build4
-rw-r--r--src/test/test-nss-hosts.c2
-rw-r--r--src/test/test-nss-users.c2
-rw-r--r--test/fuzz/meson.build5
-rwxr-xr-xtools/debug-sd-boot.sh85
-rwxr-xr-xtools/oss-fuzz.sh2
25 files changed, 339 insertions, 112 deletions
diff --git a/docs/HACKING.md b/docs/HACKING.md
index e194df64cf..117ed92533 100644
--- a/docs/HACKING.md
+++ b/docs/HACKING.md
@@ -330,3 +330,43 @@ To debug systemd components other than PID 1, set "program" to the full path of
debug and set "processId" to "${command:pickProcess}". Now, when starting the debugger, VSCode will ask you
the PID of the process you want to debug. Run `systemctl show --property MainPID --value <component>` in the
container to figure out the PID and enter it when asked and VSCode will attach to that process instead.
+
+# Debugging systemd-boot
+
+During boot, systemd-boot and the stub loader will output a message like `systemd-boot@0x0A,0x0B`,
+providing the location of the text and data sections. These location can then be used to attach
+to a QEMU session (provided it was run with `-s`) with these gdb commands:
+
+```
+ (gdb) file build/src/boot/efi/systemd-bootx64.efi
+ (gdb) add-symbol-file build/src/boot/efi/systemd_boot.so 0x0A -s .data 0x0B
+ (gdb) set architecture i386:x86-64
+ (gdb) target remote :1234
+```
+
+This process can be automated by using the `debug-sd-boot.sh` script in the tools folder. If run
+without arguments it will provide usage information.
+
+If the debugger is too slow to attach to examine an early boot code passage, we can uncomment the
+call to `debug_break()` inside of `efi_main()`. As soon as the debugger has control we can then run
+`set variable wait = 0` or `return` to continue. Once the debugger has attached, setting breakpoints
+will work like usual.
+
+To debug systemd-boot in an IDE such as VSCode we can use a launch configuration like this:
+```json
+{
+ "name": "systemd-boot",
+ "type": "cppdbg",
+ "request": "launch",
+ "program": "${workspaceFolder}/build/src/boot/efi/systemd-bootx64.efi",
+ "cwd": "${workspaceFolder}",
+ "MIMode": "gdb",
+ "miDebuggerServerAddress": ":1234",
+ "setupCommands": [
+ { "text": "shell mkfifo /tmp/sdboot.{in,out}" },
+ { "text": "shell qemu-system-x86_64 [...] -s -serial pipe:/tmp/sdboot" },
+ { "text": "shell ${workspaceFolder}/tools/debug-sd-boot.sh ${workspaceFolder}/build/src/boot/efi/systemd-bootx64.efi /tmp/sdboot.out systemd-boot.gdb" },
+ { "text": "source /tmp/systemd-boot.gdb" },
+ ]
+}
+```
diff --git a/hwdb.d/70-analyzers.hwdb b/hwdb.d/70-analyzers.hwdb
index 4865f0b669..899ece3a01 100644
--- a/hwdb.d/70-analyzers.hwdb
+++ b/hwdb.d/70-analyzers.hwdb
@@ -12,7 +12,7 @@
# Total Phase
###########################################################
# Aarvark I2C/SPI Host Adapter
-usb:v0403pe0d0*
+usb:v0403pE0D0*
ID_SIGNAL_ANALYZER=1
# Beagle Protocol Analyzers
@@ -29,5 +29,16 @@ usb:v1679p3001*
# Power Delivery Analyzers
usb:v1679p6003*
-usb:v0483pdf11*
+usb:v0483pDF11*
+ ID_SIGNAL_ANALYZER=1
+
+###########################################################
+# XGecu
+###########################################################
+# TL866A/CS
+usb:v04D8pE11C*
+ ID_SIGNAL_ANALYZER=1
+
+# TL866II+
+usb:vA466p0A53*
ID_SIGNAL_ANALYZER=1
diff --git a/hwdb.d/parse_hwdb.py b/hwdb.d/parse_hwdb.py
index 941adf28f7..0268bf9580 100755
--- a/hwdb.d/parse_hwdb.py
+++ b/hwdb.d/parse_hwdb.py
@@ -212,21 +212,23 @@ def check_matches(groups):
# This is a partial check. The other cases could be also done, but those
# two are most commonly wrong.
- grammars = { 'usb' : 'v' + upperhex_word(4) + Optional('p' + upperhex_word(4)),
- 'pci' : 'v' + upperhex_word(8) + Optional('d' + upperhex_word(8)),
+ grammars = { 'usb' : 'v' + upperhex_word(4) + Optional('p' + upperhex_word(4) + Optional(':')) + '*',
+ 'pci' : 'v' + upperhex_word(8) + Optional('d' + upperhex_word(8) + Optional(':')) + '*',
}
for match in matches:
prefix, rest = match.split(':', maxsplit=1)
gr = grammars.get(prefix)
if gr:
+ # we check this first to provide an easy error message
+ if rest[-1] not in '*:':
+ error('pattern {} does not end with "*" or ":"', match)
+
try:
gr.parseString(rest)
except ParseBaseException as e:
error('Pattern {!r} is invalid: {}', rest, e)
continue
- if rest[-1] not in '*:':
- error('pattern {} does not end with "*" or ":"', match)
matches.sort()
prev = None
diff --git a/rules.d/50-udev-default.rules.in b/rules.d/50-udev-default.rules.in
index 8fae58f115..685b59a78a 100644
--- a/rules.d/50-udev-default.rules.in
+++ b/rules.d/50-udev-default.rules.in
@@ -12,7 +12,6 @@ SUBSYSTEM=="rtc", KERNEL=="rtc0", SYMLINK+="rtc", OPTIONS+="link_priority=-100"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}"
-SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="hwdb 'usb:v$attr{idVendor}p$attr{idProduct}'"
ACTION!="add", GOTO="default_end"
diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c
index fd92135fc7..5a3095cbba 100644
--- a/src/backlight/backlight.c
+++ b/src/backlight/backlight.c
@@ -395,8 +395,16 @@ static int run(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a backlight or LED device: '%s:%s'", ss, sysname);
r = sd_device_new_from_subsystem_sysname(&device, ss, sysname);
- if (r < 0)
- return log_error_errno(r, "Failed to get backlight or LED device '%s:%s': %m", ss, sysname);
+ if (r < 0) {
+ bool ignore = r == -ENODEV;
+
+ /* Some drivers, e.g. for AMD GPU, removes acpi backlight device soon after it is added.
+ * See issue #21997. */
+ log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, r,
+ "Failed to get backlight or LED device '%s:%s'%s: %m",
+ ss, sysname, ignore ? ", ignoring" : "");
+ return ignore ? 0 : r;
+ }
/* If max_brightness is 0, then there is no actual backlight device. This happens on desktops
* with Asus mainboards that load the eeepc-wmi module. */
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 0360d2a0bf..5c373be587 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -44,6 +44,7 @@ enum loader_type {
LOADER_UNDEFINED,
LOADER_EFI,
LOADER_LINUX,
+ LOADER_STUB,
};
typedef struct {
@@ -71,8 +72,8 @@ typedef struct {
typedef struct {
ConfigEntry **entries;
UINTN entry_count;
- INTN idx_default;
- INTN idx_default_efivar;
+ UINTN idx_default;
+ UINTN idx_default_efivar;
UINT32 timeout_sec; /* Actual timeout used (efi_main() override > efivar > config). */
UINT32 timeout_sec_config;
UINT32 timeout_sec_efivar;
@@ -104,6 +105,11 @@ enum {
TIMEOUT_TYPE_MAX = UINT32_MAX,
};
+enum {
+ IDX_MAX = INT16_MAX,
+ IDX_INVALID,
+};
+
static void cursor_left(UINTN *cursor, UINTN *first) {
assert(cursor);
assert(first);
@@ -375,7 +381,7 @@ static UINTN entry_lookup_key(Config *config, UINTN start, CHAR16 key) {
assert(config);
if (key == 0)
- return -1;
+ return IDX_INVALID;
/* select entry by number key */
if (key >= '1' && key <= '9') {
@@ -394,7 +400,7 @@ static UINTN entry_lookup_key(Config *config, UINTN start, CHAR16 key) {
if (config->entries[i]->key == key)
return i;
- return -1;
+ return IDX_INVALID;
}
static CHAR16 *update_timeout_efivar(UINT32 *t, BOOLEAN inc) {
@@ -583,7 +589,7 @@ static BOOLEAN menu_run(
UINTN visible_max = 0;
UINTN idx_highlight = config->idx_default;
UINTN idx_highlight_prev = 0;
- UINTN idx_first = 0, idx_last = 0;
+ UINTN idx, idx_first = 0, idx_last = 0;
BOOLEAN new_mode = TRUE, clear = TRUE;
BOOLEAN refresh = TRUE, highlight = FALSE;
UINTN x_start = 0, y_start = 0, y_status = 0;
@@ -592,10 +598,9 @@ static BOOLEAN menu_run(
_cleanup_freepool_ CHAR16 *clearline = NULL, *status = NULL;
UINT32 timeout_efivar_saved = config->timeout_sec_efivar;
UINT32 timeout_remain = config->timeout_sec == TIMEOUT_MENU_FORCE ? 0 : config->timeout_sec;
- INT16 idx;
BOOLEAN exit = FALSE, run = TRUE, firmware_setup = FALSE;
INT64 console_mode_initial = ST->ConOut->Mode->Mode, console_mode_efivar_saved = config->console_mode_efivar;
- INTN default_efivar_saved = config->idx_default_efivar;
+ UINTN default_efivar_saved = config->idx_default_efivar;
graphics_mode(FALSE);
ST->ConIn->Reset(ST->ConIn, FALSE);
@@ -693,7 +698,7 @@ static BOOLEAN menu_run(
print_at(x_start, y_start + i - idx_first,
(i == idx_highlight) ? COLOR_HIGHLIGHT : COLOR_ENTRY,
lines[i]);
- if ((INTN)i == config->idx_default_efivar)
+ if (i == config->idx_default_efivar)
print_at(x_start, y_start + i - idx_first,
(i == idx_highlight) ? COLOR_HIGHLIGHT : COLOR_ENTRY,
(CHAR16*) L"=>");
@@ -702,9 +707,9 @@ static BOOLEAN menu_run(
} else if (highlight) {
print_at(x_start, y_start + idx_highlight_prev - idx_first, COLOR_ENTRY, lines[idx_highlight_prev]);
print_at(x_start, y_start + idx_highlight - idx_first, COLOR_HIGHLIGHT, lines[idx_highlight]);
- if ((INTN)idx_highlight_prev == config->idx_default_efivar)
+ if (idx_highlight_prev == config->idx_default_efivar)
print_at(x_start , y_start + idx_highlight_prev - idx_first, COLOR_ENTRY, (CHAR16*) L"=>");
- if ((INTN)idx_highlight == config->idx_default_efivar)
+ if (idx_highlight == config->idx_default_efivar)
print_at(x_start, y_start + idx_highlight - idx_first, COLOR_HIGHLIGHT, (CHAR16*) L"=>");
highlight = FALSE;
}
@@ -826,14 +831,14 @@ static BOOLEAN menu_run(
case KEYPRESS(0, 0, 'd'):
case KEYPRESS(0, 0, 'D'):
- if (config->idx_default_efivar != (INTN)idx_highlight) {
+ if (config->idx_default_efivar != idx_highlight) {
FreePool(config->entry_default_efivar);
config->entry_default_efivar = xstrdup(config->entries[idx_highlight]->id);
config->idx_default_efivar = idx_highlight;
status = xstrdup(L"Default boot entry selected.");
} else {
config->entry_default_efivar = mfree(config->entry_default_efivar);
- config->idx_default_efivar = -1;
+ config->idx_default_efivar = IDX_INVALID;
status = xstrdup(L"Default boot entry cleared.");
}
config->use_saved_entry_efivar = FALSE;
@@ -853,8 +858,18 @@ static BOOLEAN menu_run(
case KEYPRESS(0, 0, 'e'):
case KEYPRESS(0, 0, 'E'):
/* only the options of configured entries can be edited */
- if (!config->editor || config->entries[idx_highlight]->type == LOADER_UNDEFINED)
+ if (!config->editor || !IN_SET(config->entries[idx_highlight]->type,
+ LOADER_EFI, LOADER_LINUX, LOADER_STUB))
+ break;
+
+ /* The stub will not accept command line options when secure boot is enabled
+ * unless there is none embedded in the image. Do not try to pretend we
+ * can edit it to only have it be ignored. */
+ if (config->entries[idx_highlight]->type == LOADER_STUB &&
+ secure_boot_enabled() &&
+ config->entries[idx_highlight]->options)
break;
+
/* The edit line may end up on the last line of the screen. And even though we're
* not telling the firmware to advance the line, it still does in this one case,
* causing a scroll to happen that screws with our beautiful boot loader output.
@@ -923,7 +938,7 @@ static BOOLEAN menu_run(
default:
/* jump with a hotkey directly to a matching entry */
idx = entry_lookup_key(config, idx_highlight+1, KEYCHAR(key));
- if (idx < 0)
+ if (idx == IDX_INVALID)
break;
idx_highlight = idx;
refresh = TRUE;
@@ -974,6 +989,9 @@ static void config_add_entry(Config *config, ConfigEntry *entry) {
assert(config);
assert(entry);
+ /* This is just for paranoia. */
+ assert(config->entry_count < IDX_MAX);
+
if ((config->entry_count & 15) == 0) {
UINTN i = config->entry_count + 16;
config->entries = xreallocate_pool(
@@ -1022,61 +1040,62 @@ static CHAR8 *line_get_key_value(
assert(key_ret);
assert(value_ret);
-skip:
- line = content + *pos;
- if (*line == '\0')
- return NULL;
+ for (;;) {
+ line = content + *pos;
+ if (*line == '\0')
+ return NULL;
- linelen = 0;
- while (line[linelen] && !strchra((CHAR8 *)"\n\r", line[linelen]))
- linelen++;
+ linelen = 0;
+ while (line[linelen] && !strchra((CHAR8 *) "\n\r", line[linelen]))
+ linelen++;
- /* move pos to next line */
- *pos += linelen;
- if (content[*pos])
- (*pos)++;
+ /* move pos to next line */
+ *pos += linelen;
+ if (content[*pos])
+ (*pos)++;
- /* empty line */
- if (linelen == 0)
- goto skip;
+ /* empty line */
+ if (linelen == 0)
+ continue;
- /* terminate line */
- line[linelen] = '\0';
+ /* terminate line */
+ line[linelen] = '\0';
- /* remove leading whitespace */
- while (strchra((CHAR8 *)" \t", *line)) {
- line++;
- linelen--;
- }
+ /* remove leading whitespace */
+ while (strchra((CHAR8 *) " \t", *line)) {
+ line++;
+ linelen--;
+ }
- /* remove trailing whitespace */
- while (linelen > 0 && strchra((CHAR8 *)" \t", line[linelen-1]))
- linelen--;
- line[linelen] = '\0';
+ /* remove trailing whitespace */
+ while (linelen > 0 && strchra((CHAR8 *) " \t", line[linelen - 1]))
+ linelen--;
+ line[linelen] = '\0';
- if (*line == '#')
- goto skip;
+ if (*line == '#')
+ continue;
- /* split key/value */
- value = line;
- while (*value && !strchra(sep, *value))
- value++;
- if (*value == '\0')
- goto skip;
- *value = '\0';
- value++;
- while (*value && strchra(sep, *value))
+ /* split key/value */
+ value = line;
+ while (*value && !strchra(sep, *value))
+ value++;
+ if (*value == '\0')
+ continue;
+ *value = '\0';
value++;
+ while (*value && strchra(sep, *value))
+ value++;
- /* unquote */
- if (value[0] == '"' && line[linelen-1] == '"') {
- value++;
- line[linelen-1] = '\0';
- }
+ /* unquote */
+ if (value[0] == '"' && line[linelen - 1] == '"') {
+ value++;
+ line[linelen - 1] = '\0';
+ }
- *key_ret = line;
- *value_ret = value;
- return line;
+ *key_ret = line;
+ *value_ret = value;
+ return line;
+ }
}
static void config_defaults_load_from_file(Config *config, CHAR8 *content) {
@@ -1298,7 +1317,7 @@ static void config_entry_bump_counters(
EFI_FILE_HANDLE root_dir) {
_cleanup_freepool_ CHAR16* old_path = NULL, *new_path = NULL;
- _cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
+ _cleanup_(file_handle_closep) EFI_FILE_HANDLE handle = NULL;
_cleanup_freepool_ EFI_FILE_INFO *file_info = NULL;
UINTN file_info_size;
EFI_STATUS err;
@@ -1506,7 +1525,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) {
.auto_entries = TRUE,
.auto_firmware = TRUE,
.random_seed_mode = RANDOM_SEED_WITH_SYSTEM_TOKEN,
- .idx_default_efivar = -1,
+ .idx_default_efivar = IDX_INVALID,
.console_mode = CONSOLE_MODE_KEEP,
.console_mode_efivar = CONSOLE_MODE_KEEP,
.timeout_sec_config = TIMEOUT_UNSET,
@@ -1555,7 +1574,7 @@ static void config_load_entries(
EFI_FILE *root_dir,
const CHAR16 *loaded_image_path) {
- _cleanup_(FileHandleClosep) EFI_FILE_HANDLE entries_dir = NULL;
+ _cleanup_(file_handle_closep) EFI_FILE_HANDLE entries_dir = NULL;
_cleanup_freepool_ EFI_FILE_INFO *f = NULL;
UINTN f_size = 0;
EFI_STATUS err;
@@ -1632,32 +1651,32 @@ static void config_sort_entries(Config *config) {
sort_pointer_array((void**) config->entries, config->entry_count, (compare_pointer_func_t) config_entry_compare);
}
-static INTN config_entry_find(Config *config, const CHAR16 *needle) {
+static UINTN config_entry_find(Config *config, const CHAR16 *needle) {
assert(config);
if (!needle)
- return -1;
+ return IDX_INVALID;
- for (UINTN i = 0; i < config->entry_count; i++)
+ for (INTN i = config->entry_count - 1; i >= 0; i--)
if (MetaiMatch(config->entries[i]->id, (CHAR16*) needle))
- return (INTN) i;
+ return i;
- return -1;
+ return IDX_INVALID;
}
static void config_default_entry_select(Config *config) {
- INTN i;
+ UINTN i;
assert(config);
i = config_entry_find(config, config->entry_oneshot);
- if (i >= 0) {
+ if (i != IDX_INVALID) {
config->idx_default = i;
return;
}
i = config_entry_find(config, config->use_saved_entry_efivar ? config->entry_saved : config->entry_default_efivar);
- if (i >= 0) {
+ if (i != IDX_INVALID) {
config->idx_default = i;
config->idx_default_efivar = i;
return;
@@ -1665,10 +1684,10 @@ static void config_default_entry_select(Config *config) {
if (config->use_saved_entry)
/* No need to do the same thing twice. */
- i = config->use_saved_entry_efivar ? -1 : config_entry_find(config, config->entry_saved);
+ i = config->use_saved_entry_efivar ? IDX_INVALID : config_entry_find(config, config->entry_saved);
else
i = config_entry_find(config, config->entry_default_config);
- if (i >= 0) {
+ if (i != IDX_INVALID) {
config->idx_default = i;
return;
}
@@ -1683,7 +1702,7 @@ static void config_default_entry_select(Config *config) {
}
/* no entry found */
- config->idx_default = -1;
+ config->idx_default = IDX_INVALID;
}
static BOOLEAN find_nonunique(ConfigEntry **entries, UINTN entry_count) {
@@ -1970,7 +1989,7 @@ static void config_entry_add_linux(
EFI_HANDLE *device,
EFI_FILE *root_dir) {
- _cleanup_(FileHandleClosep) EFI_FILE_HANDLE linux_dir = NULL;
+ _cleanup_(file_handle_closep) EFI_FILE_HANDLE linux_dir = NULL;
_cleanup_freepool_ EFI_FILE_INFO *f = NULL;
ConfigEntry *entry;
UINTN f_size = 0;
@@ -2098,7 +2117,7 @@ static void config_entry_add_linux(
entry = config_entry_add_loader(
config,
device,
- LOADER_LINUX,
+ LOADER_STUB,
f->FileName,
/* key= */ 'l',
good_name,
@@ -2344,7 +2363,7 @@ static void config_load_all_entries(
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
_cleanup_freepool_ EFI_LOADED_IMAGE *loaded_image = NULL;
- _cleanup_(FileHandleClosep) EFI_FILE *root_dir = NULL;
+ _cleanup_(file_handle_closep) EFI_FILE *root_dir = NULL;
_cleanup_(config_free) Config config = {};
CHAR16 *loaded_image_path;
EFI_STATUS err;
@@ -2353,6 +2372,9 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
InitializeLib(image, sys_table);
init_usec = time_usec();
+ debug_hook(L"systemd-boot");
+ /* Uncomment the next line if you need to wait for debugger. */
+ // debug_break();
err = BS->OpenProtocol(image,
&LoadedImageProtocol,
@@ -2396,7 +2418,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
config_default_entry_select(&config);
/* if no configured entry to select from was found, enable the menu */
- if (config.idx_default == -1) {
+ if (config.idx_default == IDX_INVALID) {
config.idx_default = 0;
if (config.timeout_sec == 0)
config.timeout_sec = 10;
@@ -2411,11 +2433,9 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
/* Block up to 100ms to give firmware time to get input working. */
err = console_key_read(&key, 100 * 1000);
if (!EFI_ERROR(err)) {
- INT16 idx;
-
/* find matching key in config entries */
- idx = entry_lookup_key(&config, config.idx_default, KEYCHAR(key));
- if (idx >= 0)
+ UINTN idx = entry_lookup_key(&config, config.idx_default, KEYCHAR(key));
+ if (idx != IDX_INVALID)
config.idx_default = idx;
else
menu = TRUE;
diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c
index 86cd15a235..b8142c38b3 100644
--- a/src/boot/efi/console.c
+++ b/src/boot/efi/console.c
@@ -12,7 +12,7 @@
#define VERTICAL_MAX_OK 1080
#define VIEWPORT_RATIO 10
-static inline void EventClosep(EFI_EVENT *event) {
+static inline void event_closep(EFI_EVENT *event) {
if (!*event)
return;
@@ -42,7 +42,7 @@ EFI_STATUS console_key_read(UINT64 *key, UINT64 timeout_usec) {
static BOOLEAN checked = FALSE;
UINTN index;
EFI_STATUS err;
- _cleanup_(EventClosep) EFI_EVENT timer = NULL;
+ _cleanup_(event_closep) EFI_EVENT timer = NULL;
assert(key);
diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c
index 74610cc1c7..924ac35939 100644
--- a/src/boot/efi/cpio.c
+++ b/src/boot/efi/cpio.c
@@ -316,7 +316,7 @@ EFI_STATUS pack_cpio(
void **ret_buffer,
UINTN *ret_buffer_size) {
- _cleanup_(FileHandleClosep) EFI_FILE_HANDLE root = NULL, extra_dir = NULL;
+ _cleanup_(file_handle_closep) EFI_FILE_HANDLE root = NULL, extra_dir = NULL;
UINTN dirent_size = 0, buffer_size = 0, n_items = 0, n_allocated = 0;
_cleanup_freepool_ CHAR16 *rel_dropin_dir = NULL;
_cleanup_freepool_ EFI_FILE_INFO *dirent = NULL;
diff --git a/src/boot/efi/devicetree.c b/src/boot/efi/devicetree.c
index 30ba88c4f8..476843bbce 100644
--- a/src/boot/efi/devicetree.c
+++ b/src/boot/efi/devicetree.c
@@ -66,7 +66,7 @@ static EFI_STATUS devicetree_fixup(struct devicetree_state *state, UINTN len) {
EFI_STATUS devicetree_install(struct devicetree_state *state,
EFI_FILE_HANDLE root_dir, CHAR16 *name) {
- _cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
+ _cleanup_(file_handle_closep) EFI_FILE_HANDLE handle = NULL;
_cleanup_freepool_ EFI_FILE_INFO *info = NULL;
UINTN len;
EFI_STATUS err;
diff --git a/src/boot/efi/drivers.c b/src/boot/efi/drivers.c
index 61df20e24a..851203e694 100644
--- a/src/boot/efi/drivers.c
+++ b/src/boot/efi/drivers.c
@@ -82,7 +82,7 @@ EFI_STATUS load_drivers(
EFI_LOADED_IMAGE *loaded_image,
EFI_FILE_HANDLE root_dir) {
- _cleanup_(FileHandleClosep) EFI_FILE_HANDLE drivers_dir = NULL;
+ _cleanup_(file_handle_closep) EFI_FILE_HANDLE drivers_dir = NULL;
_cleanup_freepool_ EFI_FILE_INFO *dirent = NULL;
UINTN dirent_size = 0, n_succeeded = 0;
EFI_STATUS err;
diff --git a/src/boot/efi/fuzz-bcd.c b/src/boot/efi/fuzz-bcd.c
index e5ed6638a4..3df55a5c36 100644
--- a/src/boot/efi/fuzz-bcd.c
+++ b/src/boot/efi/fuzz-bcd.c
@@ -21,6 +21,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
assert_se(p);
char16_t *title = get_bcd_title(p, size);
- assert_se(!title || char16_strlen(title) >= 0);
+ if (title)
+ (void) char16_strlen(title);
return 0;
}
diff --git a/src/boot/efi/pe.c b/src/boot/efi/pe.c
index ed3b0b8e94..2fc38f7b36 100644
--- a/src/boot/efi/pe.c
+++ b/src/boot/efi/pe.c
@@ -224,7 +224,7 @@ EFI_STATUS pe_file_locate_sections(
UINTN *offsets,
UINTN *sizes) {
_cleanup_freepool_ struct PeSectionHeader *section_table = NULL;
- _cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
+ _cleanup_(file_handle_closep) EFI_FILE_HANDLE handle = NULL;
struct DosFileHeader dos;
struct PeFileHeader pe;
UINTN len, section_table_len;
diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c
index dbf309b726..9d8e34d1ee 100644
--- a/src/boot/efi/random-seed.c
+++ b/src/boot/efi/random-seed.c
@@ -225,7 +225,7 @@ static void validate_sha256(void) {
EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
_cleanup_freepool_ void *seed = NULL, *new_seed = NULL, *rng = NULL, *for_kernel = NULL, *system_token = NULL;
- _cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
+ _cleanup_(file_handle_closep) EFI_FILE_HANDLE handle = NULL;
UINTN size, rsize, wsize, system_token_size = 0;
_cleanup_freepool_ EFI_FILE_INFO *info = NULL;
EFI_STATUS err;
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 0b1f276c41..22554a4860 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -181,6 +181,9 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
EFI_STATUS err;
InitializeLib(image, sys_table);
+ debug_hook(L"systemd-stub");
+ /* Uncomment the next line if you need to wait for debugger. */
+ // debug_break();
err = BS->OpenProtocol(
image,
diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c
index 76e4eef1eb..ab47e10898 100644
--- a/src/boot/efi/util.c
+++ b/src/boot/efi/util.c
@@ -436,7 +436,7 @@ CHAR8 *strchra(const CHAR8 *s, CHAR8 c) {
}
EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN size, CHAR8 **ret, UINTN *ret_size) {
- _cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
+ _cleanup_(file_handle_closep) EFI_FILE_HANDLE handle = NULL;
_cleanup_freepool_ CHAR8 *buf = NULL;
EFI_STATUS err;
@@ -703,7 +703,7 @@ EFI_STATUS open_directory(
const CHAR16 *path,
EFI_FILE_HANDLE *ret) {
- _cleanup_(FileHandleClosep) EFI_FILE_HANDLE dir = NULL;
+ _cleanup_(file_handle_closep) EFI_FILE_HANDLE dir = NULL;
_cleanup_freepool_ EFI_FILE_INFO *file_info = NULL;
EFI_STATUS err;
@@ -738,3 +738,20 @@ UINT64 get_os_indications_supported(void) {
return osind;
}
+
+#ifdef EFI_DEBUG
+__attribute__((noinline)) void debug_break(void) {
+ /* This is a poor programmer's breakpoint to wait until a debugger
+ * has attached to us. Just "set variable wait = 0" or "return" to continue. */
+ volatile BOOLEAN wait = TRUE;
+ while (wait)
+ /* Prefer asm based stalling so that gdb has a source location to present. */
+#if defined(__i386__) || defined(__x86_64__)
+ asm volatile("pause");
+#elif defined(__aarch64__)
+ asm volatile("wfi");
+#else
+ BS->Stall(5000);
+#endif
+}
+#endif
diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h
index b40f05eaef..58ca44443d 100644
--- a/src/boot/efi/util.h
+++ b/src/boot/efi/util.h
@@ -73,7 +73,7 @@ CHAR16 *xstra_to_str(const CHAR8 *stra);
EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size);
-static inline void FreePoolp(void *p) {
+static inline void free_poolp(void *p) {
void *q = *(void**) p;
if (!q)
@@ -82,9 +82,9 @@ static inline void FreePoolp(void *p) {
FreePool(q);
}
-#define _cleanup_freepool_ _cleanup_(FreePoolp)
+#define _cleanup_freepool_ _cleanup_(free_poolp)
-static inline void FileHandleClosep(EFI_FILE_HANDLE *handle) {
+static inline void file_handle_closep(EFI_FILE_HANDLE *handle) {
if (!*handle)
return;
@@ -159,3 +159,13 @@ static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) {
}
UINT64 get_os_indications_supported(void);
+
+#ifdef EFI_DEBUG
+void debug_break(void);
+extern UINT8 _text, _data;
+/* Report the relocated position of text and data sections so that a debugger
+ * can attach to us. See debug-sd-boot.sh for how this can be done. */
+# define debug_hook(identity) Print(identity L"@0x%x,0x%x\n", &_text, &_data)
+#else
+# define debug_hook(identity)
+#endif
diff --git a/src/partition/test-repart.sh b/src/partition/test-repart.sh
index 525be8e56a..d50a79a15e 100755
--- a/src/partition/test-repart.sh
+++ b/src/partition/test-repart.sh
@@ -8,6 +8,8 @@ set -o pipefail
repart="${1:?}"
test -x "$repart"
+PATH=$PATH:/sbin:/usr/sbin
+
D="$(mktemp --tmpdir --directory "test-repart.XXXXXXXXXX")"
# shellcheck disable=SC2064
@@ -213,6 +215,6 @@ else
fi
echo "### Testing json output ###"
-"$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --json=help
-"$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --json=pretty
-"$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --json=short
+"$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager --json=help
+"$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager --json=pretty
+"$repart" "$D/zzz" --size=3G --dry-run=no --seed="$SEED" --definitions="$D/definitions" --no-pager --json=short
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index 7724e0365e..bba8335720 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -26,6 +26,7 @@
#include "random-util.h"
#include "string-util.h"
#include "sync-util.h"
+#include "sha256.h"
#include "util.h"
#include "xattr-util.h"
@@ -106,9 +107,11 @@ static int run(int argc, char *argv[]) {
_cleanup_close_ int seed_fd = -1, random_fd = -1;
bool read_seed_file, write_seed_file, synchronous;
_cleanup_free_ void* buf = NULL;
+ struct sha256_ctx hash_state;
+ uint8_t hash[32];
size_t buf_size;
struct stat st;
- ssize_t k;
+ ssize_t k, l;
int r;
log_setup();
@@ -242,6 +245,16 @@ static int run(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
}
+ /* If we're going to later write out a seed file, initialize a hash state with
+ * the contents of the seed file we just read, so that the new one can't regress
+ * in entropy. */
+ if (write_seed_file) {
+ sha256_init_ctx(&hash_state);
+ if (k < 0)
+ k = 0;
+ sha256_process_bytes(&k, sizeof(k), &hash_state);
+ sha256_process_bytes(buf, k, &hash_state);
+ }
}
if (write_seed_file) {
@@ -277,6 +290,17 @@ static int run(int argc, char *argv[]) {
"Got EOF while reading from /dev/urandom.");
}
+ /* If we previously read in a seed file, then hash the new seed into the old one,
+ * and replace the last 32 bytes of the seed with the hash output, so that the
+ * new seed file can't regress in entropy. */
+ if (read_seed_file) {
+ sha256_process_bytes(&k, sizeof(k), &hash_state);
+ sha256_process_bytes(buf, k, &hash_state);
+ sha256_finish_ctx(&hash_state, hash);
+ l = MIN(k, 32);
+ memcpy((uint8_t *)buf + k - l, hash, l);
+ }
+
r = loop_write(seed_fd, buf, (size_t) k, false);
if (r < 0)
return log_error_errno(r, "Failed to write new random seed file: %m");
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
index 738259481d..5c2e936163 100644
--- a/src/resolve/resolved-dns-dnssec.c
+++ b/src/resolve/resolved-dns-dnssec.c
@@ -1402,6 +1402,8 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds,
if (md_algorithm < 0)
return -EOPNOTSUPP;
+ initialize_libgcrypt(false);
+
_cleanup_(gcry_md_closep) gcry_md_hd_t md = NULL;
size_t hash_size = gcry_md_get_algo_dlen(md_algorithm);
diff --git a/src/test/meson.build b/src/test/meson.build
index 364cd3dd3f..97e9ac8909 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -608,14 +608,14 @@ tests += [
'src/test/nss-test-util.h'],
[],
[libdl],
- [], 'ENABLE_NSS', 'manual'],
+ [], 'ENABLE_NSS'],
[['src/test/test-nss-users.c',
'src/test/nss-test-util.c',
'src/test/nss-test-util.h'],
[],
[libdl],
- [], 'ENABLE_NSS', 'manual'],
+ [], 'ENABLE_NSS'],
[['src/test/test-bus-util.c']],
diff --git a/src/test/test-nss-hosts.c b/src/test/test-nss-hosts.c
index eac2c74f4c..3ae38acb17 100644
--- a/src/test/test-nss-hosts.c
+++ b/src/test/test-nss-hosts.c
@@ -420,7 +420,7 @@ static int parse_argv(int argc, char **argv,
#if ENABLE_NSS_MYMACHINES
"mymachines",
#endif
- "dns");
+ NULL);
assert_se(modules);
if (argc > 2) {
diff --git a/src/test/test-nss-users.c b/src/test/test-nss-users.c
index c415c0ca3b..88e2764e99 100644
--- a/src/test/test-nss-users.c
+++ b/src/test/test-nss-users.c
@@ -214,7 +214,7 @@ static int parse_argv(int argc, char **argv,
#if ENABLE_NSS_MYMACHINES
"mymachines",
#endif
- "files");
+ NULL);
assert_se(modules);
if (argc > 2)
diff --git a/test/fuzz/meson.build b/test/fuzz/meson.build
index 30e26b09cf..706bdb329b 100644
--- a/test/fuzz/meson.build
+++ b/test/fuzz/meson.build
@@ -7,7 +7,10 @@ sanitize_address_undefined = custom_target(
project_source_root,
'@OUTPUT@',
'fuzzers',
- '-Dfuzz-tests=true -Db_lundef=false -Db_sanitize=address,undefined --optimization=@0@'.format(get_option('optimization')),
+ '-Dfuzz-tests=true -Db_lundef=false -Db_sanitize=address,undefined --optimization=@0@ @1@'.format(
+ get_option('optimization'),
+ get_option('werror') ? '--werror' : ''
+ ),
' '.join(cc.cmd_array()),
cxx_cmd])
diff --git a/tools/debug-sd-boot.sh b/tools/debug-sd-boot.sh
new file mode 100755
index 0000000000..1af97c18ec
--- /dev/null
+++ b/tools/debug-sd-boot.sh
@@ -0,0 +1,85 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+set -e
+
+if [[ $# -lt 2 ]]; then
+ echo "Usage: ${0} TARGET INPUT [GDBSCRIPT]"
+ echo "Debug systemd-boot/stub in QEMU."
+ echo
+ echo "TARGET should point to the EFI binary to be examined inside the"
+ echo "build directory (systemd-boot\$ARCH.efi or linux\$arch.efi.stub)."
+ echo
+ echo "INPUT should point to the QEMU serial output pipe. This is used to"
+ echo "extract the location of the symbols. For this to work, QEMU must"
+ echo "be run with '-s -serial pipe:PATH'. Note that QEMU will append"
+ echo ".in/.out to the path, while this script expects the out pipe directly."
+ echo
+ echo "If GDBSCRIPT is empty, gdb is run directly attached to the boot"
+ echo "loader, otherwise a script is generated in the given path that allows"
+ echo "attaching manually like this:"
+ echo " (gdb) source GDBSCRIPT"
+ echo " (gdb) target remote :1234"
+ echo
+ echo "Exmaple usage:"
+ echo " mkfifo /tmp/sdboot.{in,out}"
+ echo " qemu-system-x86_64 [...] -s -serial pipe:/tmp/sdboot"
+ echo " ./tools/debug-sd-boot.sh ./build/src/boot/efi/systemd-bootx64.efi \\"
+ echo " /tmp/sdboot.out"
+ exit 1
+fi
+
+binary=$(realpath "${1}")
+if [[ "${1}" =~ systemd-boot([[:alnum:]]+).efi ]]; then
+ target="systemd-boot"
+ symbols=$(realpath "$(dirname "${1}")/systemd_boot.so")
+elif [[ "${1}" =~ linux([[:alnum:]]+).efi.stub ]]; then
+ target="systemd-stub"
+ symbols=$(realpath "$(dirname "${1}")/linux${BASH_REMATCH[1]}.elf.stub")
+else
+ echo "Cannot detect EFI binary '${1}'."
+ exit 1
+fi
+
+case "${BASH_REMATCH[1]}" in
+ ia32) arch="i386";;
+ x64) arch="i386:x86-64";;
+ aa64) arch="aarch64";;
+ arm|riscv64) arch="${BASH_REMATCH[1]}";;
+ *)
+ echo "Unknown EFI arch '${BASH_REMATCH[1]}'."
+ exit 1
+esac
+
+# system-boot will print out a line like this to inform us where gdb is supposed to
+# look for .text and .data section:
+# systemd-boot@0x0,0x0
+while read -r line; do
+ if [[ "${line}" =~ ${target}@(0x[[:xdigit:]]+),(0x[[:xdigit:]]+) ]]; then
+ text="${BASH_REMATCH[1]}"
+ data="${BASH_REMATCH[2]}"
+ break
+ fi
+done < "${2}"
+
+if [[ -z "${text}" || -z "${data}" ]]; then
+ echo "Could not determine text and data location."
+ exit 1
+fi
+
+if [[ -z "${3}" ]]; then
+ gdb_script=$(mktemp /tmp/debug-sd-boot.XXXXXX.gdb)
+ trap 'rm -f "${gdb_script}"' EXIT
+else
+ gdb_script="${3}"
+fi
+
+echo "file ${binary}
+add-symbol-file ${symbols} ${text} -s .data ${data}
+set architecture ${arch}" > "${gdb_script}"
+
+if [[ -z "${3}" ]]; then
+ gdb -x "${gdb_script}" -ex "target remote :1234"
+else
+ echo "GDB script written to '${gdb_script}'."
+fi
diff --git a/tools/oss-fuzz.sh b/tools/oss-fuzz.sh
index a0c936f612..cff90145ce 100755
--- a/tools/oss-fuzz.sh
+++ b/tools/oss-fuzz.sh
@@ -10,7 +10,7 @@ export CXX=${CXX:-clang++}
clang_version="$($CC --version | sed -nr 's/.*version ([^ ]+?) .*/\1/p' | sed -r 's/-$//')"
SANITIZER=${SANITIZER:-address -fsanitize-address-use-after-scope}
-flags="-O1 -fno-omit-frame-pointer -gline-tables-only -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=$SANITIZER"
+flags="-O1 -fno-omit-frame-pointer -g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=$SANITIZER"
clang_lib="/usr/lib64/clang/${clang_version}/lib/linux"
[ -d "$clang_lib" ] || clang_lib="/usr/lib/clang/${clang_version}/lib/linux"