mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 14:42:08 +02:00
Miscellaneous objtool fixes:
- Remove the recently introduced ANNOTATE_IGNORE_ALTERNATIVE noise
from clac()/stac() code to make .s files more readable.
- Fix INSN_SYSCALL / INSN_SYSRET semantics
- Fix various false-positive warnings
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-----BEGIN PGP SIGNATURE-----
iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmf4MWQRHG1pbmdvQGtl
cm5lbC5vcmcACgkQEnMQ0APhK1i85w/+P/iNkUg6X9eU/Jg8p21E+bXWimvnEUOt
WAdQOLjtlhanHnvdJy1DguQTdNVT30JwIDjj3gPVkgOBIJBSg+YR7Gk7VYVJPQnl
17tPt+VdVdPRB1wpB4WYx5OLJn7mIpsHXx46uPDFZh2xCEfRiKSbTRg5y/lWb54G
vw5AITSHISAbJDRVLxXXDtMPvK8oxO8F8slEU4p4oiKEUiKpHKQ3UUCN9SM3hPtq
Lhhp3eeRCcv4Yi8CFUXLQ+9NeACVmc+2KI5T3kuxs7uyNbauWT2+oGyN/q3ofwDx
iZglEKuorK1YUAG2uwxVpv+YB1GRb3Kd0Hi28kfgzOkr3i8ECabiaVQ528bLvzxf
ujD62N0D2OXYDe/jVAZgpptO893coxdEViZOw6/pjtXw8XUGlcGN7xQ7pfkAr8ZK
xY5MRFdFRV8GIITJ/LsD3xYk//e3gyI3HXs3D4sMIDBqeksJ9kHhV1MeF17Ksxli
QoqzOJryfg1WKvHT8vLuo6TQweP92wGEYEOYeAgqejlvqOfc56AY+un5bFSPAxHb
54iCmvGUB2JzWAmRzyVEOk0Lat0OX9WnYPbBcdBiC7qkRzeEdy/tEwW1ncgDyeJY
WmDY217Fadz0/vPIgwofip3/PujKsjB2CllNWf0QUzxU3Sy1uH9Erfi6uCh96tmA
vnlE6QHRi+o=
=Iuch
-----END PGP SIGNATURE-----
Merge tag 'objtool-urgent-2025-04-10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull misc objtool fixes from Ingo Molnar:
- Remove the recently introduced ANNOTATE_IGNORE_ALTERNATIVE noise from
clac()/stac() code to make .s files more readable
- Fix INSN_SYSCALL / INSN_SYSRET semantics
- Fix various false-positive warnings
* tag 'objtool-urgent-2025-04-10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
objtool: Fix false-positive "ignoring unreachables" warning
objtool: Remove ANNOTATE_IGNORE_ALTERNATIVE from CLAC/STAC
objtool, xen: Fix INSN_SYSCALL / INSN_SYSRET semantics
objtool: Stop UNRET validation on UD2
objtool: Split INSN_CONTEXT_SWITCH into INSN_SYSCALL and INSN_SYSRET
objtool: Fix INSN_CONTEXT_SWITCH handling in validate_unret()
This commit is contained in:
commit
54a012b622
|
|
@ -16,23 +16,23 @@
|
|||
#ifdef __ASSEMBLER__
|
||||
|
||||
#define ASM_CLAC \
|
||||
ALTERNATIVE __stringify(ANNOTATE_IGNORE_ALTERNATIVE), "clac", X86_FEATURE_SMAP
|
||||
ALTERNATIVE "", "clac", X86_FEATURE_SMAP
|
||||
|
||||
#define ASM_STAC \
|
||||
ALTERNATIVE __stringify(ANNOTATE_IGNORE_ALTERNATIVE), "stac", X86_FEATURE_SMAP
|
||||
ALTERNATIVE "", "stac", X86_FEATURE_SMAP
|
||||
|
||||
#else /* __ASSEMBLER__ */
|
||||
|
||||
static __always_inline void clac(void)
|
||||
{
|
||||
/* Note: a barrier is implicit in alternative() */
|
||||
alternative(ANNOTATE_IGNORE_ALTERNATIVE "", "clac", X86_FEATURE_SMAP);
|
||||
alternative("", "clac", X86_FEATURE_SMAP);
|
||||
}
|
||||
|
||||
static __always_inline void stac(void)
|
||||
{
|
||||
/* Note: a barrier is implicit in alternative() */
|
||||
alternative(ANNOTATE_IGNORE_ALTERNATIVE "", "stac", X86_FEATURE_SMAP);
|
||||
alternative("", "stac", X86_FEATURE_SMAP);
|
||||
}
|
||||
|
||||
static __always_inline unsigned long smap_save(void)
|
||||
|
|
@ -59,9 +59,9 @@ static __always_inline void smap_restore(unsigned long flags)
|
|||
|
||||
/* These macros can be used in asm() statements */
|
||||
#define ASM_CLAC \
|
||||
ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "", "clac", X86_FEATURE_SMAP)
|
||||
ALTERNATIVE("", "clac", X86_FEATURE_SMAP)
|
||||
#define ASM_STAC \
|
||||
ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "", "stac", X86_FEATURE_SMAP)
|
||||
ALTERNATIVE("", "stac", X86_FEATURE_SMAP)
|
||||
|
||||
#define ASM_CLAC_UNSAFE \
|
||||
ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "clac", X86_FEATURE_SMAP)
|
||||
|
|
|
|||
|
|
@ -226,9 +226,7 @@ SYM_CODE_END(xen_early_idt_handler_array)
|
|||
push %rax
|
||||
mov $__HYPERVISOR_iret, %eax
|
||||
syscall /* Do the IRET. */
|
||||
#ifdef CONFIG_MITIGATION_SLS
|
||||
int3
|
||||
#endif
|
||||
ud2 /* The SYSCALL should never return. */
|
||||
.endm
|
||||
|
||||
SYM_CODE_START(xen_iret)
|
||||
|
|
|
|||
|
|
@ -522,7 +522,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
|
|||
case INAT_PFX_REPNE:
|
||||
if (modrm == 0xca)
|
||||
/* eretu/erets */
|
||||
insn->type = INSN_CONTEXT_SWITCH;
|
||||
insn->type = INSN_SYSRET;
|
||||
break;
|
||||
default:
|
||||
if (modrm == 0xca)
|
||||
|
|
@ -535,11 +535,15 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
|
|||
|
||||
insn->type = INSN_JUMP_CONDITIONAL;
|
||||
|
||||
} else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 ||
|
||||
op2 == 0x35) {
|
||||
} else if (op2 == 0x05 || op2 == 0x34) {
|
||||
|
||||
/* sysenter, sysret */
|
||||
insn->type = INSN_CONTEXT_SWITCH;
|
||||
/* syscall, sysenter */
|
||||
insn->type = INSN_SYSCALL;
|
||||
|
||||
} else if (op2 == 0x07 || op2 == 0x35) {
|
||||
|
||||
/* sysret, sysexit */
|
||||
insn->type = INSN_SYSRET;
|
||||
|
||||
} else if (op2 == 0x0b || op2 == 0xb9) {
|
||||
|
||||
|
|
@ -676,7 +680,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
|
|||
|
||||
case 0xca: /* retf */
|
||||
case 0xcb: /* retf */
|
||||
insn->type = INSN_CONTEXT_SWITCH;
|
||||
insn->type = INSN_SYSRET;
|
||||
break;
|
||||
|
||||
case 0xe0: /* loopne */
|
||||
|
|
@ -721,7 +725,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
|
|||
} else if (modrm_reg == 5) {
|
||||
|
||||
/* jmpf */
|
||||
insn->type = INSN_CONTEXT_SWITCH;
|
||||
insn->type = INSN_SYSRET;
|
||||
|
||||
} else if (modrm_reg == 6) {
|
||||
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ struct reloc *arch_find_switch_table(struct objtool_file *file,
|
|||
* indicates a rare GCC quirk/bug which can leave dead
|
||||
* code behind.
|
||||
*/
|
||||
if (reloc_type(text_reloc) == R_X86_64_PC32) {
|
||||
if (!file->ignore_unreachables && reloc_type(text_reloc) == R_X86_64_PC32) {
|
||||
WARN_INSN(insn, "ignoring unreachables due to jump table quirk");
|
||||
file->ignore_unreachables = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3505,6 +3505,34 @@ static struct instruction *next_insn_to_validate(struct objtool_file *file,
|
|||
return next_insn_same_sec(file, alt_group->orig_group->last_insn);
|
||||
}
|
||||
|
||||
static bool skip_alt_group(struct instruction *insn)
|
||||
{
|
||||
struct instruction *alt_insn = insn->alts ? insn->alts->insn : NULL;
|
||||
|
||||
/* ANNOTATE_IGNORE_ALTERNATIVE */
|
||||
if (insn->alt_group && insn->alt_group->ignore)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* For NOP patched with CLAC/STAC, only follow the latter to avoid
|
||||
* impossible code paths combining patched CLAC with unpatched STAC
|
||||
* or vice versa.
|
||||
*
|
||||
* ANNOTATE_IGNORE_ALTERNATIVE could have been used here, but Linus
|
||||
* requested not to do that to avoid hurting .s file readability
|
||||
* around CLAC/STAC alternative sites.
|
||||
*/
|
||||
|
||||
if (!alt_insn)
|
||||
return false;
|
||||
|
||||
/* Don't override ASM_{CLAC,STAC}_UNSAFE */
|
||||
if (alt_insn->alt_group && alt_insn->alt_group->ignore)
|
||||
return false;
|
||||
|
||||
return alt_insn->type == INSN_CLAC || alt_insn->type == INSN_STAC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Follow the branch starting at the given instruction, and recursively follow
|
||||
* any other branches (jumps). Meanwhile, track the frame pointer state at
|
||||
|
|
@ -3625,7 +3653,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
|
|||
}
|
||||
}
|
||||
|
||||
if (insn->alt_group && insn->alt_group->ignore)
|
||||
if (skip_alt_group(insn))
|
||||
return 0;
|
||||
|
||||
if (handle_insn_ops(insn, next_insn, &state))
|
||||
|
|
@ -3684,14 +3712,20 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
|
|||
|
||||
break;
|
||||
|
||||
case INSN_CONTEXT_SWITCH:
|
||||
if (func) {
|
||||
if (!next_insn || !next_insn->hint) {
|
||||
WARN_INSN(insn, "unsupported instruction in callable function");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case INSN_SYSCALL:
|
||||
if (func && (!next_insn || !next_insn->hint)) {
|
||||
WARN_INSN(insn, "unsupported instruction in callable function");
|
||||
return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case INSN_SYSRET:
|
||||
if (func && (!next_insn || !next_insn->hint)) {
|
||||
WARN_INSN(insn, "unsupported instruction in callable function");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case INSN_STAC:
|
||||
|
|
@ -3886,6 +3920,12 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn)
|
|||
WARN_INSN(insn, "RET before UNTRAIN");
|
||||
return 1;
|
||||
|
||||
case INSN_SYSCALL:
|
||||
break;
|
||||
|
||||
case INSN_SYSRET:
|
||||
return 0;
|
||||
|
||||
case INSN_NOP:
|
||||
if (insn->retpoline_safe)
|
||||
return 0;
|
||||
|
|
@ -3895,6 +3935,9 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn)
|
|||
break;
|
||||
}
|
||||
|
||||
if (insn->dead_end)
|
||||
return 0;
|
||||
|
||||
if (!next) {
|
||||
WARN_INSN(insn, "teh end!");
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ enum insn_type {
|
|||
INSN_CALL,
|
||||
INSN_CALL_DYNAMIC,
|
||||
INSN_RETURN,
|
||||
INSN_CONTEXT_SWITCH,
|
||||
INSN_SYSCALL,
|
||||
INSN_SYSRET,
|
||||
INSN_BUG,
|
||||
INSN_NOP,
|
||||
INSN_STAC,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user