Hello, I'm seeing surprising behavior in ksh's privileged mode versus /bin/sh's privileged mode. Bear with me for a moment, as I lay my scene:
$ ls -l -rw-rw---- 1 nobody nogroup 4 May 30 16:43 f -rwxr-s--- 1 nobody nogroup 8728 May 30 16:43 gids -rwxr-sr-x 1 nobody nogroup 8272 May 30 16:43 setgidsh -rwxr-xr-x 1 jschauma wheel 9912 May 30 16:43 showaccess "gids" is printf("real : %d %d\n", getuid(), getgid()); printf("effective: %d %d\n", geteuid(), getegid()); "setgidsh" is just wrapper to let me run a shell with egid != gid: int main(int argc, char **argv) { argv++; execv(argv[0], argv); perror("execl"); } "showaccess" just prints what access(2) and faccessat(2) say about the argument. So now: $ ./setgidsh /bin/sh $ id uid=1000(jschauma) gid=100(users) groups=100(users),0(wheel) $ ./gids sh: ./gids: permission denied $ This is expected: /bin/sh resets e[gu]id if they don't match at startup, unless '-p' is specified: $ ./setgidsh /bin/sh -p $ id uid=1000(jschauma) gid=100(users) egid=32766(nogroup) groups=100(users),0(wheel) $ ./gids real : 1000 100 effective: 1000 32766 $ Ok, so far, so good. csh flat out refuses to start if egid != gid unless you pass the "-b" flag to enter "batch" mode: $ ./setgidsh /bin/csh csh: Permission denied. $ ./setgidsh /bin/csh -b % id uid=1000(jschauma) gid=100(users) egid=32766(nogroup) groups=100(users),0(wheel) % ./gids real : 1000 100 effective: 1000 32766 Seems an odd choice for the flag, but ok. So now with ksh: $ ./setgidsh /bin/ksh $ id uid=1000(jschauma) gid=100(users) egid=32766(nogroup) groups=100(users),0(wheel) $ cat f foo $ ./gids /bin/ksh: ./gids: cannot execute - Permission denied Here, ksh at startup determines that egid != gid and so becomes "privileged". That's the same as if I had invoked "/bin/ksh -p", but it seems that even though I can use my egid for read/write access, I have no way of allowing ksh to honor egid for execution: clearing the "privileged" option resets my egid to my real gid. ksh uses access(2) in ksh/exec.c search_access() to determine if it can invoke a given command, but obviously access(2) doesn't use the effective [ug]id, so will deny the command. Now I _can_ run the command via env(1): $ ./setgidsh /bin/ksh $ id uid=1000(jschauma) gid=100(users) egid=32766(nogroup) groups=100(users),0(wheel) $ ./gids /bin/ksh: ./gids: cannot execute - Permission denied $ env ./gids real : 1000 100 effective: 1000 32766 $ because my real-[ug]id is allowed to execute env(1), so the privileged ksh does not complain, and env(1) doesn't perform any such check and will simply execve(2) "./gids" and let the kernel check the access permissions. This seems surprising if not flat out a bug: it provides no actual protection, since I can still run the command, and other shells let me explicitly allow running commands with a different egid. Is this something that should be fixed? -Jan