
问题症状※
- 现象:QQ 邮箱转发邮件到 Dovecot 邮件服务器时,lmtp 进程 CPU 占用 100%
- 结果:邮件无法接收,进程卡死
- 特点:QQ 新发邮件正常,只有转发邮件有问题
根本原因※
- QQ 转发邮件特性:使用
message/rfc822格式,原文被完整嵌套,保留原始的 GB18030/ISO-2022-CN 编码 - Dovecot 索引机制:索引时会对每个 MIME 部分进行 charset→UTF-8 转换
- glibc bug:CentOS 7 的 glibc-2.17 在处理 GB18030/ISO-2022-CN 时存在 iconv 死循环 bug(CVE-2020-27618)
- 配置限制:Dovecot 2.2.x 没有禁用字符集转换的配置选项
完整解决方案※
前置条件※
# 1. 确认系统版本
cat /etc/redhat-release
# CentOS Linux release 7.x
# 2. 确认 Dovecot 版本
dovecot --version
# 需要 2.3.x 或更高版本
# 3. 如果是 Dovecot 2.2.x,先升级到 2.3升级 Dovecot(如果需要)※
# 添加 Dovecot 官方仓库 导入GPG 密钥
curl https://repo.dovecot.org/DOVECOT-REPO-GPG-2.3 | gpg --import
# 1. 创建 Dovecot 仓库配置文件
cat > /etc/yum.repos.d/dovecot.repo << 'EOF'
[dovecot-2.3-latest]
name=Dovecot 2.3 CentOS $releasever - $basearch
baseurl=https://repo.dovecot.org/ce-2.3-latest/centos/$releasever/RPMS/$basearch
gpgkey=https://repo.dovecot.org/DOVECOT-REPO-GPG-2.3
gpgcheck=1
enabled=1
EOF
# 2. 清理 yum 缓存
yum clean all
yum makecache
# 3. 查看可用的 Dovecot 版本
yum list available dovecot --showduplicates
# 4. 升级 Dovecot
yum upgrade dovecot dovecot-pigeonhole
# 5. 重启 Dovecot
systemctl restart dovecot核心解决脚本※
#!/bin/bash
set -e
echo "=== Dovecot QQ 转发邮件 CPU 100% 问题修复脚本 ==="
echo "适用于:CentOS 7 + Dovecot 2.3.x + glibc-2.17"
echo ""
# 步骤 1: 备份配置
echo "=== 步骤 1: 备份配置 ==="
cp /etc/dovecot/conf.d/90-plugin.conf /etc/dovecot/conf.d/90-plugin.conf.bak.$(date +%s)
echo "✓ 配置已备份"
# 步骤 2: 添加 charset_aliases 到 Dovecot 配置
echo -e "\n=== 步骤 2: 配置 Dovecot charset_aliases ==="
if grep -q "charset_aliases" /etc/dovecot/conf.d/90-plugin.conf; then
echo "charset_aliases 已存在,跳过"
else
# 在第一个 plugin { 后面插入配置
sed -i '0,/^plugin {/s/^plugin {/plugin {\n charset_aliases = gb18030=utf-8 gbk=utf-8 gb2312=utf-8 iso-2022-cn=utf-8 iso-2022-cn-ext=utf-8/' /etc/dovecot/conf.d/90-plugin.conf
echo "✓ 已添加 charset_aliases 配置"
fi
# 步骤 3: 移除系统字符集模块
echo -e "\n=== 步骤 3: 移除 glibc 字符集模块 ==="
cd /usr/lib64/gconv
BACKUP_DIR="/root/gconv_disabled_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
# 移动有问题的字符集模块文件
for file in GB18030.so GBK.so GBGBK.so GBBIG5.so ISO-2022-CN.so ISO-2022-CN-EXT.so libGB.so; do
if [ -f "$file" ]; then
mv "$file" "$BACKUP_DIR/"
echo "已移除: $file"
fi
done
# 重建 gconv 模块缓存
rm -f gconv-modules.cache
iconvconfig
echo "✓ gconv 缓存已重建"
# 步骤 4: 验证配置
echo -e "\n=== 步骤 4: 验证配置 ==="
echo "1. Dovecot charset_aliases 配置:"
doveconf -n | grep charset_aliases && echo "✓ charset_aliases 已配置" || echo "❌ charset_aliases 未配置"
echo -e "\n2. 字符集模块状态:"
ls -lh /usr/lib64/gconv/ | grep -E "GB18030|GBK|ISO-2022-CN" || echo "✓ 字符集模块已移除"
echo -e "\n3. iconv 字符集测试:"
iconv -l | grep -i gb18030 && echo "❌ GB18030 仍可用" || echo "✓ GB18030 已禁用"
# 步骤 5: 重启 Dovecot
echo -e "\n=== 步骤 5: 重启 Dovecot ==="
systemctl restart dovecot
sleep 2
systemctl status dovecot | grep Active
echo -e "\n=== 修复完成 ==="
echo "现在可以测试 QQ 转发邮件了"
echo ""
echo "监控命令:"
echo " tail -f /var/log/maillog"
echo " watch -n 1 'ps aux | grep lmtp | grep -v grep'"
echo ""
echo "如需恢复字符集模块:"
echo " mv $BACKUP_DIR/* /usr/lib64/gconv/"
echo " iconvconfig"使用方法※
# 1. 保存脚本
cat > /root/fix_dovecot_qq_forward.sh << 'EOF'
[粘贴上面的脚本内容]
EOF
# 2. 赋予执行权限
chmod +x /root/fix_dovecot_qq_forward.sh
# 3. 执行修复
/root/fix_dovecot_qq_forward.sh
# 4. 测试 QQ 转发邮件技术原理说明※
为什么需要两个步骤?※
charset_aliases 配置(主要方案)
- 告诉 Dovecot:将 GB18030 等字符集当作 UTF-8 处理
- Dovecot 跳过 iconv 转换,直接使用原始数据
- 避免调用 glibc 的有问题的 iconv 函数
移除字符集模块(双重保险)
- 即使某些代码路径仍尝试调用 iconv
- 系统层面上这些字符集已不可用
- 完全阻止触发 glibc bug 的可能性
影响和副作用※
正面影响:
- ✅ lmtp 进程 CPU 占用恢复正常
- ✅ QQ 转发邮件能正常接收
- ✅ 服务器不再卡死
可能的副作用:
- ⚠️ GB18030 编码的邮件中文可能显示乱码
- ⚠️ 但用户可以下载原始邮件,使用邮件客户端正确显示
- ⚠️ 系统其他程序如需 GB18030 转换会失败(很少见)
验证和测试※
验证配置是否生效※
# 1. 检查 Dovecot 配置
doveconf -n | grep charset_aliases
# 2. 检查字符集模块
iconv -l | grep -i gb18030 # 应该没有输出
# 3. 测试 iconv 转换
echo "test" | iconv -f utf-8 -t gb18030
# 应该报错:conversion to 'GB18030' is not supported测试 QQ 转发邮件※
# 监控 CPU
watch -n 1 'ps aux | grep "[l]mtp"'
# 监控日志
tail -f /var/log/maillog
# 让 QQ 邮箱发送转发邮件
# 观察 lmtp CPU 是否正常(< 10%)
# 检查邮件是否能收到恢复方法※
如果需要恢复(通常不需要):
# 恢复字符集模块
BACKUP_DIR=$(ls -td /root/gconv_disabled_* | head -1)
mv $BACKUP_DIR/* /usr/lib64/gconv/
iconvconfig
# 移除 charset_aliases 配置
vi /etc/dovecot/conf.d/90-plugin.conf
# 删除 charset_aliases 那一行
# 重启 Dovecot
systemctl restart dovecot适用范围※
- ✅ CentOS 7 / RHEL 7(glibc-2.17)
- ✅ Dovecot 2.3.x 或更高版本
- ✅ Postfix + Dovecot 邮件服务器
- ✅ 收取 QQ 邮箱、163 邮箱等国内邮箱的转发邮件
- ✅ 症状:lmtp 进程 CPU 100%,邮件收不到
不适用:
- ❌ Dovecot 2.2.x(需先升级到 2.3+)
- ❌ CentOS 8/9(使用更新的 glibc,可能不存在此 bug)
- ❌ Ubuntu/Debian(glibc 版本不同)
相关 CVE 和 Bug※
- CVE-2020-27618:glibc iconv 处理无效多字节序列时无限循环
- glibc bug:ISO-2022-CN、GB18030 字符集转换死循环
- Dovecot 限制:2.2.x 版本无法禁用字符集转换
总结※
这个问题是 CentOS 7 老旧 glibc + QQ 转发邮件特殊编码 + Dovecot 索引机制 三者结合导致的典型案例。解决方案通过 应用层配置 + 系统层禁用 双重手段,彻底避免触发 glibc iconv bug。
关键点:
- 升级 Dovecot 到 2.3+ 以获得 charset_aliases 配置
- 配置 charset_aliases 让 Dovecot 跳过转换
- 移除系统字符集模块作为双重保险
- 代价是 GB18030 邮件可能乱码,但能正常接收