Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'objtool-urgent-2026-03-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull objtool fixes from Ingo Molnar:

- Fix cross-build bug by using HOSTCFLAGS for HAVE_XXHASH test

- Fix klp bug by fixing detection of corrupt static branch/call entries

- Handle unsupported pr_debug() usage more gracefully

- Fix hypothetical klp bug by avoiding NULL pointer dereference when
printing code symbol name

- Fix data alignment bug in elf_add_data() causing mangled strings

- Fix confusing ERROR_INSN() error message

- Handle unexpected Clang RSP musical chairs causing false positive
warnings

- Fix another objtool stack overflow in validate_branch()

* tag 'objtool-urgent-2026-03-15' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
objtool: Fix another stack overflow in validate_branch()
objtool: Handle Clang RSP musical chairs
objtool: Fix ERROR_INSN() error message
objtool: Fix data alignment in elf_add_data()
objtool: Use HOSTCFLAGS for HAVE_XXHASH test
objtool/klp: Avoid NULL pointer dereference when printing code symbol name
objtool/klp: Disable unsupported pr_debug() usage
objtool/klp: Fix detection of corrupt static branch/call entries

+74 -63
+1 -1
tools/objtool/Makefile
··· 13 13 14 14 ifeq ($(ARCH_HAS_KLP),y) 15 15 HAVE_XXHASH = $(shell printf "$(pound)include <xxhash.h>\nXXH3_state_t *state;int main() {}" | \ 16 - $(HOSTCC) -xc - -o /dev/null -lxxhash 2> /dev/null && echo y || echo n) 16 + $(HOSTCC) $(HOSTCFLAGS) -xc - -o /dev/null -lxxhash 2> /dev/null && echo y || echo n) 17 17 ifeq ($(HAVE_XXHASH),y) 18 18 BUILD_KLP := y 19 19 LIBXXHASH_CFLAGS := $(shell $(HOSTPKG_CONFIG) libxxhash --cflags 2>/dev/null) \
+26 -42
tools/objtool/arch/x86/decode.c
··· 395 395 if (!rex_w) 396 396 break; 397 397 398 - if (modrm_reg == CFI_SP) { 399 - 400 - if (mod_is_reg()) { 401 - /* mov %rsp, reg */ 402 - ADD_OP(op) { 403 - op->src.type = OP_SRC_REG; 404 - op->src.reg = CFI_SP; 405 - op->dest.type = OP_DEST_REG; 406 - op->dest.reg = modrm_rm; 407 - } 408 - break; 409 - 410 - } else { 411 - /* skip RIP relative displacement */ 412 - if (is_RIP()) 413 - break; 414 - 415 - /* skip nontrivial SIB */ 416 - if (have_SIB()) { 417 - modrm_rm = sib_base; 418 - if (sib_index != CFI_SP) 419 - break; 420 - } 421 - 422 - /* mov %rsp, disp(%reg) */ 423 - ADD_OP(op) { 424 - op->src.type = OP_SRC_REG; 425 - op->src.reg = CFI_SP; 426 - op->dest.type = OP_DEST_REG_INDIRECT; 427 - op->dest.reg = modrm_rm; 428 - op->dest.offset = ins.displacement.value; 429 - } 430 - break; 431 - } 432 - 433 - break; 434 - } 435 - 436 - if (rm_is_reg(CFI_SP)) { 437 - 438 - /* mov reg, %rsp */ 398 + if (mod_is_reg()) { 399 + /* mov reg, reg */ 439 400 ADD_OP(op) { 440 401 op->src.type = OP_SRC_REG; 441 402 op->src.reg = modrm_reg; 442 403 op->dest.type = OP_DEST_REG; 443 - op->dest.reg = CFI_SP; 404 + op->dest.reg = modrm_rm; 405 + } 406 + break; 407 + } 408 + 409 + /* skip RIP relative displacement */ 410 + if (is_RIP()) 411 + break; 412 + 413 + /* skip nontrivial SIB */ 414 + if (have_SIB()) { 415 + modrm_rm = sib_base; 416 + if (sib_index != CFI_SP) 417 + break; 418 + } 419 + 420 + /* mov %rsp, disp(%reg) */ 421 + if (modrm_reg == CFI_SP) { 422 + ADD_OP(op) { 423 + op->src.type = OP_SRC_REG; 424 + op->src.reg = CFI_SP; 425 + op->dest.type = OP_DEST_REG_INDIRECT; 426 + op->dest.reg = modrm_rm; 427 + op->dest.offset = ins.displacement.value; 444 428 } 445 429 break; 446 430 }
+19 -5
tools/objtool/check.c
··· 3000 3000 cfi->stack_size += 8; 3001 3001 } 3002 3002 3003 + else if (cfi->vals[op->src.reg].base == CFI_CFA) { 3004 + /* 3005 + * Clang RSP musical chairs: 3006 + * 3007 + * mov %rsp, %rdx [handled above] 3008 + * ... 3009 + * mov %rdx, %rbx [handled here] 3010 + * ... 3011 + * mov %rbx, %rsp [handled above] 3012 + */ 3013 + cfi->vals[op->dest.reg].base = CFI_CFA; 3014 + cfi->vals[op->dest.reg].offset = cfi->vals[op->src.reg].offset; 3015 + } 3016 + 3003 3017 3004 3018 break; 3005 3019 ··· 3748 3734 static int validate_branch(struct objtool_file *file, struct symbol *func, 3749 3735 struct instruction *insn, struct insn_state state); 3750 3736 static int do_validate_branch(struct objtool_file *file, struct symbol *func, 3751 - struct instruction *insn, struct insn_state state); 3737 + struct instruction *insn, struct insn_state *state); 3752 3738 3753 3739 static int validate_insn(struct objtool_file *file, struct symbol *func, 3754 3740 struct instruction *insn, struct insn_state *statep, ··· 4013 3999 * tools/objtool/Documentation/objtool.txt. 4014 4000 */ 4015 4001 static int do_validate_branch(struct objtool_file *file, struct symbol *func, 4016 - struct instruction *insn, struct insn_state state) 4002 + struct instruction *insn, struct insn_state *state) 4017 4003 { 4018 4004 struct instruction *next_insn, *prev_insn = NULL; 4019 4005 bool dead_end; ··· 4044 4030 return 1; 4045 4031 } 4046 4032 4047 - ret = validate_insn(file, func, insn, &state, prev_insn, next_insn, 4033 + ret = validate_insn(file, func, insn, state, prev_insn, next_insn, 4048 4034 &dead_end); 4049 4035 4050 4036 if (!insn->trace) { ··· 4055 4041 } 4056 4042 4057 4043 if (!dead_end && !next_insn) { 4058 - if (state.cfi.cfa.base == CFI_UNDEFINED) 4044 + if (state->cfi.cfa.base == CFI_UNDEFINED) 4059 4045 return 0; 4060 4046 if (file->ignore_unreachables) 4061 4047 return 0; ··· 4080 4066 int ret; 4081 4067 4082 4068 trace_depth_inc(); 4083 - ret = do_validate_branch(file, func, insn, state); 4069 + ret = do_validate_branch(file, func, insn, &state); 4084 4070 trace_depth_dec(); 4085 4071 4086 4072 return ret;
+1 -1
tools/objtool/elf.c
··· 1375 1375 memcpy(sec->data->d_buf, data, size); 1376 1376 1377 1377 sec->data->d_size = size; 1378 - sec->data->d_align = 1; 1378 + sec->data->d_align = sec->sh.sh_addralign; 1379 1379 1380 1380 offset = ALIGN(sec->sh.sh_size, sec->sh.sh_addralign); 1381 1381 sec->sh.sh_size = offset + size;
+1 -1
tools/objtool/include/objtool/warn.h
··· 107 107 #define ERROR_ELF(format, ...) __WARN_ELF(ERROR_STR, format, ##__VA_ARGS__) 108 108 #define ERROR_GLIBC(format, ...) __WARN_GLIBC(ERROR_STR, format, ##__VA_ARGS__) 109 109 #define ERROR_FUNC(sec, offset, format, ...) __WARN_FUNC(ERROR_STR, sec, offset, format, ##__VA_ARGS__) 110 - #define ERROR_INSN(insn, format, ...) WARN_FUNC(insn->sec, insn->offset, format, ##__VA_ARGS__) 110 + #define ERROR_INSN(insn, format, ...) ERROR_FUNC(insn->sec, insn->offset, format, ##__VA_ARGS__) 111 111 112 112 extern bool debug; 113 113 extern int indent;
+26 -13
tools/objtool/klp-diff.c
··· 1334 1334 * be applied after static branch/call init, resulting in code corruption. 1335 1335 * 1336 1336 * Validate a special section entry to avoid that. Note that an inert 1337 - * tracepoint is harmless enough, in that case just skip the entry and print a 1338 - * warning. Otherwise, return an error. 1337 + * tracepoint or pr_debug() is harmless enough, in that case just skip the 1338 + * entry and print a warning. Otherwise, return an error. 1339 1339 * 1340 - * This is only a temporary limitation which will be fixed when livepatch adds 1341 - * support for submodules: fully self-contained modules which are embedded in 1342 - * the top-level livepatch module's data and which can be loaded on demand when 1343 - * their corresponding to-be-patched module gets loaded. Then klp relocs can 1344 - * be retired. 1340 + * TODO: This is only a temporary limitation which will be fixed when livepatch 1341 + * adds support for submodules: fully self-contained modules which are embedded 1342 + * in the top-level livepatch module's data and which can be loaded on demand 1343 + * when their corresponding to-be-patched module gets loaded. Then klp relocs 1344 + * can be retired. 1345 1345 * 1346 1346 * Return: 1347 1347 * -1: error: validation failed 1348 - * 1: warning: tracepoint skipped 1348 + * 1: warning: disabled tracepoint or pr_debug() 1349 1349 * 0: success 1350 1350 */ 1351 1351 static int validate_special_section_klp_reloc(struct elfs *e, struct symbol *sym) 1352 1352 { 1353 1353 bool static_branch = !strcmp(sym->sec->name, "__jump_table"); 1354 1354 bool static_call = !strcmp(sym->sec->name, ".static_call_sites"); 1355 - struct symbol *code_sym = NULL; 1355 + const char *code_sym = NULL; 1356 1356 unsigned long code_offset = 0; 1357 1357 struct reloc *reloc; 1358 1358 int ret = 0; ··· 1364 1364 const char *sym_modname; 1365 1365 struct export *export; 1366 1366 1367 + if (convert_reloc_sym(e->patched, reloc)) 1368 + continue; 1369 + 1367 1370 /* Static branch/call keys are always STT_OBJECT */ 1368 1371 if (reloc->sym->type != STT_OBJECT) { 1369 1372 1370 1373 /* Save code location which can be printed below */ 1371 1374 if (reloc->sym->type == STT_FUNC && !code_sym) { 1372 - code_sym = reloc->sym; 1375 + code_sym = reloc->sym->name; 1373 1376 code_offset = reloc_addend(reloc); 1374 1377 } 1375 1378 ··· 1395 1392 if (!strcmp(sym_modname, "vmlinux")) 1396 1393 continue; 1397 1394 1395 + if (!code_sym) 1396 + code_sym = "<unknown>"; 1397 + 1398 1398 if (static_branch) { 1399 1399 if (strstarts(reloc->sym->name, "__tracepoint_")) { 1400 1400 WARN("%s: disabling unsupported tracepoint %s", 1401 - code_sym->name, reloc->sym->name + 13); 1401 + code_sym, reloc->sym->name + 13); 1402 + ret = 1; 1403 + continue; 1404 + } 1405 + 1406 + if (strstr(reloc->sym->name, "__UNIQUE_ID_ddebug_")) { 1407 + WARN("%s: disabling unsupported pr_debug()", 1408 + code_sym); 1402 1409 ret = 1; 1403 1410 continue; 1404 1411 } 1405 1412 1406 1413 ERROR("%s+0x%lx: unsupported static branch key %s. Use static_key_enabled() instead", 1407 - code_sym->name, code_offset, reloc->sym->name); 1414 + code_sym, code_offset, reloc->sym->name); 1408 1415 return -1; 1409 1416 } 1410 1417 ··· 1425 1412 } 1426 1413 1427 1414 ERROR("%s()+0x%lx: unsupported static call key %s. Use KLP_STATIC_CALL() instead", 1428 - code_sym->name, code_offset, reloc->sym->name); 1415 + code_sym, code_offset, reloc->sym->name); 1429 1416 return -1; 1430 1417 } 1431 1418