Reputation: 63
Below code can hook lsm successfully on Redhat8 server, but it will cause crash on Redhat9 server. I have try to find any resource about hlist_add_head_rcu or hook way change on linux 5.1x but cannot find any useful workaround. Could you help check about why that the same way can work on linux 4.x but cannot work on linux 5.1x? If you know the reason, could you help provide some workaround or suggestions. Thanks for your help.
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/version.h>
#include <linux/security.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0)
#include <linux/lsm_hooks.h>
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
#define KPROBE_LOOKUP 1
#include <linux/kprobes.h>
static struct kprobe kp = {
.symbol_name = "kallsyms_lookup_name"
};
#endif
#define SECURITY_HOOK_ADDR_NAME "security_hook_heads"
static unsigned long find_symbol_addr(const char *sym){
const char *cpsMethod = "cris test: find_symbol_addr";
unsigned long addr;
#ifdef KPROBE_LOOKUP
typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
kallsyms_lookup_name_t kallsyms_lookup_name;
register_kprobe(&kp);
kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr;
unregister_kprobe(&kp);
#endif
addr = kallsyms_lookup_name(sym);
if (addr == 0) {
pr_err("%s: unable to find addr\n", cpsMethod);
return -EINVAL;
}
pr_info("%s: address is %lx\n", cpsMethod, addr);
return addr;
}
struct security_hook_list cris_hooks[1] = {
};
static int hook_execve_test(struct file *file, int mask)
{
pr_info("cris test: hook_execve_test\n");
return 0;
}
static struct security_hook_heads *cris_lsm_hook = NULL;
bool hook_lsm(void){
const char *cpsMethod = "cris test: hook_lsm";
int count = 0;
int i = 0;
unsigned long addr1;
addr1 = find_symbol_addr(SECURITY_HOOK_ADDR_NAME);
if (addr1 == 0)
{
pr_err("%s: [Fatal] Lookup address for security hook heads failed. Can't enable execve Hook\n", cpsMethod);
return false;
}
cris_lsm_hook = (struct security_hook_heads*)addr1;
cris_hooks[0].head = &(cris_lsm_hook->file_permission);
cris_hooks[0].hook.file_permission = hook_execve_test;
count = ARRAY_SIZE(cris_hooks);
for (i = 0; i < count; i++){
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0)
list_add_rcu(&cris_hooks[i].list, cris_hooks[i].head);
#else
hlist_add_head_rcu(&cris_hooks[i].list, cris_hooks[i].head);
#endif
}
pr_info("%s: finish hook_lsm.\n", cpsMethod);
return true;
}
void unhook_lsm(void){
const char *cpsMethod = "cris test: unhook_lsm";
int count = 0;
int i = 0;
count = ARRAY_SIZE(cris_hooks);
for (i = 0; i < count; i++){
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0)
list_del_rcu(&cris_hooks[i].list);
#else
hlist_del_rcu(&cris_hooks[i].list);
#endif
}
pr_info("%s: Unregister hook module\n", cpsMethod);
}
static int __init prsyms_init(void)
{
hook_lsm();
return 0;
}
static void __exit prsyms_exit(void)
{
unhook_lsm();
}
module_init(prsyms_init);
module_exit(prsyms_exit);
MODULE_LICENSE("GPL");
The version of test servers are: Redhat8: 4.18.0-147.el8.x86_64 Redhat9: 5.14.0-70.13.1.el9_0.x86_64
And below is dump log from Redhat9 crash dump:
[ 2644.871335] cris test: find_symbol_addr: address is ffffffffb3215c60
[ 2644.871354] BUG: unable to handle page fault for address: ffffffffb3215ea0
[ 2644.871361] #PF: supervisor write access in kernel mode
[ 2644.871363] #PF: error_code(0x0003) - permissions violation
[ 2644.871365] PGD b5a15067 P4D b5a15067 PUD b5a16063 PMD 80000000b54000e1
[ 2644.871377] Oops: 0003 [#1] PREEMPT SMP PTI
[ 2644.871387] CPU: 0 PID: 2437 Comm: insmod Kdump: loaded Tainted: G S OE --------- --- 5.14.0-70.13.1.el9_0.x86_64 #1
[ 2644.871394] Hardware name: VMware, Inc. VMware7,1/440BX Desktop Reference Platform, BIOS VMW71.00V.13989454.B64.1906190538 06/19/2019
[ 2644.871396] RIP: 0010:hook_lsm.cold+0x47/0x95 [testcris]
[ 2644.871416] Code: 02 00 00 48 8d 93 40 02 00 00 48 c7 05 8f 23 00 00 83 70 72 c0 48 89 15 80 23 00 00 48 89 05 69 23 00 00 48 89 15 6a 23 00 00 <48> c7 83 40 02 00 00 40 94 72 c0 48 85 c0 74 08 48 c7 40 08 40 94
[ 2644.871418] RSP: 0018:ffffb5c00260fde0 EFLAGS: 00010246
[ 2644.871421] RAX: ffffffffb3216cf8 RBX: ffffffffb3215c60 RCX: 0000000000000000
[ 2644.871423] RDX: ffffffffb3215ea0 RSI: ffff917efbc17cc0 RDI: ffff917efbc17cc0
[ 2644.871424] RBP: ffffffffc072c000 R08: 0000000000000000 R09: ffffb5c00260fc28
[ 2644.871425] R10: ffffb5c00260fc20 R11: ffffffffb3be8228 R12: ffff917dc12226f0
[ 2644.871427] R13: ffffb5c00260fe88 R14: 0000000000000003 R15: 0000000000000000
[ 2644.871428] FS: 00007f8005409740(0000) GS:ffff917efbc00000(0000) knlGS:0000000000000000
[ 2644.871444] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 2644.871447] CR2: ffffffffb3215ea0 CR3: 000000003f536003 CR4: 00000000001706f0
[ 2644.871467] Call Trace:
[ 2644.871473] prsyms_init+0xa/0x1000 [testcris]
[ 2644.871477] do_one_initcall+0x44/0x200
[ 2644.871500] ? load_module+0xab8/0xb80
[ 2644.871503] ? kmem_cache_alloc_trace+0x45/0x420
[ 2644.871523] do_init_module+0x5c/0x270
[ 2644.871536] __do_sys_finit_module+0xae/0x110
[ 2644.871544] do_syscall_64+0x3b/0x90
[ 2644.871592] entry_SYSCALL_64_after_hwframe+0x44/0xae
Upvotes: 0
Views: 788