Skip to content

Commit

Permalink
Fix the fstat/statat/etc. fallback when statx fails with EPERM.
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
sunfishcode committed May 7, 2023
1 parent bff1d53 commit a1ee9b6
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 10 deletions.
13 changes: 8 additions & 5 deletions src/backend/libc/fs/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ pub(crate) fn renameat2(
new_path: &CStr,
flags: RenameFlags,
) -> io::Result<()> {
// `getrandom` wasn't supported in glibc until 2.28.
// `renameat2` wasn't supported in glibc until 2.28.
weak_or_syscall! {
fn renameat2(
olddirfd: c::c_int,
Expand Down Expand Up @@ -442,14 +442,13 @@ pub(crate) fn symlinkat(

#[cfg(not(target_os = "redox"))]
pub(crate) fn statat(dirfd: BorrowedFd<'_>, path: &CStr, flags: AtFlags) -> io::Result<Stat> {
// 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use
// `statx`.
// See the comments in `fstat` about using `crate::fs::statx` here.
#[cfg(all(
any(target_os = "android", target_os = "linux"),
any(target_pointer_width = "32", target_arch = "mips64"),
))]
{
match statx(dirfd, path, flags, StatxFlags::BASIC_STATS) {
match crate::fs::statx(dirfd, path, flags, StatxFlags::BASIC_STATS) {
Ok(x) => statx_to_stat(x),
Err(io::Errno::NOSYS) => statat_old(dirfd, path, flags),
Err(err) => Err(err),
Expand Down Expand Up @@ -1108,12 +1107,16 @@ pub(crate) fn sync() {
pub(crate) fn fstat(fd: BorrowedFd<'_>) -> io::Result<Stat> {
// 32-bit and mips64 Linux: `struct stat64` is not y2038 compatible; use
// `statx`.
//
// And, some old platforms don't support `statx`, and some fail with a
// confusing error code, so we call `crate::fs::statx` to handle that. If
// `statx` isn't available, fall back to the buggy system call.
#[cfg(all(
any(target_os = "android", target_os = "linux"),
any(target_pointer_width = "32", target_arch = "mips64"),
))]
{
match statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) {
match crate::fs::statx(fd, cstr!(""), AtFlags::EMPTY_PATH, StatxFlags::BASIC_STATS) {
Ok(x) => statx_to_stat(x),
Err(io::Errno::NOSYS) => fstat_old(fd),
Err(err) => Err(err),
Expand Down
17 changes: 13 additions & 4 deletions src/backend/linux_raw/fs/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,9 +442,15 @@ pub(crate) fn sync() {

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

#[inline]
pub(crate) fn stat(filename: &CStr) -> io::Result<Stat> {
// See the comments in `fstat` about using `crate::fs::statx` here.
#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
{
match statx(
match crate::fs::statx(
crate::fs::cwd().as_fd(),
filename,
AtFlags::empty(),
Expand Down Expand Up @@ -537,9 +544,10 @@ fn stat_old(filename: &CStr) -> io::Result<Stat> {

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

#[inline]
pub(crate) fn lstat(filename: &CStr) -> io::Result<Stat> {
// See the comments in `fstat` about using `crate::fs::statx` here.
#[cfg(any(target_pointer_width = "32", target_arch = "mips64"))]
{
match statx(
match crate::fs::statx(
crate::fs::cwd().as_fd(),
filename,
AtFlags::SYMLINK_NOFOLLOW,
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@
//! running under seccomp.
//!
//! Things they don't do include:
//! - Detecting whether functions are supported at runtime.
//! - Detecting whether functions are supported at runtime, except in specific
//! cases where new interfaces need to be detected to support y2038 and LFS.
//! - Hiding significant differences between platforms.
//! - Restricting ambient authorities.
//! - Imposing sandboxing features such as filesystem path or network address
Expand Down

0 comments on commit a1ee9b6

Please sign in to comment.