aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2015-10-27 23:57:08 -0500
committerRob Landley <rob@landley.net>2015-10-27 23:57:08 -0500
commit55aa28467914463e9c6869cd3c8b7264f7e6e695 (patch)
treec83d8e2beda5f19337152b5913c1f6b8f4f79a94
parent87f6a93fc594934b21fcd0e9d42baad2abb209ae (diff)
downloadtoybox-55aa28467914463e9c6869cd3c8b7264f7e6e695.tar.gz
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
-rw-r--r--toys/posix/ls.c49
1 files changed, 21 insertions, 28 deletions
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);
}
}