创建权限由请求模式结合进程掩码或继承的默认 ACL 规则确定。

umask 过滤新建权限,默认 ACL 会改变规则

进程的 umask 在普通模式位创建规则下,为新文件和目录移除权限位。应用先提供请求模式,掩码再限制这份请求。它既不是完整访问策略,也不会重写所有既有文件。如果父目录具有默认访问控制列表,创建计算方式还会改变,因此只检查进程掩码,可能无法准确预测最后得到的权限。排查时需要同时看到应用请求和目录环境。 坏掉的样子 没有默认 ACL 时,普通权限结果是请求模式与 umask 按位取反后的值进行按位与。例如请求 0666、掩码 0022,得到 0644。这个计算不是算术减法:相同掩码下请求 0600,仍然得到 0600。应用没有请求执行权限时,宽松掩码也不会主动添加执行位;掩码负责移除,而不是凭空授予应用未请求的普通权限。 限制严格的 umask 不会修复已经存在的全员可写文件。打开并截断该文件,会改变内容,却保留既有模式。后续 chmod 也可以不受当前掩码限制地扩大权限。因此,把 umask 当作权限永远不能超过的上界,会遗漏既有文件与之后权限修改两类情况。必须区分文件首次创建,以及此后围绕同一 inode 发生的操作。 父目录具有默认 ACL 时,Linux 从它派生新对象的访问 ACL,再按应用请求模式限制权限,不再按普通方式应用进程 umask。因此,即使创建者掩码是 0077,共享目录里仍可能生成组可访问文件。遇到与预期不同的模式时,应检查继承的 ACL,而不能只看到严格掩码就断言内核没有遵守权限设置。 快速验证 把脚本保存为 mask.py,在安装 Python 3 和 setfacl 的 Linux 环境中运行 python3 mask.py。临时目录所在文件系统必须支持默认 ACL。实测使用 Python 3.11.2、acl 2.3.1,以及通过 TMPDIR 选择的独立 ext4 卷。最初 tmpfs 环境拒绝设置默认 ACL,因此完整实验随后在 ext4 上重新执行: ...

十月 9, 2027 · 2 分钟 · XB Field Notes
一个小工具带着属主的身份运行,换来一点集中的能力。

Setuid 已属主身份运行

setuid 二进制以文件属主的身份运行,而不是以启动它的人的身份。内核在 exec 时刻替换凭据,passwd 因此能在普通用户并不拥有 /etc/shadow 写权限的情况下改写它。这个位属于文件,而它交出去的是属主的整个身份,不是某一项窄权限。 故意做这种交换是件奇怪的事:你等于把一整个账户托付给一个程序,于是程序里任何一处缺陷都会变成提权缺陷。何况这套机制会在好几种有据可查的情况下静默失效,而 capabilities、用户命名空间与 socket 激活,今天已经覆盖了 setuid 原本的大部分用途。真正值得问的,往往不是「怎么把这个程序写对」,而是「这件事能不能不要 setuid」。 身份跟着文件走 execve(2) 把规则写得很直白:若程序文件上设置了 set-user-ID 位,调用进程的有效用户 ID 就变为该文件属主的 ID。真实 UID 与真实 GID 保持不变,新的有效 UID 随后被复制进 saved set-user-ID。真实、有效、保存这三份凭据,就是这套机制的全部。 这些位在程序跑起来之前就能看到:stat 显示 /usr/bin/sudo 的模式是 4511(-r-s--x--x)、/usr/bin/su 是 4755,两者属主都是 uid 0,而 /usr/bin/passwd 只是普通的 0755。哪些二进制带这个位,是每台机器各自的部署事实,只能去读,不能假设。 ...

十月 2, 2027 · 2 分钟 · XB Field Notes
sticky 保护其他所有者的目录项,内容访问仍由文件权限决定。

sticky bit 限制共享目录中的删除操作

Linux 目录上的 sticky bit,为删除或重命名目录项增加所有权限制。它常与宽松的目录写入、搜索权限一起使用,让多个用户能够创建临时文件,又不能任意删除彼此的条目。普通目录权限检查和 sticky 所有权检查都需要满足;sticky 是额外条件,不会替代正常访问控制,也不能只凭这一位判断整个目录里的数据是否安全。 坏掉的样子 没有 sticky 时,用户只要具备目录所需的写入与搜索权限,通常就能删除另一个用户的文件,即使文件模式完全不允许内容访问。unlink 改变的是目录里的名字与对象关系,不要求调用者能够读取或覆盖文件内容。因此,在广泛可写目录中把文件设为 000,并不能单独保护该路径不被他人删除;应分别检查父目录和文件自身的规则。 启用 sticky 后,普通用户还需要拥有该条目或包含它的目录,才能执行相关删除。具有适当 CAP_FOWNER 能力的特权进程,可以绕过这项所有权限制。因此 sticky 约束的是具体权限模型下的同级用户,并不抵御所有管理员,也不保护文件免受目录所有者删除。把它描述为绝对隔离,会夸大真实保证。 sticky 不阻止本来被允许的内容访问。一个用户可能无法 unlink 某个 0666 文件,却仍然可以读取或覆盖它。新建子目录也不会自动继承父目录的 sticky 位。混淆路径保护、内容隐私和继承,会让共享目录树表现出与顶层看起来完全不同的行为,需要沿实际数据位置检查,而不是只看根部权限字符串。 快速验证 把脚本保存为 sticky.py,在一次性 Linux 容器中以 root 运行 python3 sticky.py。控制进程需要分配三个数字身份并启动普通子进程的权限,不会创建账号。实测使用 Linux 6.12.76 和 Python 3.11.2,所有操作都发生在临时样本目录内: ...

十月 1, 2027 · 2 分钟 · XB Field Notes