Commit 54a012b6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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()
parents ab59a860 87cb582d
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -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)
+1 −3
Original line number Diff line number Diff line
@@ -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)
+11 −7
Original line number Diff line number Diff line
@@ -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) {

+1 −1
Original line number Diff line number Diff line
@@ -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;
	}
+51 −8
Original line number Diff line number Diff line
@@ -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) {
		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;
Loading