os.chmod不生效的根本原因是当前进程无权限修改目标文件权限,常见于文件属主非当前用户或挂载点为只读;需检查属主、挂载选项,并用stat模块替代硬编码八进制。

为什么 os.chmod 改权限不生效?
常见现象是调用 os.chmod('/path/to/file', 0o600) 后,ls -l 看权限没变,或者报 PermissionError: [Errno 1] Operation not permitted。根本原因不是函数写错了,而是当前进程没权限修改目标文件的权限位——尤其是当文件属主不是当前用户、或文件在只读挂载点上时。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 先确认当前用户是否为文件属主:
os.stat(path).st_uid == os.getuid(),否则chmod失败是预期行为 - 检查挂载选项:
mount | grep $(df . | tail -1 | awk '{print $1}'),若含ro(只读),任何chmod都会失败 - 避免硬编码八进制字面量;用
stat.S_IRUSR | stat.S_IWUSR更可读,也兼容不同平台对权限位的解释差异
如何让 Python 脚本启动时不带多余权限?
很多脚本一上来就用 sudo python script.py,结果后续所有生成的文件都带 root 属主,后续普通用户操作反而被卡住。这不是“要不要提权”,而是“提权时机和范围是否精准”。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 把需要特权的操作拆出来单独执行,比如用
subprocess.run(['sudo', 'ip', 'link', 'set', 'eth0', 'up']),而非全程跑在 root 下 - 启动后立刻降权:用
os.setgid()和os.setuid()切换到非特权用户(需提前查好目标 uid/gid,且当前进程必须是 root 才能调用) - 注意
os.setuid()不可逆,且一旦降权,无法再升回 root;务必在完成所有特权操作后再调用
tempfile.mkstemp 创建的文件为什么还是可被其他用户读?
默认情况下,tempfile.mkstemp() 返回的文件描述符对应文件权限是 0o600,但实际创建时受 umask 影响。如果系统 umask 是 0o022,最终权限会变成 0o644——其他用户可读。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 显式传入
dir和prefix参数还不够,必须配合mode参数:tempfile.mkstemp(mode='w+b', dir='/tmp', prefix='myapp_') - 更稳妥的做法是创建后立刻修正:
os.fchmod(fd, 0o600)(注意是fchmod,作用于 fd,不受 umask 干扰) - 别依赖
/tmp的 sticky bit 来防窥探;它只防删,不防读——真正敏感内容应写入/run/user/$(id -u)或$XDG_RUNTIME_DIR
用 subprocess 调外部命令时怎么避免继承父进程权限?
Python 进程以 root 启动,再用 subprocess.run(['curl', ...]),子进程默认继承父进程的 uid/gid 和 capability 集。这意味着 curl 也能绑定低端口、访问 root-only 文件——完全违背最小权限原则。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
preexec_fn=os.seteuid+user参数组合不可靠;推荐直接用subprocess.run(..., user='nobody')(Python 3.9+),它会自动处理 uid/gid 切换和组权限清理 - 旧版本 Python 可手动构造
preexec_fn:先os.setgroups([])清空补充组,再os.setgid(nobody_gid),最后os.setuid(nobody_uid) - 特别注意:
shell=True会让权限控制失效——因为中间多了一层 shell 进程,且环境变量(如PATH)可能引入不可控行为;一律禁用,改用列表形式传参
权限最小化不是“少开几个 sudo”,而是每次打开权限都要有明确的、不可绕过的理由,并在第一时间关掉。最容易被忽略的是子进程继承和 umask 漏洞——它们不会报错,只会悄悄扩大攻击面。










