Thread (67 messages) 67 messages, 3 authors, 2026-08-21

Re: [RFC PATCH v1 17/25] unwind_user/eh_frame: Ignore DW_CFA_GNU_args_size

From: sashiko-bot@kernel.org
Date: 2026-08-18 15:04:48
Also in: linux-s390

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:

Pre-existing issues:
- [High] An integer overflow when evaluating `cur + expr_len` bypasses bounds checks, allowing an attacker to move the instruction pointer backward and trap the kernel in an infinite loop.
- [High] The CFI interpreter loop does not impose a maximum execution limit, allowing an attacker to stall the CPU by providing a maliciously crafted, highly padded sequence of CFI instructions.
--
--- Patch [17]: [RFC PATCH v1 17/25] unwind_user/eh_frame: Ignore DW_CFA_GNU_args_size ---
commit e1c2b0ab16134f39bfe2a1cb074739516466f777
Author: Jens Remus [off-list ref]

unwind_user/eh_frame: Ignore DW_CFA_GNU_args_size

This commit updates the unwind mechanism to safely ignore the
DW_CFA_GNU_args_size DWARF instruction. This instruction is used by GCC
to track exception handling stack sizes, but is not needed for kernel
stack tracing.
quoted hunk ↗ jump to hunk
diff --git a/kernel/unwind/eh_frame.c b/kernel/unwind/eh_frame.c
index ac288cec8021f..64176242b7d8f 100644
--- a/kernel/unwind/eh_frame.c
+++ b/kernel/unwind/eh_frame.c
[ ... ]
quoted hunk ↗ jump to hunk
@@ -1012,6 +1012,17 @@ static __always_inline int __do_cfi_insn(struct eh_frame_section *sec,
 			break;
 		}
 
+		case DW_CFA_GNU_args_size: {
+			unsigned long args_size;
+
+			ret = read_uleb128(&cur, end, &args_size);
+			if (ret)
+				return ret;
+
+			/* Ignore DW_CFA_GNU_args_size */
+			break;
+		}
+
 		case DW_CFA_remember_state:
 			if (ctx->stack_depth >= EH_FRAME_MAX_STATE_STACK)
 				return -EINVAL;
[Severity: High]
This is a pre-existing issue, but does this code allow an integer overflow
when evaluating cur + expr_len?

kernel/unwind/eh_frame.c:__do_cfi_insn() {
    ...
		case DW_CFA_val_expression: {
			unsigned long reg, expr_len;

			ret = read_uleb128(&cur, end, &reg);
			if (ret)
				return ret;
			ret = read_uleb128(&cur, end, &expr_len);
			if (ret)
				return ret;

			if (cur + expr_len > end)
				return -EINVAL;
    ...
}

If a maliciously crafted .eh_frame section provides an extremely large
expr_len value, cur + expr_len can wrap around to a value less than end.
This bypasses the bounds check, and when the instruction pointer cur is
updated via cur += expr_len, it moves backwards.

Since the unwinder operates on user-supplied call frame information, can
this trap the kernel in an uninterruptible infinite loop and cause a local
denial of service?


[Severity: High]
This is a pre-existing issue, but is it possible for this loop to run without
an execution limit?

kernel/unwind/eh_frame.c:__do_cfi_program() {
    ...
		cur = fde->cfi_insn_start;
		while (cur < fde->cfi_insn_end && ip <= target_ip) {
			ret = __do_cfi_insn(sec, fde, &cur, fde->cfi_insn_end, &ip, target_ip, ctx);
			if (ret)
				return ret;
		}
    ...
}

If a local attacker maps a maximally sized frame description entry filled
with DW_CFA_nop instructions, the kernel will sequentially process billions
of instructions without yielding or aborting.

Since this can run in non-preemptible or non-maskable interrupt contexts
during stack unwinding, can this stall the processor and trigger a
watchdog panic?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260818144954.2320378-1-jremus@linux.ibm.com?part=17
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help