新闻中心

Linux内核耗时6年彻底清理strncpy,揭露C语言老隐患

2026-08-29



近日,Linux内核在7.2版本中完成了一项看似不起眼但意义深远的重构:将内核代码中所有对 strncpy 的使用彻底移除。这个工作从2020年启动,历时六年,累计提交约360次补丁,由 Kernel Self-Protection Project 发起并由众多开源开发者协作完成,所有修改过程和补丁都可公开查证。此举不仅修复了内核长期存在的内存安全问题,也为整个行业敲响了对“看似安全”的编码习惯重新审视的警钟。

strncpy 被广泛误认为是比 strcpy 更安全的字符串拷贝函数,但其设计初衷与现代字符串安全需求并不匹配。该函数起源于上世纪70年代的 Unix,用于“定长字段填充”:早期文件系统中文件名占固定字节、不需要以 NUL 结尾,strncpy 正好把不足部分用 0 填满。这种用途在当时合理,但放到现代程序里就会引发两类严重问题:

1) 不自动添加结束符导致越界读取。 当源字符串长度大于或等于指定拷贝长度 n 时,strncpy 会恰好拷贝 n 个字节而不写入终结的 '\0',导致目标缓冲区中没有字符串结束标志。后续对该缓冲区的字符串操作会继续读取相邻内存,可能造成乱码、信息泄露或崩溃。实践中已有不少因此类问题排查耗时数周的案例,比如在嵌入式固件中,当设备名恰好达到缓冲区长度时程序读取到了后续结构体数据而导致异常日志持续输出。 球友会

2) 对剩余空间填 0 带来性能浪费。 当源字符串较短时,strncpy 会把目标缓冲区剩下的所有字节都写成 0。如果缓冲区很大而实际字符串很短,这种逐字节的填零在高频路径会造成显著的性能开销和不必要的内存写入。

about image

这些缺陷使得 strncpy 在现代代码中经常成为隐患源:典型的错误用法如 char device_name[16]; strncpy(device_name, user_input_name, 16); 当输入恰好为 16 字符时,就可能没有 '\0',从而触发越界读取。基于此,业内有声音认为在多数场景下,代码中出现 strncpy 本身就说明存在潜在问题。

需要指出的是,Linux 内核的此次清理仅针对内核代码库本身,标准库(如 glibc)仍保留 strncpy,用户态程序和第三方项目仍然可以使用它,因此大量现存代码库仍然潜藏着相关风险。此次行动的意义在于通过示范性的底层修复,推动开发者在更广泛的代码中采用更明确、安全的字符串处理模式(例如显式保证终结符、使用更适合场景的安全函数或手工控制拷贝与终结符写入),而不是简单依赖历史遗留的“更安全”标签。 球友会

总之,把 strncpy 从内核中剔除并非对 C 语言的否定,而是对沿用已久但设计与现代需求不符的接口进行纠正。这个耗时六年、持续打磨的开源改进,既提升了系统稳定性与抗攻击能力,也提醒所有开发者:习以为常的编码惯例需要定期审视与替换,真正的安全来自对语义与边界的明确把控。