0x00 关于龙芯数据泄露漏洞
这两天刷到一则消息《安全内参:龙芯处理器存在架构层漏洞,应尽快更新修复》,仔细阅读了文章内容后,这让我想起来很久以前在龙芯早期MIPS64el架构中排查过的一个问题,所以也赶紧来蹭一波热度 。当然,虽然同样是数据泄露,但诱因和严重程度是不一样的,切勿混淆......
0x01 由于符号隔离引发的惨案(2023.07)
最初发现这个问题的是笔者所在公司的测试,反馈"我们的产品在某台龙芯设备中,进程退出时会打印一堆乱码,随后报错",需要笔者去排查处理。然后我就过去看了看这些乱码,其中的可见性字符中竟然包含了一些厂商名称还有一些类似base64的串,但我们的程序中根本没有硬编码这些东西。
然后笔者就进入了如下排查流程:
- 验证同一份代码在不同架构中是否现象一致
- 发现似乎除了龙芯(MIPS64el)架构,其它架构的行为都是正常的
- 验证本地系统命令执行结束后的现象
- 一切正常
- 验证本地不加任何特定编译参数编译出的可执行文件现象是否一致
- 结果正常
- 使用
make VERBOSE=ON提取我们项目的所有编译参数,逐一在本地Demo的编译过程中添加验证- 发现当使用了
-Wl,-version-script参数后,事情变得有趣起来了,所谓乱码如期而至 - 而
-Wl,-version-script是我们最初项目中遇到符号冲突,为实现符号隔离引入的编译参数,虽说现在看来这方式有点暴力了......
- 发现当使用了
0x02 联系系统厂商
一开始,首先怀疑的是系统问题,便一封邮件发往了系统厂商

附件一三重复

附件二

虽然截图中显示发送失败,但可能抄送有成功吧,又或者笔者使用工作邮箱又进行了联系,因为印象里厂商联系到了我的QQ,最后是排查未能复现还是对面缺少环境,已经忘了,总之结果是未能解决......
往后一段时间由于笔者在忙着跟进其它事情,这个问题就搁置了
0x03 进一步排查(2023.08)
时间一晃到了8月份,笔者手头的工作忙的差不多了,MIPS64el中的乱码问题也通过其它方式进行了规避,但耐不住笔者好奇心重啊......
那时我突然想到,既然问题是由编译参数导致的,而编译器源码往往是芯片厂商在维护,让系统厂商去背这个锅属实有点怨了
但如果把锅甩到芯片厂商,总得有证据啊
此时笔者想到既然问题是由-Wl,-version-script引起的,而-Wl,-version-script的目的是用来隐藏符号可见性,那么,这个问题是否是由于编译器错误的隐藏的本不改被隐藏的符号引起的呢?
于是带着疑问,笔者写了个Demo开始进行了验证
- 首先对同一个源码文件进行两种不同参数的编译,一个不带
-Wl,-version-script参数编译出test,另一个带有-Wl,-version-script参数编译出test2 - 然后分别执行
LD_DEBUG=all ./test > t1 2>&1和LD_DEBUG=all ./test2 > t2 2>&1,随后利用diffuse打开两者,在手动对齐符号装载顺序后,发现了一个醒目的符号装载差异,就是_IO_stdin_used - 再后面,修改
-Wl,-version-script指定的配置文件,将_IO_stdin_used添为global符号,使全局可见,编译出test3 - 问题消失!!!!
通过上诉的排查步骤,就已经实锤了我的猜想,编译器隐藏了本不该被隐藏的符号
0x04 联系芯片厂商
在确定问题出在编译器之后,笔者就开始整理复现过程并将邮件发往了芯片厂商
复现步骤

对应日志

邮件本体

该邮件现在看来相较于第一封有一定的误导性,印象里loongarch64是没有此问题的,乱码的多少应该是和链接库的多少或可执行程序的大小有关,并不一定是c++库的原因,但作为一次排查纪实就不在邮件内容中打码了......
和系统厂商不同,发到芯片厂商的邮件迟迟没有收到答复,当时想想可能是MIPS64el已经不再迭代,龙芯已经全面转向LoongArch64了,所以也就无所谓了吧
0x05 _IO_stdin_used 到底是什么?(2026.08.23)
写这篇文章时,时间已经过去三年有余了,但这又一次勾起了我的好奇心
当时笔者没查到、又或者说懒得去查,但今天不一样了
刚刚Ai给出的答复是这样的:
_IO_stdin_used 是 Glibc 用来判断可执行文件是否使用了新版 libio 结构的标志(通常由 crt1.o 提供)。当链接器对 -Wl,-version-script 的实现存在BUG,误将其作用域变为 Local 隐藏后,动态链接器无法将其暴露给 libc.so。这会导致 Glibc 误认为程序使用的是古老的旧版 I/O 布局。于是在进程退出执行清理或刷新流时,Glibc 按照错误的内存偏移去读取数据,触发了越界读取,最终把进程内存中的随机数据当作字符串打印到了终端上,形成了一种另类的"数据泄露"。
而打印出的数据并非硬编码在程序中的这一问题,极有可能是程序运行过程中读取到堆区未来得及释放、或清理的内容......
转载望注明出处