In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >
Share
Shulou(Shulou.com)06/01 Report--
This article introduces the knowledge of "how to intercept exception handling in Linux operating system". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
In some cases, we may need to intercept some exception handling of the Linux operating system, such as intercepting page fault exception handling.
When the kernel can be modified:
If we could modify the kernel, it would be very easy to intercept page fault exception handling. Take the linux 3.8.0 kernel as an example, after page fault occurs in the system, it will enter the page fault exception handling and call the do_page_fault function. The code for do_page_fault is as follows:
Dotraplinkage void _ kprobes do_page_fault (struct pt_regs * regs, unsigned long error_code) {exception_enter (regs); _ _ do_page_fault (regs, error_code); exception_exit (regs);}
We extract the contents of the do_page_fault function and write it into a new function default_do_page_fault. Add a function pointer do_page_fault_handler, initialized to default_do_page_fault. Change the original do_page_fault interior to call the function pointer do_page_fault_handler. The modified code is as follows:
Void default_do_page_fault (struct pt_regs * regs, unsigned long error_code) {exception_enter (regs); _ _ do_page_fault (regs, error_code); exception_exit (regs);} EXPORT_SYMBOL (default_do_page_fault); typedef void (* do_page_fault_handler_t) (struct pt_regs *, unsigned long); do_page_fault_handler_t do_page_fault_handler = default_do_page_fault; EXPORT_SYMBOL (do_page_fault_handler) Dotraplinkage void _ kprobes do_page_fault (struct pt_regs * regs, unsigned long error_code) {do_page_fault_handler (regs, error_code);}
Because do_page_fault_handler is exported by EXPORT_SYMBOL, we can easily access it in the kernel module. As long as you set the value of do_page_fault_handler to the custom page fault exception handler, you can complete the interception function. If you want to restore the original exception handler, you just need to set do_page_fault_handler to default_do_page_fault again.
When the kernel cannot be modified:
However, in some cases, we cannot modify the kernel code directly, and we need to intercept on the compiled kernel.
In the beginning, I considered inserting jump code at the beginning of the do_page_fault function to jump to a custom page fault handler. But in practice, it is found that the kernel does not allow direct modification of do_page_fault code.
After some investigation, I came up with a new way to intercept page fault by changing the IDT table.
The original IDT table of the kernel certainly cannot be written directly, so I applied for a page, copied the original IDT table, and changed the ISR (Interrupt Service Routine) corresponding to the page exception. The ISR name of page fault is page_fault, which presses the register and error number, then calls do_page_fault, restores the register after do_page_fault returns, and exits exception handling.
In the Linux kernel, ISR is written in assemblies. For example, the ISR source code for x86'64 Linux is in the kernel source arch/x86/kernel/entry_64.S, and the X86'32 is in arch/x86/kernel/entry_32.S. If you read entry_64.S or entry_32.S, you will find that these two files are very complex, using a lot of assembly macros and macro definitions, it is not easy to write a custom ISR based on them.
My solution is to compile the kernel, disassemble vmlinux.o, then look for page_fault and find its assembly code. The following assembly code is from the linux-3.8.0 X86room64 kernel:
Ffffffff8136f6f0: ffffffff8136f6f0: 66 66 90 data32 xchg% ax,%ax ffffffff8136f6f3: ff 15 07 0a 2b 00 callq * 0x2b0a07 (% rip) # ffffffff81620100 ffffffff8136f6f9: 48 83 ec 78 sub $0x78 sub% RSP ffffffff8136f6fd: E8 ae 0100 00 callq ffffffff8136f8b0 ffffffff8136f702: 48 89 E7 mov% rsp % rdi ffffffff8136f705: 48 8b 74 24 78 mov 0x78 (% rsp),% rsi ffffffff8136f70a: 48 c7 44 24 78 ffff movq $0x78 (% rsp) ffffffff8136f711: ffff ffffffff8136f713: E8 1f 2e 00 00 callq ffffffff81372537 11 ffffffff8136f718: E9 33 02 00 00 jmpq ffffffff8136f950 12 ffffffff8136f71d: 0f 1f 00 nopl (% rax)
I copied it and wrote one called my_page_fault:
Asmlinkage void my_page_fault (void); asm (".text"); asm (".type my_page_fault,@function"); asm ("my_page_fault:"); / / the first 3 bytes of the routine basically do nothing, / / but I decide to keep them because kernel may rely on them for some special purpose asm (".byte 0x66"); asm ("xchg% ax,% ax"); asm ("callq * addr_adjust_exception_frame") Asm ("sub $0x78,% rsp"); asm ("callq * addr_error_entry"); asm ("mov% rsp,% rdi"); asm ("mov 0x78 (% rsp),% rsi"); asm ("movq $0xffffffffffffffff, 0x78 (% rsp)"); asm ("callq my_do_page_fault"); asm ("jmpq * addr_error_exit"); asm ("nopl (% rax)")
Where line 9 addr_adjust_exception_frame is the value stored at the address (pv_irq_ops+0x30), line 11 addr_error_entry is the address of error_entry, and line 16 addr_error_exit is the address of error_exit. These values need to be queried from the System.map file and passed in as kernel module parameters. My_do_page_fault is our own defined page fault handler.
If you need to intercept the page fault of X86room32, you can refer to this C file. However, it is important to note that the new version of the kernel has changed, and the code here needs to be adjusted according to its own situation.
Once you have a custom ISR, you can fill the ISR into the IDT, and after the new IDT table is loaded, the custom page fault handler comes into play. This process mainly consists of the following steps:
Save existing IDT register values with store_idt (& default_idtr)
Read the IDT header address and table size from default_idtr
Apply for a page
Copy the original idt table to the page of the new application
Use pack_gate to fill my_page_fault (not my_do_page_fault) into the corresponding IDT item
Fill in the address and size of the new IDT table in idtr and load the new IDT table to the current CPU with load_idt (& idtr)
With smp_call_function, load the new IDT table on another CPU.
If you want to restore the original IDT table, load the original IDT table with load (& default_idtr) and smp_call_function to release the page of the application.
That's all for "how to intercept exception handling in Linux operating system". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.