From b031a3bc269e9cdb7bf307a757896b6ec7c4b3fe Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 19 May 2015 14:53:06 -0500 Subject: Adapted patch from José Bollo to do the "tonight we're gonna api like it's 1999 and every path ever is from cwd or root" api versions for sockets and as a fallback of the open fails. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are still some holes (symlink to socket with -L will give you info about the symlink, not the socket, and symlink to a file you can't open will give you info about the symlink, not the file) but the correct fix is to make O_PATH work in the kernel for the LSM functions. (If we can read this data by path, we should be able to read it by O_PATH. We should not need two codepaths for this.) --- toys/posix/ls.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'toys/posix/ls.c') diff --git a/toys/posix/ls.c b/toys/posix/ls.c index 84149e41..6429ce60 100644 --- a/toys/posix/ls.c +++ b/toys/posix/ls.c @@ -181,24 +181,34 @@ static int filter(struct dirtree *new) if (flags & FLAG_Z) { if (!CFG_TOYBOX_LSM_NONE) { - // In theory we can just openat(O_PATH|O_NOFOLLOW) and getcontext() on - // that filehandle, but the kernel won't let us read this "metadata" - // unless we have permission to read the data, so we do these elaborate - // bug workarounds instead. - if (S_ISLNK(new->st.st_mode) && !(toys.optflags & FLAG_L)) { + int fd; + + // Why not just openat(O_PATH|(O_NOFOLLOW*!!(toys.optflags&FLAG_L))) and + // lsm_fget_context() on that filehandle? Because the kernel is broken, + // and won't let us read this "metadata" from the filehandle unless we + // have permission to read the data. We _can_ read the same data in + // by path, we just can't do it through an O_PATH filehandle, because + // reasons. So as a bug workaround for the broken kernel, we do it + // both ways. + // + // The O_NONBLOCK is there to avoid triggering automounting (there's + // a rush of nostalgia for you) on directories we don't descend into, + // which O_PATH would have done for us but see "the kernel is broken". + if (S_ISSOCK(new->st.st_mode) || + (S_ISLNK(new->st.st_mode) && !(toys.optflags & FLAG_L)) || + -1 == (fd = openat(dirtree_parentfd(new), new->name, + O_RDONLY|O_NONBLOCK|O_NOATIME))) + { char *path; // Wouldn't it be nice if the lsm functions worked like openat(), - // fchmodat(), mknodat(), readlinkat()... but no, this is 1990's tech. + // fchmodat(), mknodat(), readlinkat() so we could do this without + // even O_PATH? But no, this is 1990's tech. path = dirtree_path(new, 0); lsm_lget_context(path, (char **)&new->extra); free(path); } else { - // Why O_NONBLOCK? No idea. Why not O_PATH|O_NOFOLLOW? Kernel's broken. - int fd = openat(dirtree_parentfd(new), new->name, - O_RDONLY|O_NONBLOCK|O_NOATIME); - - if (fd != -1) lsm_fget_context(fd, (char **)&new->extra); + lsm_fget_context(fd, (char **)&new->extra); close(fd); } } -- cgit v1.2.3