Change:
When I run this sequence of commands: I get this error: This happens due to the failing with EPERM. I believe Docker uses seccomp to limit which system calls may be made, and the call is too new, so it's . Because the syscall fails with EPERM instead of ENOSYS, the fallback to regular doesn't work. Host kernel: 4.15.0-65-generic docker version
Nominating for libs team as this is a recent regression caused by -- cc Personally this leads me to believe we should either be happier to fallback to the previous code (e.g., for any error) or revert the PR entirely since breaking usage of Rust code in Docker is not really feasible (even if this is arguably a Docker bug).
Alternatively, we can try statx on something that should always succeed (maybe ?)
Cannot it match ENOSYS or EPERM just like getrandom syscall does?
Unlike for , getting EPERM is not sufficient evidence that doesn't work.
Thanks for investigating this down to being the culprit, definitely makes sense! I was searching around for other instances of this, and definitely turns out we're not the only ones running into this - another docker user reporting the same issue. It's pointed out that Docker 18.04 apparently allows by default - another user with qt's build system finding that seccomp disallows a new syscall Looks like musl (called ) and only handles ENOSYS Seccomp itself got support for statx as a sycall in general Overaall I don't think there's a lot of prior art for this to draw from, it seems that everyone's working around the seccomp issue rather than addressing it directly. I think a reasonable solution might be to do something like try to stat initially and if that fails with EPERM or ENOSYS we disable the syscall entirely, otherwise it's cached as always good to use. would you be interested in helping to implement this?
Do you mean to check current working directory instead of the actual argument before the first call, and regard EPERM and ENOSYS as not implemented? I'm glad to fix it.
yeah that's what I'm thinking, the idea being that if we don't know whether works we invoke it with a path which we know should work almost all the time (like the cwd) and if it returns EPERM in that situation we can be pretty certain we're seccomp blocked.
We are encountering a similar issue while building an Docker image with rustc & cargo on CircleCI. We are basically doing: and are getting: This errors happens since yesterday. Our last successful build with the same script was 2 days ago, with these versions: So basically between and , something changed that makes unable to figure out that is installed. After many tests on different Docker hosts, we haved narrowed the issue to the following: if the Docker host is using the or storage drivers, everything works perfectly; if it is using storage driver, then basically cannot see that the file exists, and treats rustfmt as not installed.
On the hosts where things don't work, what is the docker version and host kernel version? Also, can you run your command with to see if this is because of ?
I tried with docker 18.09.2 on Linux kernel 4.14.118, it seems that works well. Maybe need to update docker?
Related?
You need rather recent Docker and libseccomp packges. Old Docker versions (or new versions running on the old systems) default to aufs but in recent versions this has changed to overlay2. That's possible explanation of what you are seeing.
On CircleCI you cannot choose the storage driver, though you can opt in to newer Docker versions, which we've done. on CircleCI Kernel and Docker versions are fairly recent, but aufs is indeed being used. I also tried 's snippet on a standard image which produced the following output: Now, CircleCI may or may not be doing something unorthodox here, but I think it is clear that this change has broken things for potentially quite a few users who do not have the capability to simply update or reconfigure their docker environment by themselves.
can you confirm your issue was solved with the latest nightly?
I can confirm it seems to work well in docker again :+1: We were having these issues with last week, and to docker to solve it. Now we can remove it and it still works.
Yes, it's working perfectly again! Thank you!

Discussion:
flags: i32, mask: u32, ) -> Option<io::Result<FileAttr>> { <del> use crate::sync::atomic::{AtomicBool, Ordering}; </del> <ins> use crate::sync::atomic::{AtomicU8, Ordering}; </ins> // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx` <del> // We store the availability in a global to avoid unnecessary syscalls static HAS_STATX: AtomicBool = AtomicBool::new(true); </del> <ins> // We store the availability in global to avoid unnecessary syscalls. // 0: Unknown // 1: Not available // 2: Available static STATX_STATE: AtomicU8 = AtomicU8::new(0); </ins> syscall! { fn statx( fd: c_int,

) -> c_int } <del> if !HAS_STATX.load(Ordering::Relaxed) { return None; } let mut buf: libc::statx = mem::zeroed(); let ret = cvt(statx(fd, path, flags, mask, &mut buf)); match ret { Err(err) => match err.raw_os_error() { Some(libc::ENOSYS) => { HAS_STATX.store(false, Ordering::Relaxed); </del> <ins> match STATX_STATE.load(Ordering::Relaxed) { 0 => { // It is a trick to call `statx` with NULL pointers to check if the syscall // is available. According to the manual, it is expected to fail with EFAULT. // We do this mainly for performance, since it is nearly hundreds times // faster than a normal successfull call. let err = cvt(statx(0, ptr::null(), 0, libc::STATX_ALL, ptr::null_mut())) .err() .and_then(|e| e.raw_os_error()); // We don't check `err == Some(libc::ENOSYS)` because the syscall may be limited // and returns `EPERM`. Listing all possible errors seems not a good idea. // See: https://github.com/rust-lang/rust/issues/65662 if err != Some(libc::EFAULT) { STATX_STATE.store(1, Ordering::Relaxed); </ins> return None; } <del> _ => return Some(Err(err)), </del> <ins> STATX_STATE.store(2, Ordering::Relaxed); </ins> } <del> Ok(_) => { // We cannot fill `stat64` exhaustively because of private padding fields. let mut stat: stat64 = mem::zeroed(); // `c_ulong` on gnu-mips, `dev_t` otherwise stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; stat.st_ino = buf.stx_ino as libc::ino64_t; stat.st_nlink = buf.stx_nlink as libc::nlink_t; stat.st_mode = buf.stx_mode as libc::mode_t; stat.st_uid = buf.stx_uid as libc::uid_t; stat.st_gid = buf.stx_gid as libc::gid_t; stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; stat.st_size = buf.stx_size as off64_t; stat.st_blksize = buf.stx_blksize as libc::blksize_t; stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; let extra = StatxExtraFields { stx_mask: buf.stx_mask, stx_btime: buf.stx_btime, }; </del> <ins> 1 => return None, _ => {} } </ins> <del> Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) } </del> <ins> let mut buf: libc::statx = mem::zeroed(); if let Err(err) = cvt(statx(fd, path, flags, mask, &mut buf)) { return Some(Err(err)); </ins> } <ins> // We cannot fill `stat64` exhaustively because of private padding fields. let mut stat: stat64 = mem::zeroed(); // `c_ulong` on gnu-mips, `dev_t` otherwise stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; stat.st_ino = buf.stx_ino as libc::ino64_t; stat.st_nlink = buf.stx_nlink as libc::nlink_t; stat.st_mode = buf.stx_mode as libc::mode_t; stat.st_uid = buf.stx_uid as libc::uid_t; stat.st_gid = buf.stx_gid as libc::gid_t; stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; stat.st_size = buf.stx_size as off64_t; stat.st_blksize = buf.stx_blksize as libc::blksize_t; stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; let extra = StatxExtraFields { stx_mask: buf.stx_mask, stx_btime: buf.stx_btime, }; Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) </ins> } } else {