一次 Linux 升级引发的“全员禁登”血案:从 PAM 损坏到 RPM 诡异 ELOOP 报错的深度复盘
最近在一台腾讯云服务器上做例行维护:清理了一批不再使用的历史软件包,顺手升级了基础组件与内核。重启之后,机器网络通畅、业务容器也都在正常跑着,但诡异的事情发生了:无论是 SSH 密钥登录,还是腾讯云控制台的 VNC 账号密码登录,全部被拒绝。
整台机器仿佛变成了一座“看得见却进不去”的孤岛。就在几乎要走挂载救援盘修文件的最坏打算时,腾讯云的 TAT(自动化助手)免密登录通道 成了力挽狂澜的救命稻草。借着这个最后的窗口,展开了一场层层反转的排障。
flowchart TD
A["系统目录与符号链接属主被意外改为普通用户"] --> B["执行 dnf upgrade 升级 pam / glibc / systemd"]
B --> C["systemd 触发安全机制拒绝穿越非 root 路径"]
B --> D["RPM 解包无法穿越符号链接,报 ELOOP"]
C --> E["升级事务中断,半数包卡在中间态"]
D --> E
E --> F["PAM 核心配置丢失,SSH 与 VNC 全部无法登录"]
F --> G["通过腾讯云 TAT 免密通道绕过 PAM 直接拿到 root Shell"]
一、头功一件:为什么 SSH 和 VNC 全挂了,腾讯云 TAT 还能进?
在复盘技术细节之前,必须单独夸一夸腾讯云的 TAT(TencentCloud Automation Tools,自动化助手)。这次能做到不关机、不挂盘、业务零中断在线修复,TAT 居功至伟。
很多人遇到连不上服务器时,第一反应是去点控制台的 VNC 登录。但实际上,VNC 只相当于给机器接了一根虚拟显示器线和键盘,敲入账号密码后,负责校验身份的依然是系统里的 login 进程,底层还是要走 PAM 认证栈。因此一旦 PAM 损坏,SSH 和 VNC 会双双毙命,谁也进不去。
而腾讯云控制台里的“免密登录(OrcaTerm / TAT 通道)”原理完全不同:
- 它是通过预装在系统内的
tat_agent守护进程,以root权限常驻后台并与腾讯云管控端保持长连接。 - 当从控制台发起 TAT 免密连接时,
tat_agent收到指令后直接调用系统底层接口fork + exec派生出一个root身份的 Shell 会话,全程根本不经过sshd、login以及损坏的 PAM 认证栈。
正是这个架构差异,在系统认证体系彻底瘫痪的绝境下,为我们撕开了一道至关重要的原生 root 逃生口。对于云上运维而言,保持 tat_agent 存活,关键时刻真的能救命。
二、第一现场:SSH 服务活着,但谁也进不来
通过腾讯云 TAT 通道拿到 root Shell 后,先确认 sshd 服务状态——进程好端端地跑着,端口也在正常监听。
在机内发起一次带详细调试信息的连接测试:
ssh -vvv -p 22 devuser@127.0.0.1
观察握手过程,主机密钥交换(KEX)完全正常,服务端也正常返回了支持的认证方式,但在提交公钥后立刻被拒:
debug1: Server host key: ssh-ed25519 SHA256:xxxxxx
debug1: Authentications that can continue: publickey,password,keyboard-interactive
debug1: Offering public key: /home/devuser/.ssh/id_ed25519
devuser@127.0.0.1: Permission denied (publickey,password,keyboard-interactive).
公钥、密码、键盘交互三种方式同时失效,结合 VNC 同样无法登录的现象,立刻锁定问题不在 sshd 本身,而在更底层的系统级认证栈——PAM(Pluggable Authentication Modules)。
三、顺藤摸瓜:消失的 PAM 配置文件
去翻 /var/log/secure 认证日志,满屏都在刷同一类报错:
PAM _pam_init_handlers: no default config other
PAM no modules loaded for `systemd-user' service
pam_env(crond:setcred): Configuration file not found: pam_env.conf
pam_access(crond:account): warning: cannot open /etc/security/access.conf: No such file or directory
pam_namespace(systemd-user:session): Error opening config file /etc/security/namespace.conf
直接用 rpm -V 校验 pam 包的完整性,结果让人倒吸一口凉气:
# rpm -V pam
missing c /etc/pam.d/config-util
missing c /etc/pam.d/other
missing c /etc/security/access.conf
missing c /etc/security/faillock.conf
missing c /etc/security/group.conf
missing /etc/security/limits.d
missing c /etc/security/namespace.conf
missing /etc/security/namespace.d
missing c /etc/security/opasswd
missing c /etc/security/pam_env.conf
missing c /etc/security/pwhistory.conf
missing c /etc/security/time.conf
missing /usr/share/pam.d
missing /var/run/faillock
missing /var/run/sepermit
pam 包名下的 15 个核心配置文件与目录不翼而飞。其中最致命的是 /etc/pam.d/other(PAM 的兜底默认配置)以及 /etc/security/ 下的一众模块配置(如 namespace.conf、pam_env.conf)。由于 PAM 栈中将这些模块设为了 required,配置文件一丢,模块初始化直接返回失败,整条认证链当场熔断。
为什么这些文件会丢?翻看 dnf history:
ID | Command line | Date and time | Action(s) | Altered
------------------------------------------------------------------------
105 | upgrade kernel | 2026-10-21 15:58 | Install | 3
101 | autoremove | 2026-10-21 15:42 | Removed | 2
100 | rm php-common | 2026-10-21 15:42 | Removed | 22 EE
97 | upgrade sudo bash glibc | 2026-10-21 15:36 | Upgrade | 23 ##
96 | upgrade openssh | 2026-10-21 15:35 | Upgrade | 3 EE
注意第 97 号事务末尾的 ## 标记,代表事务执行过程中发生了故障。查看该事务详情,glibc 子包升到了新版本,但 glibc 主包、nscd 和 pam 却卡在半路失败了,导致系统处于极度危险的“半升级”撕裂状态:
# dnf check
glibc-2.38-28.x86_64 has missing requires of glibc-common = 2.38-28
glibc-common-2.38-49.2.x86_64 has missing requires of glibc = 2.38-49.2
...
四、柳暗花明又一坑:诡异的 ELOOP 报错
起初为了先恢复 SSH 登录,从另一台同版本正常机器上把 /etc/pam.d/other 和 /etc/security/*.conf 手工拷了回来,SSH 得以临时恢复。
但治标还得治本,glibc 和 pam 的版本撕裂必须通过包管理器拉齐。然而当做好系统盘快照、执行 dnf upgrade 时,真正的拦路虎露出了獠牙:
Running transaction
Upgrading : pam-1.5.3-12.x86_64 1/2
error: failed to open dir run of /var/run/: Too many levels of symbolic links
Error unpacking rpm package pam-1.5.3-12.x86_64
Failed:
pam-1.5.3-4.x86_64 pam-1.5.3-12.x86_64
Error: Transaction failed
升级 nscd 也是如出一辙的报错:
error: failed to open dir run of /var/run/: Too many levels of symbolic links
error: unpacking of archive failed on file /var/run/nscd: cpio: open failed - Too many levels of symbolic links
更要命的是,当 dnf upgrade pam 在解包阶段失败中止时,旧版文件在事务清理阶段又被抹掉了,刚刚手工拷回来的配置文件再次丢失。好在 TAT 会话一直稳稳在线,不至于失联。
五、破案:谁动了我的符号链接属主?
直面这行报错:failed to open dir run of /var/run/: Too many levels of symbolic links(即内核错误码 ELOOP)。
按照常理,ELOOP 意味着符号链接成环(例如 A -> B -> A)。但在终端里用 ls -ld 和 namei -l 反复检查:
/var/run -> ../run (目标 /run 是正常的 tmpfs 目录)
/sbin -> usr/sbin (目标 /usr/sbin 是正常的实体目录)
链接清晰明了,压根没有死循环,用 find 遍历也畅通无阻。为什么偏偏 RPM 解包时就会报 ELOOP?
回头仔细检视系统目录与日志中的异常提示:
Detected unsafe path transition / (owned by devuser) -> /var (owned by root) during canonicalization of var/log.
Detected unsafe path transition /var/lib/tpm2-tss/system (owned by devuser) -> /var/lib/tpm2-tss/system/keystore (owned by tss)
真相大白!问题根本不是“符号链接循环”,而是 系统目录与符号链接的属主(Owner)变成了普通用户 devuser!
为什么属主不对会报 Too many levels of symbolic links?
这是现代 Linux 系统中 systemd 与新版 RPM (4.18+) 为防御本地提权漏洞(CVE)而引入的安全路径穿越保护机制:
- 当以
root运行的rpm或systemd-tmpfiles沿着路径一层层向下打开目录(如/var->/var/run)时,会严格校验父目录与符号链接本身的属主。 - 如果发现某个系统路径节点或符号链接本身属于非特权用户(例如
devuser),攻击者理论上可以在瞬间替换该符号链接指向任意敏感文件,诱骗root进程覆盖写入。 - 为了阻断这种攻击,新版 RPM 在遍历目录树时会拒绝跟随非
root属主的系统符号链接;底层返回拒绝跟随的错误码后,按 POSIX 标准映射出来就是让人摸不着头脑的ELOOP (Too many levels of symbolic links)。
验证这个结论只需一行命令,查找系统目录下属主为普通用户的符号链接:
find /var /etc /usr -maxdepth 3 -type l -user devuser -ls
果不其然,包括 /var/run、/var/lock 在内的一大片核心符号链接,属主全变成了 devuser(早期某次权限变更操作留下的历史隐患,在这次升级时被集中引爆)。
六、一锤定音:修复与全量验证
找到病根后,修复只需要两条命令。注意修改符号链接本身的属主必须加 -h(--no-dereference)参数,否则 chown 会穿透去改目标目录而放过符号链接本身:
# 1. 查找确认所有被污染的符号链接
find /var /etc /usr -maxdepth 3 -type l -user devuser -ls
# 2. 使用 chown -h 批量修正符号链接本身的属主为 root:root
find /var /etc /usr -maxdepth 3 -type l -user devuser -exec chown -h root:root {} +
修正属主后,再次执行此前死活过不去的升级与重装:
dnf upgrade pam nscd -y
dnf reinstall pam nscd -y
没有任何报错,丝滑通过!最后做一轮全套健康检查收尾:
# 1. 校验包依赖是否完全闭合(输出为空即 0 问题)
dnf check
# 2. 校验 pam 与 nscd 文件是否全部归位(输出为 0 即无缺失)
rpm -V pam | grep -c '^missing'
rpm -V nscd | grep -c '^missing'
打开新的终端窗口测试 SSH 密钥登录,秒进;打开腾讯云控制台测试 VNC 密码登录,同样顺利进入系统。至此,故障彻底排除。
七、经验总结
Too many levels of symbolic links不一定是死循环:在rpm/dnf解包或systemd-tmpfiles执行场景下看到这个报错,除了用namei -l查链接环外,第一时间检查路径上每一级目录和符号链接本身的uid:gid是否为root:root。- 警惕对含符号链接目录的递归
chown:在日常运维中,如果在包含/var/run或软链的目录下误执行了chown -R user:group,很容易把系统级符号链接的属主改掉。这个隐患平时不显山露水,一旦遇上glibc、pam、systemd升级就会变成锁死系统的炸弹。 - 善用腾讯云 TAT 与系统盘快照:凡是涉及
glibc、pam、openssh、systemd的大动作前,先打好云硬盘快照兜底;一旦遭遇 PAM 损坏锁死 SSH 与 VNC 的极端情况,第一时间使用腾讯云 TAT(自动化助手)免密通道直接切入底层修复,能省去停机挂盘的巨大折腾。
作者:小李刀刀
原文链接:SSH 与 VNC 双双失联:一次 Linux 升级排障
裁纸刀下版权所有,允许非商业用途转载,转载时请原样转载并标明来源、作者,保留原文链接。