Commit 2f0f9e9a authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar
Browse files

objtool: Add Direction Flag validation



Having DF escape is BAD(tm).

Linus; you suggested this one, but since DF really is only used from
ASM and the failure case is fairly obvious, do we really need this?

OTOH the patch is fairly small and simple, so let's just do this
to demonstrate objtool's superior awesomeness.

Suggested-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent ea24213d
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -35,7 +35,9 @@
#define INSN_NOP		10
#define INSN_NOP		10
#define INSN_STAC		11
#define INSN_STAC		11
#define INSN_CLAC		12
#define INSN_CLAC		12
#define INSN_OTHER		13
#define INSN_STD		13
#define INSN_CLD		14
#define INSN_OTHER		15
#define INSN_LAST		INSN_OTHER
#define INSN_LAST		INSN_OTHER


enum op_dest_type {
enum op_dest_type {
+8 −0
Original line number Original line Diff line number Diff line
@@ -451,6 +451,14 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
		*type = INSN_CALL;
		*type = INSN_CALL;
		break;
		break;


	case 0xfc:
		*type = INSN_CLD;
		break;

	case 0xfd:
		*type = INSN_STD;
		break;

	case 0xff:
	case 0xff:
		if (modrm_reg == 2 || modrm_reg == 3)
		if (modrm_reg == 2 || modrm_reg == 3)


+25 −0
Original line number Original line Diff line number Diff line
@@ -1903,6 +1903,12 @@ static int validate_call(struct instruction *insn, struct insn_state *state)
		return 1;
		return 1;
	}
	}


	if (state->df) {
		WARN_FUNC("call to %s() with DF set",
				insn->sec, insn->offset, insn_dest_name(insn));
		return 1;
	}

	return 0;
	return 0;
}
}


@@ -2044,6 +2050,11 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
				return 1;
				return 1;
			}
			}


			if (state.df) {
				WARN_FUNC("return with DF set", sec, insn->offset);
				return 1;
			}

			if (func && has_modified_stack_frame(&state)) {
			if (func && has_modified_stack_frame(&state)) {
				WARN_FUNC("return with modified stack frame",
				WARN_FUNC("return with modified stack frame",
					  sec, insn->offset);
					  sec, insn->offset);
@@ -2172,6 +2183,20 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
			state.uaccess = false;
			state.uaccess = false;
			break;
			break;


		case INSN_STD:
			if (state.df)
				WARN_FUNC("recursive STD", sec, insn->offset);

			state.df = true;
			break;

		case INSN_CLD:
			if (!state.df && insn->func)
				WARN_FUNC("redundant CLD", sec, insn->offset);

			state.df = false;
			break;

		default:
		default:
			break;
			break;
		}
		}
+1 −1
Original line number Original line Diff line number Diff line
@@ -31,7 +31,7 @@ struct insn_state {
	int stack_size;
	int stack_size;
	unsigned char type;
	unsigned char type;
	bool bp_scratch;
	bool bp_scratch;
	bool drap, end, uaccess;
	bool drap, end, uaccess, df;
	unsigned int uaccess_stack;
	unsigned int uaccess_stack;
	int drap_reg, drap_offset;
	int drap_reg, drap_offset;
	struct cfi_reg vals[CFI_NUM_REGS];
	struct cfi_reg vals[CFI_NUM_REGS];