普通用户能修改自己密码靠的是SUID权限位实现的受控临时身份切换,而非直接赋予root权限;/etc/shadow默认权限为000,SUID使passwd以root euid写入该文件,同时用用户ruid校验旧密码,退出即恢复原权限。

普通用户能修改自己密码,靠的不是被赋予 root 权限,而是通过 SUID 权限位 实现受控、临时的身份切换——整个过程不暴露 root shell,也不开放任意文件写入,本质是“最小权限委托”。
为什么必须用 SUID 而不是直接给权限?
/etc/shadow 文件默认权限是 ----------(即 000),连读都不允许,更别说写。如果强行给普通用户写权限,等于把所有用户密码裸露出来,完全破坏系统安全边界。SUID 绕开了这个矛盾:它不改文件权限,而是让特定程序在运行时“穿一次 root 的衣服”,只做一件事——验证旧密码、加密新密码、写入 shadow,做完立刻脱掉。
passwd 命令是怎么工作的?
- 查看权限:
ls -l /usr/bin/passwd显示-rwsr-xr-x,其中属主位的s表示 SUID 已启用,且原执行位(x)存在(所以是小写 s,不是大写 S) - 普通用户执行
passwd时,内核检测到 SUID 位,自动将进程的有效 UID(euid)设为 root(即该文件属主),但真实 UID(ruid)仍是用户自己 - 程序用 euid=root 打开并更新 /etc/shadow;同时用 ruid=用户身份校验旧密码(防止越权修改他人密码)
- 进程退出后,euid 恢复为原值,无残留权限
安全依赖的关键前提
- 仅对二进制可执行文件生效:SUID 对脚本(如 bash、python)无效,避免解释器被滥用
-
执行位必须存在:若 chmod 去掉 x(如变成
-rwSr--r--),SUID 不触发(显示大写 S,实际失效) - 权限最小化:passwd 程序本身由 root 编译、静态链接、无多余功能,不调用外部命令或读取不受控配置
- 系统级防护协同:SELinux 或 AppArmor 可进一步限制 passwd 进程能访问的路径和系统调用
管理员该怎么做才真正安全?
- 定期检查高危 SUID 程序:
find / -perm -4000 -type f 2>/dev/null,确认列表中只有 /usr/bin/passwd、/usr/bin/sudo 等可信程序 - 禁用不必要的 SUID:比如
/usr/bin/chsh或/bin/ping若业务不用,可chmod u-s移除 - 不给编辑器(vim、nano)或 shell 工具设 SUID——这是常见提权入口,毫无必要
- 配合 shadow 密码策略(如
PASS_MAX_DAYS)、PAM 模块(如 pam_pwquality)共同约束密码强度

















