Skip to content

Commit 4af9d5d

Browse files
committed
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.
1 parent 98f0f3b commit 4af9d5d

File tree

2 files changed

+132
-16
lines changed

2 files changed

+132
-16
lines changed

ashmem/deps.c

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,69 @@
11
#include <linux/mm.h>
22
#include <linux/kallsyms.h>
3+
#include <linux/kprobes.h>
4+
#include <linux/version.h>
5+
6+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0))
7+
8+
#ifndef CONFIG_KPROBES
9+
# error "Your kernel does not support KProbes, but this is required to compile ashmem as a kernel module on kernel 5.7 and later"
10+
#endif
11+
12+
typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
13+
14+
static int dummy_kprobe_handler(struct kprobe *p, struct pt_regs *regs)
15+
{
16+
return 0;
17+
}
18+
19+
static kallsyms_lookup_name_t get_kallsyms_lookup_name_ptr(void)
20+
{
21+
struct kprobe probe;
22+
int ret;
23+
kallsyms_lookup_name_t addr;
24+
25+
memset(&probe, 0, sizeof(probe));
26+
probe.pre_handler = dummy_kprobe_handler;
27+
probe.symbol_name = "kallsyms_lookup_name";
28+
ret = register_kprobe(&probe);
29+
if (ret)
30+
return NULL;
31+
addr = (kallsyms_lookup_name_t) probe.addr;
32+
unregister_kprobe(&probe);
33+
34+
return addr;
35+
}
36+
#endif
37+
38+
/*
39+
* On kernel 5.7 and later, kallsyms_lookup_name() can no longer be called from a kernel
40+
* module for reasons described here: https://lwn.net/Articles/813350/
41+
* As ashmem really needs to use kallsysms_lookup_name() to access some kernel
42+
* functions that otherwise wouldn't be accessible, KProbes are used on later
43+
* kernels to get the address of kallsysms_lookup_name(). The function is
44+
* afterwards used just as before. This is a very dirty hack though and the much
45+
* better solution would be if all the functions that are currently resolved
46+
* with kallsysms_lookup_name() would get an EXPORT_SYMBOL() annotation to
47+
* make them directly accessible to kernel modules.
48+
*/
49+
static unsigned long kallsyms_lookup_name_wrapper(const char *name)
50+
{
51+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0))
52+
static kallsyms_lookup_name_t func_ptr = NULL;
53+
if (!func_ptr)
54+
func_ptr = get_kallsyms_lookup_name_ptr();
55+
56+
return func_ptr(name);
57+
#else
58+
return kallsyms_lookup_name(name);
59+
#endif
60+
}
361

462
static int (*shmem_zero_setup_ptr)(struct vm_area_struct *) = NULL;
563

664
int shmem_zero_setup(struct vm_area_struct *vma)
765
{
866
if (!shmem_zero_setup_ptr)
9-
shmem_zero_setup_ptr = kallsyms_lookup_name("shmem_zero_setup");
67+
shmem_zero_setup_ptr = kallsyms_lookup_name_wrapper("shmem_zero_setup");
1068
return shmem_zero_setup_ptr(vma);
1169
}

binder/deps.c

Lines changed: 73 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,66 @@
66
#include <linux/slab.h>
77
#include <linux/spinlock.h>
88
#include <linux/kallsyms.h>
9+
#include <linux/kprobes.h>
910
#include <linux/version.h>
1011

12+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0))
13+
14+
#ifndef CONFIG_KPROBES
15+
# error "Your kernel does not support KProbes, but this is required to compile binder as a kernel module on kernel 5.7 and later"
16+
#endif
17+
18+
typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
19+
20+
static int dummy_kprobe_handler(struct kprobe *p, struct pt_regs *regs)
21+
{
22+
return 0;
23+
}
24+
25+
static kallsyms_lookup_name_t get_kallsyms_lookup_name_ptr(void)
26+
{
27+
struct kprobe probe;
28+
int ret;
29+
kallsyms_lookup_name_t addr;
30+
31+
memset(&probe, 0, sizeof(probe));
32+
probe.pre_handler = dummy_kprobe_handler;
33+
probe.symbol_name = "kallsyms_lookup_name";
34+
ret = register_kprobe(&probe);
35+
if (ret)
36+
return NULL;
37+
addr = (kallsyms_lookup_name_t) probe.addr;
38+
unregister_kprobe(&probe);
39+
40+
return addr;
41+
}
42+
#endif
43+
44+
/*
45+
* On kernel 5.7 and later, kallsyms_lookup_name() can no longer be called from a kernel
46+
* module for reasons described here: https://lwn.net/Articles/813350/
47+
* As binder really needs to use kallsysms_lookup_name() to access some kernel
48+
* functions that otherwise wouldn't be accessible, KProbes are used on later
49+
* kernels to get the address of kallsysms_lookup_name(). The function is
50+
* afterwards used just as before. This is a very dirty hack though and the much
51+
* better solution would be if all the functions that are currently resolved
52+
* with kallsysms_lookup_name() would get an EXPORT_SYMBOL() annotation to
53+
* make them directly accessible to kernel modules.
54+
*/
55+
static unsigned long kallsyms_lookup_name_wrapper(const char *name)
56+
{
57+
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0))
58+
static kallsyms_lookup_name_t func_ptr = NULL;
59+
if (!func_ptr)
60+
func_ptr = get_kallsyms_lookup_name_ptr();
61+
62+
return func_ptr(name);
63+
#else
64+
return kallsyms_lookup_name(name);
65+
#endif
66+
}
67+
68+
1169
static struct vm_struct *(*get_vm_area_ptr)(unsigned long, unsigned long) = NULL;
1270
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
1371
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
3189
struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
3290
{
3391
if (!get_vm_area_ptr)
34-
get_vm_area_ptr = kallsyms_lookup_name("get_vm_area");
92+
get_vm_area_ptr = kallsyms_lookup_name_wrapper("get_vm_area");
3593
return get_vm_area_ptr(size, flags);
3694
}
3795

@@ -42,7 +100,7 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned
42100
#endif
43101
{
44102
if (!zap_page_range_ptr)
45-
zap_page_range_ptr = kallsyms_lookup_name("zap_page_range");
103+
zap_page_range_ptr = kallsyms_lookup_name_wrapper("zap_page_range");
46104
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
47105
zap_page_range_ptr(vma, address, size);
48106
#else
@@ -53,90 +111,90 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned
53111
int map_kernel_range_noflush(unsigned long start, unsigned long size, pgprot_t prot, struct page **pages)
54112
{
55113
if (!map_kernel_range_noflush_ptr)
56-
map_kernel_range_noflush_ptr = kallsyms_lookup_name("map_kernel_range_noflush");
114+
map_kernel_range_noflush_ptr = kallsyms_lookup_name_wrapper("map_kernel_range_noflush");
57115
return map_kernel_range_noflush_ptr(start, size, prot, pages);
58116
}
59117

60118
void unmap_kernel_range(unsigned long addr, unsigned long size)
61119
{
62120
if (!unmap_kernel_range_ptr)
63-
unmap_kernel_range_ptr = kallsyms_lookup_name("unmap_kernel_range");
121+
unmap_kernel_range_ptr = kallsyms_lookup_name_wrapper("unmap_kernel_range");
64122
unmap_kernel_range_ptr(addr, size);
65123
}
66124

67125
struct files_struct *get_files_struct(struct task_struct *task)
68126
{
69127
if (!get_files_struct_ptr)
70-
get_files_struct_ptr = kallsyms_lookup_name("get_files_struct");
128+
get_files_struct_ptr = kallsyms_lookup_name_wrapper("get_files_struct");
71129
return get_files_struct_ptr(task);
72130
}
73131

74132
void put_files_struct(struct files_struct *files)
75133
{
76134
if (!put_files_struct_ptr)
77-
put_files_struct_ptr = kallsyms_lookup_name("put_files_struct");
135+
put_files_struct_ptr = kallsyms_lookup_name_wrapper("put_files_struct");
78136
put_files_struct_ptr(files);
79137
}
80138

81139
struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, unsigned long *flags)
82140
{
83141
if (!__lock_task_sighand_ptr)
84-
__lock_task_sighand_ptr = kallsyms_lookup_name("__lock_task_sighand");
142+
__lock_task_sighand_ptr = kallsyms_lookup_name_wrapper("__lock_task_sighand");
85143
return __lock_task_sighand_ptr(tsk, flags);
86144
}
87145

88146
int __alloc_fd(struct files_struct *files, unsigned start, unsigned end, unsigned flags)
89147
{
90148
if (!__alloc_fd_ptr)
91-
__alloc_fd_ptr = kallsyms_lookup_name("__alloc_fd");
149+
__alloc_fd_ptr = kallsyms_lookup_name_wrapper("__alloc_fd");
92150
return __alloc_fd_ptr(files, start, end, flags);
93151
}
94152

95153
void __fd_install(struct files_struct *files, unsigned int fd, struct file *file)
96154
{
97155
if (!__fd_install_ptr)
98-
__fd_install_ptr = kallsyms_lookup_name("__fd_install");
156+
__fd_install_ptr = kallsyms_lookup_name_wrapper("__fd_install");
99157
__fd_install_ptr(files, fd, file);
100158
}
101159

102160
int __close_fd(struct files_struct *files, unsigned int fd)
103161
{
104162
if (!__close_fd_ptr)
105-
__close_fd_ptr = kallsyms_lookup_name("__close_fd_ptr");
163+
__close_fd_ptr = kallsyms_lookup_name_wrapper("__close_fd_ptr");
106164
return __close_fd_ptr(files, fd);
107165
}
108166

109167
int can_nice(const struct task_struct *p, const int nice)
110168
{
111169
if (!can_nice_ptr)
112-
can_nice_ptr = kallsyms_lookup_name("can_nice");
170+
can_nice_ptr = kallsyms_lookup_name_wrapper("can_nice");
113171
return can_nice_ptr(p, nice);
114172
}
115173

116174
int security_binder_set_context_mgr(struct task_struct *mgr)
117175
{
118176
if (!security_binder_set_context_mgr_ptr)
119-
security_binder_set_context_mgr_ptr = kallsyms_lookup_name("security_binder_set_context_mgr");
177+
security_binder_set_context_mgr_ptr = kallsyms_lookup_name_wrapper("security_binder_set_context_mgr");
120178
return security_binder_set_context_mgr_ptr(mgr);
121179
}
122180

123181
int security_binder_transaction(struct task_struct *from, struct task_struct *to)
124182
{
125183
if (!security_binder_transaction_ptr)
126-
security_binder_transaction_ptr = kallsyms_lookup_name("security_binder_transaction");
184+
security_binder_transaction_ptr = kallsyms_lookup_name_wrapper("security_binder_transaction");
127185
return security_binder_transaction_ptr(from, to);
128186
}
129187

130188
int security_binder_transfer_binder(struct task_struct *from, struct task_struct *to)
131189
{
132190
if (!security_binder_transfer_binder_ptr)
133-
security_binder_transfer_binder_ptr = kallsyms_lookup_name("security_binder_transfer_binder");
191+
security_binder_transfer_binder_ptr = kallsyms_lookup_name_wrapper("security_binder_transfer_binder");
134192
return security_binder_transfer_binder_ptr(from, to);
135193
}
136194

137195
int security_binder_transfer_file(struct task_struct *from, struct task_struct *to, struct file *file)
138196
{
139197
if (!security_binder_transfer_file_ptr)
140-
security_binder_transfer_file_ptr = kallsyms_lookup_name("security_binder_transfer_file");
198+
security_binder_transfer_file_ptr = kallsyms_lookup_name_wrapper("security_binder_transfer_file");
141199
return security_binder_transfer_file_ptr(from, to, file);
142200
}

0 commit comments

Comments
 (0)