Skip to content

Commit 8167c92

Browse files
committed
std.posix.faccessatZ: return error.UnsupportedFlags on android (seccomp sandbox would SIGSYS), or if we know linux version is too old
1 parent 7d68c13 commit 8167c92

File tree

1 file changed

+45
-26
lines changed

1 file changed

+45
-26
lines changed

lib/std/posix.zig

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5055,33 +5055,52 @@ pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) Acces
50555055
return faccessat(dirfd, mem.sliceTo(path, 0), mode, flags);
50565056
}
50575057

5058-
const need_flags = (flags != 0); //the older, simpler syscall should stay supported, so we only need to use faccessat2 if we need flags
5059-
const faccessat_result = switch (system) {
5060-
linux => if (need_flags)
5061-
linux.faccessat2(dirfd, path, mode, flags)
5062-
else
5063-
linux.faccessat(dirfd, path, mode),
5064-
else => system.faccessat(dirfd, path, mode, flags),
5058+
const linux_is_guaranteed_at_least_5_8 = builtin.target.os.isAtLeast(.linux, .{ .major = 5, .minor = 8, .patch = 0 });
5059+
const try_with_flags_first = try_with_flags_first: switch (system) {
5060+
linux => { //regular .faccessat syscall doesn't support flags argument
5061+
if (builtin.abi.isAndroid()) break :try_with_flags_first false; //standard android programs run in a seccomp sandbox that seems to trigger signal 31 (SIGSYS) for faccessat2
5062+
if (linux_is_guaranteed_at_least_5_8 != true) break :try_with_flags_first false; //faccessat2 was introduced in Linux 5.8
5063+
break :try_with_flags_first (flags != 0); //the older, simpler syscall should stay supported, so we only need to use faccessat2 if we need flags
5064+
},
5065+
else => true,
50655066
};
5066-
switch (errno(faccessat_result)) {
5067-
.SUCCESS => return,
5068-
.ACCES => return error.AccessDenied,
5069-
.PERM => return error.PermissionDenied,
5070-
.ROFS => return error.ReadOnlyFileSystem,
5071-
.LOOP => return error.SymLinkLoop,
5072-
.TXTBSY => return error.FileBusy,
5073-
.NOTDIR => return error.FileNotFound,
5074-
.NOENT => return error.FileNotFound,
5075-
.NAMETOOLONG => return error.NameTooLong,
5076-
.INVAL => unreachable,
5077-
.FAULT => unreachable,
5078-
.IO => return error.InputOutput,
5079-
.NOMEM => return error.SystemResources,
5080-
.ILSEQ => |err| if (native_os == .wasi)
5081-
return error.InvalidUtf8
5082-
else
5083-
return unexpectedErrno(err),
5084-
else => |err| return unexpectedErrno(err),
5067+
try_with_flags_now: switch (try_with_flags_first) {
5068+
else => |try_with_flags_now| {
5069+
if (!try_with_flags_now) {
5070+
if (flags != 0) return error.UnsupportedFlags;
5071+
}
5072+
const faccessat_result = switch (system) {
5073+
linux => if (need_flags)
5074+
linux.faccessat2(dirfd, path, mode, flags)
5075+
else
5076+
linux.faccessat(dirfd, path, mode),
5077+
else => system.faccessat(dirfd, path, mode, flags),
5078+
};
5079+
switch (errno(faccessat_result)) {
5080+
.SUCCESS => return,
5081+
.ACCES => return error.AccessDenied,
5082+
.PERM => return error.PermissionDenied,
5083+
.ROFS => return error.ReadOnlyFileSystem,
5084+
.LOOP => return error.SymLinkLoop,
5085+
.TXTBSY => return error.FileBusy,
5086+
.NOTDIR => return error.FileNotFound,
5087+
.NOENT => return error.FileNotFound,
5088+
.NAMETOOLONG => return error.NameTooLong,
5089+
.INVAL => unreachable,
5090+
.FAULT => unreachable,
5091+
.IO => return error.InputOutput,
5092+
.NOMEM => return error.SystemResources,
5093+
.ILSEQ => |err| if (native_os == .wasi)
5094+
return error.InvalidUtf8
5095+
else
5096+
return unexpectedErrno(err),
5097+
.NOSYS => |err| if (system == linux and try_with_flags_now)
5098+
continue :try_with_flags_now false //retry with older .faccessat (without support for flags)
5099+
else
5100+
return unexpectedErrno(err),
5101+
else => |err| return unexpectedErrno(err),
5102+
}
5103+
},
50855104
}
50865105
}
50875106

0 commit comments

Comments
 (0)