mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-14 06:22:34 +02:00
When computing klp checksums, instructions with non-relocated jump/call destination offsets are problematic because the offset values can change when surrounding code has moved, causing the function to be incorrectly marked as changed. Specifically, that includes jumps from alternatives to the end of the alternative, which from objtool's perspective are jumps to the end of the alternative instruction block in the original function. Note that 'jump_dest' jumps don't include sibling calls (those use call_dest), nor do they include jumps to/from .cold sub functions (those are cross-section and need a reloc). Fix it by hashing the opcode bytes (excluding the immediate operand) along with a position-independent representation of the destination. For calls, use the function name, and for jumps, use the destination's offset within its function. [Note the "9 bit hole" comment was wrong: it has been 8 bits since commit70589843b3("objtool: Add option to trace function validation") added the 'trace' field. Adding the 4-bit 'immediate_len' field now leaves a 4-bit hole.] Fixes:0d83da43b1("objtool/klp: Add --checksum option to generate per-function checksums") Acked-by: Song Liu <song@kernel.org> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
121 lines
2.4 KiB
C
121 lines
2.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
|
|
*/
|
|
|
|
#ifndef _ARCH_H
|
|
#define _ARCH_H
|
|
|
|
#include <stdbool.h>
|
|
#include <linux/list.h>
|
|
#include <objtool/objtool.h>
|
|
#include <objtool/cfi.h>
|
|
|
|
enum insn_type {
|
|
INSN_JUMP_CONDITIONAL,
|
|
INSN_JUMP_UNCONDITIONAL,
|
|
INSN_JUMP_DYNAMIC,
|
|
INSN_JUMP_DYNAMIC_CONDITIONAL,
|
|
INSN_CALL,
|
|
INSN_CALL_DYNAMIC,
|
|
INSN_RETURN,
|
|
INSN_SYSCALL,
|
|
INSN_SYSRET,
|
|
INSN_BUG,
|
|
INSN_NOP,
|
|
INSN_STAC,
|
|
INSN_CLAC,
|
|
INSN_STD,
|
|
INSN_CLD,
|
|
INSN_TRAP,
|
|
INSN_ENDBR,
|
|
INSN_LEA_RIP,
|
|
INSN_OTHER,
|
|
};
|
|
|
|
enum op_dest_type {
|
|
OP_DEST_REG,
|
|
OP_DEST_REG_INDIRECT,
|
|
OP_DEST_MEM,
|
|
OP_DEST_PUSH,
|
|
OP_DEST_PUSHF,
|
|
};
|
|
|
|
struct op_dest {
|
|
enum op_dest_type type;
|
|
unsigned char reg;
|
|
int offset;
|
|
};
|
|
|
|
enum op_src_type {
|
|
OP_SRC_REG,
|
|
OP_SRC_REG_INDIRECT,
|
|
OP_SRC_CONST,
|
|
OP_SRC_POP,
|
|
OP_SRC_POPF,
|
|
OP_SRC_ADD,
|
|
OP_SRC_AND,
|
|
};
|
|
|
|
struct op_src {
|
|
enum op_src_type type;
|
|
unsigned char reg;
|
|
int offset;
|
|
};
|
|
|
|
struct stack_op {
|
|
struct stack_op *next;
|
|
struct op_dest dest;
|
|
struct op_src src;
|
|
};
|
|
|
|
struct instruction;
|
|
|
|
int arch_ftrace_match(const char *name);
|
|
|
|
void arch_initial_func_cfi_state(struct cfi_init_state *state);
|
|
|
|
int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
|
|
unsigned long offset, unsigned int maxlen,
|
|
struct instruction *insn);
|
|
|
|
size_t arch_jump_opcode_bytes(struct objtool_file *file, struct instruction *insn,
|
|
unsigned char *buf);
|
|
|
|
bool arch_callee_saved_reg(unsigned char reg);
|
|
|
|
unsigned long arch_jump_destination(struct instruction *insn);
|
|
|
|
s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *reloc);
|
|
u64 arch_adjusted_addend(struct reloc *reloc);
|
|
|
|
const char *arch_nop_insn(int len);
|
|
const char *arch_ret_insn(int len);
|
|
|
|
int arch_decode_hint_reg(u8 sp_reg, int *base);
|
|
|
|
bool arch_is_retpoline(struct symbol *sym);
|
|
bool arch_is_rethunk(struct symbol *sym);
|
|
bool arch_is_embedded_insn(struct symbol *sym);
|
|
|
|
int arch_rewrite_retpolines(struct objtool_file *file);
|
|
|
|
bool arch_pc_relative_reloc(struct reloc *reloc);
|
|
bool arch_absolute_reloc(struct elf *elf, struct reloc *reloc);
|
|
|
|
unsigned int arch_reloc_size(struct reloc *reloc);
|
|
unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table);
|
|
|
|
extern const char *arch_reg_name[CFI_NUM_REGS];
|
|
|
|
#ifdef DISAS
|
|
|
|
#include <bfd.h>
|
|
#include <dis-asm.h>
|
|
|
|
int arch_disas_info_init(struct disassemble_info *dinfo);
|
|
|
|
#endif /* DISAS */
|
|
|
|
#endif /* _ARCH_H */
|