
上周同事把一个部署脚本chmod 4755之后跑来问我为什么脚本里访问/etc/shadow还是被拒我让他把脚本换成 C 编译出来的程序再试同样的4755立马就通了。这就是 linux 特殊权限位里最典型的一层误解——suid、sgid、sticky 这三个位不是更高级的 rwx它们改的不是谁能读谁能写而是进程的身份、新建文件的归属、以及目录里删除动作的判定规则。很多人背得下4755、2775、1777这三个数字但一旦落到到底谁的身份生效为什么脚本上不管用为什么拷贝之后就失效了就开始含糊。我准备把这三条线一次性捋到底每个位分别在什么对象上生效、内核在哪个环节动的手脚、怎么用八进制和符号两种写法准确设置、怎么在出问题时一步步排查以及审计和迁移时最容易踩的几个静默坑。文中的演示命令都可以直接在一台测试机上复现涉及动手的部分我会标清楚前置条件避免你在生产机上做出不可逆的改动。不管你是刚接触 Linux 权限的运维新人还是被共享目录折腾过的老手这篇应该都能留下点能直接抄走的东西。1. 三个真实的排错现场SUID、SGID、Sticky 分别卡在哪一步先从现场说起。脱离了具体现象去背权限位的定义你永远记不住哪个是哪个因为这三个位的语义跨度其实挺大一个改的是进程身份一个改的是文件归属一个改的是删除判定。它们唯一的共同点是——都挤在ls -l输出的那九个字符里用s和t冒充了原本该是x的位置。1.1 现场一普通用户改密码凭什么能写 /etc/shadow/etc/shadow的权限是000或者640属主 root普通用户连读都读不了。但你用普通账号敲passwd它偏偏就能改自己的密码。答案在于$ ls -l /usr/bin/passwd -rwsr-xr-x. 1 root root 32648 3月 10 2022 /usr/bin/passwd注意属主那一位的x变成了s。这个s就是 SUIDSet User ID八进制里的4。它表达的意思是这个文件被执行时进程的有效用户 IDeuid不再是发起者而是文件属主。passwd的属主是 root所以它跑起来之后 euid 变成 0自然写得进/etc/shadow。这里有个关键细节值得盯住SUID 改的是有效身份不是真实身份。进程仍然知道自己是 alice 在操作只是它现在有权以 root 的身份做事。passwd正是靠这一点——它一边以 root 权限改文件一边又通过真实身份判断你只能改你自己的那一条记录。如果 SUID 把真实身份也一起改掉了那passwd就会变成一个任人改别人密码的提权工具早就没人敢用了。1.2 现场二共享目录里新建的文件总是跑到别人的组第二个现场更常见。你给团队建了个/srv/share属组设成devs权限775想着大家都能读写。结果张三在里面存的文件属组是devs李四存进去的却变成了lisi或者users同组的人反而写不了。原因很简单目录上的权限位只管能不能在这个目录里创建文件这个动作管不了新文件归哪个组。新文件的属组默认取创建者的主组。要让它固定继承父目录的属组就得在目录上打开 SGID八进制2$ chmod 2775 /srv/share $ ls -ld /srv/share drwxrwsr-x. 3 root devs 4096 5月 20 10:12 /srv/share属组的x变成了s这就是 SGID 在位。从这个目录里新建的文件和子目录都会自动归到devs组。这一点在团队协作场景里几乎是刚需也是2775这个数字被反复使用的原因。1.3 现场三/tmp 里删不掉别人的文件到底是哪一位在拦第三个现场我猜很多人都撞过/tmp权限是1777所有人都能写但你去删同事留下的临时文件时系统回你一句Operation not permitted。而且更让人困惑的是——那个文件的权限可能是666你自己明明有写权限。这就是 Sticky八进制1在起作用$ ls -ld /tmp drwxrwxrwt. 20 root root 4096 5月 20 10:15 /tmp最后一位的x变成t。它的规则是在一个带 sticky 的目录里只有文件属主、目录属主或者具备相应特权身份的进程才能删除或重命名目录中的条目。注意它管的是删除和改名这两个动作不管读、不管写。为什么删不掉和写不了是两件完全不同的事因为删除一个文件本质上修改的是它所在目录的内容目录项被抹掉跟你对被删的那个文件本身有没有写权限毫无关系。这个认知上的错位是绝大多数权限问题的根子。1.4 三个位的共同点与分水岭把这三点摆在一起分水岭就很清楚了位八进制作用对象真正改变的东西典型场景SUID4可执行文件执行时的有效用户 IDpasswd、sudo、mountSGID2可执行文件 / 目录执行时的有效组 ID / 新条目的属组共享目录、目录树统一属组Sticky1目录删除与改名的判定条件/tmp、/var/tmp共同点是三个位都存放在ls -l那九个字符里、都用一位八进制表示分水岭是它们的生效对象完全不同。SUID 对目录基本没有意义Linux 上目录的 SUID 位是被忽略的Sticky 对普通文件在现代 Linux 上也是被忽略的历史上它表示把程序常驻内存那是上古时代的用法。把作用对象记牢比记数字管用得多。2. 把四个数字位算明白八进制、符号写法与那个容易漏看的大写字母理解了语义接下来要解决的是手别抖。我见过太多事故是把4755敲成755、把2775敲成2755或者用chmod s一次性把两个位都打开了却浑然不觉。权限位这东西没有撤销按钮改错之后往往要等别人报故障你才发现。2.1 rwx 只是低三位第一位是特殊位打包先建立一个坐标系。chmod后面那个八进制数从右往左看第 1 位最右other 的权限r4、w2、x1第 2 位group 的权限第 3 位user属主的权限第 4 位特殊位打包SUID4、SGID2、Sticky1三个值相加所以4755拆开就是特殊位 4SUID 属主 7rwx 属组 5r-x 其他 5r-x。2775是 SGID rwx rwx r-x。1777是 Sticky rwx rwx rwx。三个特殊位是可以叠加的所以最极端的情况会出现7777SUIDSGIDSticky权限全开。这种组合在系统里几乎一定能被当成异常项捞出来正常服务用不到。3755这种SUIDSGID 一起开的写法在极少数老程序里存在但新项目里基本不该出现因为多开一个位就多一个被利用的面。2.2 符号写法 chmod us / gs / ot 与 chmod s 的差别八进制写法直白但容易算错符号写法可读性好但有陷阱。推荐的方式是明确指定作用对象chmod us /usr/local/bin/tool # 只加 SUID chmod gs /srv/share # 只加 SGID chmod ot /srv/dropbox # 只加 Sticky chmod u-s /usr/local/bin/tool # 去掉 SUID chmod g-s /srv/share # 去掉 SGID chmod o-t /srv/dropbox # 去掉 Sticky而那个陷阱就是chmod s 文件——省略了u和g之后它会把SUID 和 SGID 两个位同时打开。很多人只想加 SUID敲了个s检查时看到属主和属组位置各有一个s才发现设多了。同理chmod -s 文件会一次清掉两个位。如果你不确定当前状态改完之后必须用ls -l复核一遍不要凭记忆判断。还有一个反直觉的点加特殊位和加普通位一样受权限约束。非 root 用户只能对自己拥有的文件设置这些位对别人的文件执行chmod us会直接报Operation not permitted。而属于你自己的文件上设 SUID本质上是让自己以自己身份运行没有任何提权效果所以系统不会拦你但这也不代表这么做是有意义的。2.3 ls -l 里 s、S、t、T 的读法这是全篇最值得反复看的一处细节。ls -l里出现的字母有大小写之分含义完全不同显示形式位置含义-rws------属主位SUID 已开且属主有执行权限位有效-rwS------属主位SUID 已开但属主没有执行权限位形同虚设----rws---属组位SGID 已开且属组有执行权限----rwS---属组位SGID 已开但属组没有执行权限drwxrwxrwt其他位Sticky 已开且其他人有执行权限drwxrwxrwT其他位Sticky 已开但其他人没有执行权限大写S/T的意思是特殊位本身被置上了但对应的执行位是关的。对于 SUID 来说没有执行权限的文件根本不会被执行SUID 自然不会生效所以S只是挂着一个摆设。这种状态通常是这么来的先给文件加了 SUID后来又用某种方式把执行位去掉了或者先设4644再想做调整。它在审计里很值得关注因为一个准备被执行但还差一步的提权文件往往意味着有人在调试或者误操作。对目录来说Sticky 显示成大写T通常意味着这个目录其他人进不去那 sticky 的删除保护也就没有实际意义了——因为压根没人能在这个目录里创建或删除东西。2.4 stat 和八进制输出的交叉验证用ls -l看字母只能看出哪个位开了看不出确切的数字。真正确认时我习惯用stat$ stat -c %a %A %U %G %n /usr/bin/passwd /srv/share /tmp 4755 -rwsr-xr-x root root /usr/bin/passwd 2775 drwxrwsr-x root devs /srv/share 1777 drwxrwxrwt root root /tmp%a直接给出八进制权限含特殊位%A给出人类可读形式。在写脚本做批量核对时stat -c %a是最省事的比ls -l | awk稳得多因为它不受别名、颜色输出和字段对齐的影响。顺便提一句如果你的ls配置了颜色别名在脚本里调用时最好写全路径/bin/ls或者干脆用stat。3. SUID 只对可执行文件有效生效链路与三道拦截SUID 是最容易被神化也最容易被误用的一个位。它的生效链路其实很狭窄必须在可执行文件上、必须在**执行execve**这个动作发生的时候、中间还会有好几道拦截。哪一道没过表现都是位设了但没效果很容易让人怀疑人生。3.1 内核在 execve 时改的是 euid不是 ruid进程在 Linux 里挂着好几个身份标识真实用户 IDruid、有效用户 IDeuid、保存的用户 IDsuid、文件系统用户 IDfsuid。权限判定看的是 euid文件访问还会看 fsuid而 ruid 决定你是谁比如信号发送、passwd判断你改哪条记录看的都是真实身份。带 SUID 的文件被execve执行时内核会把进程的 euid 设置为文件属主的 UID同时把原来的 euid 保存在 suid 里方便程序在需要时主动降权。想亲眼看到这个过程可以起一个 shell 对比$ ps -o pid,ruid,euid,suid,comm -p $$ PID RUID EUID SUID COMM 3821 1001 1001 1001 bash $ su - # 以 root 登录后 # ps -o pid,ruid,euid,suid,comm -p $$ PID RUID EUID SUID COMM 3902 0 0 0 bash想直接看 euid 而手上没有 root 环境时用一条 Python 就够了python3 -c import os; print(ruid%d euid%d % (os.getuid(), os.geteuid()))用ps的ruid/euid/suid列要注意老版本 procps 可能不支持这几个字段名报错时换用 Python 那条更稳。3.2 五个 UID 和 no_new_privs在 euid 之外还有两个容易被忽略的概念。一个是 fsuid它决定文件访问检查时用哪个身份绝大多数情况下跟随 euid。另一个是内核的no_new_privs标志一旦它被设上execve就不会再因为 SUID 而提升权限——也就是说在 no_new_privs 生效的进程里全盘所有 SUID 程序都会变成普通程序。查看方式很直接$ grep NoNewPrivs /proc/self/status NoNewPrivs: 0手工验证一次 SUID 被压制是什么手感可以这么干普通用户就能做$ setpriv --no-new-privs /usr/bin/passwd # 或者直接观察一个 SUID 程序在 no_new_privs 下的行为 $ setpriv --no-new-privs python3 -c import os; print(os.geteuid()) 1001这就是为什么在容器、systemd 服务单元、以及某些受限执行环境里SUID 会莫名失效。排查这类问题时先看NoNewPrivs的值比盯着文件权限瞎猜高效得多。3.3 脚本上的 SUID 是无效的亲手验证一遍回到开头那个现场。写个脚本加上 SUID$ cat /tmp/whoami.sh EOF #!/bin/bash echo ruid$(id -u) euid$(python3 -c import os;print(os.geteuid())) EOF $ chmod 4755 /tmp/whoami.sh $ ls -l /tmp/whoami.sh -rwsr-xr-x. 1 alice alice 80 5月 20 10:30 /tmp/whoami.sh用另一个普通账号跑它你会发现 euid 还是自己的SUID 完全没有起到作用。原因是Linux 内核在处理带#!解释器的脚本时不会采用脚本文件上的 SUID/SGID 位。真正被加载执行的是解释器这里是 bash脚本文件只是被当作参数喂进去所以进程身份取决于 bash 的属主root普通用户当然不能改。这不是配置问题是设计上刻意为之——早期允许脚本 SUID 的实现存在可被利用的竞争条件后来就被彻底关掉了。这条规则推出来的结论很实用你要靠 SUID 提权干活就必须是编译出来的二进制可执行文件或者 ELF 的某种等价形式shell、Python、Perl 脚本一律不行。想达到类似效果正规做法是配sudo的自定义规则用NOPASSWD限定具体命令和参数而不是去折腾脚本的 SUID。3.4 一段最小 C 验证程序从普通用户读到 root 才读得到的东西要证明 SUID 真的生效了最干净的实验是拿/etc/shadow当靶子——普通用户绝对读不到它。写一个只统计行数、不打印内容的程序避免在终端上暴露任何哈希/* countshadow.c */ #include stdio.h #include unistd.h int main(void) { FILE *fp; char line[1024]; long n 0; printf(ruid%d euid%d\n, getuid(), geteuid()); fp fopen(/etc/shadow, r); if (!fp) { perror(fopen /etc/shadow); return 1; } while (fgets(line, sizeof(line), fp)) n; fclose(fp); printf(shadow 行数%ld\n, n); return 0; }编译、放置、设位、验证一条链走完gcc -Wall -O2 -o /usr/local/bin/countshadow countshadow.c chown root:root /usr/local/bin/countshadow chmod 0755 /usr/local/bin/countshadow su - alice -c /usr/local/bin/countshadow # ruid1001 euid1001 # fopen /etc/shadow: Permission denied chmod 4755 /usr/local/bin/countshadow su - alice -c /usr/local/bin/countshadow # ruid1001 euid0 # shadow 行数6 chmod u-s /usr/local/bin/countshadow对照非常明确同一个程序、同一个用户只差一个 SUID 位一次被拒一次通过。做这个实验一定要在测试机或者你自己能随便折腾的虚机上验证完立刻chmod u-s撤掉。留一个能读/etc/shadow的自制程序在系统里等于给自己埋了一颗雷而且它不会出现在任何包管理器的清单里日后审计时你还得回忆这是谁写的。3.5 SUID 该用来干什么不该用来干什么从系统自带程序里能看出 SUID 的正确用法边界passwd干的是改密码这一件被严格约束的事sudo做的是按配置授权mount在部分发行版上用于让普通用户挂载。它们的共同点是功能单一、输入严格校验、内部还会二次判断真实身份。反过来不该用 SUID 的情况也很清楚想让整个程序都拿 root 权限跑——这是最危险的用法一个缓冲区溢出、一个路径注入就变成任意提权想给脚本提权——内核直接不支持白折腾想让某个服务常驻提权——应该用 systemd 的User/AmbientCapabilities精确配权而不是给二进制挂 SUID想省掉sudo的密码输入——正确做法是配/etc/sudoers.d/里的精细规则而不是自己写 SUID 包装脚本现代发行版正在把越来越多功能从 SUID 迁移到文件能力capabilities上。最典型的是ping早些年它是 SUID root现在是$ getcap /usr/bin/ping /usr/bin/ping cap_net_rawep只给构造原始网络包这一项能力而不是给整份 root 权限。这是权限设计上的巨大进步也解释了为什么你在新系统上ls -l /usr/bin/ping看不到s了。后面第 5 节还会回到这个话题做审计时这两份清单要对着看。4. SGID 的两种身份与 Sticky 的唯一职责SUID 讲透了SGID 和 Sticky 就好理解了。有意思的是 SGID 在可执行文件和目录上表现出的语义完全不同这也是它最容易被记混的地方。而 Sticky 反而是三个位里职责最单一的——它就管一件事。4.1 可执行文件上的 SGID借一个组身份可执行文件上的 SGID 和 SUID 是同一个套路的兄弟进程执行时有效组 ID 变成文件属组的 GID。它的用途比 SUID 窄得多典型场景是让一个程序以某个特定组的身份访问该组专属的资源。比如某个程序需要访问属组为backup、权限640的日志文件就可以把它设成2755并且属组改成backup程序跑起来之后 eGID 就等于backup读得了文件。这和 SUID 用的是同一个内核机制只是改的是组身份那一半。需要提醒的是组身份带来的权限取决于这个组被授予了什么。如果那个组恰好对某些关键目录有写权限SGID 程序就同样是一把提权钥匙。审计 SUID 程序的时候顺手把带 SGID 的可执行文件也捞出来别只盯着 SUID。4.2 目录上的 SGID组归属继承并且能传下去目录上的 SGID 走的是另一条完全不同的逻辑也是日常用得最多的一个在这个目录里新建的文件和子目录会把属组设置为该目录的属组而不是创建者的主组。并且新建的子目录会自动带上 SGID所以这个继承规则能沿着目录树一直传下去。这一点对团队共享目录意义重大。没有它的时候你只能靠让所有人把主组都改成同一个组这种土办法而人一旦属于多个组主组就不一定是什么了最终结果是一堆乱七八糟的属组。有了它只要在根节点设一次2775整棵树就统一了。有个细节值得强调属组是继承了但组权限位仍然受 umask 影响。设了 SGID 的目录里如果用户的 umask 是022新建文件会变成644属组虽然有写权限位但文件本身根本没给组开写。结果是组归属对了但同组的人还是写不了。解法有两个把 umask 调成002要在登录环境里统一改不能靠临时命令或者用默认 ACL这个在第 4.5 节展开。4.3 Sticky 只管删除和改名不管读和写Sticky 的规则简单到一句话就能说完在带 sticky 位的目录里只有文件属主、目录属主或者具备相应特权的进程才可以删除或重命名目录里的条目。它不限制读取不限制写入也不限制在目录里创建新文件。为什么共享目录需要它因为一个所有人可写的目录天然有个致命问题如果所有人都能删别人的文件那这个目录就不能用来放任何重要的东西。/tmp是典型例子——它权限1777所有人可写但如果没有 sticky任何一个本地用户都能把别人的会话文件、socket、临时数据删掉那就是一个本地的服务拒绝入口。Sticky 存在的意义就是给人人可写加一道仅限自己的删除限制。顺带说一个容易被忽略的边界sticky 不会被新建的子目录继承。在/tmp里创建一个目录这个新目录的权限是0777 ~umask的结果不带 sticky。所以你在/tmp里自己建的目录里面的文件反而可能被别人删掉。要保护的话得手动给那个子目录也加上chmod ot。这套规则在排查删不掉文件时非常好用判断链路是看目录本身是不是有写权限——没有写权限谁都删不了除非是目录属主以外还有特权看目录是否带 sticky——带了就只看你是不是文件属主或目录属主看文件属主是谁——stat -c %U %G %n file一眼确认顺着这三步走几乎不用猜。而且要注意我前面提过的那条删除权限取决于目录跟文件本身的权限一点关系都没有。一个444的文件只要你在它所在目录里有写权限且目录没有 sticky你照样删得掉。4.4 搭一个真正能用的团队共享目录把 SGID 和 Sticky 组合起来用能搭出一个体验相当不错的协作目录。以下是我在几台服务器上反复用过的配置假设团队组叫devs成员是 alice 和 bobgroupadd devs usermod -aG devs alice usermod -aG devs bob mkdir -p /srv/team/{release,docs,tmp} chown -R root:devs /srv/team chmod 2775 /srv/team/release /srv/team/docs chmod 3775 /srv/team/tmp # SGID Sticky组内共享但只删自己的几个设计取舍值得说明。release和docs用2775组内所有人可读写新文件自动归devs不设 sticky 是因为这两个目录需要互相整理内容。tmp用3775既有组继承又限制只能删自己的文件适合放那些大家一起看但不想被误删的中间产物。如果还希望新建的文件默认就能被组内成员修改需要再补一步默认 ACLsetfacl -d -m g:devs:rwx /srv/team/release setfacl -d -m o::--- /srv/team/release代价是ls -l的属组位置会多出一个而且那里显示的其实是 ACL mask 而不是组的权限位容易让人误判组权限怎么变了。用getfacl看才准确。所以这个方案我一般只用在确实需要新建即可协作的目录上其他情况宁可统一把 umask 调成002来得干净。4.5 新加的用户组成员身份为什么不生效这是共享目录场景里出现频率最高的一个假故障必须单独拿出来说。你刚执行完usermod -aG devs alice让 alice 去访问/srv/team结果还是被拒。原因不是权限配错了而是Linux 的补充组列表是在会话建立时确定的已经在跑的 shell 不会自动感知新的组成员关系。验证和解决都很直接# 在 alice 已有的会话里 $ id uid1001(alice) gid1001(alice) groups1001(alice) # 看不到 devs # 重新登录或者临时切换一次 $ su - alice $ id uid1001(alice) gid1001(alice) groups1001(alice),1002(devs)newgrp devs也能临时让当前 shell 拿到这个组但它会另起一个子 shell环境变量不一定继承完整只适合用来验证不适合当作长久方案。遇到权限明明配了但某人就是访问不了第一个动作永远是id确认他当前会话里到底有没有这个组这条经验帮我省过无数次排查。5. 审计、排查与迁移特殊权限最容易丢在哪几个环节把三个位用熟练之后剩下的活基本就是两类定期找出系统里有哪些特殊权限文件以及搞清楚为什么一个明明设好的位在某个环节悄悄没了。第一类靠find和getcap第二类靠对拷贝、打包、挂载这几条路径的理解。5.1 用 find 把全盘的特殊权限文件捞出来注意 -perm - 和 -perm / 的区别find -perm的两种写法含义完全不同这是排查时最容易读错的地方写法GNU find 语义BSD/macOS find 语义-perm -4000所有给定位都置位SUID 必须有与 GNU 的/4000相同-perm /4000任意一个给定位置位要写成4000-perm 4000权限恰好等于 4000相同日常审计我用的命令是这条find / -xdev -type f \( -perm -4000 -o -perm -2000 \) \ -printf %M %u %g %p\n 2/dev/null | sort几个点解释一下。-xdev是关键它让 find 不跨越文件系统边界否则会一路爬进/proc、/sys、挂载的网络盘既慢又吵。-printf %M ...输出的是带s的权限字符串一眼能看出是 SUID 还是 SGID。2/dev/null挡掉权限不足的报错噪音——如果你需要知道哪些目录没扫到就别丢错误输出而是换成-user root之类更聚焦的条件。想把范围收窄到最近才出现的用时间条件是最有效的find /usr /opt /tmp /home -xdev -type f -perm -4000 \ -newermt 30 days ago -printf %TY-%Tm-%Td %M %p\n 2/dev/null新冒出来的 SUID 文件就是最值得看的东西因为系统自带的那些几乎都是包管理器装的不会在你不知情的时候出现。这条命令我在每次系统巡检时都会跑一遍比全量清单更省注意力。5.2 和文件能力capabilities对一遍账只盯着 SUID 会漏掉一半的提权面因为现在很多功能是用文件能力实现的。这两份清单要放在一起看getcap -r / 2/dev/null输出形如/usr/bin/ping cap_net_rawepep表示 effective 和 permitted 都置位。一个理解误区是能力比 SUID 安全得多所以不用管——只有在能力足够细的时候才成立。cap_setuidep、cap_dac_override、cap_sys_admin这类能力的杀伤力和 SUID root 基本没有区别。所以审计的结论应该统一是任何能让普通用户获得额外身份的文件无论走 SUID 还是 capabilities都要有明确的归属和用途说明说不清来历的就撤掉。5.3 拷贝、打包、挂载过程中的静默丢失这是最让人抓狂的一类问题源机器上好好的目标机器上就是不行而且没有任何报错。常见的几个丢失环节环节现象原因对策cp不带参数普通用户新文件没有 suid默认按 umask 重建权限cp -a或cp --preservemode,ownershiprsync不带-p权限位被重置-a才包含-p单用-r不含明确写rsync -aHAX或用-ptar解包到非 rootsuid 指向自己无法恢复属主为 root以 root 解包或加-p并配合正确的属主拷贝到 U 盘 / vfat / exfat全部变成777且无 suid文件系统不存储 Unix 权限用 tar 打包后再拷保留元数据NFS / 某些挂载点位设置了但不生效挂载带了nosuidfindmnt -o TARGET,OPTIONS /path检查容器内suid 程序没反应运行时默认nosuid或启用no-new-privileges用能力或明确的用户配置替代这里最需要养成肌肉记忆的是findmnt。看到 SUID 程序不生效、ls -l却明明有s直接查挂载选项$ findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS /srv TARGET SOURCE FSTYPE OPTIONS /srv /dev/sdb1 xfs rw,nosuid,nodev,noexec,relatimenosuid一出现这个挂载点下所有文件的 SUID/SGID 位都会被内核忽略无论权限怎么设。同理noexec会让可执行文件根本跑不起来。这两个选项常常出现在/tmp、/var/tmp、U 盘、以及被人为加固过的数据盘上属于配置是对的但环境不允许的典型。5.4 我平时用的一份核对清单最后给出我自己在改权限前后会过一遍的清单基本都是被事故教出来的改之前先stat -c %a %n记下当前值别凭记忆回滚设完立刻ls -l复核字母大小写大写S/T意味要重新检查执行位永远不用chmod s这种省略 who 的写法明确写us或gsSUID 只加在编译型二进制上脚本上加了也没用别浪费时间目录要 SGID 就用四位数2xxx一次设好别只改属组忘了位共享目录同时考虑 sticky否则人人可写等于人人可删涉及组权限的改动完成后让对方id确认新组已在当前会话生效验证完的临时 SUID 程序当场chmod u-s不要留到以后再说这些条目看起来琐碎但每一条背后都是一次真实的故障或者一次差点出事。权限管理最麻烦的地方在于它的失败往往不是报错而是看起来没问题。所以与其事后排查不如在改动的当下就把这几个点确认掉。我个人在实操中的体会是把这三个位当成三件不同的事来记比当成一组特殊权限来背要牢靠得多SUID 关心的是进程以谁的名义干活SGID 在目录上关心的是新东西归谁Sticky 关心的是目录里的条目能不能被动手。真正出问题的时候先问自己一句我现在遇到的是这三件事里的哪一件答案基本就出来了。另外还有一个小技巧——遇到任何权限相关的怪现象第一件事永远是stat -c %a %A %U %G %n把文件、目录和它的父目录三者一起打出来对比看清楚每一层到底是谁、什么权限比翻文档快得多。