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

Reply via email to