☰
新建的文件为什么是 644:umask 减掉了哪几位
2026/10/27 7:59:09 网站建设 项目流程

授权与合规声明
本文全部操作对象均为自建隔离靶场(本机容器或隔离虚拟机),涉及安全测试的环节必须以取得合法授权为前提。未经授权的渗透测试违反《中华人民共和国网络安全法》与《刑法》相关条款,须承担相应法律责任。本文只讲环境配置、版本对照与靶场隔离,不含任何攻击步骤、利用载荷与绕过手法,请勿将文中环境指向任何非自有系统。

一、没设过的权限是从哪来的

1.1 一个上传目录的现场

靶场里有个上传目录,部署时用普通账号把代码和目录一起拷上去,跑起来之后,上传接口一直报写入失败。

第一反应是查权限。ls -ld看目录,drwxr-xr-x,属主是部署账号。再看目录里已有的文件,清一色-rw-r--r--,属主也是部署账号。而服务进程跑在另一个账号下,对644的文件没有写权限,对755的目录也没有写权限——755只给了「读」和「进入」,没给「新建」。

到这一步问题其实已经清楚了:目录的属主不对,服务进程不是属主,落在 other 那一档,只有r-x。修法是把属主或属组调对,再按需给组写权限。

但更值得追问的是另一件事。这个目录从建出来到现在,没有人执行过chmod,部署脚本里也没有。那么644和755这两个数字,到底是谁定的?

1.2 权限不是被谁设过,是创建那一刻算出来的

多数人对权限的印象是「设出来的」:要什么权限,就chmod成什么。这个印象在修改已有文件时成立,在新建时完全不成立。

新建一个文件或目录,权限是当场算出来的,有三个参与者。

第一个是调用方给的起始 mode。open()创建普通文件时通常传0666,mkdir()建目录时通常传0777。这两个数字本身已经是「收着写」的结果:0666里没有 x,因为新建的普通文件默认不该可执行;0777是目录的满值,三位全开。

第二个是进程的文件模式创建掩码(file mode creation mask),也就是 umask。它是进程级的属性,跟着进程走,也被子进程继承。

第三个是内核,按一条固定规则把前两者合起来,算出最终权限。

chmod改的是第三条的结果,改不动前两条。所以「没人chmod过,权限却是 644」这件事一点也不奇怪:根本没轮到chmod出场。

1.3 三个数字的来路

把常见的几个新建动作摆在一起,规律就出来了。

新建什么谁在建起始 mode常见掩码结果
普通文件open()、creat()、shell 的touch0666022644,rw-r--r--
目录mkdir()、mkdir -p0777022755,rwxr-xr-x
命名管道mkfifo()、mkfifo0666022644,prw-r--r--

这张表里,「常见掩码」这一列是唯一会变的一列。起始 mode 由程序写死,结果由掩码决定。同一台机器上,两个不同的服务各自建出来的目录权限不一样,差别通常就在这一列。

要想复现现场,先把这三样东西读出来。

⚠️代码待验证

# 路径与账号名按各自部署替换ls-ld/srv/www/uploadls-l/srv/www/uploadidwww-dataps-ouser=-p"$(pgrep-f'nginx: worker'|head-1)"

四行分别回答四个问题:目录权限和属主是谁、里面已有文件的权限是什么、服务账号属于哪些组、服务进程实际以谁的身份在跑。这四行里有任何一行是猜的,后面的结论都不作数。

本章可以带走的一句:新建时的权限是「起始 mode」被掩码清位算出来的,不是谁设的;chmod只改结果,不改这条算式。

二、umask 的语义:置 1 的位被清掉

2.1 POSIX 的那一句

关于 umask 的语义,POSIX 只有一句话,但足够定案:

「Bit positions that are set in cmask are cleared in the mode of the created file.」

这句话出自 POSIX.1-2017 的umask(),描述段。

逐字读:在 cmask 里被 set(置 1)的位,会在创建出来的文件的 mode 里被 cleared(清掉)。主语是 cmask,也就是调用方传进来的掩码;动作是清除;受影响的位,是「创建出来的文件的 mode」。

所以umask 022的意思不是「给 group 和 other 设成r-x」,而是「把 group 的 w 位和 other 的 w 位清掉」。这两句话在 022 这一组值上恰好指向同一个结果,但它们是两回事,换一组值就分道扬镳了。

举个能立刻分辨的例子。起始 mode 是0666,掩码022:清掉两个 w,剩644。起始 mode 是0644,掩码还是022:那两个 w 本来就不在,清等于没清,结果仍是644。如果 umask 是「赋权」,0644起手就该被拉高成别的样子;它没有。它只会做减法。

这个区分不是文字游戏。把它当成「赋权」的人,会自然推出两个错误结论:一是以为umask 000等于「给所有人全部权限」,其实它只是「什么都不清」,最终拿到多少还得看起始 mode;二是以为「换个小一点的 umask 就能把权限加上去」,而实际上掩码只能让结果变小或不变,永远变不大。

2.2 用位图看清 022 到底做了什么

九位上,掩码里的 1 表示「这一位我不要」,0 表示「这一位我不动」。

位八进制权值022的这一位含义
user r04000不动
user w02000不动
user x01000不动
group r00400不动
group w00201清掉
group x00100不动
other r00040不动
other w00021清掉
other x00010不动

022 展开成二进制是三组000 010 010,1 正好落在 group w 和 other w 两位上。user 那三位全是 0,所以 022 对属主权限一点影响都没有——这就是为什么umask 022之后,属主拿到的还是rwx或rw-。

这张表还能顺手解释一个常见困惑:为什么 022 下新建的目录是755而不是744。因为掩码只清 w,不清 x,而0777起手的目录三位 x 都在,清完 w 之后 x 原样保留。

顺着这张表往下推,077、027、007这些值分别清哪几位,也就一目了然了。077清掉 group 与 other 的全部六位;027清 group 的 w 和 other 的三位;007只清 other 的三位。

2.3 特殊位:S_ISVTX被忽略,其余不归 POSIX 管

截至 2026-10-26,POSIX 的umask()页面已经更新到 Issue 8(IEEE Std 1003.1-2024)的措辞,句子本身有微调,把「Bit positions」改成了「Permission bit positions」:

「Permission bit positions that are set in cmask are cleared in the mode of the created file.」

同一版还补了一句关于特殊位的处理:

「Only the file permission bits of cmask (see <sys/stat.h>) shall be used; the S_ISVTX bit shall be ignored, and the meaning of the other bits is implementation-defined.」

这句话要按字面读。S_ISVTX这一位在 cmask 里是被忽略的;除了它之外的其他非权限位,语义是implementation-defined(由实现自定)。返回值那一侧也补了一句:返回的旧掩码里,S_ISVTX位是清零的。

由此得出一个很实用的边界:不要指望用 umask 去设 setuid、setgid 或 sticky 这类位。它不表达这些位。POSIX 只保证「九个权限位会被清」,对特殊位要么明确忽略,要么交给实现自定——这不是一条能写进部署脚本的规则。

本章可以带走的一句:umask 只会清位,不会给位;它管的是九个权限位,特殊位不在其中。

三、生效范围:哪些调用受它管

3.1 一份清单,出自 POSIX

POSIX 没有含糊其辞,它直接列了清单:

「The file mode creation mask of the process is used to turn off permission bits in the mode argument supplied during calls to the following functions: open(), openat(), creat(), mkdir(), mkdirat(), mkfifo(), and mkfifoat()」

后面还另列了 XSI 选做部分的mknod()、mknodat(),以及消息队列与信号量选做部分的mq_open()、sem_open()。

函数干什么起始 mode 常见值
open()/openat()带O_CREAT时创建普通文件0666
creat()创建或截断一个文件0666
mkdir()/mkdirat()创建目录0777
mkfifo()/mkfifoat()创建命名管道0666
mknod()/mknodat()(XSI)创建设备节点等特殊文件视类型而定
mq_open()/sem_open()(可选)POSIX 消息队列、信号量视实现而定

清单是穷举式的,这一点很重要。不在清单里的操作,不受 umask 约束。最典型的对照是chmod:它改的是已经存在的 inode,这时候掩码早就退场了,改成什么就是什么,不会再被清一遍。

「改了chmod却不生效」这类现象,原因在别处,不在 umask;本篇不展开,只把边界划清:umask 只在创建那一刻起作用,之后再也不参与。

清单还有一个容易漏掉的推论。mkdir -p一次建出多层目录时,每一层都是在创建那一刻各自算一遍掩码,算完就定了;如果某一层已经存在,那一层根本不参与计算——既不重建,也不顺手改权限。所以「用mkdir -p补齐目录结构」这件事,结果取决于每一层是新是旧,不能假设最终状态整齐划一。

3.2 open() 的原文:与掩码的补集做按位与

清单只说了「哪些函数受影响」,具体怎么算,要看open()的描述:

「the access permission bits (see <sys/stat.h>) of the file mode shall be set to the value of the argument following the oflag argument taken as type mode_t modified as follows: a bitwise AND is performed on the file-mode bits and the corresponding bits in the complement of the process’ file mode creation mask. Thus, all bits in the file mode whose corresponding bit in the file mode creation mask is set are cleared.」

三个动作,按顺序:取 mode 参数里的权限位;取掩码的补集;两者按位与。

「补集」这个词在二进制上就是逐位取反:1 变 0,0 变 1。掩码022的补集,在那九位上就是「除了 group w 和 other w 之外全开」。拿 mode 去和它按位与,效果就是掩码里为 1 的位置被抹掉。

后半句是第一句的白话版:「Thus, all bits in the file mode whose corresponding bit in the file mode creation mask is set are cleared.」——mode 里那些「掩码对应位为 1」的位,全被清掉。两句话说的是同一件事,方向都是清,不是给。

0666 & ~022这个写法,就是这句话的直译。~是补集,&是按位与。

3.3 mkdir() 没有豁免

有人以为目录是特殊的,比如「目录必须有 x,所以 umask 对目录不生效」。mkdir()的描述把这条路堵死了:

「The file permission bits of the new directory shall be initialized from mode. These file permission bits of the mode argument shall be modified by the process’ file creation mask.」

从 mode 初始化,再被掩码修改。两句和open()一个套路,没有「目录除外」这一条。

所以777 & ~022 = 755与666 & ~022 = 644是同一个规则的两个实例,区别只在起始 mode。目录确实需要 x 才能进入,但那是目录搜索权限的要求,不是 umask 加上去的——umask 在这里只是没把 x 清掉而已。这两件事经常被混成一句「umask 保证目录可进入」,那是错的:umask 077出来的目录是700,属主能进,别人进不去,umask 一点都没打算「保证可进入」。

本章可以带走的一句:受 umask 约束的是一份明确的函数清单,清单外的操作不受影响;目录和文件走同一条规则,只是起始 mode 不同。

四、0666 & ~022 = 0644:这条等式就写在原文里

4.1 man-pages 自己算了一遍

上面那条等式不是我推的,Linux man-pages 的umask(2)自己写了一遍,还带上前提:

「The typical default value for the process umask is S_IWGRP | S_IWOTH (octal 022). In the usual case where the mode argument to open(2) is specified as: S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (octal 0666) when creating a new file, the permissions on the resulting file will be: S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH (because 0666 & ~022 = 0644; i.e., rw-r–r–).」

这段话里有三处需要咬住。

第一处是typical default。原文说的是「典型的默认值」,不是「规定的默认值」。所以正确的说法是「常见默认 022」,不是「Linux 规定 022」。这个区别有实际后果:容器镜像、systemd 单元、某些服务的启动脚本,都可能把掩码改成别的值,而你如果相信「规定就是 022」,就会在一次排查里绕远路。

至于某个发行版的登录 shell 究竟从哪个文件读到 022,本篇不给结论——不同发行版、不同 shell 的配置来源不一样,这一点需要查各自文档,本条待验证。

第二处是括号里的because 0666 & ~022 = 0644。这是原文里的等式,可以照抄,也可以当作验算的锚点。

第三处是结尾的i.e., rw-r--r--。原文把八进制和符号写法并排放在一起,等于替你把「数字 → 位 → 可读形式」这条链走完了一遍。

4.2 目录从 0777 起算

同一条规则,换个起始 mode 就是目录的答案:777 & ~022 = 755。

为什么目录起始是0777而不是0666?因为目录的 x 位不是「执行」,是「进入/搜索」,没有它连目录里的文件名都列不出来。所以目录的满值是三位全开,再由掩码去清。

把两组起始 mode 和两组掩码交叉起来,四个结果一次看全:

起始 mode掩码结果符号形式典型场景
0666022644rw-r--r--普通文件,常见默认
0666077600rw-------私钥、凭据文件
0777022755rwxr-xr-x站点目录、可执行目录
0777077700rwx------只给属主用的私有目录

这张表的用法是反过来查:先看结果不对,再问「起始 mode 是多少、掩码是多少」,两个变量里改哪一个,答案不一样。改起始 mode 要动代码或命令参数,改掩码只需在创建前设一次。

再补一格,用来验算 7.1 那张场景表:777 & ~027 = 750。022 到 027 看着只差一位,实际把 other 的 r 和 x 也一起清掉了,于是 other 那一档从r-x变成---,目录从755掉到750。这种「只差一点点」的对照,比背一堆数字管用。

4.3 一个容易被忽略的前提:掩码只影响「位」,不影响类型

ls -l第一列有十个字符,第一位是类型(-普通文件、d目录、p管道),后九位才是权限。umask 只作用于后九位。

这意味着两件事。一是「umask 能把文件变成目录」这种想法不成立,类型由调用的函数决定,跟掩码无关。二是判断一个文件的权限,先看类型位再看九位权限,别把d当成权限的一部分读进去。

本章可以带走的一句:0666 & ~022 = 0644是 man-pages 原文里的等式,777 & ~022 = 755是同一条规则换了个起始 mode;「022」是典型默认值,不是谁的规定。

五、本机实测:022 与 077 两组对照

下面三段输出,是 2026-10-26 在 macOS(Darwin 27.0.0,arm64)上原样跑出来的,没有做任何修饰。

5.1 先读当前值:数字与符号互为补集

$umask022 $umask-Su=rwx,g=rx,o=rx

这两行放在一起看,是最省事的一次观念纠正。

umask不带参数,打印的是被清掉的位:022,也就是 group w 和 other w。umask -S打印的是允许的权限:u=rwx,g=rx,o=rx。两者互为补集——022里为 1 的两位,在-S的输出里正好缺失(g=rx没有 w,o=rx没有 w);022里为 0 的位,在-S里全都出现了。

所以022从来不是「权限值 022」,它是「要清掉的那几位的编号」。把它当成权限值去读,会得出「022 表示属主什么都没有」这种荒唐结论。

5.2 022 下新建:文件 644,目录 755

$touch/tmp/t_umask_test&&ls-l/tmp/t_umask_test -rw-r--r--@1wzk wheel0Oct2606:13 /tmp/t_umask_test $mkdir/tmp/d_umask_test&&ls-ld/tmp/d_umask_test drwxr-xr-x@2wzk wheel64Oct2606:13 /tmp/d_umask_test

-rw-r--r--就是644,drwxr-xr-x就是755,与第四章那两条等式逐位对得上:666 & ~022 = 644、777 & ~022 = 755。

输出里那个@需要说明一句:它是 macOS 的扩展属性标记,表示这个文件带有附加属性,与权限无关,不要读成权限符号。在别家的ls上可能完全不出现。

5.3 077 下新建:600 与 700,然后显式恢复

这一段落在一个括号里跑,因为括号会开一个子 shell,改完不影响外层(第六章会讲为什么这一点很关键)。

$(umask 077;umask;umask-S;touch/tmp/t_umask_077;mkdir/tmp/d_umask_077;ls-l/tmp/t_umask_077;ls-ld/tmp/d_umask_077)077u=rwx,g=,o=-rw-------@1wzk wheel0Oct2606:13 /tmp/t_umask_077 drwx------@2wzk wheel64Oct2606:13 /tmp/d_umask_077 $umask022;umask022

四处值得对照。

第一,umask -S在 077 下显示成u=rwx,g=,o=,group 和 other 后面是空的,不是g=---。这个空和 5.1 的g=rx摆在一起,就能直观看出 077 清得比 022 狠得多。

第二,文件是-rw-------,即600,对上666 & ~077 = 600;目录是drwx------,即700,对上777 & ~077 = 700。

第三,整个括号里的改动没有漏到外层——否则最后那行umask会打出 077。

第四,最后一步是显式执行umask 022恢复。这一步在真机上必须做,不能省。掩码是进程级状态,077留在当前 shell 里不会自己回去;一旦忘了恢复,这个终端后面建的每个文件都会是600,而且不报错,只在某天发现同事读不了文件时才暴露。

四行输出对照下来的结论只有一句:起始 mode 不变,只动掩码,九位权限就整体跟着动。文件从644掉到600,目录从755掉到700,umask -S从g=rx,o=rx掉到g=,o=,三处变化指向同一个原因。这就是为什么「默认权限」这件事的开关在掩码上,而不在代码里。

完整的掩码取值对照表:这份资料把 000 到 077 常见取值对应的文件/目录结果、以及每种取值清掉了哪几位,做成一页可查的表,和本章两组实测一一对应。放在资料包里,扫码即可获取:

六、shell 里的 umask 与系统调用不是一回事

6.1 两个对象,两层作用域

日常说的「umask」,其实指两样东西,作用域不同。

一样是 shell 的umask,POSIX 把它定义成一个工具,作用对象是 shell 环境:

「The umask utility shall set the file mode creation mask of the current shell execution environment (see Shell Execution Environment) to the value specified by the mask operand.」

紧接着一句说明它的效果:「This mask shall affect the initial value of the file permission bits of subsequently created files.」

另一样是umask()这个系统调用,作用对象是进程:

「The umask() function shall set the file mode creation mask of the process to cmask and return the previous value of the mask.」

一个改的是「shell 执行环境」,一个改的是「进程」。二者的关系是:shell 自己也是一个进程,你在 shell 里敲umask 027,它最终就是通过系统调用把这个进程的掩码改掉;但这个改动只活在这个 shell 进程(以及它之后 fork 出来的子进程)里,shell 一退出就没了。

对比项shell 的umaskumask()系统调用
是什么POSIX 定义的命令/内建内核提供的接口
作用对象当前 shell 执行环境调用它的那个进程
生效范围该 shell 及其后续子进程该进程及其子进程
生命周期shell 退出即消失进程退出即消失
怎么查询umask不带参数返回值是旧掩码
影响谁之后由该 shell 创建的文件之后由该进程创建的文件

表里最后两行是排查时最常用的:你想知道「现在是多少」,在 shell 里敲umask就行;你想知道「某个服务建出来的文件会是多少」,得去看那个服务进程自己的掩码,而不是你终端里的那个。

这一点经常被忽略。登进机器,umask打出022,就以为「系统是 022」。可服务不是从这个终端启动的,它由 init 系统或容器运行时拉起,掩码取决于那条启动路径上的设置。你在终端里看到的 022,只代表你这个 shell。

那么服务进程的掩码究竟从哪来?这是本篇明确不回答的一处。不同发行版、不同 init 系统、不同容器运行时,注入掩码的位置各不相同,有的写在单元配置里,有的由运行时默认值决定,有的压根没人设、只是继承了父进程。本条待验证,需要查各自的官方文档。能做的是把「查」这件事变成动作:拿到服务进程的 PID,读它自己的掩码,而不是读你终端里的那个值。

6.2 加括号:子 shell 改完不回头

POSIX 专门为这件事写了一段,还给了三个例子:

「If umask is called in a subshell or separate utility execution environment, such as one of the following:(umask 002)/nohup umask .../find . -exec umask ... \;it shall not affect the file mode creation mask of the caller’s environment.」

括号、nohup、find -exec,三种写法三个场景,结论一样:改的是那个执行环境自己的掩码,调用者的不动。

本机验证过一次,输出很短但足够说明问题:

$umask022 $(umask 002;umask)002 $umask022

中间那行是子 shell 里的值,前后两行是外层的值。子 shell 里确实变成了002,退出之后外层还是022。

这个特性的实用价值在部署脚本里:需要临时放宽或收紧掩码时,把相关几行包进一对括号,就不必在末尾写「记得改回来」。用括号圈定作用域,比用「记得恢复」这种口头约定可靠。但如果改动是写在脚本主体里、后面还有别的步骤依赖它,就必须显式恢复——第五章 5.3 那个umask 022就是这种情况。

6.3 不带参数是查询,带参数才是设置

umask的两种用法,POSIX 都写了。设置是前面引过的那句;查询是另一句:

「If the mask operand is not specified, the umask utility shall write to standard output the value of the file mode creation mask of the invoking process.」

注意这里的主语是「invoking process」——打印的是调用它的那个进程的掩码。在 shell 里,那个进程就是当前 shell,所以看起来像「查询当前值」。这个细节在写脚本时要留意:脚本里执行umask,拿到的是脚本进程的掩码,而它又是从父进程继承来的。

还有一个常见误解值得点破:把umask写进.bashrc或某个启动脚本,就以为「全系统都改了」。它只改了读到这个文件的那个 shell。同理,容器里在 Dockerfile 里写一行umask 027,如果没有配合SHELL或后续的RUN串联,那行改动也只活在那一个RUN层里。

本章可以带走的一句:umask命令改的是 shell 执行环境,umask()改的是进程;括号能圈住作用域,但圈不住「以为改了全系统」这种误解。

七、按场景设值:给到具体数字

7.1 三个场景,三组值

讲完机制,落到取值。下面这四组建议按「谁能读、谁能写」来定,不按「哪个数字看起来顺眼」来定。

场景建议 umask文件 / 目录结果为什么是这组
站点静态目录、可执行目录022644/755内容要被任意账号读,写只留给属主
上传目录(属主是服务账号,组内另一个服务只读)027640/750组能读能进,other 一律不给
共享协作目录(同组多人要写)007660/770组内可写,other 完全隔离
私钥、凭据、token、备份文件077600/700只有属主能碰,组和 other 全清

第二行那个027要说明一下:相对 022,它多清的是 other 的三位(027等于022加上005),所以文件变成640、目录变成750,other 那一档彻底消失。group 那三位一位没动,640的组照样可读。要连组一起关掉,得往上走到077,而不是在 022 和 027 之间找折中。这类差值很容易记混,最稳的办法是对着 2.2 那张位图逐个核。

上传目录还有一层常被漏看:目录能进不等于能写。750的目录,组内账号可以cd进去、可以ls,但要往里面新建文件,需要的是目录本身的 w 位,而不是里面文件的权限。判断「能不能上传」,看的是目录那九位,不是文件那九位。这条和 umask 无关,但排查时几乎总会一起出现。

第三行有个坑,必须划清界限。很多团队想要的是共享目录最终呈现2775:组内多人可写,新建的文件自动归到同一个组。这里的2775有一位是 setgid(那个前导2),它的作用是「目录里新建的东西继承目录的属组」。

这个2不是 umask 给的。umask 007只能把权限位清成775,umask表达不了 setgid —— 第二章引过 POSIX 那句,特殊位要么被忽略、要么implementation-defined。想拿到2775,得在umask 007之外另行给目录设 setgid,两步是两件事,不能合并成一句「把 umask 设成 2775」。

还有一点:umask只能影响新建的东西。目录上已经存在的文件不会因为改了掩码而变,这一点和「改配置要重启才生效」是同一类认知——作用点在过去还是将来,决定了你要不要回头补一遍。

7.2 两条边界:ACL 会接管,777不能当兜底

第一条边界是 ACL。man-pages 写得很明确:

「Alternatively, if the parent directory has a default ACL (see acl(5)), the umask is ignored, the default ACL is inherited, the permission bits are set based on the inherited ACL, and permission bits absent in the mode argument are turned off.」

父目录设了默认 ACL 时,umask 会被忽略,权限改由继承来的 ACL 决定。这是另一套机制,本篇只点到这里,ACL 的具体写法不展开。

它的实际含义是:如果你排查半天下发现「改了 umask 但新建文件的权限没变」,先去看父目录有没有默认 ACL,别在掩码上反复试。

第二条边界是chmod 777。这里必须把话说死:不要用777兜底。

理由有两个,都能落回原文。其一,umask 的语义是「把不想给的位清掉」,这是0666 & ~022那条等式的出发点;777等于把这份收窄一次性作废,前面所有的取值讨论都白做。其二,对目录而言777意味着任何账号都能在里面新建、改名、替换文件——上传目录一旦是这个权限,前面 1.1 那个「服务账号写不进去」的问题会瞬间反转成另一个更难收场的问题。

权限不够时的正确动作有三个,按顺序试:查属主和属组对不对、查父目录有没有 ACL、按最小权限给到组。三个都不是777。

7.3 一次核对,写成命令顺序

把上面这些落成动作,就是下面这个顺序。命令按各自环境替换路径。

⚠️代码待验证

# 1. 读当前掩码(数字与符号各看一遍)umaskumask-S# 2. 看父目录有没有默认 ACL(有则掩码不生效)ls-ld/srv/www# 3. 在受控作用域里按目标值建目录,再核对结果(umask 027;mkdir-p/srv/www/upload/new;touch/srv/www/upload/new/.keep)ls-ld/srv/www/upload/newls-l/srv/www/upload/new/.keep

第 2 步最容易被跳过,也最容易白干一场。第 3 步用括号圈住,跑完外层不受影响;如果这段要写进部署脚本、后面还有依赖,就把括号去掉,并在末尾补一行显式恢复到站点统一值。

本章可以带走的一句:取值按「谁能读、谁能写」定,不按数字顺眼定;2775里那位 setgid 不是 umask 给的;权限不够时先查属主和 ACL,777不在选项里。

完整的权限自查清单:这份资料把本文七个章节的判断点压缩成一页顺序清单——先读掩码、再看起始 mode、再看父目录 ACL、最后核对结果,附常见取值的预期输出。放在资料包里,扫码即可获取:

附表 A:本文引用事实与官方出处对照表

序号事实出处核验日期本文位置
1掩码语义:cmask 里置 1 的位,在创建出的文件 mode 里被清掉POSIX.1-2017umask()(UMASK-03)2026-10-26第二章 2.1
2Issue 8 措辞改为 Permission bit positions,语义不变POSIX.1-2024umask()(UMASK-04)2026-10-26第二章 2.3
3S_ISVTX在 cmask 里被忽略,其余非权限位 implementation-definedPOSIX.1-2024umask()(UMASK-04)2026-10-26第二章 2.3
4返回的旧掩码中S_ISVTX位为清零POSIX.1-2024umask()(UMASK-04)2026-10-26第二章 2.3
5umask()设置进程掩码并返回旧值,只用权限位POSIX.1-2017umask()(UMASK-01)2026-10-26第六章 6.1
6受影响的函数清单:open/openat/creat/mkdir/mkdirat/mkfifo/mkfifoatPOSIX.1-2017umask()(UMASK-02)2026-10-26第三章 3.1
7XSI 另列mknod()/mknodat(),可选部分含mq_open()/sem_open()POSIX.1-2017umask()(UMASK-02)2026-10-26第三章 3.1
8open():mode 的权限位与掩码补集做按位与,掩码为 1 的位被清POSIX.1-2017open()(UMASK-05)2026-10-26第三章 3.2
9mkdir():权限位从 mode 初始化,再被掩码修改,无豁免POSIX.1-2017mkdir()(UMASK-06)2026-10-26第三章 3.3
10shell 的umask作用于 current shell execution environmentPOSIX.1-2017umask工具(UMASK-07)2026-10-26第六章 6.1
11掩码影响之后创建文件的初始权限位POSIX.1-2017umask工具(UMASK-07)2026-10-26第六章 6.1
12在子 shell、nohup、find -exec里调用不影响调用者环境POSIX.1-2017umask工具(UMASK-08)2026-10-26第六章 6.2
13不带 mask 参数时,打印 invoking process 的掩码值POSIX.1-2017umask工具(UMASK-09)2026-10-26第六章 6.3
14典型默认值是S_IWGRP与S_IWOTH,即八进制 022Linux man-pagesumask(2)(UMASK-11)2026-10-26第四章 4.1
150666 & ~022 = 0644,即rw-r--r--Linux man-pagesumask(2)(UMASK-13)2026-10-26第四章 4.1
16父目录有 default ACL 时掩码被忽略,权限由继承 ACL 决定Linux man-pagesumask(2)(UMASK-14)2026-10-26第七章 7.2
17本机实测:umask022 与umask -S的u=rwx,g=rx,o=rx本机实测(UMASK-17)2026-10-26第五章 5.1
18本机实测:022 下 touch 得 644、mkdir 得 755本机实测(UMASK-18)2026-10-26第五章 5.2
19本机实测:077 下得 600 与 700,umask -S显示g=,o=本机实测(UMASK-19)2026-10-26第五章 5.3
20本机实测:括号内改 002 不影响外层,之后显式恢复 022本机实测(UMASK-08 行为验证)2026-10-26第六章 6.2
21某发行版登录 shell 的掩码由哪个文件决定(待验证,正文仅写需查各自文档)未取得发行版手册(UMASK-12)2026-10-26第四章 4.1

附表 B:术语速查表

术语一句话解释
umask文件模式创建掩码,进程级属性,创建文件时用来清位
起始 mode调用方传给open()/mkdir()的权限值,文件常用 0666,目录常用 0777
清位掩码为 1 的位置,在结果的 mode 里被置 0,不会把位设成 1
补集逐位取反,掩码 022 的补集在那九位上是「除两个 w 之外全开」
起始 mode 与掩码的运算按位与,写作0666 & ~022
S_ISVTX特殊位之一,POSIX 明确它在 cmask 里被忽略
特殊位setuid、setgid、sticky 一类,不属于 umask 的表达范围
shell execution environmentshell 的执行环境,umask命令作用的对象
子 shell括号等方式开出的执行环境,改动不外泄
default ACL父目录上设定的默认访问控制,会使 umask 被忽略
最小权限只给完成工作所必需的那几位,多一位都不给

写在最后:这篇用到的资料

写这篇文章时,我把一台机器上的 022 和 077 两组掩码各跑了一遍,对着ls -l的十位字符逐位核到等式上,顺手也整理了几份配套的东西:

  • 靶场环境对照表:DVWA、upload-labs 在 Windows / macOS / Linux 三平台的可行性与推荐路径
  • Web 安全学习路线图:从基础打牢到安全管理,四个阶段各学什么
  • 常用靶场清单:每个靶场练什么、适合哪个阶段

资料是我自己整理的,放在下面这个码上,扫码即可获取:

添加时备注「靶场」,优先通过。

拿到之后建议先看环境对照表那一份,把要动手的环境先对齐,再回来对权限这一节,会顺很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询