libfastjson 1.2304.0 重建修复记录
📑 目录
一、项目简介
本仓库归档了 libfastjson 1.2304.0 在 openEuler 2509(含 Kylin 组件)主机上,
因自编译 glibc 2.44 升级引发的 rsyslogd SIGSEGV 崩溃循环 的完整修复过程:
- 📦 发行版源码包(
src.rpm)、spec 与上游源码 - 🔧 可复现的构建脚本(关键参数:
-Wl,--no-as-needed -lm强制直接链接libm.so.6) - 📥 重建后的 RPM 产物
- 📄 问题根因、反汇编证据、验证结果
背景:2026-08-22 主机手动构建并安装了 glibc 2.44-1(无签名,替代发行版
glibc 2.38-71.oe2509),随后 rsyslog 服务崩溃循环,系统日志收集中断。
二、问题背景
升级 glibc 2.44 后,rsyslog.service 陷入崩溃循环:
rsyslog.service: Main process exited, code=dumped, status=11/SEGV
rsyslogd: Relink `/usr/lib64/libfastjson.so.4' with `/usr/lib64/libm.so.6' for IFUNC symbol `modf'
rsyslogd[xxxxx]: segfault at 9f ip ... in libm.so.6[46d52,...] error 4
影响范围:
- 每 1.5~2 秒崩溃一次(SIGSEGV),systemd 无限自动重启
/var/log/messages、secure、cron等全部停写- journald 被崩溃信息刷屏(近 3 天 7018 条 err 日志)
- 堆积 33,473 个 coredump,占用 4.1GB 磁盘
三、根因分析
3.1 崩溃定位链
-
rsyslogd -N1配置测试直接段错误(exit=139);gdb 回溯显示崩溃发生在
动态链接器ld-linux-x86-64.so.2调用 libm.so.6 内 IFUNC 解析器期间。 -
反汇编
libm.so.6 + 0x46d52(即modf@@GLIBC_2.2.5IFUNC 解析器):46d40: endbr64 46d44: mov 0xca285(%rip),%rax ; 取 GOT 槽 0x110fd0 内容 46d52: testb $0x10, 0x9f(%rax) ; <<< 崩溃:%rax == 0,读地址 0x9f解析器从 GOT 槽读取
_rtld_global_ro@GLIBC_PRIVATE指针(CPU 特性数据),
运行时该 GOT 槽为 NULL。 -
libfastjson.so.4的 DT_NEEDED 只有libc.so.6,缺少libm.so.6:
libc.so.6 也导出modf(弱 IFUNC),链接期--as-needed把-lm丢弃。 -
运行时 libfastjson 的
modf引用经全局作用域预取(symbol preemption)
绑定到 libm 的 IFUNC;该路径下解析器执行时_rtld_global_roGOT 槽
尚未正确填充 → NULL 解引用 → SIGSEGV。
3.2 关键对照实验
| 场景 | 结果 |
|---|---|
直接 gcc test.c -lm 调用 modf |
✅ 正常(exit=0),即使 -Wl,-z,now |
| libfastjson 不直接链接 libm,modf 经全局作用域预取 | ❌ 崩溃(exit=139) |
结论:问题不是 glibc 2.44 的 modf 本身损坏,而是 libfastjson 未直接链接
libm 导致的 IFUNC 预取路径问题。动态链接器给出的提示正是修复方向:
“Relink libfastjson.so.4 with libm.so.6 for IFUNC symbol modf”。
四、修复方案
保留 glibc 2.44,重建 libfastjson,强制其直接链接 libm.so.6:
rpmbuild --rebuild \
--define 'dist .oe2509' \
--define 'build_ldflags -Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/generic-hardened-ld -Wl,--no-as-needed -lm' \
libfastjson-1.2304.0-2.oe2509.src.rpm
| 要点 | 说明 |
|---|---|
移除 --as-needed 并追加 -lm |
使 DT_NEEDED 包含 libm.so.6,modf 直接绑定、不再预取 |
--define 'dist .oe2509' |
保持 release 后缀与发行版一致,便于 rpm -Uvh --replacepkgs 同版本替换 |
| rsyslog 本体无需改动 | 仅 libfastjson 需重建;rsyslog 单独重建见 micoder/rsyslog |
五、验证结果
| 验证项 | 修复前 | 修复后 |
|---|---|---|
readelf -d libfastjson.so.4 NEEDED |
仅 libc.so.6 |
libm.so.6 + libc.so.6 |
rsyslogd -N1 配置测试 |
exit=139(SIGSEGV) | exit=0 |
| rsyslog.service | 崩溃循环 | active (running),PID 稳定 |
/var/log/messages |
空(停写) | 正常写入 |
| 新增 coredump | 每 2 秒一个 | 无 |
六、仓库结构
libfastjson/
├── README.md # 本文件(项目总览)
├── REPORT.md # 完整修复总结报告
├── build.sh # 可复现构建脚本(含关键参数说明)
├── SOURCES/
│ ├── libfastjson-1.2304.0.tar.gz # 上游源码包
│ └── libfastjson.spec # 发行版 spec(未改动)
├── SRPMS/
│ └── libfastjson-1.2304.0-2.oe2509.src.rpm # 发行版源码 RPM
└── RPMS/
├── libfastjson-1.2304.0-2.oe2509.x86_64.rpm # 重建后的主包(修复产物)
├── libfastjson-devel-1.2304.0-2.oe2509.x86_64.rpm # 开发头文件包
├── libfastjson-debuginfo-1.2304.0-2.oe2509.x86_64.rpm # 调试信息包
└── libfastjson-debugsource-1.2304.0-2.oe2509.x86_64.rpm # 调试源码包
七、快速开始(重建步骤)
# 1. 环境准备(确保 source 仓库已启用、构建工具链就绪)
dnf repolist --enabled | grep -i source
dnf install -y gcc make cmake rpm-build
# 2. 获取源码包并安装构建依赖
cd /root/rpmbuild/SRPMS
dnf download --source libfastjson
dnf builddep -y libfastjson-1.2304.0-2.oe2509.src.rpm
# 3. 重建 RPM(关键参数见 build.sh 注释)
rpmbuild --rebuild \
--define 'dist .oe2509' \
--define 'build_ldflags -Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/generic-hardened-ld -Wl,--no-as-needed -lm' \
libfastjson-1.2304.0-2.oe2509.src.rpm
# 4. 安装重建后的 RPM(同版本替换)
cd /root/rpmbuild/RPMS/x86_64
rpm -Uvh --replacepkgs \
libfastjson-1.2304.0-2.oe2509.x86_64.rpm \
libfastjson-devel-1.2304.0-2.oe2509.x86_64.rpm
# 5. 验证
readelf -d /usr/lib64/libfastjson.so.4 | grep NEEDED # 应包含 libm.so.6
rsyslogd -N1 # 应 exit=0
完整脚本见
build.sh,可直接执行。
八、相关仓库
| 仓库 | 说明 |
|---|---|
[micoder/rsyslog]https://atomgit.com/micoder/rsyslog |
rsyslog 8.2312.0 重建修复记录(依赖本仓库修复 libfastjson) |
[micoder/glibc] https://atomgit.com/micoder/glibc |
自编译 glibc 2.44 的构建工程(问题源头) |
九、遗留事项
- coredump 清理:已删除
/var/lib/systemd/coredump/*(33,473 个文件,释放约 4GB)。
生产环境如需保留事故现场,可先归档再清理。 - openssh 10.5p1:本机同为自编译(依赖新 glibc),当前 sshd 运行正常;
若日后出现类似 IFUNC 崩溃,可套用本方案(--no-as-needed -lm)重建。 - glibc 2.44 为无签名自编译包:建议保留 src.rpm 备份,避免 dnf 升级时被
系统 glibc 意外覆盖造成版本错乱。
十、经验总结
- 自编译 glibc 替换系统 glibc 影响面极大:所有发行版二进制都按旧 glibc ABI
构建,IFUNC / symbol preemption 路径最容易踩坑;升级后必须全量回归常驻服务
(日志、网络、数据库等)。 - 动态链接器的 “Relink X with Y for IFUNC symbol S” 警告是直接可用的修复
指引——把引用方与被引用库直接链接即可。 - 排查手法沉淀:
dmesg定位段错误 → gdb 回溯 → 反汇编崩溃地址 →
readelf -d检查 DT_NEEDED → 最小程序对照验证。 - 版本化 RPM 重建(
--define 'dist'+ 同版本替换)可保证系统可回退、
可审计,优于直接覆盖二进制。
许可协议
本仓库内容遵循上游项目的 MIT License(见 libfastjson.spec(SOURCES/libfastjson.spec)
License: MIT)。重建产物 RPM 均基于 openEuler 发行版源码包构建,构建产物
的许可遵循对应上游与发行版约定。
- 点赞
- 收藏
- 关注作者
评论(0)