Linux 移除 strncpy

Hacker News Top 新闻

摘要

Linux 内核历经六年、超过 360 个补丁,终于移除了危险的 strncpy 函数,改用 strscpy 等更安全的替代方案,确保 NULL 终止。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/06/28 19:59

# Linux 杀死 strncpy 来源:https://smist08.wordpress.com/2026/06/25/linux-kills-strncpy/ ## 介绍 C 字符串库紧凑、快速且高效。然而,如果使用不当或不加小心,会导致缓冲区溢出错误,要么使程序崩溃,更糟的是允许任意代码执行。黑客发现在 C 字符串函数使用中的错误,是可供利用的安全弱点的金矿。Linux 内核是用 C 语言编写的,并使用这些字符串函数,花了很多时间修复内核中字符串使用的问题,并改进字符串库的 API。 许多问题的根源最初在于 `strcpy(dest, src);` 函数,它从 src 向 dest 复制字节,直到遇到空终止符。问题在于,如果 src 字符串大于目标缓冲区,或者 src 字符串根本没有空终止符,那么 dest 缓冲区就会被覆盖,之后内存中的任何内容都会被擦除。如果缓冲区在栈上,这就允许黑客覆盖函数的返回地址,并将地址设置为黑客选择的某个地址。 最初的修复是 `strncpy(dest, src, n);`,其中 n 是目标缓冲区的大小,因此当达到 n 时复制就停止。这样就不会覆盖内存。问题是 dest 中生成的字符串没有空终止符。这导致了很多如下形式的代码: `` strncpy(dest, src, sizeof(dest)); dest[sizeof(dest)-1] = '\0'; `` 这带来的问题是人们忘记添加第二条语句,或者弄错了大小,比如忘记 -1。 `strncpy` 还有第二个特性:它总是复制 n 个字节,如果 src 比 dest 短,则用更多的空字节填充到 n 个字节。大多数程序员甚至不知道它这样做,而且通常这是不必要的、很少需要的工作。 ## 移除 strncpy 是一项浩大的工程 花费了六年时间和超过 360 个补丁来清理 Linux 内核中所有 strncpy 的实例。这是相当多的工作,主要是因为每个实例都必须仔细考虑,并用正确的函数替代它。这绝非简单的复制粘贴。新函数还提供了更好的错误返回值,因此可以根据返回码测试发生了什么。 Linux 内核中许多较老的内存和字符串库都有针对各种支持处理器的汇编语言版本。对于新的字符串函数,我很少看到汇编版本,因此也许还有优化空间,通过巧妙的汇编语言生成更快的代码。 ## 用什么替代 strncpy? 新函数保证了字符串就是字符串,并将字符串溢出保护与 strncpy 的缓冲区填充功能分离开来。这样可以更清晰地表明正在做什么,并通过消除不必要的代码执行来提高效率。 最常见的替代是 `strscpy(dest, src, n);`,它确保 dest 缓冲区是一个字符串,即必要时将最后一个字节设置为 '\0'。它不做任何缓冲区填充,并且如果 src 字符串被截断,会返回 E2BIG。 `strscpy_pad()` 增加了缓冲区填充功能。下面是相关函数的完整列表。请注意,`mem*` 函数始终用于固定大小,并将空字符视为任何其他字符。 **用例** | **首选函数** | **为何更清晰** --- | --- | --- 复制到普通的 NUL 结尾目标字符串 | `strscpy()` | 限定复制范围,并在目标大小非零时保证终止。 复制到 NUL 结尾字符串并零填充剩余部分 | `strscpy_pad()` | 有意保留填充,而不是从 `strncpy()` 中偶然继承。 将文本复制到固定宽度的非字符串内存字段 | `strtomem_pad()` | 明确表明目标是内存,而非 C 字符串。 复制有界值并显式填充未使用空间 | `memcpy_and_pad()` | 将字节复制语义与字符串语义分离。 复制已知数量的字节 | `memcpy()` | 表明不需要字符串终止或填充行为。 ## 总结 C 编程语言及其字符串库自 1972 年以来一直存在。在此期间,今天几乎每个操作系统都是用 C 语言编写的,还有编译器、系统软件、应用软件和游戏。在 1972 年,目标是尽可能快速高效。黑客并不是问题,因为计算机没有联网。C 字符串库有很多优点,因而得到了如此广泛的使用。在随后的岁月中,API 的裂痕出现了,而且很难恰当地修复它们,你修补了一个地方,问题又在别处出现。希望通过这些改动,Linux 内核在保持其引以为傲的效率的同时,变得更加安全。这确实表明了良好 API 设计的重要性,尽管存在各种问题,C 字符串库已经存在了很长时间。这些调整似乎在保留库设计意图的同时,修复了最明显的缺陷。

相似文章

C字符串:一个50年的错误

Lobsters Hottest

对C语言中空终止字符串的批评,认为基于长度的字符串在现代编程中更优越,可以减少错误并提高性能。

killswitch:一种基于函数粒度的短路熔断原语

Lobsters Hottest

# 新 Linux 内核补丁提议引入"killswitch"原语,可即时禁用存在漏洞的内核函数 一项新的 Linux 内核补丁提议引入一种"killswitch"原语,允许管理员立即禁用存在漏洞的内核函数(例如 `af_alg_sendmsg`),使其返回 `-EPERM`,从而为安全问题提供快速的临时缓解措施,无需重启系统或重新编译内核。

CVE-2026-31431: Copy Fail

Lobsters Hottest

CVE-2026-31431(Copy Fail)是Linux内核中的一个本地提权漏洞,影响自2017年以来的所有主流发行版,允许非特权用户通过AF_ALG加密子系统对任何可读文件的页缓存进行确定性的4字节写入,从而获得root shell访问权限。

Linux内核中因单个错误字符导致的高危漏洞

Ars Technica

Linux内核中一个错误的字符引入了一个use-after-free漏洞(CVE-2026-53111),允许非特权用户在Debian和Ubuntu系统上将权限提升至root;该漏洞已修复并移植回旧版本。