Fix compilation of binder and ashmem on kernel 5.7 and later
On kernel 5.7 and later, kallsyms_lookup_name() can no longer be called from a kernel module for reasons described here: https://lwn.net/Articles/813350/ As binder really needs to use kallsysms_lookup_name() to access some kernel functions that otherwise wouldn't be accessible, KProbes are used on later kernels to get the address of kallsysms_lookup_name(). The function is afterwards used just as before. This is a very dirty hack though and the much better solution would be if all the functions that are currently resolved with kallsysms_lookup_name() would get an EXPORT_SYMBOL() annotation to make them directly accessible to kernel modules.
This commit is contained in:
parent
98f0f3b3b1
commit
4af9d5d591
|
@ -1,11 +1,69 @@
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/kallsyms.h>
|
#include <linux/kallsyms.h>
|
||||||
|
#include <linux/kprobes.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0))
|
||||||
|
|
||||||
|
#ifndef CONFIG_KPROBES
|
||||||
|
# error "Your kernel does not support KProbes, but this is required to compile ashmem as a kernel module on kernel 5.7 and later"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
|
||||||
|
|
||||||
|
static int dummy_kprobe_handler(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static kallsyms_lookup_name_t get_kallsyms_lookup_name_ptr(void)
|
||||||
|
{
|
||||||
|
struct kprobe probe;
|
||||||
|
int ret;
|
||||||
|
kallsyms_lookup_name_t addr;
|
||||||
|
|
||||||
|
memset(&probe, 0, sizeof(probe));
|
||||||
|
probe.pre_handler = dummy_kprobe_handler;
|
||||||
|
probe.symbol_name = "kallsyms_lookup_name";
|
||||||
|
ret = register_kprobe(&probe);
|
||||||
|
if (ret)
|
||||||
|
return NULL;
|
||||||
|
addr = (kallsyms_lookup_name_t) probe.addr;
|
||||||
|
unregister_kprobe(&probe);
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On kernel 5.7 and later, kallsyms_lookup_name() can no longer be called from a kernel
|
||||||
|
* module for reasons described here: https://lwn.net/Articles/813350/
|
||||||
|
* As ashmem really needs to use kallsysms_lookup_name() to access some kernel
|
||||||
|
* functions that otherwise wouldn't be accessible, KProbes are used on later
|
||||||
|
* kernels to get the address of kallsysms_lookup_name(). The function is
|
||||||
|
* afterwards used just as before. This is a very dirty hack though and the much
|
||||||
|
* better solution would be if all the functions that are currently resolved
|
||||||
|
* with kallsysms_lookup_name() would get an EXPORT_SYMBOL() annotation to
|
||||||
|
* make them directly accessible to kernel modules.
|
||||||
|
*/
|
||||||
|
static unsigned long kallsyms_lookup_name_wrapper(const char *name)
|
||||||
|
{
|
||||||
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0))
|
||||||
|
static kallsyms_lookup_name_t func_ptr = NULL;
|
||||||
|
if (!func_ptr)
|
||||||
|
func_ptr = get_kallsyms_lookup_name_ptr();
|
||||||
|
|
||||||
|
return func_ptr(name);
|
||||||
|
#else
|
||||||
|
return kallsyms_lookup_name(name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static int (*shmem_zero_setup_ptr)(struct vm_area_struct *) = NULL;
|
static int (*shmem_zero_setup_ptr)(struct vm_area_struct *) = NULL;
|
||||||
|
|
||||||
int shmem_zero_setup(struct vm_area_struct *vma)
|
int shmem_zero_setup(struct vm_area_struct *vma)
|
||||||
{
|
{
|
||||||
if (!shmem_zero_setup_ptr)
|
if (!shmem_zero_setup_ptr)
|
||||||
shmem_zero_setup_ptr = kallsyms_lookup_name("shmem_zero_setup");
|
shmem_zero_setup_ptr = kallsyms_lookup_name_wrapper("shmem_zero_setup");
|
||||||
return shmem_zero_setup_ptr(vma);
|
return shmem_zero_setup_ptr(vma);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,66 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/kallsyms.h>
|
#include <linux/kallsyms.h>
|
||||||
|
#include <linux/kprobes.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
|
||||||
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0))
|
||||||
|
|
||||||
|
#ifndef CONFIG_KPROBES
|
||||||
|
# error "Your kernel does not support KProbes, but this is required to compile binder as a kernel module on kernel 5.7 and later"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
|
||||||
|
|
||||||
|
static int dummy_kprobe_handler(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static kallsyms_lookup_name_t get_kallsyms_lookup_name_ptr(void)
|
||||||
|
{
|
||||||
|
struct kprobe probe;
|
||||||
|
int ret;
|
||||||
|
kallsyms_lookup_name_t addr;
|
||||||
|
|
||||||
|
memset(&probe, 0, sizeof(probe));
|
||||||
|
probe.pre_handler = dummy_kprobe_handler;
|
||||||
|
probe.symbol_name = "kallsyms_lookup_name";
|
||||||
|
ret = register_kprobe(&probe);
|
||||||
|
if (ret)
|
||||||
|
return NULL;
|
||||||
|
addr = (kallsyms_lookup_name_t) probe.addr;
|
||||||
|
unregister_kprobe(&probe);
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On kernel 5.7 and later, kallsyms_lookup_name() can no longer be called from a kernel
|
||||||
|
* module for reasons described here: https://lwn.net/Articles/813350/
|
||||||
|
* As binder really needs to use kallsysms_lookup_name() to access some kernel
|
||||||
|
* functions that otherwise wouldn't be accessible, KProbes are used on later
|
||||||
|
* kernels to get the address of kallsysms_lookup_name(). The function is
|
||||||
|
* afterwards used just as before. This is a very dirty hack though and the much
|
||||||
|
* better solution would be if all the functions that are currently resolved
|
||||||
|
* with kallsysms_lookup_name() would get an EXPORT_SYMBOL() annotation to
|
||||||
|
* make them directly accessible to kernel modules.
|
||||||
|
*/
|
||||||
|
static unsigned long kallsyms_lookup_name_wrapper(const char *name)
|
||||||
|
{
|
||||||
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0))
|
||||||
|
static kallsyms_lookup_name_t func_ptr = NULL;
|
||||||
|
if (!func_ptr)
|
||||||
|
func_ptr = get_kallsyms_lookup_name_ptr();
|
||||||
|
|
||||||
|
return func_ptr(name);
|
||||||
|
#else
|
||||||
|
return kallsyms_lookup_name(name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct vm_struct *(*get_vm_area_ptr)(unsigned long, unsigned long) = NULL;
|
static struct vm_struct *(*get_vm_area_ptr)(unsigned long, unsigned long) = NULL;
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||||
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;
|
||||||
|
@ -31,7 +89,7 @@ static int (*security_binder_transfer_file_ptr)(struct task_struct *from, struct
|
||||||
struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
|
struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
|
||||||
{
|
{
|
||||||
if (!get_vm_area_ptr)
|
if (!get_vm_area_ptr)
|
||||||
get_vm_area_ptr = kallsyms_lookup_name("get_vm_area");
|
get_vm_area_ptr = kallsyms_lookup_name_wrapper("get_vm_area");
|
||||||
return get_vm_area_ptr(size, flags);
|
return get_vm_area_ptr(size, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +100,7 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (!zap_page_range_ptr)
|
if (!zap_page_range_ptr)
|
||||||
zap_page_range_ptr = kallsyms_lookup_name("zap_page_range");
|
zap_page_range_ptr = kallsyms_lookup_name_wrapper("zap_page_range");
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||||
zap_page_range_ptr(vma, address, size);
|
zap_page_range_ptr(vma, address, size);
|
||||||
#else
|
#else
|
||||||
|
@ -53,90 +111,90 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned
|
||||||
int map_kernel_range_noflush(unsigned long start, unsigned long size, pgprot_t prot, struct page **pages)
|
int map_kernel_range_noflush(unsigned long start, unsigned long size, pgprot_t prot, struct page **pages)
|
||||||
{
|
{
|
||||||
if (!map_kernel_range_noflush_ptr)
|
if (!map_kernel_range_noflush_ptr)
|
||||||
map_kernel_range_noflush_ptr = kallsyms_lookup_name("map_kernel_range_noflush");
|
map_kernel_range_noflush_ptr = kallsyms_lookup_name_wrapper("map_kernel_range_noflush");
|
||||||
return map_kernel_range_noflush_ptr(start, size, prot, pages);
|
return map_kernel_range_noflush_ptr(start, size, prot, pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unmap_kernel_range(unsigned long addr, unsigned long size)
|
void unmap_kernel_range(unsigned long addr, unsigned long size)
|
||||||
{
|
{
|
||||||
if (!unmap_kernel_range_ptr)
|
if (!unmap_kernel_range_ptr)
|
||||||
unmap_kernel_range_ptr = kallsyms_lookup_name("unmap_kernel_range");
|
unmap_kernel_range_ptr = kallsyms_lookup_name_wrapper("unmap_kernel_range");
|
||||||
unmap_kernel_range_ptr(addr, size);
|
unmap_kernel_range_ptr(addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct files_struct *get_files_struct(struct task_struct *task)
|
struct files_struct *get_files_struct(struct task_struct *task)
|
||||||
{
|
{
|
||||||
if (!get_files_struct_ptr)
|
if (!get_files_struct_ptr)
|
||||||
get_files_struct_ptr = kallsyms_lookup_name("get_files_struct");
|
get_files_struct_ptr = kallsyms_lookup_name_wrapper("get_files_struct");
|
||||||
return get_files_struct_ptr(task);
|
return get_files_struct_ptr(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
void put_files_struct(struct files_struct *files)
|
void put_files_struct(struct files_struct *files)
|
||||||
{
|
{
|
||||||
if (!put_files_struct_ptr)
|
if (!put_files_struct_ptr)
|
||||||
put_files_struct_ptr = kallsyms_lookup_name("put_files_struct");
|
put_files_struct_ptr = kallsyms_lookup_name_wrapper("put_files_struct");
|
||||||
put_files_struct_ptr(files);
|
put_files_struct_ptr(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, unsigned long *flags)
|
struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, unsigned long *flags)
|
||||||
{
|
{
|
||||||
if (!__lock_task_sighand_ptr)
|
if (!__lock_task_sighand_ptr)
|
||||||
__lock_task_sighand_ptr = kallsyms_lookup_name("__lock_task_sighand");
|
__lock_task_sighand_ptr = kallsyms_lookup_name_wrapper("__lock_task_sighand");
|
||||||
return __lock_task_sighand_ptr(tsk, flags);
|
return __lock_task_sighand_ptr(tsk, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int __alloc_fd(struct files_struct *files, unsigned start, unsigned end, unsigned flags)
|
int __alloc_fd(struct files_struct *files, unsigned start, unsigned end, unsigned flags)
|
||||||
{
|
{
|
||||||
if (!__alloc_fd_ptr)
|
if (!__alloc_fd_ptr)
|
||||||
__alloc_fd_ptr = kallsyms_lookup_name("__alloc_fd");
|
__alloc_fd_ptr = kallsyms_lookup_name_wrapper("__alloc_fd");
|
||||||
return __alloc_fd_ptr(files, start, end, flags);
|
return __alloc_fd_ptr(files, start, end, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __fd_install(struct files_struct *files, unsigned int fd, struct file *file)
|
void __fd_install(struct files_struct *files, unsigned int fd, struct file *file)
|
||||||
{
|
{
|
||||||
if (!__fd_install_ptr)
|
if (!__fd_install_ptr)
|
||||||
__fd_install_ptr = kallsyms_lookup_name("__fd_install");
|
__fd_install_ptr = kallsyms_lookup_name_wrapper("__fd_install");
|
||||||
__fd_install_ptr(files, fd, file);
|
__fd_install_ptr(files, fd, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
int __close_fd(struct files_struct *files, unsigned int fd)
|
int __close_fd(struct files_struct *files, unsigned int fd)
|
||||||
{
|
{
|
||||||
if (!__close_fd_ptr)
|
if (!__close_fd_ptr)
|
||||||
__close_fd_ptr = kallsyms_lookup_name("__close_fd_ptr");
|
__close_fd_ptr = kallsyms_lookup_name_wrapper("__close_fd_ptr");
|
||||||
return __close_fd_ptr(files, fd);
|
return __close_fd_ptr(files, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int can_nice(const struct task_struct *p, const int nice)
|
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("can_nice");
|
can_nice_ptr = kallsyms_lookup_name_wrapper("can_nice");
|
||||||
return can_nice_ptr(p, nice);
|
return can_nice_ptr(p, nice);
|
||||||
}
|
}
|
||||||
|
|
||||||
int security_binder_set_context_mgr(struct task_struct *mgr)
|
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("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 security_binder_set_context_mgr_ptr(mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int security_binder_transaction(struct task_struct *from, struct task_struct *to)
|
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("security_binder_transaction");
|
security_binder_transaction_ptr = kallsyms_lookup_name_wrapper("security_binder_transaction");
|
||||||
return security_binder_transaction_ptr(from, to);
|
return security_binder_transaction_ptr(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
|
int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
|
||||||
{
|
{
|
||||||
if (!security_binder_transfer_binder_ptr)
|
if (!security_binder_transfer_binder_ptr)
|
||||||
security_binder_transfer_binder_ptr = kallsyms_lookup_name("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 security_binder_transfer_binder_ptr(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
|
int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
|
||||||
{
|
{
|
||||||
if (!security_binder_transfer_file_ptr)
|
if (!security_binder_transfer_file_ptr)
|
||||||
security_binder_transfer_file_ptr = kallsyms_lookup_name("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 security_binder_transfer_file_ptr(from, to, file);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue