[lkml]   [1998]   [Apr]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
    SubjectRe: [patch 2.1.97] more capabilities support
    On Sun, Apr 19, 1998 at 03:17:54AM -0700, Andrew Morgan wrote:

    > + 1.1.2 File capabilities
    > +
    > + WARNING: there is currently no support for file capabilities
    > +
    > + Each file has three sets of capabilities, when the file is exec()'d
    > + these three capabilities combine with those of the exec()'ing process
    > + to establish the newly exec()'d process' capabilities.
    > +
    > + Inheritable
    > +
    > + This is a mask against which the Inheritable capabilities of the
    > + exec()'ing process are filtered. Only capabilities in this set may be
    > + inherited by the exec()'d process.
    > +

    This is the "allowed" set. [I use this term since it is much clearer
    in order to understand what is going on].

    > + Note, on filesystems that do not support capabilities, all executables
    > + are assumed to have { ~0 } Inheritable capabilities.

    No, this is not correct. On file systems without capability support,
    files are assumed to have a { 0 } inheritable (allowed) set. We
    _could_ do the above, maybe we should, but we don't _do_ this
    currently. Some reasons:

    * The draft says so :-)
    * You get a kind of inverse protection. A file system without
    capabilities will grant an executable more capabilities than the
    same executable executed from a different file system. This is a
    "threat" that will always be there since we live in a world with
    lots of other file systems than ext2. I think this collides
    somewhat with the principle of least surprise.
    * Since we have a CAP_SETPCAP capability (set process' capabilities)
    we can implement file-system capability support using a daemon.
    * It would arguably be better to have it as a per file system mount

    > +
    > + Effective
    > +
    > + This set must have either all capabilities raised or all capabilities
    > + lowered. It is used to indicate whether the program knows about
    > + capabilities. If this set has capabilities raised, the program will
    > + start with all of its Permitted capabilities in its Effective set. If
    > + this set is empty, the program will start with an empty Effective set,
    > + and will have to explicitly raise the capabilities it needs.
    > +

    This is a single bit saying whether the executable knows about
    capabilities (internally it's represented as a bit mask however).

    > + Permitted
    > +
    > + This set is the set of capabilities required by the executable in
    > + order to do its job. These will appear in the Permitted set of the
    > + process after exec()ing this executable.

    This is the "forced" set. It is also read as { 0 } on a file system
    without capabilities support.

    > +
    > + 1.2 Capability inheritance
    > +
    > + Following a sys_exec() call, the process' capability sets are modified
    > + in the following way:
    > +
    > + pI' = pI
    > + pP' = fP | (fI & pI)
    > + pE' = pP' & fE [NB. fE is 0 or ~0]
    > +
    > + Key: I=Inheritable, P=Permitted, E=Effective // p=process, f=file
    > + ' indicates post-exec().
    > +
    > + Note, the Inheritable set is fully preserved across a sys_exec()
    > + call.
    > +
    > + Process capabilities are _not_ modified on fork (clone).
    > +
    > + 1.3 Compatibility mode
    > +
    > + The historical situation, of the superuser being omnipotent, is
    > + partially preserved following a system call to sys_exec(). This

    ..and on set*uid calls.

    > + backward compatibility is preserved only in the case that
    > + (issecure(SECURE_NOROOT) == 0).
    > +
    > + 1.3.1 Details
    > +
    > + Backward compatibility takes the following form:
    > +
    > + 1 setuid-root binaries, automatically have their Effective
    > + and Permitted capabilities raised to equal the Inheritable
    > + capabilities of the process that calls sys_exec().
    > +


    > + 2 setuid-NON-root binaries, automatically have their Effective
    > + capabilities cleared. If the UID of the process calling
    > + sys_exec() is 0, the Permitted capabilities are raised to
    > + equal the Inheritable capabilities of the process that called
    > + sys_exec(). Such processes become "capability smart".
    > +


    > + 3 non-setuid binaries directly inherit the capabilities of the
    > + process that sys_exec()s them.
    > +

    No! What happens is the following:

    1. When the effective uid or real uid of the resulting process is 0
    [ execing a suid-root binary, normal exec by root, or
    exec by root who has done a setreuid operation ]
    then the allowed set is set to { ~0 }.

    2. When the effective uid of the resulting process is 0
    [ exec of a suid-root binary or normal exec by root ]
    then the forced set is set to { ~0 }.

    After the above operations, the capability laws described in 1.2 are
    used. This means that as long as the allowed set is read as { 0 } from
    the file system, we don't inherit any capabilities at all except for
    the inheritable ones. We don't need to in order to be backward

    A very important part of backward compatibility that should be
    mentioned is dealing with the set*uid functions. Current software
    relies on losing privileges on a setuid or setreuid operation. This
    compatibility is in effect if issecure(SECURE_NO_SETUID_FIXUP) ==
    0. It works by letting the effective set be a reflection of the
    current effective uid. The permitted set is a reflection of the
    current effective/real/saved uid. The following rules are used.

    1. When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of
    {r,e,s}uid != 0, the permitted and effective capabilities are

    2. When set*uiding _from_ euid == 0 _to_ euid != 0, the effective
    capabilities of the process are cleared.

    3. When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
    capabilities are set to the permitted capabilities.

    4. When setfsuiding _from_ fsuid == 0 _to_ fsuid != 0, the effective
    capabilities of the process are filtered for fs-specific capabilities

    5. When setfsuiding _from_ fsuid != 0 _to_ fsuid == 0, the fs-specific
    parts of the effective capabilities of the process are copied from
    the permitted capabilities.

    > + 1.3.2 Discussion
    > +
    > + Firstly, we note that this backward compatibility has only one effect
    > + on systems that are not capability aware:
    > +
    > + Point 2, of section 1.3.1, implies that such binaries
    > + inherit the EUID of root, but none of root's kernel level
    > + privileges.
    > +

    No this is not correct. When root runs a non-root setuid program, the
    effective uid of the resulting process is _not_ 0. However, the real
    uid is 0. Letting the permitted set of the resulting program be set
    but not the effective makes perfect sense.

    > + Secondly, on a system that runs binaries which are capability aware,
    > + without setting SECURE_NOROOT mode, it is possible to further restrict
    > + the root account:
    > +
    > + Point 1, of section 1.3.1, implies that a parent process
    > + can reduce its Inheritable capabilities and thus prevent any
    > + of its children from _ever_ acquiring all/any of root's kernel
    > + level privileges. An immediate consequence of this is that it
    > + becomes possible to implement escape proof sys_chroot() cells.
    > +

    This does not depend on the SECURE_NOROOT setting. The only way you
    can increase your effective capabilities beyond your inheritable ones
    is if you somehow, through exec or other means, get "forced"
    capabilities. "Forced" capabilities can either come from a
    capability-aware file system during exec (which we don't have
    currently), or from another process having the SETPCAP capability.

    [ patch.. ]
    > +/*
    > + * The restrictions on setting capabilities are specified by POSIX:
    > + *
    > + * I: any raised capabilities must be a subset of the (old) Permitted
    > + * P: permitted capabilities can only be removed and never added.
    > + * E: must be set to a subset of (new) Permitted
    > + */

    I'd like to see an additional restriction. Many programs do privilege
    checking at the beginning and don't correctly check all return values
    on system calls. On a capability-system this can probably be exploited
    in ways not possible on a normal Linux system by using the inheritable
    set. If a normally suid program needs several capabilities to perform
    a task, you can engineer an inheritable set which will make a system
    call fail that would succeed on a normal system and possibly exploit a
    buffer overrun condition. On some systems it is therefore desirable to
    be unable to _clear_ capabilities in the inheritable set unless you
    are privileged. This also has the effect that you cannot selectively
    delegate capabilities to your own child processes unless you are
    privileged. When raising capabilities in the inheritable set, this
    argument doesn't apply since the process would already be "trusted" by
    having some forced capabilities.

    The above rules should be disregarded for a process having the
    CAP_SETPCAP capability. This makes it possible for a
    "capability-daemon" to do some interesting things such as raising a
    capability only in the effective capability set of a process. This
    makes it possible for the daemon to grant a _non-transferable_
    capability, something which is not possible with the POSIX rules
    (unless you limit setting capabilities in the inheritable set as

    Another point is that the system calls in your patch doesn't support
    setting capabilities on other processes. This is needed to implement
    the "capability-daemon".


    Alexander Kjeldaas, Guardian Networks AS, Trondheim, Norway

    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to

     \ /
      Last update: 2005-03-22 13:42    [W:0.033 / U:5.740 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site