| 核心结论 | 细节 |
|---|---|
| SUID 改变进程有效用户 | 普通用户执行带 SUID 的二进制程序时,进程临时获得该程序属主权限,典型例子是 /usr/bin/passwd |
| SGID 对文件和目录含义不同 | 用在可执行文件上改变有效组;用在目录上让新建文件继承目录属组 |
| Sticky Bit 主要用于公共可写目录 | 目录可写不代表可以删除别人文件,带 t 后只有文件属主、目录属主、root 可以删除或重命名 |
1777 比 777 更安全 | 1777 没有增加写权限,而是在 777 基础上收缩删除/重命名权限 |
| 大写 S/T 通常表示缺少执行位 | rwS、rwT 说明特殊权限位存在,但对应 x 位不存在,通常不是预期结果 |
1.简介
在 Kubernetes 中部署 MariaDB 时,挂载 local-storage 后 binlog 目录曾出现权限不足。目录已设置 777,后续通过 chmod 1777 binlog/ 处理。
从权限模型看,1777 不会比 777 增加写权限,只是额外开启 Sticky Bit。因此这类问题不能只看 rwx,还需要区分特殊权限、运行用户、UID/GID、挂载参数、SELinux/AppArmor 等因素。
这类问题容易暴露一个误区:Linux 权限不只有 rwx,还存在三类特殊权限:
SUIDSGIDSticky Bit,也就是常见的t权限
需要注意的是,1777 中真正改变的是 Sticky Bit,它主要限制公共目录中文件的删除行为,不负责解决所有写入权限问题。
2.说明
2.1 特殊权限总览
| 权限 | 数字位 | 显示位置 | 常见对象 | 核心作用 |
|---|---|---|---|---|
| SUID | 4 | 用户执行位 | 可执行二进制文件 | 执行进程临时拥有文件属主权限 |
| SGID | 2 | 组执行位 | 可执行二进制文件、目录 | 文件:进程临时拥有文件属组权限;目录:新文件继承目录属组 |
| Sticky Bit | 1 | 其他用户执行位 | 目录 | 公共可写目录中,限制删除/重命名他人文件 |
权限显示位置如下:
| 普通权限 | 特殊权限 | 说明 |
|---|---|---|
-rwxr-xr-x | -rwsr-xr-x | SUID,占用用户执行位 |
-rwxr-xr-x | -rwxr-sr-x | SGID,占用组执行位 |
drwxrwxrwx | drwxrwxrwt | Sticky Bit,占用其他用户执行位 |
user/group/other 的执行位显示位置。因此 s/t 与 x 的关系必须一起看。2.2 SUID:执行程序时临时获得文件属主权限
SUID 全称是 Set UID。
它的作用是:普通用户执行某个带 SUID 的可执行程序时,该进程的有效用户 ID 会变成这个程序的属主。
典型例子是 /usr/bin/passwd。
普通用户没有权限直接写 /etc/shadow:
| |
但普通用户可以执行 passwd 修改自己的密码,因为 /usr/bin/passwd 带 SUID:
| |
关键点:
passwd属主是root;- 权限是
4755,用户执行位显示为s; - 普通用户执行
passwd时,进程临时具备root权限; passwd程序内部再按规则修改/etc/shadow。
安全风险:
- SUID 程序如果属主是
root,相当于给普通用户开放了一条受控提权路径; - 如果程序存在命令注入、路径劫持、越权读写等问题,容易变成提权漏洞;
- 不建议随意给自写程序设置 SUID root。
限制:
- SUID 主要用于可执行二进制文件;
- 不建议依赖 SUID shell 脚本实现提权,Linux 出于安全原因通常会忽略脚本文件上的 SUID 位;
- 脚本内部调用的命令是否提权,取决于被调用的二进制程序自身权限,而不是脚本文件权限。
2.3 SGID:文件看执行组,目录看继承组
SGID 全称是 Set GID。
它有两种常见用法。
2.3.1 用在可执行文件上
如果 SGID 设置在可执行文件上,用户执行该程序时,进程的有效组会变成该文件的属组。
典型例子是 plocate:
| |
说明:
/var/lib/plocate/plocate.db属组是plocate,普通用户不能直接读取;/usr/bin/plocate带 SGID,属组也是plocate;- 普通用户执行
plocate时,进程临时获得plocate组权限; - 因此程序可以读取
plocate.db。
2.3.2 用在目录上
如果 SGID 设置在目录上,用户在该目录下新建文件时,文件属组会继承目录属组,而不是用户当前默认组。
适用场景:多人协作目录。
| |
效果:
| |
后续任何有写权限的用户在 /data/project 下创建文件,新文件属组都会是 dev。
常见用途:
- 团队共享目录;
- 应用日志目录;
- 需要保持统一属组的构建产物目录。
2.4 Sticky Bit:公共目录中只能删除自己的文件
Sticky Bit 主要用于目录,对普通文件基本没有实际意义。
它解决的问题是:目录对所有人可写时,如何防止用户删除别人的文件。
典型例子是 /tmp:
| |
/tmp 是 1777:
777:所有用户都可以进入、创建、修改自己有权限的文件;1:开启 Sticky Bit;t:显示在 other 的执行位上。
开启 Sticky Bit 后,目录中的文件只能由以下用户删除或重命名:
- 文件属主;
- 目录属主;
- root。
验证示例:
| |
普通用户尝试删除 root 创建的文件:
| |
即使文件本身是 666,由于目录启用了 Sticky Bit,普通用户也不能删除不属于自己的文件。
2.5 设置和移除特殊权限
数字方式是在普通三位权限前再加一位:
| 数字 | 含义 | 常见程度 |
|---|---|---|
| 0 | 无特殊权限 | 默认 |
| 1 | Sticky Bit | 常见,典型如 /tmp 的 1777 |
| 2 | SGID | 常见,典型如共享目录的 2775 |
| 3 | SGID + Sticky Bit | 较少,用于既要继承属组、又要限制删除的共享目录 |
| 4 | SUID | 常见,典型如 /usr/bin/passwd 的 4755 |
| 5 | SUID + Sticky Bit | 罕见,实际很少使用 |
| 6 | SUID + SGID | 较少,同时改变有效用户和有效组 |
| 7 | SUID + SGID + Sticky Bit | 罕见,不建议无明确原因使用 |
常用命令:
| 操作 | 数字方式 | 符号方式 |
|---|---|---|
| 设置 SUID | chmod 4755 <file> | chmod u+s <file> |
| 移除 SUID | - | chmod u-s <file> |
| 设置 SGID 文件 | chmod 2755 <file> | chmod g+s <file> |
| 设置 SGID 目录 | chmod 2775 <dir> | chmod g+s <dir> |
| 移除 SGID | - | chmod g-s <file-or-dir> |
| 设置 Sticky Bit | chmod 1777 <dir> | chmod o+t <dir> |
| 移除 Sticky Bit | - | chmod o-t <dir> |
举例:
| |
不建议对不明确来源的程序执行:
| |
2.6 大写 S 与大写 T
chmod 不会判断特殊权限是否合理。即使没有执行位,也可以设置 s/t。
示例:
| |
结果:
| |
S 为大写,原因是用户执行位没有 x。
规则如下:
| 显示 | 条件 | 说明 |
|---|---|---|
s | SUID/SGID + 对应执行位存在 | 特殊权限位存在,执行位也存在 |
S | SUID/SGID 存在,但对应执行位不存在 | 通常不是预期结果 |
t | Sticky Bit + other 执行位存在 | 公共目录常见显示 |
T | Sticky Bit 存在,但 other 执行位不存在 | 目录无法被 other 进入,通常不是预期结果 |
总结:
- 小写
s/t:对应x位存在; - 大写
S/T:对应x位不存在; - 大写通常表示权限设置不完整,需要重点检查。
2.7 K8s / Docker 场景:为什么 MariaDB 卷挂载会遇到权限问题
容器挂载宿主机目录时,权限判断仍然发生在 Linux 文件系统层面。常见问题不是 MariaDB 特有,而是容器 UID/GID 与宿主机目录权限不匹配。
以 MariaDB 为例:
- 容器内数据库进程通常不是 root,而是
mysql用户; - 宿主机目录经常由 root 创建,例如
root:root; - MariaDB 数据目录、binlog 目录需要创建文件、重命名文件、轮转日志、清理旧 binlog;
- 如果目录属主、属组、SELinux/AppArmor、挂载参数不匹配,就会出现
Permission denied、初始化失败、binlog 创建失败等问题。
这里需要区分两件事:
| 权限 | 能力 | 说明 |
|---|---|---|
777 | 所有人可读、可写、可进入目录 | 允许任意用户创建、删除、重命名目录中的文件 |
1777 | 所有人可读、可写、可进入目录,但删除受限 | 只有文件属主、目录属主、root 可以删除或重命名文件 |
1777 不是比 777 放大权限,而是在 777 的基础上开启 Sticky Bit,收缩删除/重命名权限。它更安全,不是更宽松。对于 MariaDB binlog 目录,1777 的价值主要在保护删除行为:
- MariaDB 可以创建、轮转、清理自己生成的 binlog;
- 其他同样具备目录写权限的进程,不能随意删除 MariaDB 创建的 binlog;
- 多容器、initContainer、运维脚本共用挂载目录时,可以降低误删风险。
需要注意的是,如果问题是“无法写入”,1777 本身不比 777 多提供写权限。真正需要检查的是:
- 容器进程运行 UID/GID;
- 宿主机目录属主和属组;
- K8s
securityContext; - 挂载是否只读;
- SELinux/AppArmor 是否拦截。
K8s 中更推荐的处理方式:runAsUser / runAsGroup / fsGroup / initContainer
方式一:显式声明运行用户和卷属组
Kubernetes 官方推荐通过 securityContext 控制容器进程身份。常用字段:
| 字段 | 作用 |
|---|---|
runAsUser | 指定容器主进程使用哪个 UID 运行 |
runAsGroup | 指定容器主进程使用哪个 GID 运行 |
fsGroup | 挂载卷中文件系统对象补充属组,便于进程通过组权限访问卷 |
关键配置示例,UID/GID 需要以镜像内 id mysql 的实际结果为准:
| |
这种方式比直接 chmod 777 更适合生产环境。
方式二:initContainer 初始化目录权限
如果使用 hostPath 或 local-storage,宿主机目录可能提前由 root 创建。可以用 initContainer 在数据库启动前修正目录权限。
| |
说明:
- 数据目录建议使用
770或750,不要无脑777; - binlog 如果是共享可写目录,可以使用
1777收缩删除权限; - 如果目录只被 MariaDB 单实例使用,更推荐
chown mysql:mysql+750/770; hostPath依赖宿主机路径和权限,不建议作为数据库生产存储首选。
方式三:排查是否为 SELinux / 只读挂载
如果 chmod 777 后仍然报 Permission denied,需要确认不是 Linux DAC 权限之外的问题。
| |
重点检查:
volumeMounts.readOnly是否为true;- PV/PVC 是否只读挂载;
- 节点是否启用 SELinux;
- 容器是否被 AppArmor/seccomp 限制;
- 存储插件是否支持
fsGroup。
Docker run / docker compose 场景
Docker bind mount 会把宿主机目录直接挂进容器。目录属主、属组、权限仍以宿主机文件系统为准。
| |
启动示例:
| |
如果宿主机启用 SELinux,Docker bind mount 还可能需要 :z 或 :Z:
| |
需要注意:
:z表示该目录可被多个容器共享;:Z表示该目录私有给当前容器;- 不要对系统关键目录随意使用
:Z,可能影响宿主机文件标签。
2.8 对比表
| 对比项 | SUID | SGID | Sticky Bit |
|---|---|---|---|
| 数字位 | 4 | 2 | 1 |
| 常见权限 | 4755 | 2755 / 2775 | 1777 |
| 显示样例 | -rwsr-xr-x | -rwxr-sr-x / drwxrwsr-x | drwxrwxrwt |
| 常见对象 | 可执行二进制文件 | 可执行二进制文件、目录 | 目录 |
| 文件效果 | 执行时使用文件属主身份 | 执行时使用文件属组身份 | 基本无意义 |
| 目录效果 | 通常无意义 | 新建文件继承目录属组 | 限制删除/重命名他人文件 |
| 典型场景 | /usr/bin/passwd | 共享目录、plocate | /tmp、公共缓存目录 |
| 风险点 | 提权风险最高 | 组权限扩大 | 误以为解决读写权限,实际只限制删除 |
3.总结
SUID用于可执行二进制文件,核心是让进程临时拥有文件属主权限,典型场景是普通用户通过passwd修改自己的密码;SGID用在文件上表示执行进程临时拥有文件属组权限,用在目录上表示新建文件继承目录属组;Sticky Bit主要用于公共可写目录,目录中只有文件属主、目录属主、root 可以删除或重命名文件;chmod 1777 <dir>中的1不是增加写权限,而是在777基础上收缩删除/重命名权限,因此比777更安全;- K8s / Docker 挂载 MariaDB 卷时,优先检查 UID/GID、
fsGroup、runAsUser、挂载只读、SELinux/AppArmor,不建议把777当成长期方案; - 看到大写
S/T时,需要检查对应执行位是否缺失,这通常不是预期权限配置。
4.参考
[注1]: 鸟哥-特殊权限SUID说明
[注2]: 鸟哥-常见指令需要的基本权限