LWN:不再export kallsyms_lookup_name()!

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

Unexporting kallsyms_lookup_name()

By Jonathan Corbet
February 28, 2020

原文来自:https://lwn.net/Articles/813350/

kernel module开发中有一条基本原则,module只能访问那些明确export出来的符号(symbols,指函数和数据结构)。甚至,有许多symbol明确指明了只有哪些兼容GPL license的module才可以访问。不过,现在看来其实有一些workaround方式,可以让module来访问任意的symbol。这个workaround方式很快会被堵上,尽管这会导致一些使用者碰到问题。这个事情的来龙去脉值得给大家详细讲讲。

这个后门就是kallsyms_lookup_name(),它会利用kernel的symbol table来查找,返回指定symbol的地址。module的代码直接访问symbol的话都会被拒绝,但是可以利用kallsyms_lookup_name()来获取地址,然后直接使用这个地址。这个函数本身被export为GPL-only的,理论上来说只有free software(自由软件)才能使用它。不过如果某个proprietary(专有的、私有的) module先通过虚假声明一个自由软件的license,那么就能访问到这些GPL-only的symbol。这种事情发生了不止一次。

Will Deacon提交了一组patch set,移除了对kallsyms_lookup_name()和kallsyms_on_each_symbol()的export声明。马上就有许多人对此表示赞同。毕竟很少有kernel开发者愿意看到module作者能有办法绕过export的限制。不过,还是有些人表达了一些担心。

其中一个问题在于,有一些out-of-tree用户在利用kallsyms_lookup_name(),这种用法其实开发者们都能理解、也认为是合理的,这就是用作kernel的live-patching系统。很讽刺的是,kernel bug通常都有export出来的函数,那么可以使用live patch来确定kernel里某个函数的位置,从而对它进行修补。kallsyms_lookup_name()可以很轻松地实现这个功能。在讨论中,Joe Lawrence提醒大家要多用用kpatch系统,它完全可以替代kallsyms_lookup_name()在live patch中的作用,并且在mainline kernel中已经完全可用了。不过,看起来Ksplice系统还在使用kallsyms_lookup_name。不过Miroslave Benes说了句大实话:“没人关心现在kernel里的ksplice功能”。这样看来,live patch功能应该不会阻止这组patch set的合入了。

Masami Hiramatsu提出了另一个问题,在kernel里面其实还有其他一些方法可以拿到kernel symbol对应的地址。User space可以使用kprobe来提取这些信息,kernel module也可以利用snprintf()的“%pF”格式(会打印出某个函数的对应地址)来遍历获取symbol地址(当然这个比较费时间和CPU资源)。他有点担心做了这个改动之后,普通开发者会碰到一些麻烦,而真正想要滥用module机制的人却不会担心这点麻烦。

Deacon回复的时候,解释了一下他做这个改动的来龙去脉。虽然Kernel开发者们都很喜欢做这些会让滥用Linux系统的人碰到更多麻烦的事情,不过这次来说,他的动力其实是为了帮Google解决一个问题。

在2018年的时候,LWN就报道过,为了能让Android kernel跟mainline尽量接近,有许多工作在进行中。其中之一就是把kernel放到Android generic system image (GSI)里,这是一个通用的Android image版本,可以在任何满足了Android的要求的设备上直接启动并正常运行。把kernel作为GSI的一部分,就意味着硬件厂商不能再修改kernel,所以就只能通过在GSI增加kernel module的方式来实现他们所要做的功能。

通过限制供应商只能使用kernel module,就能限制住他们所做的大多数改动。比如,不会再有Android设备能把CPU scheduler换成vendor自己的特制版本。不过,这就要求module必须只能使用这些export出来的symbol。如果module开始利用kernel里任意的代码,那么这个保护就完全没有意义了。Deacon虽然没有明说,不过看起来很明显有些厂商就在考虑这么做(译者注:哈哈,太鸡贼了吧大家~就不能跟Google好好玩吗?)。所以,要对移除这个接口的export做个冠冕堂皇的解释的话,就是:“如果kallsyms_lookup_name()包含了所有的数据和函数,那么就无法有效地监控和管理ABI接口”。

Hiramatsu接受了这个解释,回复了自己的Reviewed-by tag。所以,他原本担心的问题,也不会组织这组patch set被合入了。

其实,再说一遍,仅仅“给那些绕过export机制的module开发者找些麻烦”这个理由,就足够推动大家合入这个patch set了。不过很有意思的是看到一个大公司也支持这种做法。Google在把Android kernel跟mainline绑定得更加紧密之后,它和kernel社区的长期目标(至少在文中讲到的这一点上)也更加吻合了。希望这种吻合能够在我们那些使用了更像mainline kernel的设备上,为我们带来更好的kernel!

全文完

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

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

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

你可能感兴趣的:(LWN:不再export kallsyms_lookup_name()!)