Skip to content

Commit a1ee9b6

Browse files
committed
Fix the fstat/statat/etc. fallback when statx fails with EPERM.
On some old non-y2038-safe container runtimes, `statx` fails with `EPERM`, so use `crate::fs::statx` instead of calling the statx syscall directly. This includes code to check whether it was a "real" `EPERM` we should return to the user, or an `EPERM` which indicates that statx isn't supported, allowing rustix to fall back to the old non-y2038-safe syscalls. Also, update the crate-level comment mentionintg that rustix does sometimes do dynamic feature detection in order to support y2038 and LFS. And fix a copy and paste in a comment in `renameat2`.
1 parent bff1d53 commit a1ee9b6

File tree

3 files changed

+23
-10
lines changed

3 files changed

+23
-10
lines changed

src/backend/libc/fs/syscalls.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ pub(crate) fn renameat2(
385385
new_path: &CStr,
386386
flags: RenameFlags,
387387
) -> io::Result<()> {
388-
// `getrandom` wasn't supported in glibc until 2.28.
388+
// `renameat2` wasn't supported in glibc until 2.28.
389389
weak_or_syscall! {
390390
fn renameat2(
391391
olddirfd: c::c_int,
@@ -442,14 +442,13 @@ pub(crate) fn symlinkat(
442442

443443
#[cfg(not(target_os = "redox"))]
444444
pub(crate) fn statat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> {
445-
// 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use
446-
// `statx`.
445+
// See the comments in `fstat` about using `crate::fs::statx` here.
447446
#[cfg(all(
448447
any(target_os = "android", target_os = "linux"),
449448
any(target_pointer_width = "32", target_arch = "mips64"),
450449
))]
451450
{
452-
match statx(dirfd, path, flags, StatxFlags::BASIC_STATS) {
451+
match crate::fs::statx(dirfd, path, flags, StatxFlags::BASIC_STATS) {
453452
Ok(x) => statx_to_stat(x),
454453
Err(io::Errno::NOSYS) => statat_old(dirfd, path, flags),
455454
Err(err) => Err(err),
@@ -1108,12 +1107,16 @@ pub(crate) fn sync() {
11081107
pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> {
11091108
// 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use
11101109
// `statx`.
1110+
//
1111+
// And, some old platforms don't support `statx`, and some fail with a
1112+
// confusing error code, so we call `crate::fs::statx` to handle that. If
1113+
// `statx` isn't available, fall back to the buggy system call.
11111114
#[cfg(all(
11121115
any(target_os = "android", target_os = "linux"),
11131116
any(target_pointer_width = "32", target_arch = "mips64"),
11141117
))]
11151118
{
1116-
match statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) {
1119+
match crate::fs::statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) {
11171120
Ok(x) => statx_to_stat(x),
11181121
Err(io::Errno::NOSYS) => fstat_old(fd),
11191122
Err(err) => Err(err),

src/backend/linux_raw/fs/syscalls.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -442,9 +442,15 @@ pub(crate) fn sync() {
442442

443443
#[inline]
444444
pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> {
445+
// 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use
446+
// `statx`.
447+
//
448+
// And, some old platforms don't support `statx`, and some fail with a
449+
// confusing error code, so we call `crate::fs::statx` to handle that. If
450+
// `statx` isn't available, fall back to the buggy system call.
445451
#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
446452
{
447-
match statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) {
453+
match crate::fs::statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) {
448454
Ok(x) => statx_to_stat(x),
449455
Err(io::Errno::NOSYS) => fstat_old(fd),
450456
Err(err) => Err(err),
@@ -478,9 +484,10 @@ fn fstat_old(fd: BorrowedFd<'_>) -> io::Result<Stat> {
478484

479485
#[inline]
480486
pub(crate) fn stat(filename: &CStr) -> io::Result<Stat> {
487+
// See the comments in `fstat` about using `crate::fs::statx` here.
481488
#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
482489
{
483-
match statx(
490+
match crate::fs::statx(
484491
crate::fs::cwd().as_fd(),
485492
filename,
486493
AtFlags::empty(),
@@ -537,9 +544,10 @@ fn stat_old(filename: &CStr) -> io::Result<Stat> {
537544

538545
#[inline]
539546
pub(crate) fn statat(dirfd: BorrowedFd<'_>, filename: &CStr, flags: AtFlags) -> io::Result<Stat> {
547+
// See the comments in `fstat` about using `crate::fs::statx` here.
540548
#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
541549
{
542-
match statx(dirfd, filename, flags, StatxFlags::BASIC_STATS) {
550+
match crate::fs::statx(dirfd, filename, flags, StatxFlags::BASIC_STATS) {
543551
Ok(x) => statx_to_stat(x),
544552
Err(io::Errno::NOSYS) => statat_old(dirfd, filename, flags),
545553
Err(err) => Err(err),
@@ -591,9 +599,10 @@ fn statat_old(dirfd: BorrowedFd<'_>, filename: &CStr, flags: AtFlags) -> io::Res
591599

592600
#[inline]
593601
pub(crate) fn lstat(filename: &CStr) -> io::Result<Stat> {
602+
// See the comments in `fstat` about using `crate::fs::statx` here.
594603
#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
595604
{
596-
match statx(
605+
match crate::fs::statx(
597606
crate::fs::cwd().as_fd(),
598607
filename,
599608
AtFlags::SYMLINK_NOFOLLOW,

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@
7171
//! running under seccomp.
7272
//!
7373
//! Things they don't do include:
74-
//! - Detecting whether functions are supported at runtime.
74+
//! - Detecting whether functions are supported at runtime, except in specific
75+
//! cases where new interfaces need to be detected to support y2038 and LFS.
7576
//! - Hiding significant differences between platforms.
7677
//! - Restricting ambient authorities.
7778
//! - Imposing sandboxing features such as filesystem path or network address

0 commit comments

Comments
 (0)