Previously if you were root, and you tried to change directory into a
directory which was not owned by you and not readable (eg. 0700
bin:bin), it would fail.
This doesn't fail on regular directories because when you are root the
kernel just ignores permissions.
Although libguestfs in general tries not to duplicate kernel code, in
the case where we emulate the FUSE access(2) system call,
unfortunately we have to do it by stat-ing the object and performing
some (half-arsed) heuristics.
This commit modifies the FUSE access(2) system call, so root is now
able to chdir to any directory.
It also adds some debugging so we can debug these complex permissions
checks in the field if some other problem arises in future.
---
src/fuse.c | 51 ++++++++++++++++++++++++++++++++++++---------------
1 file changed, 36 insertions(+), 15 deletions(-)
diff --git a/src/fuse.c b/src/fuse.c
index dd63729..292ebee 100644
--- a/src/fuse.c
+++ b/src/fuse.c
@@ -301,21 +301,42 @@ mount_local_access (const char *path, int mask)
fuse = fuse_get_context ();
- if (mask & R_OK)
- ok = ok &&
- ( fuse->uid == statbuf.st_uid ? statbuf.st_mode & S_IRUSR
- : fuse->gid == statbuf.st_gid ? statbuf.st_mode & S_IRGRP
- : statbuf.st_mode & S_IROTH);
- if (mask & W_OK)
- ok = ok &&
- ( fuse->uid == statbuf.st_uid ? statbuf.st_mode & S_IWUSR
- : fuse->gid == statbuf.st_gid ? statbuf.st_mode & S_IWGRP
- : statbuf.st_mode & S_IWOTH);
- if (mask & X_OK)
- ok = ok &&
- ( fuse->uid == statbuf.st_uid ? statbuf.st_mode & S_IXUSR
- : fuse->gid == statbuf.st_gid ? statbuf.st_mode & S_IXGRP
- : statbuf.st_mode & S_IXOTH);
+ /* Root user should be able to access everything, so only bother
+ * with these fine-grained tests for non-root. (RHBZ#1106548).
+ */
+ if (fuse->uid != 0) {
+ if (mask & R_OK)
+ ok = ok &&
+ ( fuse->uid == statbuf.st_uid ? statbuf.st_mode & S_IRUSR
+ : fuse->gid == statbuf.st_gid ? statbuf.st_mode & S_IRGRP
+ : statbuf.st_mode & S_IROTH);
+ if (mask & W_OK)
+ ok = ok &&
+ ( fuse->uid == statbuf.st_uid ? statbuf.st_mode & S_IWUSR
+ : fuse->gid == statbuf.st_gid ? statbuf.st_mode & S_IWGRP
+ : statbuf.st_mode & S_IWOTH);
+ if (mask & X_OK)
+ ok = ok &&
+ ( fuse->uid == statbuf.st_uid ? statbuf.st_mode & S_IXUSR
+ : fuse->gid == statbuf.st_gid ? statbuf.st_mode & S_IXGRP
+ : statbuf.st_mode & S_IXOTH);
+ }
+
+ debug (g, "%s: "
+ "testing access mask%s%s%s%s: "
+ "caller UID:GID = %d:%d, "
+ "file UID:GID = %d:%d, "
+ "file mode = %o, "
+ "result = %s",
+ path,
+ mask & R_OK ? " R_OK" : "",
+ mask & W_OK ? " W_OK" : "",
+ mask & X_OK ? " X_OK" : "",
+ mask == 0 ? " 0" : "",
+ fuse->uid, fuse->gid,
+ statbuf.st_uid, statbuf.st_gid,
+ statbuf.st_mode,
+ ok ? "OK" : "EACCESS");
return ok ? 0 : -EACCES;
}
--
1.9.0