Bugzilla – Bug 746
Wrong first param to execve if rules have several matches
Last modified: 2016-06-18 05:57:23 MDT
I am using sudo 1.8.16 in Linux (Ubuntu 16.04) and I am seeing a very strange behaviour that looks like a bug to me (issue did not happen in older Ubuntu distributions). This is the relevant configuration for my user. ---------------- # sudo -u foouser "sudo" -l Matching Defaults entries for foouser on xprod: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin User foouser may run the following commands on xprod: (root) NOPASSWD: /absolute/path/*/tools/directories.php change-ownership ---------------- Then, I invoke sudo -n -k /absolute/path/foo/tools/directories.php change-ownership And argv[0] (as seen in script directories.php) is not /absolute/path/foo/tools/directories.php (as I wrote in command line) but /absolute/path/bar/tools/directories.php (another path that also exists, and has the same inode number (because of symbolic links)). When I use strace on the above command to see why this is happening I see this: ---------------- ... setresgid(-1, 0, -1) = 0 setgroups(1, [0]) = 0 open("/absolute/path", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 8 fstat(8, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 getdents(8, /* 23 entries */, 32768) = 712 getdents(8, /* 0 entries */, 32768) = 0 close(8) = 0 stat("/absolute/path/bar/tools", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 stat("/absolute/path/foo/tools", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 stat("/absolute/path/zap/tools", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 stat("/absolute/path/bar/tools/directories.php", {st_mode=S_IFREG|0755, st_size=347, ...}) = 0 stat("/absolute/path/foo/tools/directories.php", {st_mode=S_IFREG|0755, st_size=347, ...}) = 0 stat("/absolute/path/zap/tools/directories.php", {st_mode=S_IFREG|0755, st_size=347, ...}) = 0 ... execve("/absolute/path/bar/tools/directories.php", ["/absolute/path/foo/tools/directories.php", "change-ownership"], [/* 15 vars */] <unfinished ...> ... ---------------- So, the first parameter of execve looks wrong (uses "bar"), while the second is right (uses "foo"). I am not sure why sudo is checking all the files that match its rule (/absolute/path/*/tools/directories.php) or why is picking one at random, when I am specifying which one I want to execute. Is this a bug? Is this a feature? Any advice on how to workaround this issue would be greatly appreciated (since bad things happen to me if argv[0] looks wrong on the tool I am calling).
Sudo matches based on the inode and device so it is possible for it to call execve() on a different file path than you might expect as long as it has the same base name. Since the argv[0] passed to execve() is what the user specified, this shouldn't be an issue. However, it appears that recent versions of Linux change argv[0] for scripts based on the execve() path. No other version of Unix I'm aware of does that.
"Sudo matches based on the inode and device so it is possible for it to call execve() on a different file path than you might expect as long as it has the same base name" I am curious about why is that done. I mean, in the strace I can see sudo is looking for (calling stat on) all the scripts that match the rule. I fail to see the need of it, since in the command I specify the full path. Using a different name breaks the convention used by execve. I quote the manual (in Linux): "argv is an array of argument strings passed to the new program. By convention, the first of these strings should contain the filename associated with the file being executed." I would agree that what sudo is doing is not against POSIX execve() specification ("The argument path points to a pathname that identifies the new process image file", "The value in argv[0] should point to a filename that is associated with the process being started by one of the exec functions.") It seems like recent Linuxes assume the convention is a requirement. Would it be hard to honour that convention in Linux?
Using the inode and dev helps avoid time of check vs. time of use issues with the '!' operator. As a workaround for your specific case, try adding the following line to sudoers: Defaults fast_glob That will cause sudo to use fnmatch() instead of glob() for wild card matched.
This is fixed by https://www.sudo.ws/repos/sudo/rev/29bdba0cf2eb which will be in sudo 1.8.17.
Wow that was fast! Thanks for the fast_glob workaround, too.
Fixed in sudo 1.8.17 which is now available.