diff options
-rw-r--r-- | docs/HACKING.md | 40 | ||||
-rw-r--r-- | hwdb.d/70-analyzers.hwdb | 15 | ||||
-rwxr-xr-x | hwdb.d/parse_hwdb.py | 10 | ||||
-rw-r--r-- | rules.d/50-udev-default.rules.in | 1 | ||||
-rw-r--r-- | src/backlight/backlight.c | 12 | ||||
-rw-r--r-- | src/boot/efi/boot.c | 180 | ||||
-rw-r--r-- | src/boot/efi/console.c | 4 | ||||
-rw-r--r-- | src/boot/efi/cpio.c | 2 | ||||
-rw-r--r-- | src/boot/efi/devicetree.c | 2 | ||||
-rw-r--r-- | src/boot/efi/drivers.c | 2 | ||||
-rw-r--r-- | src/boot/efi/fuzz-bcd.c | 3 | ||||
-rw-r--r-- | src/boot/efi/pe.c | 2 | ||||
-rw-r--r-- | src/boot/efi/random-seed.c | 2 | ||||
-rw-r--r-- | src/boot/efi/stub.c | 3 | ||||
-rw-r--r-- | src/boot/efi/util.c | 21 | ||||
-rw-r--r-- | src/boot/efi/util.h | 16 | ||||
-rwxr-xr-x | src/partition/test-repart.sh | 8 | ||||
-rw-r--r-- | src/random-seed/random-seed.c | 26 | ||||
-rw-r--r-- | src/resolve/resolved-dns-dnssec.c | 2 | ||||
-rw-r--r-- | src/test/meson.build | 4 | ||||
-rw-r--r-- | src/test/test-nss-hosts.c | 2 | ||||
-rw-r--r-- | src/test/test-nss-users.c | 2 | ||||
-rw-r--r-- | test/fuzz/meson.build | 5 | ||||
-rwxr-xr-x | tools/debug-sd-boot.sh | 85 | ||||
-rwxr-xr-x | tools/oss-fuzz.sh | 2 |
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" |