根据Linux内核邮件列表的消息,社区近日讨论了是否要<强>为内核采用现代C语言标准。
虽然Linux内核在快速发展,但它同时依赖着一些非常古老的工具,其中之一就是内核代码仍在使用1989年版本的C语言标准,此标准在30多年前内核项目启动之前就已经编写完成。从讨论结果来看,这一情况有望在5.18版本内核中改变。
Jakob Koschel在向Linus Torvalds递交的补丁(建议投机安全列表迭代器)中<强>修复了内核链表相关的预测执行漏洞。
起因是Jakob发现了一个问题,Linux内核广泛使用由struct list_head定义的双向链表:
& # 13; <代码> struct list_head {& # 13; struct list_head *, * prev; & # 13; };这种结构体通常被嵌入到其他结构体中,通过这种方式,开发者可以使用任何感兴趣的结构类型制作链表。除此之外,内核还提供了大量可用于遍历和操作链表的函数和宏。其中之一是list_for_each_entry(),这是一个伪装成控制结构的宏。要了解如何使用此宏,请假设内核包含如下结构:
& # 13; <代码> struct foo {& # 13; int fooness; & # 13; struct list_head列表;& # 13; };列表成员可用于创建foo结构体的双向链表,假设我们有一个叫做foo_list的结构声明作为此类链表的头,使用以下代码可以遍历此列表:
& # 13; <代码> struct foo *迭代器;& # 13; & # 13; list_for_each_entry(迭代器,foo_list列表){& # 13; do_something_with (iterator); & # 13; }& # 13;/*不应该使用迭代器*/列表参数告诉宏在foo结构中list_head结构体的名称。此循环将为列表中的每个元素执行一次,迭代器指向该元素,由此导致了USB子系统中的一个错误:传递给该宏的迭代器在退出宏后还能被使用。
Koschel通过重新编写有问题的代码,以在循环后停止使用迭代器来解决问题。
不过莱纳斯却对补丁修复的问题表示不解,也没有看到它与预测执行漏洞的关系.Koschel对此进行了进一步解释,对此李纳斯认为这只是一个普通的错误。但不久之后李纳斯发现了问题的根源所在:传递给列表遍历宏的迭代器,必须在循环本身之外的范围内声明。
<跨风格=" background - color: # ffffff;颜色:# 474747 ">随后,莱纳斯认为也许可以采用更直接的修复如<强>块级变量声明强。但C89不支持,而1999年发布的C99标准支持。所以Linux内核也许是时候转向使用C99标准了。
<跨风格=" background - color: # ffffff;颜色:# 474747 ">李纳斯说到,内核代码一直停留在C89的原因之一是编译器gcc的旧版本会出现奇怪的问题,导致初始化程序被破坏。不过现在内核要求的gcc最低版本已经提高到了v5.1,那些错误可能不再相关了。
<跨风格=" background - color: # ffffff;颜色:# 474747 ">另一位密切关注架构编译器问题的内核开发者Arnd伯格曼提议直接升级到C11甚至C2x, 尽管他不确定C11是否会带来任何对内核有用的新内容,不过如果升级到C17或C2x,会破坏对gcc-5/6/7的支持,因此升级到C11更容易实现,<跨风格=" background - color: # ffffff;颜色:# 474747 ">而且跨越太大内核社区未必接受。
<跨风格=" background - color: # ffffff;颜色:# 474747 ">李纳斯赞成了这个想法,在伯格曼确认应该可以这样做之后,莱纳斯<跨风格=" background - color: # ffffff;颜色:# 474747 ">宣布将在下一个内核版本v5.18中尝试使用C11标准。如果一切顺利,下一个内核版本使用的C语言标准有望升级到C11。
0 留言