Merge tag 'x86_core_for_5.18_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 CET-IBT (Control-Flow-Integrity) support from Peter Zijlstra: "Add support for Intel CET-IBT, available since Tigerlake (11th gen), which is a coarse grained, hardware based, forward edge Control-Flow-Integrity mechanism where any indirect CALL/JMP must target an ENDBR instruction or suffer #CP. Additionally, since Alderlake (12th gen)/Sapphire-Rapids, speculation is limited to 2 instructions (and typically fewer) on branch targets not starting with ENDBR. CET-IBT also limits speculation of the next sequential instruction after the indirect CALL/JMP [1]. CET-IBT is fundamentally incompatible with retpolines, but provides, as described above, speculation limits itself" [1] https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/branch-history-injection.html * tag 'x86_core_for_5.18_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (53 commits) kvm/emulate: Fix SETcc emulation for ENDBR x86/Kconfig: Only allow CONFIG_X86_KERNEL_IBT with ld.lld >= 14.0.0 x86/Kconfig: Only enable CONFIG_CC_HAS_IBT for clang >= 14.0.0 kbuild: Fixup the IBT kbuild changes x86/Kconfig: Do not allow CONFIG_X86_X32_ABI=y with llvm-objcopy x86: Remove toolchain check for X32 ABI capability x86/alternative: Use .ibt_endbr_seal to seal indirect calls objtool: Find unused ENDBR instructions objtool: Validate IBT assumptions objtool: Add IBT/ENDBR decoding objtool: Read the NOENDBR annotation x86: Annotate idtentry_df() x86,objtool: Move the ASM_REACHABLE annotation to objtool.h x86: Annotate call_on_stack() objtool: Rework ASM_REACHABLE x86: Mark __invalid_creds() __noreturn exit: Mark do_group_exit() __noreturn x86: Mark stop_this_cpu() __noreturn objtool: Ignore extra-symbol code objtool: Rename --duplicate to --lto ...
This commit is contained in:
+4
-16
@@ -117,18 +117,6 @@ static void bpf_trampoline_module_put(struct bpf_trampoline *tr)
|
||||
tr->mod = NULL;
|
||||
}
|
||||
|
||||
static int is_ftrace_location(void *ip)
|
||||
{
|
||||
long addr;
|
||||
|
||||
addr = ftrace_location((long)ip);
|
||||
if (!addr)
|
||||
return 0;
|
||||
if (WARN_ON_ONCE(addr != (long)ip))
|
||||
return -EFAULT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
|
||||
{
|
||||
void *ip = tr->func.addr;
|
||||
@@ -160,12 +148,12 @@ static int modify_fentry(struct bpf_trampoline *tr, void *old_addr, void *new_ad
|
||||
static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
|
||||
{
|
||||
void *ip = tr->func.addr;
|
||||
unsigned long faddr;
|
||||
int ret;
|
||||
|
||||
ret = is_ftrace_location(ip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
tr->func.ftrace_managed = ret;
|
||||
faddr = ftrace_location((unsigned long)ip);
|
||||
if (faddr)
|
||||
tr->func.ftrace_managed = true;
|
||||
|
||||
if (bpf_trampoline_module_get(tr))
|
||||
return -ENOENT;
|
||||
|
||||
+1
-1
@@ -870,7 +870,7 @@ static void dump_invalid_creds(const struct cred *cred, const char *label,
|
||||
/*
|
||||
* report use of invalid credentials
|
||||
*/
|
||||
void __invalid_creds(const struct cred *cred, const char *file, unsigned line)
|
||||
void __noreturn __invalid_creds(const struct cred *cred, const char *file, unsigned line)
|
||||
{
|
||||
printk(KERN_ERR "CRED: Invalid credentials\n");
|
||||
printk(KERN_ERR "CRED: At %s:%u\n", file, line);
|
||||
|
||||
+1
-1
@@ -895,7 +895,7 @@ SYSCALL_DEFINE1(exit, int, error_code)
|
||||
* Take down every thread in the group. This is called by fatal signals
|
||||
* as well as by sys_exit_group (below).
|
||||
*/
|
||||
void
|
||||
void __noreturn
|
||||
do_group_exit(int exit_code)
|
||||
{
|
||||
struct signal_struct *sig = current->signal;
|
||||
|
||||
+54
-20
@@ -1488,25 +1488,69 @@ bool within_kprobe_blacklist(unsigned long addr)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* arch_adjust_kprobe_addr - adjust the address
|
||||
* @addr: symbol base address
|
||||
* @offset: offset within the symbol
|
||||
* @on_func_entry: was this @addr+@offset on the function entry
|
||||
*
|
||||
* Typically returns @addr + @offset, except for special cases where the
|
||||
* function might be prefixed by a CFI landing pad, in that case any offset
|
||||
* inside the landing pad is mapped to the first 'real' instruction of the
|
||||
* symbol.
|
||||
*
|
||||
* Specifically, for things like IBT/BTI, skip the resp. ENDBR/BTI.C
|
||||
* instruction at +0.
|
||||
*/
|
||||
kprobe_opcode_t *__weak arch_adjust_kprobe_addr(unsigned long addr,
|
||||
unsigned long offset,
|
||||
bool *on_func_entry)
|
||||
{
|
||||
*on_func_entry = !offset;
|
||||
return (kprobe_opcode_t *)(addr + offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* If 'symbol_name' is specified, look it up and add the 'offset'
|
||||
* to it. This way, we can specify a relative address to a symbol.
|
||||
* This returns encoded errors if it fails to look up symbol or invalid
|
||||
* combination of parameters.
|
||||
*/
|
||||
static kprobe_opcode_t *_kprobe_addr(kprobe_opcode_t *addr,
|
||||
const char *symbol_name, unsigned int offset)
|
||||
static kprobe_opcode_t *
|
||||
_kprobe_addr(kprobe_opcode_t *addr, const char *symbol_name,
|
||||
unsigned long offset, bool *on_func_entry)
|
||||
{
|
||||
if ((symbol_name && addr) || (!symbol_name && !addr))
|
||||
goto invalid;
|
||||
|
||||
if (symbol_name) {
|
||||
/*
|
||||
* Input: @sym + @offset
|
||||
* Output: @addr + @offset
|
||||
*
|
||||
* NOTE: kprobe_lookup_name() does *NOT* fold the offset
|
||||
* argument into it's output!
|
||||
*/
|
||||
addr = kprobe_lookup_name(symbol_name, offset);
|
||||
if (!addr)
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
addr = (kprobe_opcode_t *)(((char *)addr) + offset);
|
||||
/*
|
||||
* So here we have @addr + @offset, displace it into a new
|
||||
* @addr' + @offset' where @addr' is the symbol start address.
|
||||
*/
|
||||
addr = (void *)addr + offset;
|
||||
if (!kallsyms_lookup_size_offset((unsigned long)addr, NULL, &offset))
|
||||
return ERR_PTR(-ENOENT);
|
||||
addr = (void *)addr - offset;
|
||||
|
||||
/*
|
||||
* Then ask the architecture to re-combine them, taking care of
|
||||
* magical function entry details while telling us if this was indeed
|
||||
* at the start of the function.
|
||||
*/
|
||||
addr = arch_adjust_kprobe_addr((unsigned long)addr, offset, on_func_entry);
|
||||
if (addr)
|
||||
return addr;
|
||||
|
||||
@@ -1516,7 +1560,8 @@ invalid:
|
||||
|
||||
static kprobe_opcode_t *kprobe_addr(struct kprobe *p)
|
||||
{
|
||||
return _kprobe_addr(p->addr, p->symbol_name, p->offset);
|
||||
bool on_func_entry;
|
||||
return _kprobe_addr(p->addr, p->symbol_name, p->offset, &on_func_entry);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1562,14 +1607,10 @@ static inline int warn_kprobe_rereg(struct kprobe *p)
|
||||
|
||||
static int check_ftrace_location(struct kprobe *p)
|
||||
{
|
||||
unsigned long ftrace_addr;
|
||||
unsigned long addr = (unsigned long)p->addr;
|
||||
|
||||
ftrace_addr = ftrace_location((unsigned long)p->addr);
|
||||
if (ftrace_addr) {
|
||||
if (ftrace_location(addr) == addr) {
|
||||
#ifdef CONFIG_KPROBES_ON_FTRACE
|
||||
/* Given address is not on the instruction boundary */
|
||||
if ((unsigned long)p->addr != ftrace_addr)
|
||||
return -EILSEQ;
|
||||
p->flags |= KPROBE_FLAG_FTRACE;
|
||||
#else /* !CONFIG_KPROBES_ON_FTRACE */
|
||||
return -EINVAL;
|
||||
@@ -2047,11 +2088,6 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
|
||||
}
|
||||
NOKPROBE_SYMBOL(pre_handler_kretprobe);
|
||||
|
||||
bool __weak arch_kprobe_on_func_entry(unsigned long offset)
|
||||
{
|
||||
return !offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* kprobe_on_func_entry() -- check whether given address is function entry
|
||||
* @addr: Target address
|
||||
@@ -2067,15 +2103,13 @@ bool __weak arch_kprobe_on_func_entry(unsigned long offset)
|
||||
*/
|
||||
int kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset)
|
||||
{
|
||||
kprobe_opcode_t *kp_addr = _kprobe_addr(addr, sym, offset);
|
||||
bool on_func_entry;
|
||||
kprobe_opcode_t *kp_addr = _kprobe_addr(addr, sym, offset, &on_func_entry);
|
||||
|
||||
if (IS_ERR(kp_addr))
|
||||
return PTR_ERR(kp_addr);
|
||||
|
||||
if (!kallsyms_lookup_size_offset((unsigned long)kp_addr, NULL, &offset))
|
||||
return -ENOENT;
|
||||
|
||||
if (!arch_kprobe_on_func_entry(offset))
|
||||
if (!on_func_entry)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -124,19 +124,6 @@ unlock:
|
||||
ftrace_test_recursion_unlock(bit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a function address into the appropriate ftrace location.
|
||||
*
|
||||
* Usually this is just the address of the function, but on some architectures
|
||||
* it's more complicated so allow them to provide a custom behaviour.
|
||||
*/
|
||||
#ifndef klp_get_ftrace_location
|
||||
static unsigned long klp_get_ftrace_location(unsigned long faddr)
|
||||
{
|
||||
return faddr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void klp_unpatch_func(struct klp_func *func)
|
||||
{
|
||||
struct klp_ops *ops;
|
||||
@@ -153,8 +140,7 @@ static void klp_unpatch_func(struct klp_func *func)
|
||||
if (list_is_singular(&ops->func_stack)) {
|
||||
unsigned long ftrace_loc;
|
||||
|
||||
ftrace_loc =
|
||||
klp_get_ftrace_location((unsigned long)func->old_func);
|
||||
ftrace_loc = ftrace_location((unsigned long)func->old_func);
|
||||
if (WARN_ON(!ftrace_loc))
|
||||
return;
|
||||
|
||||
@@ -186,8 +172,7 @@ static int klp_patch_func(struct klp_func *func)
|
||||
if (!ops) {
|
||||
unsigned long ftrace_loc;
|
||||
|
||||
ftrace_loc =
|
||||
klp_get_ftrace_location((unsigned long)func->old_func);
|
||||
ftrace_loc = ftrace_location((unsigned long)func->old_func);
|
||||
if (!ftrace_loc) {
|
||||
pr_err("failed to find location for function '%s'\n",
|
||||
func->old_name);
|
||||
|
||||
+40
-8
@@ -1568,17 +1568,34 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end)
|
||||
}
|
||||
|
||||
/**
|
||||
* ftrace_location - return true if the ip giving is a traced location
|
||||
* ftrace_location - return the ftrace location
|
||||
* @ip: the instruction pointer to check
|
||||
*
|
||||
* Returns rec->ip if @ip given is a pointer to a ftrace location.
|
||||
* That is, the instruction that is either a NOP or call to
|
||||
* the function tracer. It checks the ftrace internal tables to
|
||||
* determine if the address belongs or not.
|
||||
* If @ip matches the ftrace location, return @ip.
|
||||
* If @ip matches sym+0, return sym's ftrace location.
|
||||
* Otherwise, return 0.
|
||||
*/
|
||||
unsigned long ftrace_location(unsigned long ip)
|
||||
{
|
||||
return ftrace_location_range(ip, ip);
|
||||
struct dyn_ftrace *rec;
|
||||
unsigned long offset;
|
||||
unsigned long size;
|
||||
|
||||
rec = lookup_rec(ip, ip);
|
||||
if (!rec) {
|
||||
if (!kallsyms_lookup_size_offset(ip, &size, &offset))
|
||||
goto out;
|
||||
|
||||
/* map sym+0 to __fentry__ */
|
||||
if (!offset)
|
||||
rec = lookup_rec(ip, ip + size - 1);
|
||||
}
|
||||
|
||||
if (rec)
|
||||
return rec->ip;
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4962,7 +4979,8 @@ __ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
|
||||
{
|
||||
struct ftrace_func_entry *entry;
|
||||
|
||||
if (!ftrace_location(ip))
|
||||
ip = ftrace_location(ip);
|
||||
if (!ip)
|
||||
return -EINVAL;
|
||||
|
||||
if (remove) {
|
||||
@@ -5131,11 +5149,16 @@ int register_ftrace_direct(unsigned long ip, unsigned long addr)
|
||||
struct ftrace_func_entry *entry;
|
||||
struct ftrace_hash *free_hash = NULL;
|
||||
struct dyn_ftrace *rec;
|
||||
int ret = -EBUSY;
|
||||
int ret = -ENODEV;
|
||||
|
||||
mutex_lock(&direct_mutex);
|
||||
|
||||
ip = ftrace_location(ip);
|
||||
if (!ip)
|
||||
goto out_unlock;
|
||||
|
||||
/* See if there's a direct function at @ip already */
|
||||
ret = -EBUSY;
|
||||
if (ftrace_find_rec_direct(ip))
|
||||
goto out_unlock;
|
||||
|
||||
@@ -5243,6 +5266,10 @@ int unregister_ftrace_direct(unsigned long ip, unsigned long addr)
|
||||
|
||||
mutex_lock(&direct_mutex);
|
||||
|
||||
ip = ftrace_location(ip);
|
||||
if (!ip)
|
||||
goto out_unlock;
|
||||
|
||||
entry = find_direct_entry(&ip, NULL);
|
||||
if (!entry)
|
||||
goto out_unlock;
|
||||
@@ -5375,6 +5402,11 @@ int modify_ftrace_direct(unsigned long ip,
|
||||
mutex_lock(&direct_mutex);
|
||||
|
||||
mutex_lock(&ftrace_lock);
|
||||
|
||||
ip = ftrace_location(ip);
|
||||
if (!ip)
|
||||
goto out_unlock;
|
||||
|
||||
entry = find_direct_entry(&ip, &rec);
|
||||
if (!entry)
|
||||
goto out_unlock;
|
||||
|
||||
Reference in New Issue
Block a user