Skip to content

[lib][uefi] fix a heap overflow, uninitialized con_out, and stale event list links - #531

Merged
zhangxp1998 merged 4 commits into
littlekernel:masterfrom
zhangxp1998:uefi-memory-safety-fixes
Aug 31, 2026
Merged

[lib][uefi] fix a heap overflow, uninitialized con_out, and stale event list links#531
zhangxp1998 merged 4 commits into
littlekernel:masterfrom
zhangxp1998:uefi-memory-safety-fixes

Conversation

@zhangxp1998

Copy link
Copy Markdown
Contributor

Four independent memory-safety fixes in lib/uefi, found while auditing the loader:

  • allocate the right size for debug image info entries: efi_core_new_debug_image_info_entry() allocated sizeof(union EfiDebugImageInfo) (8 bytes, a single pointer) for the normal_image entry and then wrote a 24-byte struct EfiDebugImageInfoNormal through it, a 16-byte pool overflow on every image load.

  • fully initialize the simple text output protocol: get_text_output_protocol() returned a struct with every member except output_string uninitialized. An application calling reset, clear_screen, or query_mode, or dereferencing mode, jumped through stack garbage. All callbacks now have benign implementations and mode points at a static 80x25 description.

  • unlink completed events before invoking callbacks: process_pending_events() moved ready events onto a stack-local list and left the nodes chained there after returning. A later close_event/check_event passed delete_if_in_list's non-null check and wrote through pointers into the dead stack frame. Events are now popped off the local list (which clears their links) before their callbacks run.

  • set the output index when wait_for_event succeeds: the event_wait_timeout success path returned without storing which event finished the wait, so callers read an uninitialized index.

Validation (qemu-virt-arm64-test, Clang/LLD, WERROR=1):

  • helloworld_aa64.efi loads and runs (return code 0), ut all passes 36/36, no faults in the log
  • The event-list and wait_for_event paths are exercised by async block IO (EFI_BLOCK_IO2), which GBL uses to load images
  • Also validated with [lib][uefi] fix FreePages on identity-mapped pages and per-run teardown leaks #530 applied on top: two consecutive uefi_load runs both succeed with PMM free_count identical before/after, ut all 36/36

The series is based on current master and is independent of #530; the two touch different hunks and apply cleanly in either order.

efi_core_new_debug_image_info_entry allocated sizeof(union
EfiDebugImageInfo), the size of a single pointer, for the normal_image
entry, then wrote a struct EfiDebugImageInfoNormal through it,
overflowing the pool allocation by 16 bytes on every image load.
Allocate the size of the structure actually stored there.
get_text_output_protocol returned a protocol struct with every member
except output_string left uninitialized, so an application calling
reset, clear_screen, or query_mode, or dereferencing the mode pointer,
would jump through stack garbage. Zero-initialize the struct, provide
benign implementations for the remaining callbacks, and point mode at a
static 80x25 mode description.
process_pending_events moved ready events onto a stack-local list and
invoked their callbacks with the nodes still chained to that local list
head. After the function returned, each completed event's node kept
pointing into the dead stack frame, so a later close_event or
check_event calling delete_if_in_list would pass the non-null check and
write through the dangling pointers, corrupting whatever occupied that
stack memory. Pop each event off the local list, which clears its
links, before invoking its callback.
Copilot AI lite review requested due to automatic review settings August 29, 2026 18:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR applies targeted memory-safety and correctness fixes in lib/uefi around debug image table allocation, console output protocol initialization, and event processing/wait behavior to prevent heap overflows, use of uninitialized function pointers/state, and stale list-node linkage.

Changes:

  • Fix debug image info entry allocation to use the correct structure size.
  • Fully initialize EfiSimpleTextOutputProtocol callbacks and provide a stable mode object.
  • Prevent stale list-node links in completed event processing and ensure wait_for_event() stores the signaled event index.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
lib/uefi/text_protocol.cpp Initializes all Simple Text Output protocol callbacks and provides a static mode descriptor.
lib/uefi/events.cpp Unlinks completed events before callbacks and sets the output index on wait completion.
lib/uefi/debug_support.cpp Fixes pool allocation size for debug image info “normal” entries to avoid overflow.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread lib/uefi/events.cpp
Comment on lines 102 to +106
auto status = event_wait_timeout(&ev->ev, 200);
if (status == ERR_TIMED_OUT) {
continue;
}
*index = i;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right — in the current single-threaded app model the only values that come back are NO_ERROR and ERR_TIMED_OUT (nothing else can destroy the event while the app is blocked here), but there's no reason to bake that assumption in. Updated: any other status now returns EFI_STATUS_DEVICE_ERROR instead of reporting a signaled event.

When event_wait_timeout completed without timing out, wait_for_event
returned EFI_STATUS_SUCCESS without storing which event finished the
wait, so callers read an uninitialized index. Store the index of the
event that completed, and report EFI_STATUS_DEVICE_ERROR instead of
success if the wait itself failed (e.g. the event was destroyed while
being waited on).
@zhangxp1998
zhangxp1998 merged commit 39614ea into littlekernel:master Aug 31, 2026
118 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants