Linux setuid 与 setgid 机制详解

3次阅读

setuid通过将进程有效uid临时设为文件所有者uid(如root)实现权限提升,仅限可执行文件生效;setgid对文件改进程有效gid,对目录则使新文件继承目录所属组;权限数字中4为setuid、2为setgid,不可随意叠加,且上线前须严格审查必要性、依赖安全与环境变量清理。

Linux setuid 与 setgid 机制详解

setuid 是怎么让普通用户临时变 root 的

它不改变你的登录身份,只在执行那个程序的瞬间,把进程的 effective UID 换成文件所有者的 UID。比如 /usr/bin/passwd 属于 root、带 setuid,你一运行它,内核就悄悄把当前进程的 eUID 设为 0(root),所以它能写 /etc/shadow;但你一退出,权限立刻还原。

  • 必须是可执行文件(chmod +x 后才能设 setuid),对脚本(如 .sh)基本无效——多数 shell 会主动忽略,防止绕过安全限制
  • 设置命令是 chmod u+s /path/to/executable,或数字写法 chmod 4755 /path/to/executable
  • 检查是否生效:用 ls -l 看所有者 x 位变成 s(如 -rwsr-xr-x),不是 S(大写说明 x 权限没开,setuid 不起作用)

setgid 对目录和文件的作用完全不同

同一个 setgid 标志,在文件和目录上干的是两件事,这点特别容易混淆。

  • 对可执行文件:和 setuid 类似,只是改的是进程的 effective GID,比如 /usr/bin/mlocate 属于 slocate 组,设了 setgid 就能读 /var/lib/mlocate/mlocate.db
  • 对目录:这才是它最常用的地方——新创建的文件/子目录自动继承该目录的所属组,而不是创建者默认的 primary group。命令是 chmod g+s /shared/dir
  • 验证目录是否生效:新建一个文件,用 ls -l 看它的 group 是否和目录一致;如果 group 名显示为 ? 或报错,说明组 ID 已被删除,setgid 仍存在但实际失效

为什么 chmod 2755 和 4755 不能混着用

数字权限里,4setuid2setgid1 是 sticky bit。它们可以叠加,但含义不会叠加——比如 6755(4+2)同时开了 setuidsetgid,但普通文件极少需要两者都开。

  • 4755 → 所有者有 setuid,组和其他人有 r-x
  • 2755 → 所属组有 setgid,所有人有 r-x(常用于共享目录的父目录)
  • 错误做法:chmod 6755 给一个普通工具程序,既没意义又增加攻击面;chmod 4777 更危险——等同于“任何人执行都变 root”,严重违反最小权限原则

setuid/setgid 程序上线前必须检查的三件事

它们本质是权限提升通道,一旦程序有漏洞(比如路径注入、缓冲区溢出),攻击者就能直接拿到高权限。生产环境部署前务必确认:

  • 程序是否真的必须用 root 或特定组权限?能否用 capabilities(如 cap_net_bind_service)替代?
  • 二进制是否静态链接、无外部依赖?动态加载的库若被劫持(如 LD_PRELOAD),setuid 程序会直接执行恶意代码
  • 程序是否清除了敏感环境变量?比如 setuid 程序启动时应调用 unsetenv("LD_LIBRARY_PATH") 等,glibc 默认会忽略大多数环境变量,但并非全部

别只盯着权限位有没有加对,真正决定安全边界的,是那个二进制本身干了什么、信任了什么、又忽略了什么。

text=ZqhQzanResources