Process Capabilities on 2.2.16, Sendmail problem revisited

From: Joseph Gooch (mrwizard@psu.edu)
Date: Sat Jun 10 2000 - 01:58:07 EST


Ok guys, this isn't going to work. The 2.2.16 patch pretty much took the
inheritable set and threw it out the window. At least before, you could
mask an entire capset and not have to worry about suid programs getting
elevated caps (if the program was capabilities 'smart'). Now we're back to
the uid 0 is root no matter what situation. Instead of fixing exec(), you
broke capabilites. Grr! I've been trying to track this down, here's what I
see.

Comment from kernel/sys.c (around line 410):
/*
 * setuid() is implemented like SysV with SAVED_IDS
 *
 * Note that SAVED_ID's is deficient in that a setuid root program
 * like sendmail, for example, cannot set its uid to be a normal
 * user and then switch back, because if you're root, setuid() sets
 * the saved uid too. If you don't like this, blame the bright people
 * in the POSIX committee and/or USG. Note that the BSD-style setreuid()
 * will allow a root program to temporarily drop privileges and be able to
 * regain them by swapping the real and effective uid.
 */

[Wow, they even directly mention sendmail. Go figure. :)]

Anyway, the main code here (line 427):
        if (capable(CAP_SETUID))
                new_ruid = current->euid = current->suid = current->fsuid =
uid;
        else if ((uid == current->uid) || (uid == current->suid))
                current->fsuid = current->euid = uid;
        else
                return -EPERM;

Now to me, the second case there should be expanded to include something
like
        if (!issecure(SECURE_NOROOT)) {
            if ((uid == current->uid) && (current->suid == 0))
                  current->fsuid = current->euid = current->suid = uid;
        }
Probably as an added check to whats there. I mean, if we're going to keep
these compatibility options around, they should be in the broken functions,
not in the new features, right? Please correct me if i'm wrong.

The evil code from capability.c that i have a problem with is in fs/exec.c
around line 623:
       if (!issecure(SECURE_NOROOT)) {
                if (bprm->e_uid == 0 || current->uid == 0) {
                        cap_set_full(bprm->cap_inheritable);
                        cap_set_full(bprm->cap_permitted); /* This line is
evil */
                }
                if (bprm->e_uid == 0)
                        cap_set_full(bprm->cap_effective);
        }

Because right after that, it computes the new capabilities:
        {
                kernel_cap_t permitted, working;

                permitted = cap_intersect(bprm->cap_permitted, cap_bset);
                working = cap_intersect(bprm->cap_inheritable,
                                        current->cap_inheritable);
                working = cap_combine(permitted, working);
                if (!cap_issubset(working, current->cap_permitted)) {
                        cap_raised = 1;
                }
        }

No matter what the inheritable set is (it'll be in 'working'), we're still
going to have the entire permitted set (masked by cap_bset). At least for
root. But this includes a root process with a null capability set spawning
another process.

As I see it, this is broken. If i'm wrong, please let me know. The only
thing I can see that would make this all pretty would be to do a prctl type
thing (as i think was done in 2.3) but instead of it being KEEPCAPS, it
really should be the SECURE_NOROOT toggle (on a per process basis?). I
don't think it needs to come to that kind of fix, the above pseudo-code
should be sufficient to make things work. If i get a chance tomorrow I'll
test and make a diff, but please give me input, make sure I'm not looking at
this crosseyed (it's early).

Please comment/flame to me directly, I'm not on the list.

Joe Gooch

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Jun 15 2000 - 21:00:20 EST