When tar executes remote command for remote archive (by default
/usr/bin/ssh), it calls sys_reset_uid_gid in rmt_open__ in forked
child right before execl. So it seems like the intent in
set-uid/set-gid situations is to run the remote command with the
privileges of the invoking user, not with the elevated privileges.

The sys_reset_uid_gid is defined in lib/system.h as

# define sys_reset_uid_gid()                                    \
  do {                                                          \
    if (! (setuid (getuid ()) == 0 && setgid (getgid ()) == 0)) \
      abort ();                                                 \
  } while (0)

This code means that supplementary groups are not cleared and saved
set-group-ID is not reset.

Affected version: tar-1.32


Steps to Reproduce:
1. Prepare "remote command" to display privileges of the process on
standard error output -- create /usr/local/bin/id with content

#!/bin/bash -p
/usr/bin/id >&2

2. Make it executable: chmod +x /usr/local/bin/id
3. Create test program suid-tar-with-groups.c to be run as
set-uid/set-gid which also sets some supplementary groups:

#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <stdlib.h>

int main(void) {
        const gid_t list[] = { 992, 993 };
        setgroups(2, list);
        execl("/usr/bin/tar", "tar", "-c", "--rsh-command=/usr/local/bin/id",
"-f", "root@localhost:/tmp/out.tar", "/something/somewhere", (char *)
NULL);
}

4. Build it as root: gcc -o /usr/local/bin/suid-tar-with-groups
suid-tar-with-groups.c
5. Make it set-uid/set-gid as root: chmod ug+s
/usr/local/bin/suid-tar-with-groups
6. Have a non-privileged account which has no supplemental groups: run
id to check:
   uid=1000(test) gid=1000(test) groups=1000(test)
context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
7. From this account, execute: /usr/local/bin/suid-tar-with-groups

Actual results:

uid=1000(test) gid=1000(test)
groups=1000(test),992(chrony),993(unbound)
context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
tar: root@localhost\:/tmp/out.tar: Cannot open: Input/output error
tar: Error is not recoverable: exiting now

Expected results:

uid=1000(test) gid=1000(test) groups=1000(test)
context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
tar: root@localhost\:/tmp/out.tar: Cannot open: Input/output error
tar: Error is not recoverable: exiting now

Additional info:

This demonstrates that when tar drops the privileges back to the
invoking real uid and real gid to execute the remote command, the
process still has the extra supplementary groups of that set-uid
process.

Based on 
https://wiki.sei.cmu.edu/confluence/display/c/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges,
calling setgroups() before setuid is needed. I tried with plain
setgroups(0, NULL); added at the start of sys_reset_uid_gid that the
supplementary groups will be purged.

Another issue is the order of the setuid() and setgid() -- since
sys_reset_uid_gid does setuid first, by the time it runs setgid, the
process no longer has permissions to drop the saved set-group-ID. The
reproducer above does not demonstrate this second problem
specifically, let's just say the order should be reversed.

Regards,

Ondrej Dubaj

Reply via email to