2014-05-06 85 views
2

我必须编写LKM,它拦截一些系统调用。 解决办法是:sys_call_table的符号的安全卸载内核模块

  1. 查找地址,检查是否地址是正确的(检查例如该sys_call_table的[__ NR_close]指向SYS_CLOSE的地址)
  2. 禁止中断在CR0
  3. 禁用WP位
  4. 变化sys_call_table的[__ NR_close]我自己的功能
  5. 启用WP位
  6. 允许中断。加载模块工作正常。

但是,模块的安全卸载呢?

考虑到我将sys_call_table恢复到原始状态并卸载模块的情况 - 如果内核仍在其他CPU的其他进程的系统调用上下文中执行代码,该怎么办?我会在内核模式下发生页面错误(因为模块代码段的页面不可用,因为模块已被卸载)。 共享资源是sys_call_table中的条目。如果我可以访问受锁定保护的条目 - 那么我可以安全地卸载我的模块。

但是,由于内核系统调用处理程序没有任何这种锁(例如/ x86/kernel/entry_32.S) - 这意味着没有安全的方式卸载我的模块?这是真的吗?

UPDATE1

我需要得到有关文件的信息访问旧内核(其中fanotify(2)不可用),从2.4内核版本开始。我需要这些信息才能通过防病毒引擎执行访问扫描。

+3

你可能想弄清楚为什么你要首先拦截/挂钩系统调用。这里的人们会认为你要么解决XY问题,要么写恶意软件。 – tangrs

回答

1

你说得对,没有安全的方式卸载你的模块,一旦你这样做了。这就是为什么以这种方式替换/打包系统调用表条目的原因之一。

在最新版本中,sys_call_table不是导出符号 - 至少部分是为了阻止这件事。

理论上可以支持更强大的系统调用替换机制,但内核维护人员认为整个概念充满错误和困惑的潜力,他们拒绝支持它。 (网络搜索会显示几个很久以前的辩论关于Linux内核邮件列表上的这个问题。)

(说到此处为一个确切几年前谁使用相同的技术。)

当然你也可以无论如何。然后,你可以“冒险”卸载你的模块 - 因此可能导致内核恐慌(但当然它可能会工作99%的时间)。或者,您无法允许您的模块完全卸载(需要重新启动才能升级或卸载)。