rsyslog 8.2312.0 重建修复记录
📑 目录
一、项目简介
本仓库归档了 rsyslog 8.2312.0 在 openEuler 2509(含 Kylin 组件)主机上,
因自编译 glibc 2.44 升级引发的 rsyslogd SIGSEGV 崩溃循环 的完整修复过程:
- 📦 发行版源码包(
src.rpm)、spec、上游源码与全部补丁 - 🔧 可复现的构建脚本(与 libfastjson 一致的
build_ldflags,保持 ABI 一致) - 📥 重建后的 RPM 产物
- ⚙️ 实际生效的配置文件(
rsyslog.conf、haproxy.conf、systemd 单元等) - 📄 问题根因、修复方案、验证结果
依赖:必须先重建并安装 libfastjson(修复
modfIFUNC 预取崩溃),详见
micoder/libfastjson(#八相关仓库)。
二、问题背景
升级 glibc 2.44 后,rsyslog.service 陷入崩溃循环,每次重启后约 2 秒即再次崩溃:
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
影响范围:
- 系统日志服务不可用:
/var/log/messages、secure、cron等全部停写 - journald 被崩溃信息刷屏(近 3 天 7018 条 err 日志几乎全是崩溃循环)
- 堆积 33,473 个 coredump,占用 4.1GB 磁盘(已清理,见第九节)
三、根因分析
崩溃的直接触发点是 libfastjson.so.4,而非 rsyslog 本体:
-
rsyslogd -N1配置测试即段错误(exit=139),gdb 回溯定位到
ld-linux 调用 libm.so.6 内modfIFUNC 解析器时崩溃。 -
反汇编
modf@@GLIBC_2.2.5解析器(libm+0x46d40):46d44: mov 0xca285(%rip),%rax ; 取 GOT 槽 0x110fd0(_rtld_global_ro@GLIBC_PRIVATE) 46d52: testb $0x10, 0x9f(%rax) ; <<< %rax==NULL,读 0x9f 崩溃 -
libfastjson.so.4 的 DT_NEEDED 只有 libc.so.6,缺少 libm.so.6:
libc 也导出modf(弱 IFUNC),链接期--as-needed因此丢弃了-lm。 -
运行时 libfastjson 的
modf引用经全局作用域预取绑定到 libm 的 IFUNC,
该预取路径下解析器读取_rtld_global_roGOT 槽时为 NULL → SIGSEGV。 -
对照实验:直接
gcc test.c -lm调用 modf 正常(exit=0),证明 glibc 2.44
的 modf 本身没有坏,是链接/预取方式的问题。
修复方向由动态链接器直接给出:“Relink libfastjson.so.4 with libm.so.6 for
IFUNC symbol modf”。详细证据链见 REPORT.md。
四、修复方案
保留 glibc 2.44,分两步重建:
| 步骤 | 仓库 | 内容 |
|---|---|---|
| 1️⃣ | [micoder/libfastjson]https://gitcode.com/micoder/libfastjson |
重建 libfastjson:build_ldflags 追加 -Wl,--no-as-needed -lm,DT_NEEDED 加入 libm.so.6 |
| 2️⃣ | 本仓库(rsyslog) | 重建 rsyslog:使用一致的 build_ldflags,保持 ABI 一致性 |
rsyslog 重建命令:
rpmbuild --rebuild --nocheck \
--define 'dist .oe2509' \
--define 'build_ldflags -Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/generic-hardened-ld -Wl,--no-as-needed -lm' \
rsyslog-8.2312.0-8.oe2509.src.rpm
| 要点 | 说明 |
|---|---|
--define 'dist .oe2509' |
保持 release 后缀与原发行版一致,rpm -Uvh --replacepkgs 可同版本替换,RPM 数据库不产生版本回退 |
--nocheck |
跳过 rsyslog 自身耗时的 make check 测试套件(10+ 分钟),最终以服务实际启动验证为准 |
版本号不变(-8.oe2509) |
仅二进制重新构建,配置与数据文件不受影响 |
五、验证结果
| 验证项 | 修复前 | 修复后 |
|---|---|---|
rsyslogd -N1 配置测试 |
exit=139(SIGSEGV) | exit=0 |
| rsyslog.service 状态 | 崩溃循环(每 ~2s 重启) | active (running) |
| Main PID 稳定性 | 每次崩溃更换 | 30 秒观察保持不变 |
/var/log/messages |
空(停写) | 测试日志正常落盘 |
| 新增 coredump | 每 ~2s 一个 | 无 |
六、仓库结构
rsyslog/
├── README.md # 本文件(项目总览)
├── REPORT.md # 完整修复总结报告
├── build.sh # 可复现构建脚本(含关键参数说明)
├── SOURCES/
│ ├── rsyslog-8.2312.0.tar.gz # 上游源码包
│ ├── rsyslog-doc-8.2312.0.tar.gz # 上游文档源码包
│ ├── rsyslog.spec # 发行版 spec(未改动)
│ ├── *.patch # 发行版携带的补丁(backport/bugfix)
│ └── *.sh # 发行版附带脚本(时区检查、日志轮转等)
├── SRPMS/
│ └── rsyslog-8.2312.0-8.oe2509.src.rpm # 发行版源码 RPM
├── RPMS/
│ ├── rsyslog-8.2312.0-8.oe2509.x86_64.rpm # 重建后的主包(修复产物)
│ ├── rsyslog-help-8.2312.0-8.oe2509.noarch.rpm # 帮助文档包
│ └── rsyslog-{crypto,elasticsearch,gnutls,gssapi,hiredis,kafka,mmaudit,mmjsonparse,mmkubernetes,mmnormalize,mmsnmptrapd,mmtaghostname,mongodb,mysql,omamqp1,pgsql,rabbitmq,relp,snmp,udpspoof}-8.2312.0-8.oe2509.x86_64.rpm # 20 个功能子包(模块产物)
└── CONFIG/
├── rsyslog.conf # 实际生效的主配置(/etc/rsyslog.conf)
├── rsyslog.d/
│ └── haproxy.conf # 附加配置(haproxy 日志)
├── rsyslog.service # systemd 单元文件
└── rsyslog.sysconfig # sysconfig 配置
说明:重建过程共生成 20 个功能子包(mysql / mongodb / kafka / relp /
gnutls / elasticsearch 等模块),本次修复只需基础包(系统仅安装了基础包,
子包未安装),但全部子包产物已随本仓库归档,可按需安装。
七、快速开始(重建步骤)
# 0. 前置:先按 micoder/libfastjson 仓库重建并安装 libfastjson
# (关键:DT_NEEDED 包含 libm.so.6,modf IFUNC 直接绑定)
# 1. 环境准备(确保 source 仓库已启用)
dnf repolist --enabled | grep -i source
# 2. 获取源码包并安装构建依赖
cd /root/rpmbuild/SRPMS
dnf download --source rsyslog
dnf builddep -y rsyslog-8.2312.0-8.oe2509.src.rpm
# 3. 重建 RPM(--nocheck 跳过耗时测试;关键参数见 build.sh 注释)
rpmbuild --rebuild --nocheck \
--define 'dist .oe2509' \
--define 'build_ldflags -Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/generic-hardened-ld -Wl,--no-as-needed -lm' \
rsyslog-8.2312.0-8.oe2509.src.rpm
# 4. 安装重建后的基础 RPM(同版本替换)
cd /root/rpmbuild/RPMS/x86_64
rpm -Uvh --replacepkgs rsyslog-8.2312.0-8.oe2509.x86_64.rpm
# 5. 验证
rsyslogd -N1 # 应 exit=0
systemctl start rsyslog && systemctl is-active rsyslog # 应 active
logger "verification" && tail -3 /var/log/messages # 应恢复写入
完整脚本见
build.sh,可直接执行。
八、相关仓库
| 仓库 | 说明 |
|---|---|
[micoder/libfastjson]https://gitcode.com/micoder/libfastjson |
libfastjson 1.2304.0 重建修复记录(本修复的前置依赖) |
[micoder/glibc]https://gitcode.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 为无签名自编译包:RPM 数据库层面建议保留 src.rpm 备份,
避免后续 dnf 升级时被系统 glibc 意外覆盖造成版本错乱。
十、经验总结
- 自编译 glibc 替换系统 glibc 影响面极大,IFUNC / symbol preemption 是
最容易踩坑的路径;升级后必须全量回归常驻服务(日志、网络、数据库等)。 - 动态链接器的 “Relink X with Y for IFUNC symbol S” 警告是直接可用的修复
指引——把引用方与被引用库直接链接即可。 - 排查手法沉淀:
dmesg定位段错误 → gdb 回溯 → 反汇编崩溃地址 →
readelf -d检查 DT_NEEDED → 最小程序对照验证。 - 版本化 RPM 重建(
--define 'dist'+ 同版本替换)可保证系统可回退、
可审计,优于直接覆盖二进制。
许可协议
本仓库内容遵循上游项目的 GPLv3+ 与 ASL 2.0(见 [rsyslog.spec]SOURCES/rsyslog.spec
License: (GPLv3+ and ASL 2.0))。重建产物 RPM 均基于 openEuler 发行版源码包
构建,构建产物的许可遵循对应上游与发行版约定。
- 点赞
- 收藏
- 关注作者
评论(0)