拦截Android内核中的系统调用-卸下模块后设备重新启动 [英] Intercepting syscalls in Android kernel -- device reboots when module is removed

查看:162
本文介绍了拦截Android内核中的系统调用-卸下模块后设备重新启动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试拦截Android内核(maguro为3.0.72)中的read syscall.我正在为此目的使用内核模块.一个例子如下:

I have been trying to intercept the read syscall in Android kernel (3.0.72 for maguro). I am using kernel module for such purpose. An example is as follows:

#include <linux/module.h>
#include <linux/unistd.h>    

MODULE_LICENSE ("Dual BSD/GPL");

asmlinkage long
  (*orig_call_open) (const char __user * filename, int flags, int mode);

asmlinkage long
  (*orig_call_read) (unsigned int fd, char __user * buf, size_t count);

#define SYS_CALL_TABLE_ADDR 0xc0058828

void **sys_call_table;

asmlinkage long
new_sys_open (const char __user * filename, int flags, int mode)
{
  printk ("Calling my open\n");
  return orig_call_open (filename, flags, mode);
}

asmlinkage long
new_sys_read (unsigned int fd, char __user * buf, size_t count)
{
  printk ("Calling my read\n");
  return orig_call_read (fd, buf, count);
}

/* Module initialization and cleanup functions */

int
init_module ()
{
  sys_call_table = (void *) SYS_CALL_TABLE_ADDR;

  // save original function ptrs
  orig_call_open = (void *) sys_call_table[__NR_open];
  orig_call_read = (void*) sys_call_table[__NR_read];

  // replace existing functions with ours
  sys_call_table[__NR_open] = (unsigned long *) new_sys_open;
  sys_call_table[__NR_read] = (unsigned long *) new_sys_read;

  printk ("Initializing.\n");

  return 0;
}

void
cleanup_module ()
{
  sys_call_table[__NR_open] = (unsigned long *) orig_call_open;
  sys_call_table[__NR_read] = (unsigned long *) orig_call_read;
  printk ("Cleaning up.\n");

}

我通常可以使用insmod插入模块.但是,当我尝试使用rmmod删除它时,内核中断,设备重新启动.

I can normally insert the module by using insmod. However, when I try to remove it (with rmmod), the kernel breaks and the device reboots.

[...]
[   80.512054] Unable to handle kernel paging request at virtual address bf000040
[   80.512145] pgd = c6d98000
[   80.512237] [bf000040] *pgd=85edc811, *pte=00000000, *ppte=00000000
[   80.512634] Internal error: Oops: 80000007 [#1] PREEMPT SMP
[   80.512725] Modules linked in: [last unloaded: privacy_capsules]
[   80.513061] CPU: 0    Not tainted  (3.0.72-gfb3c9ac-dirty #4)
[   80.513214] PC is at 0xbf000040
[   80.513336] LR is at sys_read+0x6c/0x78
[   80.513427] pc : [<bf000040>]    lr : [<c01533ec>]    psr: 200f0013
[...]

我还测试了其他系统调用(例如,仅用于sys_open和sys_write,而没有sys_read),并且工作正常(insmod和rmmod).但是,该问题似乎仅在sys_read中发生.

I also tested with other syscalls (for example, only for sys_open and sys_write -- and no sys_read) and it works ok (insmod and rmmod). However, the problem seems to happen only with sys_read.

有什么主意吗?提前非常感谢!

Any idea? many thanks in advance!

这些是函数指针的地址:

These are the addresses for the function pointers:

orig_call_read : 0xc0153380
new_sys_read   : 0xbf000000

然后我从模块代码中提取了一部分汇编代码:

And I took a piece of the assembly code generated from the module code:

00000000 <new_sys_read>:
   0:   e1a0c00d    mov ip, sp
   4:   e92dd878    push    {r3, r4, r5, r6, fp, ip, lr, pc}
   8:   e24cb004    sub fp, ip, #4
   c:   e1a04000    mov r4, r0
  10:   e3000000    movw    r0, #0
  14:   e3400000    movt    r0, #0
  18:   e1a06001    mov r6, r1
  1c:   e1a05002    mov r5, r2
  20:   ebfffffe    bl  0 <printk>
  24:   e3003000    movw    r3, #0
  28:   e3403000    movt    r3, #0
  2c:   e1a00004    mov r0, r4
  30:   e1a01006    mov r1, r6
  34:   e5933000    ldr r3, [r3]
  38:   e1a02005    mov r2, r5
  3c:   e12fff33    blx r3
  40:   e89da878    ldm sp, {r3, r4, r5, r6, fp, sp, pc}

因此,正如@ChrisStratton所建议的那样,阻塞的read()返回(在这种情况下,在blx r3之后),但是找不到下一个地址(0xbf000040).

So, as @ChrisStratton suggested, a blocked read() returns (in this case, after the blx r3), but cannot find the next address (0xbf000040).

推荐答案

这确实看起来像是阻塞的或其他延迟的读取调用,尝试在代码卸载后返回.

This does indeed look like a blocking or otherwise delayed read call trying to return through your code after it is unloaded.

我认为您在地址报告中将这两个功能的地址交换了.

I think you swapped the addresses for the two functions in your report of their address.

当原始文件尝试返回到替换文件的最后一行[<bf000040>]时会发生故障,但是由于模块已卸载,因此不再存在于内存中.我希望这样的系统很容易会长时间阻塞大量的读取调用.

The failure happens when the original tries to return to the last line of your replacement at [<bf000040>] but this is no longer in memory since your module has been unloaded. I'd expect a system such as this could easily have a lot of read calls that block for long periods of time.

您可能需要在sysfs或类似程序中实现一个接口,而不是卸载模块,该接口可用于禁用新的重定向,同时将其保留在内存中.

Instead of unloading your module, you might need to implement an interface in sysfs or similar which you can use to disable new redirections while leaving it in memory.

另一种选择是查看跳动"而不是呼叫"原始文件是否可行,这样原始文件的返回将跳过您并直接返回到呼叫者.用ARM来说,这将是一个没有链接的分支.查看代码,似乎您必须首先清理本地堆栈,在代码开始时将寄存器恢复到它们的状态,然后进行跳转.

Another option would be to see if it is workable to "jump" rather than "call" to the original, so that the original's return skips you and goes straight back to your caller. In ARM speak that would be a branch without link. Looking at the code, it seems like you would have to clean up your local stack first, restoring the registers to their state at the start of your code, and then make the jump.

这篇关于拦截Android内核中的系统调用-卸下模块后设备重新启动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆