1 |
kumaneko |
442 |
/* |
2 |
|
|
* probe.c |
3 |
|
|
* |
4 |
|
|
* Copyright (C) 2010-2013 Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
5 |
kumaneko |
444 |
* |
6 |
|
|
* Functions in this file are doing runtime address resolution based on byte |
7 |
|
|
* code comparison in order to allow LKM-based LSM modules to access built-in |
8 |
|
|
* functions and variables which are not exported to LKMs. |
9 |
|
|
* Since functions in this file are assuming that using identical source code, |
10 |
|
|
* identical kernel config and identical compiler generates identical byte code |
11 |
|
|
* output, functions in this file may not work on some architectures and/or |
12 |
|
|
* environments. |
13 |
|
|
* |
14 |
|
|
* This file is used by AKARI and CaitSith. This file will become unnecessary |
15 |
|
|
* when LKM-based LSM module comes back and TOMOYO 2.x becomes a LKM-based LSM |
16 |
|
|
* module. |
17 |
kumaneko |
442 |
*/ |
18 |
|
|
|
19 |
|
|
#include "probe.h" |
20 |
|
|
|
21 |
kumaneko |
564 |
static void *__init check_function_address(void *ptr, char *symbol) |
22 |
|
|
{ |
23 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) |
24 |
|
|
static char buf[KSYM_SYMBOL_LEN]; |
25 |
|
|
const int len = strlen(symbol); |
26 |
|
|
#endif |
27 |
|
|
|
28 |
|
|
if (!ptr) { |
29 |
|
|
printk(KERN_ERR "Can't resolve %s().\n", symbol); |
30 |
|
|
return NULL; |
31 |
|
|
} |
32 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) |
33 |
|
|
snprintf(buf, sizeof(buf), "%pS", ptr); |
34 |
|
|
if (strncmp(buf, symbol, len) || strncmp(buf + len, "+0x0/", 5)) { |
35 |
|
|
printk(KERN_ERR "Guessed %s is %s\n", symbol, buf); |
36 |
|
|
return NULL; |
37 |
|
|
} |
38 |
|
|
#endif |
39 |
|
|
return ptr; |
40 |
|
|
} |
41 |
|
|
|
42 |
kumaneko |
664 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3) |
43 |
kumaneko |
442 |
|
44 |
|
|
/** |
45 |
kumaneko |
593 |
* my_kernel_read - Wrapper for kernel_read(). |
46 |
kumaneko |
442 |
* |
47 |
|
|
* @file: Pointer to "struct file". |
48 |
|
|
* @offset: Starting position. |
49 |
|
|
* @addr: Buffer. |
50 |
|
|
* @count: Size of @addr. |
51 |
|
|
* |
52 |
|
|
* Returns return value from kernel_read(). |
53 |
|
|
*/ |
54 |
kumaneko |
606 |
static inline int my_kernel_read(struct file *file, unsigned long offset, |
55 |
|
|
char *addr, unsigned long count) |
56 |
kumaneko |
442 |
{ |
57 |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 8) |
58 |
|
|
/* |
59 |
|
|
* I can't use kernel_read() because seq_read() returns -EPIPE |
60 |
|
|
* if &pos != &file->f_pos . |
61 |
|
|
*/ |
62 |
|
|
mm_segment_t old_fs; |
63 |
|
|
unsigned long pos = file->f_pos; |
64 |
|
|
int result; |
65 |
kumaneko |
564 |
|
66 |
kumaneko |
442 |
file->f_pos = offset; |
67 |
|
|
old_fs = get_fs(); |
68 |
|
|
set_fs(get_ds()); |
69 |
|
|
result = vfs_read(file, (void __user *)addr, count, &file->f_pos); |
70 |
|
|
set_fs(old_fs); |
71 |
|
|
file->f_pos = pos; |
72 |
|
|
return result; |
73 |
kumaneko |
561 |
#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) |
74 |
|
|
return kernel_read(file, offset, addr, count); |
75 |
kumaneko |
664 |
#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) |
76 |
kumaneko |
561 |
loff_t pos = offset; |
77 |
kumaneko |
564 |
|
78 |
kumaneko |
561 |
return kernel_read(file, addr, count, &pos); |
79 |
kumaneko |
664 |
#else |
80 |
|
|
struct kvec iov = { .iov_base = addr, .iov_len = count }; |
81 |
|
|
struct kiocb kiocb; |
82 |
|
|
struct iov_iter iter; |
83 |
|
|
|
84 |
|
|
init_sync_kiocb(&kiocb, file); |
85 |
|
|
iov_iter_kvec(&iter, READ, &iov, 1, count); |
86 |
|
|
kiocb.ki_pos = offset; |
87 |
|
|
return seq_read_iter(&kiocb, &iter); |
88 |
kumaneko |
442 |
#endif |
89 |
|
|
} |
90 |
|
|
|
91 |
|
|
/** |
92 |
kumaneko |
446 |
* probe_find_symbol - Find function's address from /proc/kallsyms . |
93 |
kumaneko |
442 |
* |
94 |
|
|
* @keyline: Function to find. |
95 |
|
|
* |
96 |
|
|
* Returns address of specified function on success, NULL otherwise. |
97 |
|
|
*/ |
98 |
kumaneko |
446 |
static void *__init probe_find_symbol(const char *keyline) |
99 |
kumaneko |
442 |
{ |
100 |
kumaneko |
628 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0) |
101 |
kumaneko |
606 |
char buf[128] = { }; |
102 |
|
|
char *cp; |
103 |
|
|
|
104 |
|
|
strncpy(buf, keyline + 1, sizeof(buf) - 1); |
105 |
|
|
cp = strchr(buf, '\n'); |
106 |
|
|
if (cp) |
107 |
|
|
*cp = '\0'; |
108 |
|
|
return (void *) kallsyms_lookup_name(buf); |
109 |
|
|
#else |
110 |
kumaneko |
442 |
struct file *file = NULL; |
111 |
|
|
char *buf; |
112 |
|
|
unsigned long entry = 0; |
113 |
kumaneko |
564 |
|
114 |
kumaneko |
442 |
{ |
115 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) |
116 |
|
|
struct file_system_type *fstype = get_fs_type("proc"); |
117 |
|
|
struct vfsmount *mnt = vfs_kern_mount(fstype, 0, "proc", NULL); |
118 |
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) |
119 |
|
|
struct file_system_type *fstype = NULL; |
120 |
|
|
struct vfsmount *mnt = do_kern_mount("proc", 0, "proc", NULL); |
121 |
|
|
#else |
122 |
|
|
struct file_system_type *fstype = get_fs_type("proc"); |
123 |
|
|
struct vfsmount *mnt = kern_mount(fstype); |
124 |
|
|
#endif |
125 |
|
|
struct dentry *root; |
126 |
|
|
struct dentry *dentry; |
127 |
kumaneko |
564 |
|
128 |
kumaneko |
442 |
/* |
129 |
|
|
* We embed put_filesystem() here because it is not exported. |
130 |
|
|
*/ |
131 |
|
|
if (fstype) |
132 |
|
|
module_put(fstype->owner); |
133 |
|
|
if (IS_ERR(mnt)) |
134 |
|
|
goto out; |
135 |
|
|
root = dget(mnt->mnt_root); |
136 |
kumaneko |
526 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) |
137 |
|
|
inode_lock(root->d_inode); |
138 |
|
|
dentry = lookup_one_len("kallsyms", root, 8); |
139 |
|
|
inode_unlock(root->d_inode); |
140 |
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 16) |
141 |
kumaneko |
442 |
mutex_lock(&root->d_inode->i_mutex); |
142 |
|
|
dentry = lookup_one_len("kallsyms", root, 8); |
143 |
|
|
mutex_unlock(&root->d_inode->i_mutex); |
144 |
|
|
#else |
145 |
|
|
down(&root->d_inode->i_sem); |
146 |
|
|
dentry = lookup_one_len("kallsyms", root, 8); |
147 |
|
|
up(&root->d_inode->i_sem); |
148 |
|
|
#endif |
149 |
|
|
dput(root); |
150 |
|
|
if (IS_ERR(dentry)) |
151 |
|
|
mntput(mnt); |
152 |
|
|
else { |
153 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) |
154 |
kumaneko |
555 |
struct path path = { .mnt = mnt, .dentry = dentry }; |
155 |
kumaneko |
564 |
|
156 |
kumaneko |
442 |
file = dentry_open(&path, O_RDONLY, current_cred()); |
157 |
|
|
#else |
158 |
|
|
file = dentry_open(dentry, mnt, O_RDONLY |
159 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) |
160 |
|
|
, current_cred() |
161 |
|
|
#endif |
162 |
|
|
); |
163 |
|
|
#endif |
164 |
|
|
} |
165 |
|
|
} |
166 |
|
|
if (IS_ERR(file) || !file) |
167 |
|
|
goto out; |
168 |
|
|
buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
169 |
|
|
if (buf) { |
170 |
|
|
int len; |
171 |
|
|
int offset = 0; |
172 |
kumaneko |
564 |
|
173 |
kumaneko |
593 |
while ((len = my_kernel_read(file, offset, buf, |
174 |
|
|
PAGE_SIZE - 1)) > 0) { |
175 |
kumaneko |
442 |
char *cp; |
176 |
kumaneko |
564 |
|
177 |
kumaneko |
442 |
buf[len] = '\0'; |
178 |
|
|
cp = strrchr(buf, '\n'); |
179 |
|
|
if (!cp) |
180 |
|
|
break; |
181 |
|
|
*(cp + 1) = '\0'; |
182 |
|
|
offset += strlen(buf); |
183 |
|
|
cp = strstr(buf, keyline); |
184 |
|
|
if (!cp) |
185 |
|
|
continue; |
186 |
|
|
*cp = '\0'; |
187 |
|
|
while (cp > buf && *(cp - 1) != '\n') |
188 |
|
|
cp--; |
189 |
|
|
entry = simple_strtoul(cp, NULL, 16); |
190 |
|
|
break; |
191 |
|
|
} |
192 |
|
|
kfree(buf); |
193 |
|
|
} |
194 |
|
|
filp_close(file, NULL); |
195 |
|
|
out: |
196 |
|
|
return (void *) entry; |
197 |
kumaneko |
606 |
#endif |
198 |
kumaneko |
442 |
} |
199 |
|
|
|
200 |
|
|
#endif |
201 |
|
|
|
202 |
kumaneko |
496 |
#if defined(LSM_HOOK_INIT) |
203 |
kumaneko |
442 |
|
204 |
|
|
/* |
205 |
|
|
* Dummy variable for finding location of |
206 |
kumaneko |
496 |
* "struct security_hook_heads security_hook_heads". |
207 |
kumaneko |
442 |
*/ |
208 |
kumaneko |
496 |
struct security_hook_heads probe_dummy_security_hook_heads; |
209 |
kumaneko |
442 |
|
210 |
|
|
/** |
211 |
kumaneko |
446 |
* probe_security_bprm_committed_creds - Dummy function which does identical to security_bprm_committed_creds() in security/security.c. |
212 |
kumaneko |
442 |
* |
213 |
|
|
* @bprm: Pointer to "struct linux_binprm". |
214 |
|
|
* |
215 |
|
|
* Returns nothing. |
216 |
|
|
*/ |
217 |
kumaneko |
446 |
void probe_security_bprm_committed_creds(struct linux_binprm *bprm) |
218 |
kumaneko |
442 |
{ |
219 |
|
|
do { |
220 |
kumaneko |
496 |
struct security_hook_list *p; |
221 |
kumaneko |
564 |
|
222 |
kumaneko |
592 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) |
223 |
|
|
hlist_for_each_entry(p, &probe_dummy_security_hook_heads. |
224 |
|
|
bprm_committed_creds, list) |
225 |
|
|
p->hook.bprm_committed_creds(bprm); |
226 |
|
|
#else |
227 |
kumaneko |
496 |
list_for_each_entry(p, &probe_dummy_security_hook_heads. |
228 |
|
|
bprm_committed_creds, list) |
229 |
|
|
p->hook.bprm_committed_creds(bprm); |
230 |
kumaneko |
592 |
#endif |
231 |
kumaneko |
442 |
} while (0); |
232 |
|
|
} |
233 |
|
|
|
234 |
kumaneko |
562 |
#if defined(CONFIG_ARM64) |
235 |
|
|
|
236 |
|
|
/** |
237 |
kumaneko |
655 |
* probe_security_hook_heads_on_arm64 - Find security_hook_heads on ARM64. |
238 |
kumaneko |
562 |
* |
239 |
|
|
* @base: Address of security_bprm_committed_creds(). |
240 |
|
|
* |
241 |
|
|
* Returns address of security_hook_heads.bprm_committed_creds on success, |
242 |
|
|
* NULL otherwise. |
243 |
|
|
*/ |
244 |
|
|
static void * __init probe_security_hook_heads_on_arm64(unsigned int *base) |
245 |
|
|
{ |
246 |
|
|
static unsigned int *ip4ret; |
247 |
|
|
int i; |
248 |
|
|
unsigned int *ip = (unsigned int *) base; |
249 |
|
|
|
250 |
|
|
for (i = 0; i < 32; ip++, i++) { |
251 |
|
|
unsigned long tmp; |
252 |
|
|
unsigned long offset; |
253 |
kumaneko |
564 |
|
254 |
kumaneko |
562 |
/* |
255 |
|
|
* Find |
256 |
|
|
* adrp Xd, #imm21 |
257 |
|
|
* add Xd, Xn, #uimm12 |
258 |
|
|
* sequence. |
259 |
|
|
*/ |
260 |
kumaneko |
585 |
if ((*ip & 0x9F000000) != 0x90000000 || |
261 |
kumaneko |
562 |
(*(ip + 1) & 0xFFC00000) != 0x91000000) |
262 |
|
|
continue; |
263 |
|
|
tmp = ((unsigned long) ip) & ~0xFFFUL; |
264 |
|
|
offset = (unsigned long) (((((*ip >> 5) & 0x007FFFF) << 2) | |
265 |
|
|
((*ip >> 29) & 0x3))) << 12; |
266 |
|
|
if (offset & 0x100000000UL) |
267 |
|
|
offset |= 0xFFFFFFFF00000000UL; |
268 |
|
|
tmp += offset; |
269 |
|
|
offset = (*(ip + 1) >> 10) & 0xFFF; |
270 |
|
|
tmp += offset; |
271 |
kumaneko |
585 |
/* |
272 |
|
|
* Find |
273 |
kumaneko |
655 |
* ldr Xt, [Xn, #uimm12] |
274 |
kumaneko |
585 |
* sequence. |
275 |
|
|
*/ |
276 |
|
|
for (ip += 2; i < 32 - 2; ip++, i++) { |
277 |
|
|
if ((*ip & 0xFFC00000) != 0xF9400000) |
278 |
|
|
continue; |
279 |
|
|
offset = ((*ip >> 10) & 0xFFF) << 3; |
280 |
kumaneko |
562 |
tmp += offset; |
281 |
kumaneko |
585 |
ip4ret = (unsigned int *) tmp; |
282 |
|
|
return &ip4ret; |
283 |
kumaneko |
562 |
} |
284 |
kumaneko |
585 |
break; |
285 |
kumaneko |
562 |
} |
286 |
kumaneko |
655 |
for (i = 0; i < 32; ip++, i++) { |
287 |
|
|
unsigned long tmp; |
288 |
|
|
unsigned long offset; |
289 |
|
|
|
290 |
|
|
/* |
291 |
|
|
* Find |
292 |
|
|
* adrp Xd, #imm21 |
293 |
|
|
* sequence. |
294 |
|
|
*/ |
295 |
|
|
if ((*ip & 0x9F000000) != 0x90000000) |
296 |
|
|
continue; |
297 |
|
|
tmp = ((unsigned long) ip) & ~0xFFFUL; |
298 |
|
|
offset = (unsigned long) (((((*ip >> 5) & 0x007FFFF) << 2) | |
299 |
|
|
((*ip >> 29) & 0x3))) << 12; |
300 |
|
|
if (offset & 0x100000000UL) |
301 |
|
|
offset |= 0xFFFFFFFF00000000UL; |
302 |
|
|
tmp += offset; |
303 |
|
|
/* |
304 |
|
|
* Find |
305 |
|
|
* ldr Xt, [Xn, #uimm12] |
306 |
|
|
* sequence. |
307 |
|
|
*/ |
308 |
|
|
for (ip += 1; i < 32 - 1; ip++, i++) { |
309 |
|
|
if ((*ip & 0xFFC00000) != 0xF9400000) |
310 |
|
|
continue; |
311 |
|
|
offset = ((*ip >> 10) & 0xFFF) << 3; |
312 |
|
|
tmp += offset; |
313 |
|
|
ip4ret = (unsigned int *) tmp; |
314 |
|
|
return &ip4ret; |
315 |
|
|
} |
316 |
|
|
break; |
317 |
|
|
} |
318 |
kumaneko |
562 |
return NULL; |
319 |
|
|
} |
320 |
|
|
|
321 |
|
|
#endif |
322 |
|
|
|
323 |
|
|
#if defined(CONFIG_ARM) |
324 |
|
|
|
325 |
|
|
/** |
326 |
|
|
* probe_security_hook_heads_on_arm - Find security_hook_heads on ARM. |
327 |
|
|
* |
328 |
|
|
* @base: Address of security_bprm_committed_creds(). |
329 |
|
|
* |
330 |
|
|
* Returns address of security_hook_heads.bprm_committed_creds on success, |
331 |
|
|
* NULL otherwise. |
332 |
|
|
*/ |
333 |
|
|
static void * __init probe_security_hook_heads_on_arm(unsigned int *base) |
334 |
|
|
{ |
335 |
|
|
static unsigned int *ip4ret; |
336 |
|
|
int i; |
337 |
|
|
const unsigned long addr = (unsigned long) &probe_dummy_security_hook_heads; |
338 |
|
|
const unsigned long offset = (unsigned long) &probe_dummy_security_hook_heads.bprm_committed_creds - addr; |
339 |
|
|
unsigned int *ip = (unsigned int *) probe_security_bprm_committed_creds; |
340 |
kumaneko |
564 |
|
341 |
kumaneko |
562 |
for (i = 0; i < 32; ip++, i++) { |
342 |
|
|
if (*(ip + 2 + ((*ip & 0xFFF) >> 2)) != addr) |
343 |
|
|
continue; |
344 |
|
|
ip = base + i; |
345 |
|
|
ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2))); |
346 |
|
|
ip4ret += offset >> 2; |
347 |
|
|
return &ip4ret; |
348 |
|
|
} |
349 |
|
|
return NULL; |
350 |
|
|
} |
351 |
|
|
|
352 |
|
|
#endif |
353 |
|
|
|
354 |
kumaneko |
442 |
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) |
355 |
|
|
|
356 |
|
|
/* |
357 |
|
|
* Dummy variable for finding address of |
358 |
|
|
* "struct security_operations *security_ops". |
359 |
|
|
*/ |
360 |
kumaneko |
446 |
static struct security_operations *probe_dummy_security_ops; |
361 |
kumaneko |
442 |
|
362 |
|
|
/** |
363 |
kumaneko |
446 |
* probe_security_file_alloc - Dummy function which does identical to security_file_alloc() in security/security.c. |
364 |
kumaneko |
442 |
* |
365 |
|
|
* @file: Pointer to "struct file". |
366 |
|
|
* |
367 |
|
|
* Returns return value from security_file_alloc(). |
368 |
|
|
*/ |
369 |
kumaneko |
446 |
static int probe_security_file_alloc(struct file *file) |
370 |
kumaneko |
442 |
{ |
371 |
kumaneko |
446 |
return probe_dummy_security_ops->file_alloc_security(file); |
372 |
kumaneko |
442 |
} |
373 |
|
|
|
374 |
|
|
#if defined(CONFIG_ARM) |
375 |
|
|
|
376 |
|
|
/** |
377 |
kumaneko |
446 |
* probe_security_ops_on_arm - Find security_ops on ARM. |
378 |
kumaneko |
442 |
* |
379 |
|
|
* @base: Address of security_file_alloc(). |
380 |
|
|
* |
381 |
|
|
* Returns address of security_ops on success, NULL otherwise. |
382 |
|
|
*/ |
383 |
kumaneko |
446 |
static void * __init probe_security_ops_on_arm(unsigned int *base) |
384 |
kumaneko |
442 |
{ |
385 |
|
|
static unsigned int *ip4ret; |
386 |
|
|
int i; |
387 |
kumaneko |
446 |
const unsigned long addr = (unsigned long) &probe_dummy_security_ops; |
388 |
|
|
unsigned int *ip = (unsigned int *) probe_security_file_alloc; |
389 |
kumaneko |
564 |
|
390 |
kumaneko |
442 |
for (i = 0; i < 32; ip++, i++) { |
391 |
|
|
if (*(ip + 2 + ((*ip & 0xFFF) >> 2)) != addr) |
392 |
|
|
continue; |
393 |
|
|
ip = base + i; |
394 |
|
|
ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2))); |
395 |
|
|
return &ip4ret; |
396 |
|
|
} |
397 |
kumaneko |
446 |
ip = (unsigned int *) probe_security_file_alloc; |
398 |
kumaneko |
442 |
for (i = 0; i < 32; ip++, i++) { |
399 |
|
|
/* |
400 |
|
|
* Find |
401 |
|
|
* ldr r3, [pc, #offset1] |
402 |
|
|
* ldr r3, [r3, #offset2] |
403 |
|
|
* sequence. |
404 |
|
|
*/ |
405 |
|
|
if ((*ip & 0xFFFFF000) != 0xE59F3000 || |
406 |
|
|
(*(ip + 1) & 0xFFFFF000) != 0xE5933000) |
407 |
|
|
continue; |
408 |
|
|
ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2))); |
409 |
|
|
ip4ret += (*(ip + 1) & 0xFFF) >> 2; |
410 |
|
|
if ((unsigned long) ip4ret != addr) |
411 |
|
|
continue; |
412 |
|
|
ip = base + i; |
413 |
|
|
ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2))); |
414 |
|
|
ip4ret += (*(ip + 1) & 0xFFF) >> 2; |
415 |
|
|
return &ip4ret; |
416 |
|
|
} |
417 |
|
|
return NULL; |
418 |
|
|
} |
419 |
|
|
|
420 |
|
|
#endif |
421 |
|
|
|
422 |
|
|
#endif |
423 |
|
|
|
424 |
|
|
#if defined(CONFIG_ARM) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) |
425 |
|
|
/** |
426 |
kumaneko |
446 |
* probe_find_vfsmount_lock_on_arm - Find vfsmount_lock spinlock on ARM. |
427 |
kumaneko |
442 |
* |
428 |
|
|
* @ip: Address of dummy function's entry point. |
429 |
|
|
* @addr: Address of the variable which is used within @function. |
430 |
|
|
* @base: Address of function's entry point. |
431 |
|
|
* |
432 |
|
|
* Returns address of vfsmount_lock on success, NULL otherwise. |
433 |
|
|
*/ |
434 |
kumaneko |
446 |
static void * __init probe_find_vfsmount_lock_on_arm(unsigned int *ip, |
435 |
|
|
unsigned long addr, |
436 |
|
|
unsigned int *base) |
437 |
kumaneko |
442 |
{ |
438 |
|
|
int i; |
439 |
kumaneko |
564 |
|
440 |
kumaneko |
442 |
for (i = 0; i < 32; ip++, i++) { |
441 |
|
|
static unsigned int *ip4ret; |
442 |
kumaneko |
564 |
|
443 |
kumaneko |
442 |
if (*(ip + 2 + ((*ip & 0xFFF) >> 2)) != addr) |
444 |
|
|
continue; |
445 |
|
|
ip = base + i; |
446 |
|
|
ip4ret = (unsigned int *) (*(ip + 2 + ((*ip & 0xFFF) >> 2))); |
447 |
|
|
return &ip4ret; |
448 |
|
|
} |
449 |
|
|
return NULL; |
450 |
|
|
} |
451 |
|
|
#endif |
452 |
|
|
|
453 |
|
|
/** |
454 |
kumaneko |
446 |
* probe_find_variable - Find variable's address using dummy. |
455 |
kumaneko |
442 |
* |
456 |
|
|
* @function: Pointer to dummy function's entry point. |
457 |
|
|
* @addr: Address of the variable which is used within @function. |
458 |
|
|
* @symbol: Name of symbol to resolve. |
459 |
|
|
* |
460 |
|
|
* This trick depends on below assumptions. |
461 |
|
|
* |
462 |
|
|
* (1) @addr is found within 128 bytes from @function, even if additional |
463 |
|
|
* code (e.g. debug symbols) is added. |
464 |
|
|
* (2) It is safe to read 128 bytes from @function. |
465 |
|
|
* (3) @addr != Byte code except @addr. |
466 |
|
|
*/ |
467 |
kumaneko |
446 |
static void * __init probe_find_variable(void *function, unsigned long addr, |
468 |
|
|
const char *symbol) |
469 |
kumaneko |
442 |
{ |
470 |
|
|
int i; |
471 |
|
|
u8 *base; |
472 |
|
|
u8 *cp = function; |
473 |
kumaneko |
564 |
|
474 |
kumaneko |
442 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3) |
475 |
|
|
if (*symbol == ' ') |
476 |
kumaneko |
446 |
base = probe_find_symbol(symbol); |
477 |
kumaneko |
442 |
else |
478 |
|
|
#endif |
479 |
|
|
base = __symbol_get(symbol); |
480 |
|
|
if (!base) |
481 |
|
|
return NULL; |
482 |
kumaneko |
562 |
#if defined(CONFIG_ARM64) && defined(LSM_HOOK_INIT) |
483 |
|
|
if (function == probe_security_bprm_committed_creds) |
484 |
|
|
return probe_security_hook_heads_on_arm64((unsigned int *) base); |
485 |
|
|
#endif |
486 |
|
|
#if defined(CONFIG_ARM) && defined(LSM_HOOK_INIT) |
487 |
|
|
if (function == probe_security_bprm_committed_creds) |
488 |
|
|
return probe_security_hook_heads_on_arm((unsigned int *) base); |
489 |
|
|
#endif |
490 |
kumaneko |
496 |
#if defined(CONFIG_ARM) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && !defined(LSM_HOOK_INIT) |
491 |
kumaneko |
446 |
if (function == probe_security_file_alloc) |
492 |
|
|
return probe_security_ops_on_arm((unsigned int *) base); |
493 |
kumaneko |
442 |
#endif |
494 |
|
|
#if defined(CONFIG_ARM) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) |
495 |
kumaneko |
446 |
return probe_find_vfsmount_lock_on_arm(function, addr, |
496 |
|
|
(unsigned int *) base); |
497 |
kumaneko |
442 |
#endif |
498 |
kumaneko |
666 |
/* First, assume absolute addressing mode is used. */ |
499 |
kumaneko |
442 |
for (i = 0; i < 128; i++) { |
500 |
|
|
if (*(unsigned long *) cp == addr) |
501 |
|
|
return base + i; |
502 |
|
|
cp++; |
503 |
|
|
} |
504 |
|
|
/* Next, assume PC-relative addressing mode is used. */ |
505 |
kumaneko |
463 |
#if defined(CONFIG_S390) |
506 |
kumaneko |
442 |
cp = function; |
507 |
|
|
for (i = 0; i < 128; i++) { |
508 |
kumaneko |
463 |
if ((unsigned long) (cp + (*(int *) cp) * 2 - 2) == addr) { |
509 |
|
|
static void *cp4ret; |
510 |
kumaneko |
564 |
|
511 |
kumaneko |
463 |
cp = base + i; |
512 |
|
|
cp += (*(int *) cp) * 2 - 2; |
513 |
|
|
cp4ret = cp; |
514 |
|
|
return &cp4ret; |
515 |
|
|
} |
516 |
|
|
cp++; |
517 |
|
|
} |
518 |
|
|
#endif |
519 |
|
|
cp = function; |
520 |
|
|
for (i = 0; i < 128; i++) { |
521 |
kumaneko |
442 |
if ((unsigned long) (cp + sizeof(int) + *(int *) cp) == addr) { |
522 |
|
|
static void *cp4ret; |
523 |
kumaneko |
564 |
|
524 |
kumaneko |
442 |
cp = base + i; |
525 |
|
|
cp += sizeof(int) + *(int *) cp; |
526 |
|
|
cp4ret = cp; |
527 |
|
|
return &cp4ret; |
528 |
|
|
} |
529 |
|
|
cp++; |
530 |
|
|
} |
531 |
|
|
cp = function; |
532 |
|
|
for (i = 0; i < 128; i++) { |
533 |
|
|
if ((unsigned long) (long) (*(int *) cp) == addr) { |
534 |
|
|
static void *cp4ret; |
535 |
kumaneko |
564 |
|
536 |
kumaneko |
442 |
cp = base + i; |
537 |
|
|
cp = (void *) (long) (*(int *) cp); |
538 |
|
|
cp4ret = cp; |
539 |
|
|
return &cp4ret; |
540 |
|
|
} |
541 |
|
|
cp++; |
542 |
|
|
} |
543 |
|
|
return NULL; |
544 |
|
|
} |
545 |
|
|
|
546 |
kumaneko |
643 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) |
547 |
kumaneko |
442 |
|
548 |
|
|
/** |
549 |
kumaneko |
496 |
* probe_security_hook_heads - Find address of "struct security_hook_heads security_hook_heads". |
550 |
kumaneko |
442 |
* |
551 |
kumaneko |
496 |
* Returns pointer to "struct security_hook_heads" on success, NULL otherwise. |
552 |
kumaneko |
442 |
*/ |
553 |
kumaneko |
496 |
struct security_hook_heads * __init probe_security_hook_heads(void) |
554 |
kumaneko |
442 |
{ |
555 |
kumaneko |
496 |
const unsigned int offset = offsetof(struct security_hook_heads, |
556 |
|
|
bprm_committed_creds); |
557 |
kumaneko |
442 |
void *cp; |
558 |
kumaneko |
564 |
struct security_hook_heads *shh; |
559 |
|
|
struct security_hook_list *entry; |
560 |
kumaneko |
643 |
void *cap = probe_find_symbol(" cap_bprm_creds_from_file\n"); |
561 |
|
|
|
562 |
|
|
/* Get location of cap_bprm_set_creds(). */ |
563 |
|
|
cap = check_function_address(cap, "cap_bprm_creds_from_file"); |
564 |
|
|
if (!cap) |
565 |
|
|
return NULL; |
566 |
|
|
/* Guess "struct security_hook_heads security_hook_heads;". */ |
567 |
|
|
cp = probe_find_variable(probe_security_bprm_committed_creds, |
568 |
|
|
((unsigned long) |
569 |
|
|
&probe_dummy_security_hook_heads) + offset, |
570 |
|
|
" security_bprm_committed_creds\n"); |
571 |
|
|
if (!cp) { |
572 |
|
|
printk(KERN_ERR |
573 |
|
|
"Can't resolve security_bprm_committed_creds().\n"); |
574 |
|
|
return NULL; |
575 |
|
|
} |
576 |
|
|
/* This should be "struct security_hook_heads security_hook_heads;". */ |
577 |
|
|
shh = ((void *) (*(unsigned long *) cp)) - offset; |
578 |
|
|
hlist_for_each_entry(entry, &shh->bprm_creds_from_file, list) |
579 |
|
|
if (entry->hook.bprm_creds_from_file == cap) |
580 |
|
|
return shh; |
581 |
|
|
printk(KERN_ERR "Guessed security_hook_heads is 0x%lx\n", |
582 |
|
|
(unsigned long) shh); |
583 |
|
|
return NULL; |
584 |
|
|
} |
585 |
|
|
|
586 |
kumaneko |
683 |
#elif defined(RHEL_MAJOR) && RHEL_MAJOR == 8 && defined(RHEL_MINOR) && RHEL_MINOR >= 6 |
587 |
|
|
|
588 |
|
|
/** |
589 |
|
|
* probe_security_hook_heads - Find address of "struct security_hook_heads security_hook_heads". |
590 |
|
|
* |
591 |
|
|
* Returns pointer to "struct security_hook_heads" on success, NULL otherwise. |
592 |
|
|
*/ |
593 |
|
|
struct security_hook_heads * __init probe_security_hook_heads(void) |
594 |
|
|
{ |
595 |
|
|
const unsigned int offset = offsetof(struct security_hook_heads, |
596 |
|
|
bprm_committed_creds); |
597 |
|
|
void *cp; |
598 |
|
|
struct security_hook_heads *shh; |
599 |
|
|
struct security_hook_list *entry; |
600 |
|
|
void *cap = probe_find_symbol(" cap_bprm_repopulate_creds\n"); |
601 |
|
|
|
602 |
|
|
/* Get location of cap_bprm_repopulate_creds(). */ |
603 |
|
|
cap = check_function_address(cap, "cap_bprm_repopulate_creds"); |
604 |
|
|
if (!cap) |
605 |
|
|
return NULL; |
606 |
|
|
/* Guess "struct security_hook_heads security_hook_heads;". */ |
607 |
|
|
cp = probe_find_variable(probe_security_bprm_committed_creds, |
608 |
|
|
((unsigned long) |
609 |
|
|
&probe_dummy_security_hook_heads) + offset, |
610 |
|
|
" security_bprm_committed_creds\n"); |
611 |
|
|
if (!cp) { |
612 |
|
|
printk(KERN_ERR |
613 |
|
|
"Can't resolve security_bprm_committed_creds().\n"); |
614 |
|
|
return NULL; |
615 |
|
|
} |
616 |
|
|
/* This should be "struct security_hook_heads security_hook_heads;". */ |
617 |
|
|
shh = ((void *) (*(unsigned long *) cp)) - offset; |
618 |
|
|
hlist_for_each_entry(entry, &shh->bprm_repopulate_creds, list) |
619 |
|
|
if (entry->hook.bprm_repopulate_creds == cap) |
620 |
|
|
return shh; |
621 |
|
|
printk(KERN_ERR "Guessed security_hook_heads is 0x%lx\n", |
622 |
|
|
(unsigned long) shh); |
623 |
|
|
return NULL; |
624 |
|
|
} |
625 |
|
|
|
626 |
kumaneko |
643 |
#elif defined(LSM_HOOK_INIT) |
627 |
|
|
|
628 |
|
|
/** |
629 |
|
|
* probe_security_hook_heads - Find address of "struct security_hook_heads security_hook_heads". |
630 |
|
|
* |
631 |
|
|
* Returns pointer to "struct security_hook_heads" on success, NULL otherwise. |
632 |
|
|
*/ |
633 |
|
|
struct security_hook_heads * __init probe_security_hook_heads(void) |
634 |
|
|
{ |
635 |
|
|
const unsigned int offset = offsetof(struct security_hook_heads, |
636 |
|
|
bprm_committed_creds); |
637 |
|
|
void *cp; |
638 |
|
|
struct security_hook_heads *shh; |
639 |
|
|
struct security_hook_list *entry; |
640 |
kumaneko |
564 |
void *cap = probe_find_symbol(" cap_bprm_set_creds\n"); |
641 |
|
|
|
642 |
|
|
/* Get location of cap_bprm_set_creds(). */ |
643 |
|
|
cap = check_function_address(cap, "cap_bprm_set_creds"); |
644 |
|
|
if (!cap) |
645 |
|
|
return NULL; |
646 |
kumaneko |
496 |
/* Guess "struct security_hook_heads security_hook_heads;". */ |
647 |
kumaneko |
446 |
cp = probe_find_variable(probe_security_bprm_committed_creds, |
648 |
kumaneko |
496 |
((unsigned long) |
649 |
|
|
&probe_dummy_security_hook_heads) + offset, |
650 |
kumaneko |
446 |
" security_bprm_committed_creds\n"); |
651 |
kumaneko |
442 |
if (!cp) { |
652 |
|
|
printk(KERN_ERR |
653 |
|
|
"Can't resolve security_bprm_committed_creds().\n"); |
654 |
kumaneko |
496 |
return NULL; |
655 |
kumaneko |
442 |
} |
656 |
kumaneko |
496 |
/* This should be "struct security_hook_heads security_hook_heads;". */ |
657 |
kumaneko |
564 |
shh = ((void *) (*(unsigned long *) cp)) - offset; |
658 |
kumaneko |
592 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) |
659 |
|
|
hlist_for_each_entry(entry, &shh->bprm_set_creds, list) |
660 |
|
|
if (entry->hook.bprm_set_creds == cap) |
661 |
|
|
return shh; |
662 |
|
|
#else |
663 |
kumaneko |
564 |
list_for_each_entry(entry, &shh->bprm_set_creds, list) |
664 |
|
|
if (entry->hook.bprm_set_creds == cap) |
665 |
|
|
return shh; |
666 |
kumaneko |
592 |
#endif |
667 |
kumaneko |
564 |
printk(KERN_ERR "Guessed security_hook_heads is 0x%lx\n", |
668 |
|
|
(unsigned long) shh); |
669 |
|
|
return NULL; |
670 |
kumaneko |
442 |
} |
671 |
|
|
|
672 |
|
|
#else |
673 |
|
|
|
674 |
|
|
/** |
675 |
kumaneko |
446 |
* probe_security_ops - Find address of "struct security_operations *security_ops". |
676 |
kumaneko |
442 |
* |
677 |
|
|
* Returns pointer to "struct security_operations" on success, NULL otherwise. |
678 |
|
|
*/ |
679 |
kumaneko |
446 |
struct security_operations * __init probe_security_ops(void) |
680 |
kumaneko |
442 |
{ |
681 |
|
|
struct security_operations **ptr; |
682 |
|
|
struct security_operations *ops; |
683 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) |
684 |
|
|
void *cp; |
685 |
kumaneko |
564 |
|
686 |
kumaneko |
442 |
/* Guess "struct security_operations *security_ops;". */ |
687 |
kumaneko |
446 |
cp = probe_find_variable(probe_security_file_alloc, (unsigned long) |
688 |
|
|
&probe_dummy_security_ops, |
689 |
|
|
" security_file_alloc\n"); |
690 |
kumaneko |
442 |
if (!cp) { |
691 |
|
|
printk(KERN_ERR "Can't resolve security_file_alloc().\n"); |
692 |
|
|
return NULL; |
693 |
|
|
} |
694 |
|
|
/* This should be "struct security_operations *security_ops;". */ |
695 |
|
|
ptr = *(struct security_operations ***) cp; |
696 |
|
|
#else |
697 |
|
|
/* This is "struct security_operations *security_ops;". */ |
698 |
|
|
ptr = (struct security_operations **) __symbol_get("security_ops"); |
699 |
|
|
#endif |
700 |
|
|
if (!ptr) { |
701 |
|
|
printk(KERN_ERR "Can't resolve security_ops structure.\n"); |
702 |
|
|
return NULL; |
703 |
|
|
} |
704 |
|
|
ops = *ptr; |
705 |
|
|
if (!ops) { |
706 |
|
|
printk(KERN_ERR "No security_operations registered.\n"); |
707 |
|
|
return NULL; |
708 |
|
|
} |
709 |
|
|
return ops; |
710 |
|
|
} |
711 |
|
|
|
712 |
|
|
#endif |
713 |
|
|
|
714 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) |
715 |
|
|
|
716 |
|
|
/** |
717 |
kumaneko |
446 |
* probe_find_task_by_vpid - Find address of find_task_by_vpid(). |
718 |
kumaneko |
442 |
* |
719 |
|
|
* Returns address of find_task_by_vpid() on success, NULL otherwise. |
720 |
|
|
*/ |
721 |
kumaneko |
446 |
void * __init probe_find_task_by_vpid(void) |
722 |
kumaneko |
442 |
{ |
723 |
|
|
void *ptr; |
724 |
kumaneko |
564 |
|
725 |
kumaneko |
442 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) |
726 |
kumaneko |
446 |
ptr = probe_find_symbol(" find_task_by_vpid\n"); |
727 |
kumaneko |
442 |
#else |
728 |
|
|
ptr = __symbol_get("find_task_by_vpid"); |
729 |
|
|
#endif |
730 |
kumaneko |
564 |
return check_function_address(ptr, "find_task_by_vpid"); |
731 |
kumaneko |
442 |
} |
732 |
|
|
|
733 |
|
|
/** |
734 |
kumaneko |
446 |
* probe_find_task_by_pid_ns - Find address of find_task_by_pid(). |
735 |
kumaneko |
442 |
* |
736 |
|
|
* Returns address of find_task_by_pid_ns() on success, NULL otherwise. |
737 |
|
|
*/ |
738 |
kumaneko |
446 |
void * __init probe_find_task_by_pid_ns(void) |
739 |
kumaneko |
442 |
{ |
740 |
|
|
void *ptr; |
741 |
kumaneko |
564 |
|
742 |
kumaneko |
442 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31) |
743 |
kumaneko |
446 |
ptr = probe_find_symbol(" find_task_by_pid_ns\n"); |
744 |
kumaneko |
442 |
#else |
745 |
|
|
ptr = __symbol_get("find_task_by_pid_ns"); |
746 |
|
|
#endif |
747 |
kumaneko |
564 |
return check_function_address(ptr, "find_task_by_pid_ns"); |
748 |
kumaneko |
442 |
} |
749 |
|
|
|
750 |
|
|
#endif |
751 |
|
|
|
752 |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) |
753 |
|
|
|
754 |
|
|
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) |
755 |
|
|
|
756 |
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3) |
757 |
|
|
|
758 |
|
|
/* Dummy variable for finding address of "spinlock_t vfsmount_lock". */ |
759 |
kumaneko |
447 |
static spinlock_t probe_dummy_vfsmount_lock __cacheline_aligned_in_smp = |
760 |
kumaneko |
446 |
SPIN_LOCK_UNLOCKED; |
761 |
kumaneko |
442 |
|
762 |
kumaneko |
446 |
static struct list_head *probe_mount_hashtable; |
763 |
|
|
static int probe_hash_mask, probe_hash_bits; |
764 |
kumaneko |
442 |
|
765 |
|
|
/** |
766 |
|
|
* hash - Copy of hash() in fs/namespace.c. |
767 |
|
|
* |
768 |
|
|
* @mnt: Pointer to "struct vfsmount". |
769 |
|
|
* @dentry: Pointer to "struct dentry". |
770 |
|
|
* |
771 |
|
|
* Returns hash value. |
772 |
|
|
*/ |
773 |
|
|
static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) |
774 |
|
|
{ |
775 |
|
|
unsigned long tmp = ((unsigned long) mnt / L1_CACHE_BYTES); |
776 |
kumaneko |
564 |
|
777 |
kumaneko |
442 |
tmp += ((unsigned long) dentry / L1_CACHE_BYTES); |
778 |
kumaneko |
446 |
tmp = tmp + (tmp >> probe_hash_bits); |
779 |
|
|
return tmp & probe_hash_mask; |
780 |
kumaneko |
442 |
} |
781 |
|
|
|
782 |
|
|
/** |
783 |
kumaneko |
446 |
* probe_lookup_mnt - Dummy function which does identical to lookup_mnt() in fs/namespace.c. |
784 |
kumaneko |
442 |
* |
785 |
|
|
* @mnt: Pointer to "struct vfsmount". |
786 |
|
|
* @dentry: Pointer to "struct dentry". |
787 |
|
|
* |
788 |
|
|
* Returns pointer to "struct vfsmount". |
789 |
|
|
*/ |
790 |
kumaneko |
446 |
static struct vfsmount *probe_lookup_mnt(struct vfsmount *mnt, |
791 |
|
|
struct dentry *dentry) |
792 |
kumaneko |
442 |
{ |
793 |
kumaneko |
446 |
struct list_head *head = probe_mount_hashtable + hash(mnt, dentry); |
794 |
kumaneko |
442 |
struct list_head *tmp = head; |
795 |
|
|
struct vfsmount *p, *found = NULL; |
796 |
|
|
|
797 |
kumaneko |
447 |
spin_lock(&probe_dummy_vfsmount_lock); |
798 |
kumaneko |
442 |
for (;;) { |
799 |
|
|
tmp = tmp->next; |
800 |
|
|
p = NULL; |
801 |
|
|
if (tmp == head) |
802 |
|
|
break; |
803 |
|
|
p = list_entry(tmp, struct vfsmount, mnt_hash); |
804 |
|
|
if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) { |
805 |
|
|
found = mntget(p); |
806 |
|
|
break; |
807 |
|
|
} |
808 |
|
|
} |
809 |
kumaneko |
447 |
spin_unlock(&probe_dummy_vfsmount_lock); |
810 |
kumaneko |
442 |
return found; |
811 |
|
|
} |
812 |
|
|
|
813 |
|
|
/** |
814 |
kumaneko |
446 |
* probe_vfsmount_lock - Find address of "spinlock_t vfsmount_lock". |
815 |
kumaneko |
442 |
* |
816 |
|
|
* Returns address of vfsmount_lock on success, NULL otherwise. |
817 |
|
|
*/ |
818 |
kumaneko |
446 |
void * __init probe_vfsmount_lock(void) |
819 |
kumaneko |
442 |
{ |
820 |
|
|
void *cp; |
821 |
|
|
spinlock_t *ptr; |
822 |
kumaneko |
564 |
|
823 |
kumaneko |
442 |
/* Guess "spinlock_t vfsmount_lock;". */ |
824 |
kumaneko |
446 |
cp = probe_find_variable(probe_lookup_mnt, (unsigned long) |
825 |
kumaneko |
447 |
&probe_dummy_vfsmount_lock, " lookup_mnt\n"); |
826 |
kumaneko |
442 |
if (!cp) { |
827 |
|
|
printk(KERN_ERR "Can't resolve lookup_mnt().\n"); |
828 |
|
|
return NULL; |
829 |
|
|
} |
830 |
|
|
/* This should be "spinlock_t *vfsmount_lock;". */ |
831 |
|
|
ptr = *(spinlock_t **) cp; |
832 |
|
|
if (!ptr) { |
833 |
|
|
printk(KERN_ERR "Can't resolve vfsmount_lock .\n"); |
834 |
|
|
return NULL; |
835 |
|
|
} |
836 |
|
|
return ptr; |
837 |
|
|
} |
838 |
|
|
|
839 |
|
|
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) |
840 |
|
|
|
841 |
|
|
/* Dummy variable for finding address of "spinlock_t vfsmount_lock". */ |
842 |
kumaneko |
447 |
static spinlock_t probe_dummy_vfsmount_lock; |
843 |
kumaneko |
442 |
|
844 |
|
|
/** |
845 |
kumaneko |
446 |
* probe_follow_up - Dummy function which does identical to follow_up() in fs/namei.c. |
846 |
kumaneko |
442 |
* |
847 |
|
|
* @mnt: Pointer to "struct vfsmount *". |
848 |
|
|
* @dentry: Pointer to "struct dentry *". |
849 |
|
|
* |
850 |
kumaneko |
666 |
* Returns 1 if followed up, 0 otherwise. |
851 |
kumaneko |
442 |
*/ |
852 |
kumaneko |
446 |
static int probe_follow_up(struct vfsmount **mnt, struct dentry **dentry) |
853 |
kumaneko |
442 |
{ |
854 |
|
|
struct vfsmount *parent; |
855 |
|
|
struct dentry *mountpoint; |
856 |
kumaneko |
564 |
|
857 |
kumaneko |
447 |
spin_lock(&probe_dummy_vfsmount_lock); |
858 |
kumaneko |
442 |
parent = (*mnt)->mnt_parent; |
859 |
|
|
if (parent == *mnt) { |
860 |
kumaneko |
447 |
spin_unlock(&probe_dummy_vfsmount_lock); |
861 |
kumaneko |
442 |
return 0; |
862 |
|
|
} |
863 |
|
|
mntget(parent); |
864 |
|
|
mountpoint = dget((*mnt)->mnt_mountpoint); |
865 |
kumaneko |
447 |
spin_unlock(&probe_dummy_vfsmount_lock); |
866 |
kumaneko |
442 |
dput(*dentry); |
867 |
|
|
*dentry = mountpoint; |
868 |
|
|
mntput(*mnt); |
869 |
|
|
*mnt = parent; |
870 |
|
|
return 1; |
871 |
|
|
} |
872 |
|
|
|
873 |
|
|
/** |
874 |
kumaneko |
446 |
* probe_vfsmount_lock - Find address of "spinlock_t vfsmount_lock". |
875 |
kumaneko |
442 |
* |
876 |
|
|
* Returns address of vfsmount_lock on success, NULL otherwise. |
877 |
|
|
*/ |
878 |
kumaneko |
446 |
void * __init probe_vfsmount_lock(void) |
879 |
kumaneko |
442 |
{ |
880 |
|
|
void *cp; |
881 |
|
|
spinlock_t *ptr; |
882 |
kumaneko |
564 |
|
883 |
kumaneko |
442 |
/* Guess "spinlock_t vfsmount_lock;". */ |
884 |
kumaneko |
446 |
cp = probe_find_variable(probe_follow_up, (unsigned long) |
885 |
kumaneko |
447 |
&probe_dummy_vfsmount_lock, "follow_up"); |
886 |
kumaneko |
442 |
if (!cp) { |
887 |
|
|
printk(KERN_ERR "Can't resolve follow_up().\n"); |
888 |
|
|
return NULL; |
889 |
|
|
} |
890 |
|
|
/* This should be "spinlock_t *vfsmount_lock;". */ |
891 |
|
|
ptr = *(spinlock_t **) cp; |
892 |
|
|
if (!ptr) { |
893 |
|
|
printk(KERN_ERR "Can't resolve vfsmount_lock .\n"); |
894 |
|
|
return NULL; |
895 |
|
|
} |
896 |
|
|
return ptr; |
897 |
|
|
} |
898 |
|
|
|
899 |
|
|
#else |
900 |
|
|
|
901 |
|
|
/* Dummy variable for finding address of "spinlock_t vfsmount_lock". */ |
902 |
kumaneko |
447 |
static spinlock_t probe_dummy_vfsmount_lock; |
903 |
kumaneko |
442 |
|
904 |
|
|
/** |
905 |
kumaneko |
446 |
* probe_mnt_pin - Dummy function which does identical to mnt_pin() in fs/namespace.c. |
906 |
kumaneko |
442 |
* |
907 |
|
|
* @mnt: Pointer to "struct vfsmount". |
908 |
|
|
* |
909 |
|
|
* Returns nothing. |
910 |
|
|
*/ |
911 |
kumaneko |
446 |
static void probe_mnt_pin(struct vfsmount *mnt) |
912 |
kumaneko |
442 |
{ |
913 |
kumaneko |
447 |
spin_lock(&probe_dummy_vfsmount_lock); |
914 |
kumaneko |
442 |
mnt->mnt_pinned++; |
915 |
kumaneko |
447 |
spin_unlock(&probe_dummy_vfsmount_lock); |
916 |
kumaneko |
442 |
} |
917 |
|
|
|
918 |
|
|
/** |
919 |
kumaneko |
446 |
* probe_vfsmount_lock - Find address of "spinlock_t vfsmount_lock". |
920 |
kumaneko |
442 |
* |
921 |
|
|
* Returns address of vfsmount_lock on success, NULL otherwise. |
922 |
|
|
*/ |
923 |
kumaneko |
446 |
void * __init probe_vfsmount_lock(void) |
924 |
kumaneko |
442 |
{ |
925 |
|
|
void *cp; |
926 |
|
|
spinlock_t *ptr; |
927 |
kumaneko |
564 |
|
928 |
kumaneko |
442 |
/* Guess "spinlock_t vfsmount_lock;". */ |
929 |
kumaneko |
446 |
cp = probe_find_variable(probe_mnt_pin, (unsigned long) |
930 |
kumaneko |
447 |
&probe_dummy_vfsmount_lock, "mnt_pin"); |
931 |
kumaneko |
442 |
if (!cp) { |
932 |
|
|
printk(KERN_ERR "Can't resolve mnt_pin().\n"); |
933 |
|
|
return NULL; |
934 |
|
|
} |
935 |
|
|
/* This should be "spinlock_t *vfsmount_lock;". */ |
936 |
|
|
ptr = *(spinlock_t **) cp; |
937 |
|
|
if (!ptr) { |
938 |
|
|
printk(KERN_ERR "Can't resolve vfsmount_lock .\n"); |
939 |
|
|
return NULL; |
940 |
|
|
} |
941 |
|
|
return ptr; |
942 |
|
|
} |
943 |
|
|
|
944 |
|
|
#endif |
945 |
|
|
|
946 |
|
|
#else |
947 |
|
|
|
948 |
|
|
/* |
949 |
|
|
* Never mark this variable as __initdata , for this variable might be accessed |
950 |
kumaneko |
446 |
* by caller of probe_find_vfsmount_lock(). |
951 |
kumaneko |
442 |
*/ |
952 |
kumaneko |
447 |
static spinlock_t probe_dummy_vfsmount_lock; |
953 |
kumaneko |
442 |
|
954 |
|
|
/** |
955 |
kumaneko |
446 |
* probe_vfsmount_lock - Find address of "spinlock_t vfsmount_lock". |
956 |
kumaneko |
442 |
* |
957 |
|
|
* Returns address of vfsmount_lock. |
958 |
|
|
*/ |
959 |
kumaneko |
446 |
void * __init probe_vfsmount_lock(void) |
960 |
kumaneko |
442 |
{ |
961 |
kumaneko |
447 |
return &probe_dummy_vfsmount_lock; |
962 |
kumaneko |
442 |
} |
963 |
|
|
|
964 |
|
|
#endif |
965 |
|
|
|
966 |
|
|
#endif |
967 |
|
|
|
968 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) |
969 |
|
|
|
970 |
|
|
/** |
971 |
kumaneko |
446 |
* probe___d_path - Find address of "__d_path()". |
972 |
kumaneko |
442 |
* |
973 |
|
|
* Returns address of __d_path() on success, NULL otherwise. |
974 |
|
|
*/ |
975 |
kumaneko |
446 |
void * __init probe___d_path(void) |
976 |
kumaneko |
442 |
{ |
977 |
kumaneko |
446 |
void *ptr = probe_find_symbol(" __d_path\n"); |
978 |
kumaneko |
564 |
|
979 |
|
|
return check_function_address(ptr, "__d_path"); |
980 |
kumaneko |
442 |
} |
981 |
|
|
|
982 |
|
|
#endif |
983 |
|
|
|
984 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) |
985 |
|
|
|
986 |
|
|
/** |
987 |
kumaneko |
446 |
* probe_d_absolute_path - Find address of "d_absolute_path()". |
988 |
kumaneko |
442 |
* |
989 |
|
|
* Returns address of d_absolute_path() on success, NULL otherwise. |
990 |
|
|
*/ |
991 |
kumaneko |
446 |
void * __init probe_d_absolute_path(void) |
992 |
kumaneko |
442 |
{ |
993 |
kumaneko |
446 |
void *ptr = probe_find_symbol(" d_absolute_path\n"); |
994 |
kumaneko |
564 |
|
995 |
|
|
return check_function_address(ptr, "d_absolute_path"); |
996 |
kumaneko |
442 |
} |
997 |
|
|
|
998 |
|
|
#endif |
999 |
kumaneko |
688 |
|
1000 |
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) |
1001 |
|
|
|
1002 |
|
|
/** |
1003 |
|
|
* probe_copy_to_kernel_nofault - Find address of "copy_to_kernel_nofault()". |
1004 |
|
|
* |
1005 |
|
|
* Returns address of copy_to_kernel_nofault() on success, NULL otherwise. |
1006 |
|
|
*/ |
1007 |
|
|
void * __init probe_copy_to_kernel_nofault(void) |
1008 |
|
|
{ |
1009 |
|
|
void *ptr = probe_find_symbol(" copy_to_kernel_nofault\n"); |
1010 |
|
|
|
1011 |
|
|
return check_function_address(ptr, "copy_to_kernel_nofault"); |
1012 |
|
|
} |
1013 |
|
|
|
1014 |
|
|
#endif |