This commit is contained in:
dedeanth 2026-10-14 10:39:23 +08:00 committed by GitHub
commit 64eac1bd8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 58 additions and 14 deletions

View File

@ -1003,6 +1003,10 @@ enum lru_status binder_alloc_free_page(struct list_head *item,
size_t index; size_t index;
struct vm_area_struct *vma; struct vm_area_struct *vma;
/* Since 6.13 the list_lru callback gets no lock; it lives in lru. */
if (!lock)
lock = &lru->lock;
alloc = page->alloc; alloc = page->alloc;
if (!mutex_trylock(&alloc->mutex)) if (!mutex_trylock(&alloc->mutex))
goto err_get_alloc_mutex_failed; goto err_get_alloc_mutex_failed;
@ -1044,8 +1048,16 @@ enum lru_status binder_alloc_free_page(struct list_head *item,
trace_binder_unmap_kernel_end(alloc, index); trace_binder_unmap_kernel_end(alloc, index);
spin_lock(lock);
mutex_unlock(&alloc->mutex); mutex_unlock(&alloc->mutex);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 13, 0) && \
!defined(RHEL_10_1_BACKPORTS))
/* Before 6.13, LRU_REMOVED_RETRY means the lock was reacquired. */
spin_lock(lock);
#endif
/*
* Since 6.13 the walker relocks itself after LRU_REMOVED_RETRY;
* taking the lock here would make it spin forever (kswapd at 100%).
*/
return LRU_REMOVED_RETRY; return LRU_REMOVED_RETRY;
err_mmap_read_lock_failed: err_mmap_read_lock_failed:

View File

@ -9,11 +9,43 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/linkage.h>
#include <linux/objtool.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/task_work.h> #include <linux/task_work.h>
#include "deps.h" #include "deps.h"
#ifdef CONFIG_X86_KERNEL_IBT
/*
* With IBT the kernel seals the ENDBR64 of functions it never calls
* indirectly (kallsyms_lookup_name, can_nice, the security_binder_* hooks...),
* so an indirect call to an address looked up here raises #CP (kernel BUG at
* arch/x86/kernel/cet.c). Reach them with push+ret instead, which IBT does
* not track; the callee then returns straight to our caller.
*/
unsigned long binder_ibt_call(void *fn, unsigned long a, unsigned long b,
unsigned long c, unsigned long d);
asm(".pushsection .text\n"
".type binder_ibt_call, @function\n"
"binder_ibt_call:\n"
" mov %rdi, %r11\n"
" mov %rsi, %rdi\n"
" mov %rdx, %rsi\n"
" mov %rcx, %rdx\n"
" mov %r8, %rcx\n"
" push %r11\n"
" " ASM_RET
".size binder_ibt_call, .-binder_ibt_call\n"
".popsection\n");
STACK_FRAME_NON_STANDARD(binder_ibt_call);
#define IBT_ARGS(a, b, c, d, ...) \
(unsigned long)(a), (unsigned long)(b), (unsigned long)(c), (unsigned long)(d)
#define deps_call(fn, ...) binder_ibt_call((void *)(fn), IBT_ARGS(__VA_ARGS__, 0, 0, 0, 0))
#else
#define deps_call(fn, ...) (fn)(__VA_ARGS__)
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0))
#ifndef CONFIG_KPROBES #ifndef CONFIG_KPROBES
@ -64,7 +96,7 @@ static unsigned long kallsyms_lookup_name_wrapper(const char *name)
if (!func_ptr) if (!func_ptr)
func_ptr = get_kallsyms_lookup_name_ptr(); func_ptr = get_kallsyms_lookup_name_ptr();
return func_ptr(name); return deps_call(func_ptr, name);
#else #else
return kallsyms_lookup_name(name); return kallsyms_lookup_name(name);
#endif #endif
@ -97,9 +129,9 @@ int __close_fd_get_file(unsigned int fd, struct file **res)
#endif #endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,19,0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,19,0))
return close_fd_get_file_ptr(fd); return (struct file *)deps_call(close_fd_get_file_ptr, fd);
#else #else
return close_fd_get_file_ptr(fd, res); return (int)deps_call(close_fd_get_file_ptr, fd, res);
#endif #endif
} }
@ -109,7 +141,7 @@ int can_nice(const struct task_struct *p, const int nice)
{ {
if (!can_nice_ptr) if (!can_nice_ptr)
can_nice_ptr = kallsyms_lookup_name_wrapper("can_nice"); can_nice_ptr = kallsyms_lookup_name_wrapper("can_nice");
return can_nice_ptr(p, nice); return (int)deps_call(can_nice_ptr, p, nice);
} }
static void (*mmput_async_ptr)(struct mm_struct *mm) = NULL; static void (*mmput_async_ptr)(struct mm_struct *mm) = NULL;
@ -118,7 +150,7 @@ void mmput_async(struct mm_struct *mm)
{ {
if (!mmput_async_ptr) if (!mmput_async_ptr)
mmput_async_ptr = kallsyms_lookup_name_wrapper("mmput_async"); mmput_async_ptr = kallsyms_lookup_name_wrapper("mmput_async");
return mmput_async_ptr(mm); deps_call(mmput_async_ptr, mm);
} }
static int (*security_binder_set_context_mgr_ptr)(struct task_struct *mgr) = NULL; static int (*security_binder_set_context_mgr_ptr)(struct task_struct *mgr) = NULL;
@ -127,7 +159,7 @@ int security_binder_set_context_mgr(struct task_struct *mgr)
{ {
if (!security_binder_set_context_mgr_ptr) if (!security_binder_set_context_mgr_ptr)
security_binder_set_context_mgr_ptr = kallsyms_lookup_name_wrapper("security_binder_set_context_mgr"); security_binder_set_context_mgr_ptr = kallsyms_lookup_name_wrapper("security_binder_set_context_mgr");
return security_binder_set_context_mgr_ptr(mgr); return (int)deps_call(security_binder_set_context_mgr_ptr, mgr);
} }
static int (*security_binder_transaction_ptr)(struct task_struct *from, struct task_struct *to) = NULL; static int (*security_binder_transaction_ptr)(struct task_struct *from, struct task_struct *to) = NULL;
@ -136,7 +168,7 @@ int security_binder_transaction(struct task_struct *from, struct task_struct *to
{ {
if (!security_binder_transaction_ptr) if (!security_binder_transaction_ptr)
security_binder_transaction_ptr = kallsyms_lookup_name_wrapper("security_binder_transaction"); security_binder_transaction_ptr = kallsyms_lookup_name_wrapper("security_binder_transaction");
return security_binder_transaction_ptr(from, to); return (int)deps_call(security_binder_transaction_ptr, from, to);
} }
static int (*security_binder_transfer_binder_ptr)(struct task_struct *from, struct task_struct *to) = NULL; static int (*security_binder_transfer_binder_ptr)(struct task_struct *from, struct task_struct *to) = NULL;
@ -145,7 +177,7 @@ int security_binder_transfer_binder(struct task_struct *from, struct task_struct
{ {
if (!security_binder_transfer_binder_ptr) if (!security_binder_transfer_binder_ptr)
security_binder_transfer_binder_ptr = kallsyms_lookup_name_wrapper("security_binder_transfer_binder"); security_binder_transfer_binder_ptr = kallsyms_lookup_name_wrapper("security_binder_transfer_binder");
return security_binder_transfer_binder_ptr(from, to); return (int)deps_call(security_binder_transfer_binder_ptr, from, to);
} }
static int (*security_binder_transfer_file_ptr)(struct task_struct *from, struct task_struct *to, struct file *file) = NULL; static int (*security_binder_transfer_file_ptr)(struct task_struct *from, struct task_struct *to, struct file *file) = NULL;
@ -154,7 +186,7 @@ int security_binder_transfer_file(struct task_struct *from, struct task_struct *
{ {
if (!security_binder_transfer_file_ptr) if (!security_binder_transfer_file_ptr)
security_binder_transfer_file_ptr = kallsyms_lookup_name_wrapper("security_binder_transfer_file"); security_binder_transfer_file_ptr = kallsyms_lookup_name_wrapper("security_binder_transfer_file");
return security_binder_transfer_file_ptr(from, to, file); return (int)deps_call(security_binder_transfer_file_ptr, from, to, file);
} }
static int (*task_work_add_ptr)(struct task_struct *task, struct callback_head *work, static int (*task_work_add_ptr)(struct task_struct *task, struct callback_head *work,
@ -165,7 +197,7 @@ int task_work_add(struct task_struct *task, struct callback_head *work,
{ {
if (!task_work_add_ptr) if (!task_work_add_ptr)
task_work_add_ptr = kallsyms_lookup_name_wrapper("task_work_add"); task_work_add_ptr = kallsyms_lookup_name_wrapper("task_work_add");
return task_work_add_ptr(task, work, notify); return (int)deps_call(task_work_add_ptr, task, work, notify);
} }
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6,3,0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6,3,0))
@ -175,7 +207,7 @@ void zap_page_range_single(struct vm_area_struct *vma, unsigned long address, un
{ {
if (!zap_page_range_single_ptr) if (!zap_page_range_single_ptr)
zap_page_range_single_ptr = kallsyms_lookup_name_wrapper("zap_page_range_single"); zap_page_range_single_ptr = kallsyms_lookup_name_wrapper("zap_page_range_single");
zap_page_range_single_ptr(vma, address, size, details); deps_call(zap_page_range_single_ptr, vma, address, size, details);
} }
#else #else
static void (*zap_page_range_ptr)(struct vm_area_struct *, unsigned long, unsigned long) = NULL; static void (*zap_page_range_ptr)(struct vm_area_struct *, unsigned long, unsigned long) = NULL;
@ -184,7 +216,7 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned
{ {
if (!zap_page_range_ptr) if (!zap_page_range_ptr)
zap_page_range_ptr = kallsyms_lookup_name_wrapper("zap_page_range"); zap_page_range_ptr = kallsyms_lookup_name_wrapper("zap_page_range");
zap_page_range_ptr(vma, address, size); deps_call(zap_page_range_ptr, vma, address, size);
} }
#endif #endif
@ -194,7 +226,7 @@ void put_ipc_ns(struct ipc_namespace *ns)
{ {
if (!put_ipc_ns_ptr) if (!put_ipc_ns_ptr)
put_ipc_ns_ptr = kallsyms_lookup_name_wrapper("put_ipc_ns"); put_ipc_ns_ptr = kallsyms_lookup_name_wrapper("put_ipc_ns");
put_ipc_ns_ptr(ns); deps_call(put_ipc_ns_ptr, ns);
} }
static struct ipc_namespace *init_ipc_ns_ptr = NULL; static struct ipc_namespace *init_ipc_ns_ptr = NULL;