Re: [PATCH v6 3/4] kallsyms: delta-compress lineinfo tables for ~2.7x size reduction
From: sashiko-bot@kernel.org
Date: 2026-07-06 14:40:37
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] lineinfo_read_sleb128 contains a signed left shift that can overflow on malformed or large data, triggering a UBSAN splat in NMI/panic contexts. -- commit 3756e632dbdf4d6db79f0e2c8a39f6103ac6e8ad Author: Sasha Levin [off-list ref] kallsyms: delta-compress lineinfo tables for ~2.7x size reduction This patch replaces the flat uncompressed parallel arrays for lineinfo with a block-indexed, delta-encoded, ULEB128/SLEB128 varint compressed format to significantly reduce size. Entries are grouped into blocks of 64 and decoded entirely on the stack to ensure safety during NMI or panic contexts.
quoted hunk ↗ jump to hunk
diff --git a/include/linux/mod_lineinfo.h b/include/linux/mod_lineinfo.h index 9cda3263a0784..a3c7143433020 100644 --- a/include/linux/mod_lineinfo.h +++ b/include/linux/mod_lineinfo.h
[ ... ]
+/* Read an SLEB128 varint. Same safety guarantees as above. */
+static inline int32_t lineinfo_read_sleb128(const u8 *data, u32 *pos, u32 end)
+{
+ int32_t result = 0;
+ unsigned int shift = 0;
+ u8 byte = 0;
+
+ while (*pos < end) {
+ byte = data[*pos];
+ (*pos)++;
+ result |= (int32_t)(byte & 0x7f) << shift;[Severity: High] Can this signed left shift trigger a UBSAN splat on malformed or large data? For the 5th byte of an SLEB128 varint, shift will be 28. If the decoded byte has a value greater than 7 (e.g. 0x7F), 127 << 28 evaluates to 3409130496, which exceeds INT32_MAX. Since left-shifting into or past the sign bit of a signed integer is undefined behavior in C, a corrupted or maliciously crafted .mod_lineinfo section could trigger a CONFIG_UBSAN_SHIFT splat. If this function is called by lineinfo_search() during an NMI or panic context, would the resulting UBSAN splat attempt to take locks and call printk, potentially causing a deadlock or nested panic? Perhaps the shift should be performed as unsigned: result |= (int32_t)((u32)(byte & 0x7f) << shift);
+ shift += 7;
+ if (!(byte & 0x80))
+ break;
+ if (shift >= 32) {
+ while (*pos < end && (data[*pos] & 0x80))
+ (*pos)++;[ ... ] -- Sashiko AI review · https://sashiko.dev/#/patchset/20260706142914.2398993-1-sashal@kernel.org?part=3