拦截Android内核中的系统调用 - 设备在删除模块时重新启动

时间:2014-08-07 17:43:15

标签: android kernel kernel-module system-calls

我一直在尝试拦截Android内核中的读取系统调用(针对maguro的3.0.72)。我正在使用内核模块用于此目的。一个例子如下:

#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)时,内核会中断,设备会重新启动。

[...]
[   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上。

有什么想法吗?非常感谢提前!

编辑:

这些是函数指针的地址:

orig_call_read : 0xc0153380
new_sys_read   : 0xbf000000

我从模块代码中获取了一段汇编代码:

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)。

1 个答案:

答案 0 :(得分:1)

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

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

当原始版本尝试在[<bf000040>]处返回替换的最后一行时发生故障,但由于您的模块已卸载,因此不再在内存中。我预计像这样的系统很容易会有很多长时间阻塞的读取呼叫。

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

另一个选择是看看它是否可以跳过&#34;跳跃&#34;而不是&#34;呼叫&#34;原来,原来的回程会跳过你并直接回到你的来电者那里。在ARM中,这将是一个没有链接的分支。查看代码,看起来你必须首先清理你的本地堆栈,在代码开始时将寄存器恢复到它们的状态,然后进行跳转。