sudo 权限唯一来自 /etc/sudoers,按行匹配用户、主机、目标身份、命令四要素,首条匹配即生效;验证的是用户自身密码(PAM),非 root 密码;执行时以 root 身份调用 seteuid 切换有效 UID,环境变量默认被清理。

sudo 是怎么知道谁有权限的?
sudo 的权限来源只有一个地方:/etc/sudoers。它不是读取用户组(比如 sudo 或 wheel)就直接放行,而是严格按该文件里定义的规则逐行匹配:用户、来源主机、可切换身份、允许执行的命令——四者全对才通过。哪怕你被加进了 %sudo 组,如果那一行被注释了或写在了拒绝规则后面,照样被拒。
- 永远用
visudo编辑/etc/sudoers,它会语法检查,避免锁死 sudo - 规则顺序很重要:sudo 从上到下匹配,遇到第一条匹配即停止,不会继续找“更精确”的
-
ALL=(ALL:ALL) ALL看似宽松,但若前面有user1 ALL=(root) /bin/ls,user1 就只能跑ls,后面的 ALL 不生效
为什么输的是自己的密码,而不是 root 的?
因为 sudo 的设计哲学是「验证操作者身份」,不是「获取 root 账户凭证」。它要求你证明“此刻坐在终端前的就是你本人”,所以校验的是你的用户密码(由 PAM 模块完成),而非 root 密码。这也是它比 su 更安全的基础——root 密码无需暴露给普通用户。
- 若配置了
NOPASSWD,这一步直接跳过,但仅限于规则中明确列出的命令 - 密码错误三次后,sudo 默认会记录日志并可能触发告警(取决于
/etc/sudoers中的badpass_message或 syslog 配置) - 输入密码时屏幕不显示任何字符(包括
*),这是故意的安全行为,不是卡住了
执行命令时,权限到底怎么切换的?
sudo 并不启动新 shell 再 setuid,而是自身以 root 权限运行,fork 出子进程后,在子进程中调用 seteuid() 和 setegid() 切换有效 UID/GID,再 execve() 执行目标命令。这意味着:命令看到的 geteuid() 是 root,但 getuid() 仍是原用户——部分程序(如某些脚本检测)会据此判断是否“真 root”。
-
环境变量默认被清理,
PATH重设为secure_path(在/etc/sudoers中定义),所以sudo myscript.sh可能报command not found,即使myscript.sh在你 home 下 - 要用当前环境变量,得加
-E;要完整继承 shell 环境(含 alias、函数),得用sudo -i或sudo -s -
sudo -u user2 cmd时,实际是以 root 身份调用seteuid(user2),不是先 su 到 user2 再执行——所以 user2 的 shell 配置文件(如~user2/.bashrc)不会自动加载
为什么有时输完密码还提示“不在 sudoers 文件中”?
这不是权限不足,而是根本没被授权——sudo 在解析 /etc/sudoers 时,连你的用户名都没匹配上任何一条规则。常见原因不是漏加用户,而是:用户属于 %sudo 组,但该组那行被注释了;或用了 Defaults requiretty,而你在非 tty 环境(如 cron、SSH 无 PTY)下调用 sudo;又或者系统用的是 wheel 组策略(如 CentOS),但你被加进了 sudo 组。
- 快速自查:运行
sudo -l,如果直接报错“not in sudoers file”,说明零授权;如果列出了命令,说明有权限但可能受限 - 别手动改
/etc/sudoers权限(如chmod u+w),现代发行版多启用sudoers.d目录,推荐把自定义规则放进/etc/sudoers.d/myrule并保持 0440 权限 - SELinux 或 AppArmor 启用时,还可能拦截 sudo 行为,此时
dmesg | grep avc会看到拒绝日志










