Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [Bug] Strange Globing Behaviour when used with sudo



> 2018/06/01 03:15, Daniel Tameling <tamelingdaniel@xxxxxxxxx> wrote:
> 
> As s is NULL and buf is in the example ./file/, statfullpath adds to
> buf a . so that it's "./file/.".
(snip)
>  So one possibility to fix this is to
> call stat before adding the . to ./file/, and the return non-zero if
> it is not a directory.

Yes, but users can add '.' by themselves, for example
sudo zsh -c 'echo */.'. And of course you can not just
"return !S_ISDIR(st->st_mode)", and st may be NULL.

I've also fond that stat("file/..") is similarly broken.

In the patch below, I enclosed everything within "#ifdef __APPLE__"
to minimize the side effects. It is difficult to detect the bug
by configure since it requires sudo.


diff --git a/Src/glob.c b/Src/glob.c
index 66a95329f..95b3c7ca0 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -288,6 +288,26 @@ statfullpath(const char *s, struct stat *st, int l)
     DPUTS(strlen(s) + !*s + pathpos - pathbufcwd >= PATH_MAX,
 	  "BUG: statfullpath(): pathname too long");
     strcpy(buf, pathbuf + pathbufcwd);
+ 
+#ifdef __APPLE__
+    /*
+     * Workaround for broken stat()/lstat()/access() on macOS.
+     * If called by root, these syscalls mistakenly return success for
+     * path like "foo/bar/." or "foo/bar/.." even if "bar" is a file.
+     * We should make sure "bar" is a directory.
+     */
+    if (!*s || !strcmp(s, ".") || !strcmp(s, "..")) {
+	struct stat stbuf;
+	if (stat(unmeta(buf), &stbuf) || !S_ISDIR(stbuf.st_mode))
+		return -1;
+	if (strcmp(s, "..")) {	    /* done if s is "" or "." */
+	    if (st)
+		*st = stbuf;
+	    return 0;
+	}
+    }
+#endif
+
     strcpy(buf + pathpos - pathbufcwd, s);
     if (!*s && *buf) {
 	/*







Messages sorted by: Reverse Date, Date, Thread, Author