Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle AT_EMPTY_PATH for fstatat64 #1812

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

zhaofengli
Copy link

This PR adds correct handling for the AT_EMPTY_PATH flag in fstatat64. AT_EMPTY_PATH allows an empty string to be specified as the path, in which case fstatat should operate on the file pointed at by the fd itself:

       AT_EMPTY_PATH (since Linux 2.6.39)
              If pathname is an empty string, operate on the file
              referred to by dirfd (which may have been obtained using
              the open(2) O_PATH flag).  In this case, dirfd can refer
              to any type of file, not just a directory, and the
              behavior of fstatat() is similar to that of fstat().  If
              dirfd is AT_FDCWD, the call operates on the current
              working directory.  This flag is Linux-specific; define
              _GNU_SOURCE to obtain its definition.

This behavior is relied on by newer glibc when loading shared objects. Currently we return -ENOENT for empty paths, leading to behavior like:

/ # bash
bash: error while loading shared libraries: libreadline.so.8: cannot stat shared object: No such file or directory
/ # dmesg
[snip]
2 call 295 openat(-100, "/nix/store/kslb3am4237in6m7i6qi210vc6w7rsfn-readline-8.1p2/lib/libreadline.so.8", 0x88000, 0x0) = 0x3
2 call 3   read(3, 0xffffd110, 512) "ELF" = 0x200
2 call 180 pread(3, 0xffffcee0, 40, 314308) "" = 0x28
2 call 300 stat(at=3, path="", statbuf=0xffffce78, follow_links=1) = 0xfffffffe
2 call 6   close(3) = 0x0
2 call 146 writev(2, 0xffffcd90, 10) {"bash", 4} {": ", 2} {"error while loading shared libraries", 36} {": ", 2} {"libreadline.so.8", 16} {": ", 2} {"cannot stat shared object", 25} {": ", 2} {"No such file or directory", 25} {"
", 1} = 0x73
2 call 252 exit_group(127)

With the fix:

/ # bash
bash-5.1# exit
/ # dmesg
[snip]
4 call 295 openat(-100, "/nix/store/kslb3am4237in6m7i6qi210vc6w7rsfn-readline-8.1p2/lib/libreadline.so.8", 0x88000, 0x0) = 0x3
4 call 3   read(3, 0xffffd110, 512) "ELF" = 0x200
4 call 180 pread(3, 0xffffcee0, 40, 314308) "" = 0x28
4 call 300 stat(at=3, path="", statbuf=0xffffce78, flags=0x1000) = 0x0

Note that many glibc programs are still broken. I'm playing around with getting a Nix-based environment running in iSH and while I was able to start bash and run some small programs, Nix itself still doesn't run:

  • getcontext() and setcontext() save and restore fs (racket needs fs register #370)
    • 5 illegal instruction at 0xf749e35f: 66 8c e2 89 50 18 8d 88 (mov dx, fs)
  • Need to implement/stub more syscalls: 126 (sigprocmask), 435 (clone3)
  • ... and more, because Nix still hangs after some quick hacks

This is used by newer glibc when loading shared objects.

       AT_EMPTY_PATH (since Linux 2.6.39)
              If pathname is an empty string, operate on the file referred to by dirfd (which may have been ob‐
              tained using the open(2) O_PATH flag).  In this case, dirfd can refer to any type  of  file,  not
              just  a  directory,  and  the  behavior  of fstatat() is similar to that of fstat().  If dirfd is
              AT_FDCWD, the call operates on the current working directory.  This flag is  Linux-specific;  de‐
              fine _GNU_SOURCE to obtain its definition.
emkey1 pushed a commit to emkey1/ish-AOK that referenced this pull request May 25, 2022
emkey1 pushed a commit to emkey1/ish-AOK that referenced this pull request May 25, 2022
@pinneno
Copy link

pinneno commented Jun 2, 2022

Thank

@pinneno
Copy link

pinneno commented Jun 2, 2022

Thk

@pinneno
Copy link

pinneno commented Jun 2, 2022

zhaofengli:fstat-empty-path

@zhaofengli
Copy link
Author

@emkey1 I just tried the latest AOK release on TestFlight and it doesn't appear to have my PR. I think you merged the master branch in my fork which is not the PR.

@emkey1
Copy link
Contributor

emkey1 commented Jun 12, 2022

@emkey1 I just tried the latest AOK release on TestFlight and it doesn't appear to have my PR. I think you merged the master branch in my fork which is not the PR.

Thank you for the heads up and sorry about that. I’ll take a look in a bit.

@yassernasc
Copy link

nix on iSH? 👀

@@ -49,17 +69,18 @@ static struct fd *at_fd(fd_t f) {
return f_get(f);
}

static dword_t sys_stat_path(fd_t at_f, addr_t path_addr, addr_t statbuf_addr, bool follow_links) {
// The `flags` parameter accepts AT_ flags
static dword_t sys_stat_path(fd_t at_f, addr_t path_addr, addr_t statbuf_addr, int flags) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function now has the exact signature of sys_fstatat64 so maybe rename to sys_fstatat64

at = current->fs->pwd;
}

err = generic_getpath(at, path);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this should be calling fstat instead

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants