recently , I made a low-level mistake while writing kernel modules :

* direct access User mode memory not used copy_to_user/copy_from_user!
In the view of kernel , The virtual address provided by user state is not trusted , Therefore, in case of a page fault in kernel state access to user state memory , It's very tricky to deal with .

Linux The kernel approach is to provide a Exception handling table , Using proprietary functions to access user state memory . similar
try-catch Block general . For details, please refer to copy_to_user/copy_from_user Implementation and kernel documentation of Documentation/x86/exception-tables.txt Description of .

How can I play this exception handling table .

first , We can write a piece of code , Exception handling table of kernel dump come down :
// show_extable.c #include <linux/module.h> #include <linux/kallsyms.h> int (*
_lookup_symbol_name)(unsigned long, char *); unsigned long (*_get_symbol_pos)(
unsigned long, void *, void *); unsigned long start_ex, end_ex; int init_module(
void) { unsigned long i; unsigned long orig, fixup, originsn, fixinsn, offset,
size; char name[128], fixname[128]; _lookup_symbol_name = (void *)
kallsyms_lookup_name("lookup_symbol_name"); _get_symbol_pos = (void *)
kallsyms_lookup_name("get_symbol_pos"); start_ex = (unsigned long)
kallsyms_lookup_name("__start___ex_table"); end_ex = (unsigned long)
kallsyms_lookup_name("__stop___ex_table"); //
according to exception_table_entry Of sizeof from start Traverse to end. for(i = start_ex; i < end_ex; i += 2
*sizeof(unsigned long)) { orig = i; // take out exception_table_entry Of insn Field address . fixup =
i+ sizeof(unsigned int); // take out fixup Field address . originsn = orig + *(unsigned int *)
orig; // Find the absolute address according to the relative offset field originsn |= 0xffffffff00000000; fixinsn = fixup + *(
unsigned int *)fixup; fixinsn |= 0xffffffff00000000; _get_symbol_pos(originsn, &
size, &offset); _lookup_symbol_name(originsn, name); _lookup_symbol_name(fixinsn
, fixname); printk("[%lx]%s+0x%lx/0x%lx [%lx]%s\n", originsn, name, offset, size
, fixinsn, fixname); } return -1; } MODULE_LICENSE("GPL");
Let's look at the output :
# ___sys_recvmsg+0x253 Abnormal location , Jump to ffffffff81649396 Handling exceptions . [ 7655.267616] [
ffffffff8150d7a3]___sys_recvmsg+0x253/0x2b0 [ffffffff81649396]bad_to_user ... #
create_elf_tables+0x3cf If there is an exception at the location , Jump to ffffffff81648a07 Address execution exception handling . [ 7655.267727] [
ffffffff8163250e]create_elf_tables+0x3cf/0x509 [ffffffff81648a1b]bad_gs
generally speaking , similar bad_to_user,bad_from_user Exception handling functions like these all directly return an error code to the user , such as Bad
address Like that , It's not a direct user program direct segment error , This point and user state access illegal address directly sent SIGSEGV Different . such as :
#include <fcntl.h> int main(int argc, char **argv) { int fd; int ret; char *buf
= (char *)0x56; // It's obviously an illegal address . fd = open("/proc/sys/net/nf_conntrack_max", O_RDWR
| O_CREAT, S_IRWXU); perror("open"); ret = read(fd, buf, 100); perror("read"); }
Implementation :
[root@localhost test]# ./a.out open: Success read: Bad address #
No segment errors , It's just a common mistake .
Can we modify its behavior to be consistent with the illegal address of user state access ? simple , Replace bad_to_user that will do , The code is as follows :
// fix_ex.c #include <linux/module.h> #include <linux/sched.h> #include
<linux/kallsyms.h> int (*_lookup_symbol_name)(unsigned long, char *); unsigned
long (*_get_symbol_pos)(unsigned long, void *, void *); unsigned long start_ex,
end_ex; void *_bad_from_user, *_bad_to_user; void kill_user_from(void) { printk(
" manager !rush tighten beat electric discourse!\n"); force_sig(SIGSEGV, current); }
void kill_user_to(void) { printk(" manager !rush tighten beat electric discourse! SB
leather shoes \n"); force_sig(SIGSEGV, current); } unsigned int old, new; int (*
_lookup_symbol_name)(unsigned long, char *); unsigned long (*_get_symbol_pos)(
unsigned long, void *, void *); int hook_fixup(void *origfunc1, void *origfunc2,
void *newfunc1, void *newfunc2) { unsigned long i; unsigned long fixup, fixinsn;
char fixname[128]; for(i = start_ex; i < end_ex; i += 2*sizeof(unsigned long)) {
fixup= i + sizeof(unsigned int); fixinsn = fixup + *(unsigned int *)fixup;
fixinsn|= 0xffffffff00000000; _lookup_symbol_name(fixinsn, fixname); if (!strcmp
(fixname, origfunc1) || !strcmp(fixname, origfunc2)) { unsigned long new;
unsigned int newfix; if (!strcmp(fixname, origfunc1)) { new = (unsigned long)
newfunc1; } else { new = (unsigned long)newfunc2; } new -= fixup; newfix = (
unsigned int)new; *(unsigned int *)fixup = newfix; } } return 0; } int
init_module(void) { _lookup_symbol_name = (void *)kallsyms_lookup_name(
"lookup_symbol_name"); _get_symbol_pos = (void *)kallsyms_lookup_name(
"get_symbol_pos"); _bad_from_user = (void *)kallsyms_lookup_name("bad_from_user"
); _bad_to_user = (void *)kallsyms_lookup_name("bad_to_user"); start_ex = (
unsigned long)kallsyms_lookup_name("__start___ex_table"); end_ex = (unsigned
long)kallsyms_lookup_name("__stop___ex_table"); hook_fixup("bad_from_user",
"bad_to_user", kill_user_from, kill_user_to); return 0; } void cleanup_module(
void) { hook_fixup("kill_user_from", "kill_user_to", _bad_from_user,
_bad_to_user); } MODULE_LICENSE("GPL");
compile , load , Re execute our a.out:
[root@localhost test]# insmod ./fix_ex.ko [root@localhost test]# ./a.out open:
Success Segment error [root@localhost test]# dmesg [ 8686.091738] manager !rush tighten beat
electric discourse! SB leather shoes [root@localhost test]#
Segment error occurred , And printed out a sentence for the manager to call quickly .

actually , That's not what I'm aiming for , What I really mean is ,Linux Exception handling list of , It's another good place to hide dirt , We can be on it hook Code hidden in function , for instance inline
hook Like that , so what ? Then quietly wait for the user state process bug Cause exception handling to be executed . Lengthen the timeline for code injection , This makes it harder for O & M and managers to notice .

Separate the time point of code injection from the time point of module insertion , Make things more chaotic .

however , Pay attention to the hidden module or oneshot Oh .

Zhejiang Wenzhou leather shoes wet , It's not fat when it's raining .

©2019-2020 Toolsou All rights reserved,
Gude Haowen serial - You deserve to be an engineer ( Preface ) A single key controls multiple water lamp states Bitcoin in ten years ,VDS Opportunity or fraud CSS architecture design Programmer Tanabata Valentine's Day confession code Python+OpenCV Detailed explanation of face recognition technology Bug Can data be used as the basis of technical personnel assessment KPI?Jsp+Ajax+Servlet+Mysql Add, delete, modify and query ( one ) Thorough explanation from Zhongtai Unity Scene loading asynchronously ( Implementation of loading interface )