From 55aa28467914463e9c6869cd3c8b7264f7e6e695 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Tue, 27 Oct 2015 23:57:08 -0500 Subject: Use the /proc/self/fd/%d workaround for O_PATH not letting you read xattrs, inspired by: https://android-review.googlesource.com/#/c/152663/4/libc/bionic/fgetxattr.cpp --- toys/posix/ls.c | 49 +++++++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 28 deletions(-) (limited to 'toys/posix/ls.c') diff --git a/toys/posix/ls.c b/toys/posix/ls.c index 968b2537..7d15935c 100644 --- a/toys/posix/ls.c +++ b/toys/posix/ls.c @@ -186,34 +186,27 @@ static int filter(struct dirtree *new) if (flags & FLAG_Z) { if (!CFG_TOYBOX_LSM_NONE) { - 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() 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 { - lsm_fget_context(fd, (char **)&new->extra); + + // (Wouldn't it be nice if the lsm functions worked like openat(), + // fchmodat(), mknodat(), readlinkat() so we could do this without + // even O_PATH? But no, this is 1990's tech.) + int fd = openat(dirtree_parentfd(new), new->name, + O_PATH|(O_NOFOLLOW*!!(toys.optflags&FLAG_L))); + + if (fd != -1) { + if (-1 == lsm_fget_context(fd, (char **)&new->extra) && errno == EBADF) + { + char hack[32]; + + // Work around kernel bug that won't let us read this "metadata" from + // the filehandle unless we have permission to read the data. (We can + // query the same data in by path, but can't do it through an O_PATH + // filehandle, because reasons. But for some reason, THIS is ok? If + // they ever fix the kernel, this should stop triggering.) + + sprintf(hack, "/proc/self/fd/%d", fd); + lsm_lget_context(hack, (char **)&new->extra); + } close(fd); } } -- cgit v1.2.3