Skip to content

Commit dc664b3

Browse files
committed
test: check supplementary groups and ACLs for -r/-w/-x permissions.
Replace manual permission checking logic with platform-specific libc functions that properly handle supplementary groups and ACLs: - Linux, Hurd, Redox, Cygwin, Solaris, Illumos: euidaccess() - FreeBSD: eaccess() - macOS, iOS, NetBSD, OpenBSD, DragonFly: faccessat() with AT_EACCESS - Android: faccessat() - Other OSes: fall back to libc:access() These functions delegate permission checks to the kernel, which correctly evaluates all of the user's group memberships (both primary and supplementary), as well as ACLs and other advanced permission features. Fixes #8960 Fixes #9147
1 parent 017efe4 commit dc664b3

File tree

2 files changed

+66
-16
lines changed

2 files changed

+66
-16
lines changed

.vscode/cspell.dictionaries/workspace.wordlist.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ vmsplice
152152

153153
# * vars/libc
154154
COMFOLLOW
155+
EACCESS
155156
EXDEV
157+
FDCWD
156158
FILENO
157159
FTSENT
158160
HOSTSIZE
@@ -196,7 +198,10 @@ blocksize
196198
canonname
197199
chroot
198200
dlsym
201+
eaccess
202+
euidaccess
199203
execvp
204+
faccessat
200205
fdatasync
201206
freeaddrinfo
202207
getaddrinfo

src/uu/test/src/test.rs

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -258,26 +258,71 @@ enum PathCondition {
258258

259259
#[cfg(not(windows))]
260260
fn path(path: &OsStr, condition: &PathCondition) -> bool {
261-
use std::fs::Metadata;
261+
use std::ffi::CString;
262+
use std::os::unix::ffi::OsStrExt;
262263
use std::os::unix::fs::FileTypeExt;
263264

264265
const S_ISUID: u32 = 0o4000;
265266
const S_ISGID: u32 = 0o2000;
266267
const S_ISVTX: u32 = 0o1000;
267268

268-
enum Permission {
269-
Read = 0o4,
270-
Write = 0o2,
271-
Execute = 0o1,
272-
}
269+
// Helper function to check file access permissions.
270+
// Uses platform-specific access functions that properly handle supplementary groups
271+
// and ACLs.
272+
let check_access = |path: &OsStr, mode: i32| -> bool {
273+
let path_bytes = path.as_bytes();
274+
let Ok(c_path) = CString::new(path_bytes) else {
275+
return false; // Path contains null byte
276+
};
273277

274-
let perm = |metadata: Metadata, p: Permission| {
275-
if geteuid() == metadata.uid() {
276-
metadata.mode() & ((p as u32) << 6) != 0
277-
} else if getegid() == metadata.gid() {
278-
metadata.mode() & ((p as u32) << 3) != 0
279-
} else {
280-
metadata.mode() & (p as u32) != 0
278+
unsafe {
279+
#[cfg(any(
280+
target_os = "linux",
281+
target_os = "hurd",
282+
target_os = "redox",
283+
target_os = "cygwin",
284+
target_os = "solaris",
285+
target_os = "illumos"
286+
))]
287+
{
288+
libc::euidaccess(c_path.as_ptr(), mode) == 0
289+
}
290+
291+
#[cfg(target_os = "freebsd")]
292+
{
293+
libc::eaccess(c_path.as_ptr(), mode) == 0
294+
}
295+
296+
#[cfg(any(
297+
target_os = "macos",
298+
target_os = "ios",
299+
target_os = "netbsd",
300+
target_os = "openbsd",
301+
target_os = "dragonfly"
302+
))]
303+
{
304+
libc::faccessat(libc::AT_FDCWD, c_path.as_ptr(), mode, libc::AT_EACCESS) == 0
305+
}
306+
307+
// Fallback for other OSes
308+
#[cfg(not(any(
309+
target_os = "linux",
310+
target_os = "hurd",
311+
target_os = "redox",
312+
target_os = "cygwin",
313+
target_os = "solaris",
314+
target_os = "illumos",
315+
target_os = "freebsd",
316+
target_os = "macos",
317+
target_os = "ios",
318+
target_os = "netbsd",
319+
target_os = "openbsd",
320+
target_os = "dragonfly"
321+
)))]
322+
{
323+
// fallback: use regular access()
324+
libc::access(c_path.as_ptr(), mode) == 0
325+
}
281326
}
282327
};
283328

@@ -308,12 +353,12 @@ fn path(path: &OsStr, condition: &PathCondition) -> bool {
308353
PathCondition::Sticky => metadata.mode() & S_ISVTX != 0,
309354
PathCondition::UserOwns => metadata.uid() == geteuid(),
310355
PathCondition::Fifo => file_type.is_fifo(),
311-
PathCondition::Readable => perm(metadata, Permission::Read),
356+
PathCondition::Readable => check_access(path, libc::R_OK),
312357
PathCondition::Socket => file_type.is_socket(),
313358
PathCondition::NonEmpty => metadata.size() > 0,
314359
PathCondition::UserIdFlag => metadata.mode() & S_ISUID != 0,
315-
PathCondition::Writable => perm(metadata, Permission::Write),
316-
PathCondition::Executable => perm(metadata, Permission::Execute),
360+
PathCondition::Writable => check_access(path, libc::W_OK),
361+
PathCondition::Executable => check_access(path, libc::X_OK),
317362
}
318363
}
319364

0 commit comments

Comments
 (0)