commit 4ae68b26c3ab5a82aa271e6e9fc9b1a06e1d6b40 upstream. Objtool --rethunk does two things: - it collects all (tail) call's of __x86_return_thunk and places them into .return_sites. These are typically compiler generated, but RET also emits this same. - it fudges the validation of the __x86_return_thunk symbol; because this symbol is inside another instruction, it can't actually find the instruction pointed to by the symbol offset and gets upset. Because these two things pertained to the same symbol, there was no pressing need to separate these two separate things. However, alas, along comes SRSO and more crazy things to deal with appeared. The SRSO patch itself added the following symbol names to identify as rethunk: 'srso_untrain_ret', 'srso_safe_ret' and '__ret' Where '__ret' is the old retbleed return thunk, 'srso_safe_ret' is a new similarly embedded return thunk, and 'srso_untrain_ret' is completely unrelated to anything the above does (and was only included because of that INT3 vs UD2 issue fixed previous). Clear things up by adding a second category for the embedded instruction thing. Fixes: fb3bd914b3ec ("x86/srso: Add a Speculative RAS Overflow mitigation") Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Link: https://lore.kernel.org/r/20230814121148.704502245@infradead.org Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
158 lines
4.2 KiB
C
158 lines
4.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
|
|
*/
|
|
|
|
#ifndef _OBJTOOL_ELF_H
|
|
#define _OBJTOOL_ELF_H
|
|
|
|
#include <stdio.h>
|
|
#include <gelf.h>
|
|
#include <linux/list.h>
|
|
#include <linux/hashtable.h>
|
|
#include <linux/rbtree.h>
|
|
#include <linux/jhash.h>
|
|
|
|
#ifdef LIBELF_USE_DEPRECATED
|
|
# define elf_getshdrnum elf_getshnum
|
|
# define elf_getshdrstrndx elf_getshstrndx
|
|
#endif
|
|
|
|
/*
|
|
* Fallback for systems without this "read, mmaping if possible" cmd.
|
|
*/
|
|
#ifndef ELF_C_READ_MMAP
|
|
#define ELF_C_READ_MMAP ELF_C_READ
|
|
#endif
|
|
|
|
struct section {
|
|
struct list_head list;
|
|
struct hlist_node hash;
|
|
struct hlist_node name_hash;
|
|
GElf_Shdr sh;
|
|
struct rb_root symbol_tree;
|
|
struct list_head symbol_list;
|
|
struct list_head reloc_list;
|
|
struct section *base, *reloc;
|
|
struct symbol *sym;
|
|
Elf_Data *data;
|
|
char *name;
|
|
int idx;
|
|
unsigned int len;
|
|
bool changed, text, rodata, noinstr;
|
|
};
|
|
|
|
struct symbol {
|
|
struct list_head list;
|
|
struct rb_node node;
|
|
struct hlist_node hash;
|
|
struct hlist_node name_hash;
|
|
GElf_Sym sym;
|
|
struct section *sec;
|
|
char *name;
|
|
unsigned int idx;
|
|
unsigned char bind, type;
|
|
unsigned long offset;
|
|
unsigned int len;
|
|
struct symbol *pfunc, *cfunc, *alias;
|
|
u8 uaccess_safe : 1;
|
|
u8 static_call_tramp : 1;
|
|
u8 retpoline_thunk : 1;
|
|
u8 return_thunk : 1;
|
|
u8 fentry : 1;
|
|
u8 kcov : 1;
|
|
u8 embedded_insn : 1;
|
|
};
|
|
|
|
struct reloc {
|
|
struct list_head list;
|
|
struct hlist_node hash;
|
|
union {
|
|
GElf_Rela rela;
|
|
GElf_Rel rel;
|
|
};
|
|
struct section *sec;
|
|
struct symbol *sym;
|
|
unsigned long offset;
|
|
unsigned int type;
|
|
s64 addend;
|
|
int idx;
|
|
bool jump_table_start;
|
|
};
|
|
|
|
#define ELF_HASH_BITS 20
|
|
|
|
struct elf {
|
|
Elf *elf;
|
|
GElf_Ehdr ehdr;
|
|
int fd;
|
|
bool changed;
|
|
char *name;
|
|
struct list_head sections;
|
|
DECLARE_HASHTABLE(symbol_hash, ELF_HASH_BITS);
|
|
DECLARE_HASHTABLE(symbol_name_hash, ELF_HASH_BITS);
|
|
DECLARE_HASHTABLE(section_hash, ELF_HASH_BITS);
|
|
DECLARE_HASHTABLE(section_name_hash, ELF_HASH_BITS);
|
|
DECLARE_HASHTABLE(reloc_hash, ELF_HASH_BITS);
|
|
};
|
|
|
|
#define OFFSET_STRIDE_BITS 4
|
|
#define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS)
|
|
#define OFFSET_STRIDE_MASK (~(OFFSET_STRIDE - 1))
|
|
|
|
#define for_offset_range(_offset, _start, _end) \
|
|
for (_offset = ((_start) & OFFSET_STRIDE_MASK); \
|
|
_offset >= ((_start) & OFFSET_STRIDE_MASK) && \
|
|
_offset <= ((_end) & OFFSET_STRIDE_MASK); \
|
|
_offset += OFFSET_STRIDE)
|
|
|
|
static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)
|
|
{
|
|
u32 ol, oh, idx = sec->idx;
|
|
|
|
offset &= OFFSET_STRIDE_MASK;
|
|
|
|
ol = offset;
|
|
oh = (offset >> 16) >> 16;
|
|
|
|
__jhash_mix(ol, oh, idx);
|
|
|
|
return ol;
|
|
}
|
|
|
|
static inline u32 reloc_hash(struct reloc *reloc)
|
|
{
|
|
return sec_offset_hash(reloc->sec, reloc->offset);
|
|
}
|
|
|
|
struct elf *elf_open_read(const char *name, int flags);
|
|
struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr);
|
|
|
|
int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
|
|
unsigned int type, struct symbol *sym, s64 addend);
|
|
int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
|
|
unsigned long offset, unsigned int type,
|
|
struct section *insn_sec, unsigned long insn_off);
|
|
|
|
int elf_write_insn(struct elf *elf, struct section *sec,
|
|
unsigned long offset, unsigned int len,
|
|
const char *insn);
|
|
int elf_write_reloc(struct elf *elf, struct reloc *reloc);
|
|
int elf_write(struct elf *elf);
|
|
void elf_close(struct elf *elf);
|
|
|
|
struct section *find_section_by_name(const struct elf *elf, const char *name);
|
|
struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
|
|
struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
|
|
struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
|
|
struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
|
|
struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
|
|
struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
|
|
unsigned long offset, unsigned int len);
|
|
struct symbol *find_func_containing(struct section *sec, unsigned long offset);
|
|
|
|
#define for_each_sec(file, sec) \
|
|
list_for_each_entry(sec, &file->elf->sections, list)
|
|
|
|
#endif /* _OBJTOOL_ELF_H */
|