From: Rob Landley Date: Tue, 19 May 2015 19:53:06 +0000 (-0500) Subject: Adapted patch from José Bollo to do the "tonight we're gonna api like X-Git-Tag: upstream/0.6.0~56 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b031a3bc269e9cdb7bf307a757896b6ec7c4b3fe;p=platform%2Fupstream%2Ftoybox.git 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. 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.) --- diff --git a/toys/posix/ls.c b/toys/posix/ls.c index 84149e4..6429ce6 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); } }