libfastjson 1.2304.0 重建修复记录

举报
山涧烟雨村 发表于 2026/08/23 19:56:46 2026/08/23
【摘要】 libfastjson 1.2304.0 重建修复记录适配自编译 glibc 2.44 的 IFUNC modf 崩溃修复工程归档 📑 目录一、项目简介二、问题背景三、根因分析四、修复方案五、验证结果六、仓库结构七、快速开始(重建步骤)八、相关仓库九、遗留事项十、经验总结许可协议 一、项目简介本仓库归档了 libfastjson 1.2304.0 在 openEuler 2509(含 K...

libfastjson 1.2304.0 重建修复记录

适配自编译 glibc 2.44 的 IFUNC modf 崩溃修复工程归档


📑 目录


一、项目简介

本仓库归档了 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/messagessecurecron 等全部停写
  • journald 被崩溃信息刷屏(近 3 天 7018 条 err 日志)
  • 堆积 33,473 个 coredump,占用 4.1GB 磁盘

三、根因分析

3.1 崩溃定位链

  1. rsyslogd -N1 配置测试直接段错误(exit=139);gdb 回溯显示崩溃发生在
    动态链接器 ld-linux-x86-64.so.2 调用 libm.so.6 内 IFUNC 解析器期间。

  2. 反汇编 libm.so.6 + 0x46d52(即 modf@@GLIBC_2.2.5 IFUNC 解析器):

    46d40:  endbr64
    46d44:  mov  0xca285(%rip),%rax   ;GOT0x110fd0 内容
    46d52:  testb $0x10, 0x9f(%rax)   ; <<< 崩溃:%rax == 0,读地址 0x9f
    

    解析器从 GOT 槽读取 _rtld_global_ro@GLIBC_PRIVATE 指针(CPU 特性数据),
    运行时该 GOT 槽为 NULL

  3. libfastjson.so.4 的 DT_NEEDED 只有 libc.so.6,缺少 libm.so.6
    libc.so.6 也导出 modf(弱 IFUNC),链接期 --as-needed-lm 丢弃。

  4. 运行时 libfastjson 的 modf 引用经全局作用域预取(symbol preemption)
    绑定到 libm 的 IFUNC;该路径下解析器执行时 _rtld_global_ro GOT 槽
    尚未正确填充 → 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 的构建工程(问题源头)

九、遗留事项

  1. coredump 清理:已删除 /var/lib/systemd/coredump/*(33,473 个文件,释放约 4GB)。
    生产环境如需保留事故现场,可先归档再清理。
  2. openssh 10.5p1:本机同为自编译(依赖新 glibc),当前 sshd 运行正常;
    若日后出现类似 IFUNC 崩溃,可套用本方案(--no-as-needed -lm)重建。
  3. glibc 2.44 为无签名自编译包:建议保留 src.rpm 备份,避免 dnf 升级时被
    系统 glibc 意外覆盖造成版本错乱。

十、经验总结

  1. 自编译 glibc 替换系统 glibc 影响面极大:所有发行版二进制都按旧 glibc ABI
    构建,IFUNC / symbol preemption 路径最容易踩坑;升级后必须全量回归常驻服务
    (日志、网络、数据库等)。
  2. 动态链接器的 “Relink X with Y for IFUNC symbol S” 警告是直接可用的修复
    指引
    ——把引用方与被引用库直接链接即可。
  3. 排查手法沉淀dmesg 定位段错误 → gdb 回溯 → 反汇编崩溃地址 →
    readelf -d 检查 DT_NEEDED → 最小程序对照验证。
  4. 版本化 RPM 重建--define 'dist' + 同版本替换)可保证系统可回退、
    可审计,优于直接覆盖二进制。

许可协议

本仓库内容遵循上游项目的 MIT License(见 libfastjson.spec(SOURCES/libfastjson.spec)
License: MIT)。重建产物 RPM 均基于 openEuler 发行版源码包构建,构建产物
的许可遵循对应上游与发行版约定。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。