LWN:GNU C 库 2.39 版本!

GNUCLibrary(glibc)版本2.39包含了子进程孵化新函数、x86_64影子堆支持、安全改进,如pidfd处理和CET支持,以及未实现的qsort优化。glibc还关注了异步取消安全性和内存管理效率。
摘要由CSDN通过智能技术生成

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

GNU C Library version 2.39

By Daroc Alden
February 6, 2024
Gemini translation
https://lwn.net/Articles/960309/

GNU C 库 (glibc) 发布了 2.39 版,1 月 31 日,其中包含了些新特性。值得一提的重要内容包括用于孵化(spawning)子进程的新函数、对 x86_64 上的影子堆的支持、新的安全特性、以及移除了 libcrypt。此外,glibc 维护人员还希望能包含对 qsort() 的改进,最终在该版本中尚未实现。Glibc 版本每六个月更新一次。

Pidfd 的改动

Linux 内核在 2018 年的 5.1 开发周期中添加了 pidfd 支持。2019 年 在内核中添加了更多支持,但是仍然需要一些用户空间支持才更普通有用。不同进程可以重复使用进程 ID (PID),因此在获取和使用 PID 之间会出现竞态;如果在该时间段内重复使用 PID,将会对错误的进程实施操作。类似于系统中的其他对象,Unix 系统通常使用文件来表示 — pidfd 是一些唯一的文件描述符,它们指向特定进程,即使其他进程重新使用了相同的 PID 也是如此。但要使一般程序以通用方式利用此功能,需要一些用户空间支持。新版本的 glibc 包含了几个用于处理 pidfd 的新增函数;当引入这项功能时,LWN 涵盖 了创建两个新帮助函数 pidfd_spawn() 和 pidfd_spawnp() 。这些函数用于创建进程并直接返回其 pidfd,这样可以避免潜在的竞态条件,在竞态条件中进程可能退出并被其他进程替换,其父进程在这之前无法为其打开 pidfd。这些功能仅适用于使用 clone3() 系统调用的系统。

但以上并不是唯一用于处理 pidfd 的新函数。该版本还添加了 posix_spawnattr_setcgroup_np() 和 posix_spawnattr_getcgroup_np() ,在进程启动之前,可以使用这些函数来设置衍生进程将属于哪个控制组。提前设定进程的控制组可避免进程启动和向其应用资源限制之间的竞态条件。这些函数是一系列函数中的成员,用于修改由 posix_spawn() 系列函数使用的 posix_spawnattr_t 结构,以指定要衍生的进程的实现定义的属性。

int posix_spawnattr_getcgroup_np(const posix_spawnattr_t /restrict attr,
                                 int /restrict cgroup);

int posix_spawnattr_setcgroup_np(posix_spawnattr_t /attr,
                                 int cgroup);

最后,无论出于何种原因,如果使用新 pidfd 接口的程序仍然需要确定子进程的 PID,可以使用 pidfd_getpid():

pid_t pidfd_getpid(int fd);

影子堆栈

此版本允许程序员利用的另一个内核特性是对 x86 控制流强制技术 (CET) 的支持。CET 包含两种技术:影子堆栈和间接分支跟踪。两者旨在减少或消除面向返回的编程 (ROP) 攻击。Glibc 已支持使用间接分支跟踪支持编译的程序。本次 glibc 更新主要是针对添加对影子堆栈的支持,因为设置影子堆栈也 需要 动态链接器的配合。影子堆栈的工作原理是在受特殊保护的内存中保留函数返回地址的第二个副本,因此覆盖堆栈的攻击无法控制程序。

从第 6.6 版本开始,Linux 内核 允许 程序选择使用影子堆栈,但是一直没有一种好方法可以在不进行直接系统调用的情况下利用该功能。此版本的 glibc 包含一个 --enable-cet 配置选项,用于启用对影子堆栈的支持。使用此标记进行构建时,glibc 会要求内核为影子堆栈分配内存,并在程序启动期间启用保护。

不过,程序还需要使用影子堆栈支持进行编译才能利用此特性。GNU 编译器套件 (GCC) 和 Clang 都支持通过 -fcf-protection 标记使用影子堆栈支持编译程序。一些发行版已经默认启用此标记(包括 Ubuntu 和 Fedora)。Glibc 的 --enable-cet 配置选项更改了加载共享对象的的行为方式。当进程启动时,glibc 会检查二进制文件是否支持 CET。如果是,那么加载不支持 CET 的共享对象将变成一个错误。Glibc 还支持 --enable-cet=permissive ,它在打开非影子堆栈感知共享对象时会无提示地禁用影子堆栈。

PLT 重写

本版本中的最后一个主动安全特性是添加了在启动时重写 过程链接表 (PLT) 的支持。一个动态链接程序无法在编译期间得知运行时任何共享对象在内存中的位置。因此,当该程序调用另一个共享对象中的某个函数时,该调用会通过 PLT 进行。在 PLT 中初次调用给定函数时,代码会跳转到动态链接器,该链接器会搜索以找到该函数的正确偏移,然后重写 PLT 项以直接指向该函数;后续调用无需涉及动态链接器。

此版本的 glibc 添加了一个调优项,名为 glibc.cpu.plt_rewrite 。如果启用此选项,动态链接器会在启动时将 PLT 重写为直接跳转到正确的位置,而不是等待调用某个特定函数。PLT 一旦被重写,它将被重新映射为只读内存。这会略微增加程序的启动时间,但可避免攻击通过恶意选择的跳转目标来控制程序的潜在路径:用恶意选择的跳转目标覆盖 PLT。可以使用 GLIBC_TUNABLES 环境变量按如下所示设置 Glibc 调优项:GLIBC_TUNABLES=glibc.cpu.plt_rewrite=1 。

qsort()

有一项更改没有纳入此次版本,即对 qsort() 的改进建议。10 月份,Adhemerval Zanella 撰写了一份 补丁,将 qsort()' 的老旧 归并排序 实现换成了基于 内插排序 的实现。他指出归并排序在已经排序或几乎排序的数组上表现不佳,而内插排序中不存在该问题。他还指出“归并排序实现有一些问题”,并进一步指出归并排序需要辅助内存,这意味着 qsort() 可能调用 malloc()=。对额外内存的需求意味着调用 =qsort() 可能会引入不确定的延迟,在该延迟期间,系统会为归并排序的辅助数组集结足够的内存。

这种潜在延迟还使得该函数不是 异步取消安全的。POSIX 要求在特定情况下(例如信号处理程序中或创建新线程后)的程序只能调用异步取消安全的函数,否则就会有未定义的行为。POSIX 仅要求少数函数是异步取消安全的,但 glibc 维护了一份列表,其中列出了哪些库函数在实践中是异步取消安全的,以帮助希望依赖 glibc 实现细节的开发人员。在 邮件列表上早先的讨论 中,Zanella 指出,他认为在可能的情况下使 glibc 函数异步取消安全是一种提升用户体验

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

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

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

3449afb6177795d78577e758a7387c95.jpeg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值