摘要
上周《LINUX设备驱动程序第三版》的第一作者、LWN网路刊物创始人兼主编JonathanCorbet发表了对于Linux内核的一些想法,他觉得似乎内核项目总体发展快速,但内核代码仍旧使用1989年版本的C语言标准,而5.18内核可能会结束这些情况。
整理|章雨铭责编|屠敏
出品|csDN(ID:CSDNnews)
上周《LINUX设备驱动程序第三版》的第一作者、LWN网路刊物创始人兼主编JonathanCorbet发表了对于Linux内核的一些想法,他觉得似乎内核项目总体发展快速,但内核代码仍旧使用1989年版本的C语言标准,而5.18内核可能会结束这些情况。
是的,没错,拥有30年历史的Linux内核C语言要升级了。Linux开源社区早已宣布,2022年四月将把内核C语言版本升级到C11。
始于一次补丁,Linux内核缺陷凸显
这一决定很迅速,从问题发起到官方拍板宣布用时短短一周。
这一议案要从Linux内核贡献者JakobKoschel的补丁系列说起。
他在研究制止与内核数组primitive相关的预测执行漏洞时,发觉了这样一个问题。Linux内核中大量使用了由structlist_head定义的双数组。
struct list_head {
struct list_head *next, *prev;
};
这些结构一般被嵌入到一些其他结构中。通过这些方法,让任何相关的结构类型都能创建数组。随着类型的出现,内核提供了大量可以拿来遍历和操作数组的函数和宏。其中之一是list_for_each_entry(),它是一个伪装成控制结构的宏。为了了解这个宏的使用方式,内核中包括以下结构:
struct foo {
int fooness;
struct list_head list;
};
list中的元素可以拿来创建一个由foo结构组成的双链列表;一个单独的list_head结构一般被视为这个列表的开头,假定有一个称作foo_list的列表。可以用下边的代码遍历这个列表。
struct foo *iterator;
list_for_each_entry(iterator, &foo_list, list) {
do_something_with(iterator);
}
/* Should not use iterator here */
list参数告诉宏在foo结构中的list_head结构的名称。对于迭代器指向的列表中的每位元素,该循环将执行一次。
但这样USB子系统中会出现错误,传递给这个宏的迭代器在退出宏后仍可以使用,这是件十分危险的事。Koschel递交补丁,修补了这个错误。按照列表中发生的情况linux操作系统下载,该迭代器的内容可能出人预料,虽然在没有预测执行的情况下。Koschel重画了相关代码,循环后不再须要通过迭代器解决问题。
Linus拍板:Linux内核C语言将升级为C11
事实上,Linux内核的发明人及该计划的合作者LinusTorvalds开始对于这一补丁并不发烧,也不理解它和预测执行漏洞的关系。
不过升级linux内核版本,在Koschel进一步解释情况后,Torvalds认同"这只是一个常规的错误,简单明了"。但随即他又提到了问题的真正症结:传递给列表遍历宏的迭代器必须在循环本身之外的范围内申明。
这些非投机性错误之所以会发生,是由于我们在历史上没有C99风格的"在循环中申明变量"。所以list_for_each_entry()——以及所有其他的——往往会将最后一个HEAD条目从循环中窃取下来,仅仅是由于我们难以在循环本身中申明迭代器变量。
假如有可能编撰一个可以申明自己的迭代器的列表遍历宏,这么这个迭代器在循环之外是不可见的,就不会出现这些问题。并且,因为内核逗留在C89标准上,在循环中申明变量是不可能的。
Torvalds说,其实现今早已到了考虑转向C99标准的时侯了——虽然它早已有了20多年的历史,但仍然是最新的版本,足以容许块级变量申明。正如他所强调的,之所以过去没有这样做,"由于我们在一些古老的gcc版本中遇见了一些问题升级linux内核版本,破坏了文件的初始化器"。并且,与此同时,内核早已把它的最低GCC要求移到了5.1版本,所以其实这些错误早已不重要了。
Linux内核的开发者ArndBergmann也十分赞成这一观点,他觉得内核有往前发展的可能。事实上,他建议,在进行改变的同时,有可能达到C11标准(从2011年开始),虽然他不确定C11是否会带来对内核有用的新东西。甚至有可能转移到C17甚至仍未完成的C2x版本的语言。但是,这同样存在一个问题,那就是"会破坏对gcc-5/6/7的支持",而目前内核一直支持这种版本。将GCC的最低版本提升到8.x,可能会和用户社区目前乐意接受的版本有很大的差别。
不过LINUX虚机,转移到C11将不须要改变GCC的最低版本,因而可能更容易做到。Torvalds对这个看法表示赞成,但是希望最终能否取得成果。在Bergmann确认这可行以后,Torvalds宣布在5.18合并窗口进行初期尝试。
值得注意的是,在合并窗口和5.18版本之间可能发生好多事情。迁移到新版本的语言标准,可能造成内核中一些不显著的地方出现小bug,而常常一个小小的bug就有可能造成现今的改变被撤消。并且,假如一切顺利的话,下一个内核版本就可能会被即将迁移到C11上。将list_for_each_entry()的所有用户和变种(在内核中有超过15,000个)转换为不曝露内部迭代器的新版本,不过这可能要花不少时间。
你对此次升级有哪些想法呢,你认为升级后会带来哪些改变?欢迎你们在下方留言!
参考资料:
—END—
《新程序员001-004》全面上市,对话世界级大师,报导中国IT行业创新创造
文章评论