不可靠。access("/")仅检查传统dac权限,无法反映cap_sys_admin、user namespace、sip、uac等实际限制;应改用mkdir()等轻量syscall试探并捕获errno。

Linux/macOS 下用 access() 检查对 / 的写权限是否可靠?
不可靠。直接调用 access("/", W_OK) 返回 0,不代表你真能往 / 下创建或修改文件——它只检查当前进程的有效 UID/GID 是否在文件系统权限模型中被允许,而现代系统(尤其是启用了 capability 或 rootless 容器的环境)会绕过这套检查。
真正起作用的是内核级权限控制:是否拥有 CAP_SYS_ADMIN(传统 root)、CAP_DAC_OVERRIDE(绕过 DAC),或者是否运行在 unprivileged user namespace 中。普通用户即使 access() 返回成功,执行 open("/etc/hosts", O_WRONLY) 仍大概率失败并返回 EACCES 或 EROFS。
-
access()是静态权限快照,不反映实际 syscall 执行时的上下文(如 seccomp、SELinux、mount options) - 若程序以非 root 用户启动但通过
setuid或sudo提权,access()可能误判(取决于调用时机) - macOS 上还需考虑 SIP(System Integrity Protection):即使 root 也无法修改
/System、/usr等路径,access()完全不感知 SIP
更务实的做法:直接尝试最小化操作 + 捕获 errno
与其预测权限,不如做一次轻量、无副作用的试探性 syscall,并根据错误码反推能力边界。例如:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
int fd = open("/tmp/.perm_test_XXXXXX", O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd == -1) {
if (errno == EACCES || errno == EROFS) {
// /tmp 不可写 → 根本没机会碰 /
}
}
close(fd);
unlink("/tmp/.perm_test_XXXXXX");
// 再试根目录下极小代价操作
int ret = mkdir("/.test_perm_XXXXXX", 0700);
if (ret == -1 && (errno == EACCES || errno == EPERM || errno == EROFS)) {
// 明确知道无法在 / 下创建目录 → 几乎肯定不能改系统文件
}
rmdir("/.test_perm_XXXXXX");
- 避免用
stat("/")查 uid/gid:root 用户也可能被 chroot 或 namespace 隔离,stat 结果无意义 - 不要用
geteuid() == 0判断:容器里 uid=0 ≠ 真实特权(user namespace 默认启用) - 优先选
mkdir()而非open():前者不触发 page cache 或日志写入,副作用更小;且多数系统对/的 mkdir 权限和文件写权限一致
Windows 下判断对 C: 的修改权限要特别注意 UAC 和完整性级别
Windows 没有“root”概念,而是靠完整性级别(IL)和 UAC 虚拟化共同决定。即使你是 Administrator 组成员,进程默认 IL 是 MEDIUM,对 C: 写入会被重定向到 VirtualStore 或直接拒绝。
- 用
CheckTokenMembership()+GetTokenInformation(TokenIntegrityLevel)获取当前 token 的 IL;只有 IL ≥SECURITY_MANDATORY_HIGH_RID才可能真实写入C: - UAC 弹窗不是“授权”,而是启动一个新高 IL 进程;原进程 IL 不会改变
- 不要依赖
GetFileAttributes("C:\") & FILE_ATTRIBUTE_READONLY:该标志在 NTFS 上几乎总为 0,与实际写权限无关 - 真实检测必须用
CreateFile("C:\test.perm", GENERIC_WRITE, ...)并检查是否返回INVALID_HANDLE_VALUE且GetLastError()为ERROR_ACCESS_DENIED或ERROR_PRIVILEGE_NOT_HELD
跨平台封装时最容易忽略的点
没有“统一判断根目录写权限”的安全方式。不同系统底层机制差异太大,强行抽象只会掩盖风险。
- Linux/macOS:
mkdir("/")是非法操作(ENOTEMPTY),必须用子路径如"/."或"/tmp"做代理;但"/."在某些只读挂载下仍可能返回 ENOENT - Windows:
GetDriveType("C:\")返回DRIVE_FIXED不代表可写,SSD 硬件写保护或 BitLocker 挂起状态都会导致后续失败 - 所有试探性调用都应设超时或限制重试次数——某些 NFS 或 FUSE 文件系统在权限检查阶段就可能卡住
- 如果程序需要持续修改系统文件,正确做法是提前申请、明确告知用户需提升权限,而不是运行时悄悄降级行为
真正难的不是“怎么测”,而是测完之后如何让程序在权限不足时给出准确、可操作的反馈——比如区分“你不是管理员”和“你虽然是管理员但启用了 SIP/UAC 虚拟化”。这些边界情况,代码里留一个 // TODO: refine error message per platform 往往比写一百行通用检测更有价值。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










