[cap-talk] Confused Deputy, multiple authorities - Norm?

David Wagner daw at cs.berkeley.edu
Tue Oct 24 19:15:14 CDT 2006


Charles Landau <clandau at macslab.com> writes:
>At 1:30 PM -0700 10/24/06, Jed at Webstart wrote:
>>That is system dependent.  If the compiler could check the users
>>UID (as in the Unix case) then the compiler could solve the Confused
>>Deputy problem in so far as that ambient authority model goes.
>>
>>If the compiler could know the users UID it could check to insure
>>that the user had write access to their debugging information file.
>
>In general, user X shouldn't be able to find out whether user Y has 
>access to object Z.

In general, sure.  But when X = the root user, it's not a problem for
the root user to be able to learn whether user Y has access to object Z.
And remember that in Unix, the main mechanism for privilege escalation
(providing an unpriviliged user with access to a program that needs more
privilege than the user has) is through setuid-root programs.

(You can essentially ignore programs that are setuid to non-root uids,
since Unix's support for them is so sucky that there are very few programs
that are setuid-non-root.)

Of course, the setuid mechanism in Unix has not been a success, and
using UIDs as the basis for defining privileges has not been conducive
to the design and implementation of least privilege software
(e.g., so-called "privilege separated" applications).  The Unix approach
tends to lead to very coarse-grained privilege decomposition, at best, or
to no privilege decomposition, more typically.

>I take the term "confused deputy" to mean a situation in which a 
>service fails to enforce its intended security policy because, 
>lacking capabilities, it has no natural way to express the notion 
>"take this action, but only by the authority vested in me from this 
>source".
>
>It may or may not be possible to express that notion in Unix, but 
>even if possible, it doesn't seem to me to be natural or easy.

It's certainly possible.  The pattern goes like this:
    fd = open_as(filename, getuid(), ...);
where the program defines the following helper function:
    // precondition: geteuid()==0
    int open_as(char *file, uid_t uid, int flags) {
        int fd;
        seteuid(uid);
        fd = open(file, flags);
        seteuid(0);
        return fd;
    }
This works for setuid-root programs.  The problem is that it is not
very convenient, it is potentially error-prone, and maybe most importantly,
it is not automatic.  The primary advantage of capabilities is that this
happens automatically.

One disadvantage of the above coding pattern is that it is too easy for
the filename to get separated from the appropriate uid.  It's possible to
devise coding idioms that make that error slightly less likely.  For instance,
you can create an abstract data type for holding a filename together with
the authority that should be used when accessing that file, like this:
    struct fileauthority {
        char *filename;
        uid_t uid;
    };
    int safer_open(struct fileauthority fa, int flags) {
        return open_as(fa.filename, fa.uid, flags);
    }
Note that fa_open is a convenience wrapper around open(), and you'd
presumably implement similar convenience wrappers around all the other
file-oriented functions.  Then, in main(), the first thing you do is
replace each filename specified on the command line with a "struct
fileauthority", maybe something like this:
    int main(int argc, char **argv) {
        while (*++argv) {
            if (is_filename(*argv)) {
                struct fileauthority fa = {*argv, getuid());
                dostuffwith(fa); // this might eventually call safer_open(fa)
            } else if (is_option(*argv)) {
                ... whatever ...
            }
        }
        dosomemorestuff();
    }
The key here is that you never manipulate files as "char *"'s; you
only manipulate them as "struct fileauthority"'s.  This is analogous
to saying that in Java, instead of passing around filenames as "String"s,
you should manipulate them as "java.io.File" objects.  However, even this
approach has significant limits in how far it can take you, and object
capabilities will still have advantages over this.


More information about the cap-talk mailing list