LWN:在Linux中模拟Windows系统调用!

关注了就能看到更多这么棒的文章哦~

Emulating Windows system calls in Linux

By Jonathan Corbet
June 25, 2020
原文来自:https://lwn.net/Articles/824380/
主译:deepL

一直以来,人们有一个想法,希望根据进程地址空间中每次调用的来源不同而对系统调用进行不同处理。例如,OpenBSD里有一种安全增强机制,如果系统调用不是经过C库API来发出的话则会拒绝服务这次系统调用。5月底,Gabriel Krisman Bertazi为Linux提出了类似的机制,但完全不是出于安全性考虑,而是致力于让Windows游戏在Wine下更好地运行。计划能检测和模拟Windows系统调用。这个需求可以通过审查系统调用来源而实现,但这可能不是最终能够合入mainline的解决方案。

为了以最快速度运行,Wine必须尽可能直接在CPU上运行Windows代码。不过,一旦Windows程序进行系统调用,就无法直接执行了,为了Windows系统调用而进入Linux内核态,很可能会出问题。因此过去Wine一直提供自己特制的用户空间Windows API来处理这个问题,该API底层会调用Linux系统调用,来实现所需功能。不过正如patch中所解释的,Windows应用程序越来越多地直接执行系统调用,而不是通过其Windows API,导致Wine无法拦截到这些调用了。

幸好,Linux通过seccomp()的形式提供了拦截系统调用的能力。可惜的是,当前内核中的这种机制,无法做到在这个大进程中只拦截Windows代码这部分的系统调用。如果拦截所有系统调用的话,会大大降低速度,肯定会让游戏玩家不满意的。在seccomp()使用的classic BPF program中,跟踪一个进程的地址空间中哪些部分进行了Linux系统调用,哪些进行了Windows调用,这样实现还是很麻烦的,同样也会影响系统执行效率。所以,这里需要一种新的机制。

这组patch为mmap()增加了一个新的内存保护位,叫做PROTNOSYSCALL,默认情况下,它不会改变内核的行为。然而,如果某个进程在seccomp()中开启了新的SECCOMPMODEMMAP模式,那么任何从标有PROTNOSYSCALL的内存区域进行的系统调用都会被捕获,这样相应的handler代码就可以模拟(emulate)完成这次的系统调用。

Patch的说明里面指出,人们不应该像OpenBSD那样,用syscall来源检查这种方式来解决这个问题:

不言而喻,尽管这个机制是建立在seccomp之上的,但它绝不是一个安全机制,因为恶意的应用程序总是有办法跳转到位于白名单内的内存区域并发起syscall调用。对于Wine游戏这种场景来说,并不需要担心这一点。

说明文档里面指出,之所以使用seccomp()来实现这个跟安全无关的功能,是因为如果不这样做的话,就需要复制大量seccomp()代码来实现这个功能,完全是重复代码。

这一系列的patch引起了不少开发者的讨论,他们对这种机制并不完全适应。例如,Kees Cook问道,是否可以改为在加载时重写Windows二进制代码,把调用syscall的代码换成调用emulate仿真函数的代码。答案似乎是 "不行"。修改游戏代码很可能会触发那些防止作弊的机制,因为作弊者可能就是通过修改代码来达到目的的。Wine开发者Paul Gofman补充说,要进行这样的修改,Wine "需要一些方法来找到那些高度混淆过的、动态生成的代码中的syscall,这些代码防护混淆主要就是为了防止拆解、调试等等恶意操作"。

Matthew Wilcox则建议可以扩展personality()机制来支持一个新的Windows personality。从本质上讲,这就是创建一个新的系统调用entry,专门模拟Windows调用。Gofman回答说,这种方法之前已经考虑过了,但在Linux和Windows代码之间的每次切换时执行personality()调用的成本也太高。这里一个可能的解决方案是实现一个特殊的personality,会查看存储在用户空间内存中的flag来决定如何处理系统调用。Gofman说如果有这样的机制,他可以基于此来开发相关的Wine patch。Krisman打算先试一试。

Andy Lutomirski 还有一些其他建议,首先是 prctl()操作,它可以将所有系统调用通过user-space trampoline来重定向。来自trampoline本身的系统调用将被正常执行。在Wine的例子中,这个trampoline可以模拟来自Windows代码的系统调用,同时将Linux系统调用传递给内核。Krisman表示对这种方法很感兴趣,可能也会开发出来试一下。

Lutomirski的另一个主意是允许一个进程为所有的系统调用建立一个(extended)BPF filter program;他后来将这个想法扩展为让它处理进程的所有 "architectural priviledge transitions(架构特权转换)"。这种方法提供了很大的灵活性,可能在Wine以外的地方也很有用,但它存在一个重大的缺陷:在unprivileged BPF能实现之前,它只能供特权进程调用,这对Wine来说无法接受这个限制。除非有什么新的动向,否则Linux里面目前的观点是无法接受unprivileged BPF,所以BPF filter program看起来并不是一个Wine可以接受的解决方案。

经过这次讨论,这个问题本身大家都已经理解了,并且大家都赞同要解决这个问题。不过这个解决方案将采取什么形式还远未明确,有多种方法需要试验。随着开发者们正在努力寻找哪种想法最合适,未来应该可以看到更多的patch。

全文完

LWN文章遵循CC BY-SA 4.0许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注LWN深度文章以及开源社区的各种新近言论~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值