[lkml]   [1998]   [Apr]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
    SubjectRe: [patch 2.1.97] more capabilities support
    Alexander Kjeldaas wrote:
    > On Mon, Apr 27, 1998 at 02:26:22PM +0200, Andrej Presern wrote:
    > > Theodore Y. Ts'o wrote:
    > > >
    > > > Huh? That's hardly a pure-capability system. In a pure capaibility
    > > > system, you have something that is effectively like a "key", which can
    > > > get passed around between processes, and a privileged program is merely
    > > > a program that has several keys that confer more abilities than the
    > > > standard default capability.
    > >
    > > Don't you think that the two syscall capabilities are essentially two
    > > 'keys' that 'open different syscalls'? I designed the syscall capability
    > > the way I did exactly to demonstrate that you don't neccessarily have to
    > > pass the capability like a fd when you invoke it, keeping existing
    > > syscall interfaces unchanged.
    > >
    > > I stated in the mail that for starters I don't want a process to be able
    > > to pass the syscall capability around to other processes (which it could
    > > nonetheless if we don't tie the memory containing the copy of the
    > > sys_call_table to the process that requested it).
    > >
    > > You don't need a special authority granting daemon to have pure
    > > capabilities because every object can have its own set that it can give
    > > away. In the case of a syscall capability that I described, the kernel
    > > gives a single syscall capability to all processes by default, and if
    > > the process wants it can create its own subset of the system calls that
    > > it received. As I already stated, if we don't tie this syscall
    > > capability to the process (that is if we don't free the memory that it
    > > occupies when the process exits), a process could as well communicate it
    > > to other processes (the reference is just 4 bytes) if, of course, it
    > > includes the authority to call system calls that can be used to
    > > communicate with other processes.
    > >
    > What you are suggesting is simply a less useful version of POSIX
    > capabilities. They are
    > 1) less expressive
    > I mentioned a few things you couldn't express with your model in
    > another post, but let me just mention that you can express
    > _everything_ you can do with _your_ model using POSIX capabilities.
    > I have already described this in an earlier mail when someone
    > wanted a CAP_NETWORK capability to be able to restrict access to
    > the network to a process. This requires the following changes to
    > the kernel which I didn't want to do to avoid complexity at this
    > time.
    > 1.1) You have to read some capabilities as "set" in the allowed
    > set when reading them from the file system.
    > 1.2) You have to add credentials checks to the kernel that
    > currently don't exist.
    > The reason you don't have CAP_EXEC and CAP_NETWORK isn't that it is
    > inherently difficult to do, but that we want to take one step at a
    > time. Partitioning the root privilege is a well-defined step.

    install_sys_call_table( without_socket );
    (But this is not the issue.)

    If we talk about pure capabilities, we talk about expressivity. A pure
    capability system will perform an action for you if you are able to
    express the request. In contrast, a list based system will let you
    express the request and then verify if the request should be performed
    for you (ie if you are authorized).

    In a drawing, the difference would be something like this:

    +----+ +-------+
    |obj1| ---request----|-->obj2|
    +----+ +-------+

    After the border of authority has already been passed, obj2 checks if
    obj1 is authorized for the action, and if not, the action is denied and
    the execution returns to obj1.

    +----+ +----+
    +----+ +----+

    The border of authority is not passed, for if it were, obj2 will simply
    perform the action without any checking. If obj1 is not authorized to
    request that an action be performed for it by obj2, obj1 cannot even
    pass the border of authority. This means that obj2 doesn't have to
    execute not even a single instruction if obj1 doesn't have the
    authorization to invoke a capability on it.

    Because a capability can have an arbitrary amount of authority, it can
    have an arbitrary amount of expressiveness. But as you can see, the
    issue is not about how much you can express in a request but rather _if_
    you can express the request, because the latter is what makes the
    difference between lists and capabilities.

    You stated in your mail (as quoted) that you didn't want to do
    CAP_NETWORK yet because it would introduce more complexity to the
    system. The always increasing complexity is exactly one of the
    disadvantages of a lists design! With every additional authority you
    need an additional check/branch in the program that will handle it, for
    if you don't you have a security hole. This means that an additional
    amount of code is needed to accomodate the check, which then reflects in
    increased complexity, increased storage use and worse performance.

    With pure capabilities on the other hand, time and storage required to
    perform a check is always constant: 0 (zero), because the check is done
    implicitly at the object border, so the object does not have to waste
    any resources to perform it explicitly.

    > 2) not pure
    > I can emulate your sys_call_table with a 183 bit long integer
    > with each bit corresponding to being allowed to invoke a system
    > call. How can you argue that POSIX capabilities are inherently
    > broken when the similarities between POSIX and your suggestion are
    > so obvious?

    You only emulate what you already have: a lists design. That is also
    exactly the reason why the proposed extension may seem as not very
    efficient: it is indeed an emulation of a lists design, which is needed
    however to support backward compatibility.

    While the proposed extension suffers from increased use of memory, it
    still sports good performance, which is not so if we used a 183-bit list
    as you proposed. Consider the following:


    If you want to apply a lists design to verify that an application is
    allowed to perform a system call (say, write()), you can nullify the
    pointer to write and then at syscall time check if the value of the
    pointer is NULL, or create a different list using a bit-array and check
    if the corresponding bit is zero:


    Such an approach involves a check in the code, such as
    if ( ! is_syscall_valid(num) ) return;
    do_syscall( num );

    This can be modified to use some capability ideas. Instead of storing a
    NULL pointer in the sys_call_table, we store a pointer to a dummy
    function that returns from the syscall, effectively revoking the write()
    capability from the application:


    Now if the application requests write(), the operation will
    automatically fail because dummy_exit() will be called instead of
    write(), no checks performed.

    The code would now be something like:
    do_syscall( num );

    To give a capability to write(), the kernel only needs to replace the
    pointer to dummy_exit() with a pointer to write(). If the kernel wants
    to perform some action when a syscall is attempted that is not
    permitted, kernel only needs to change the pointer to dummy_exit() to a
    pointer to log_breakin_attempt() or kill_offending_caller(). The kernel
    might even want to play games with the offending application, so it
    might store a pointer to fake_write() instead of write() to see what the
    application is up to and the application will never know that it is
    being monitored. Please note that the complexity of the system call
    mechanism has still not changed even though we're now already doing an
    analysis of the breakin attempt.

    > 3) they require 60 times the memory, and
    > 4) are harder to administer, and
    > 5) are probably slower

    As you can see, the above mechanism can hardly be slower than what you
    propose, and I'm sure you will also agree that it's also easier to
    administer. As for memory, the reason for increased memory is because
    we're emulating a lists design, where the whole list needs to be
    initialized if it should work. If the syscall mechanism wasn't
    fundamentally broken in the first place, the emulation would not be so
    inefficient memory-wise.

    > I think simply the cache effects of having different
    > system_call_tables makes them slower than looking up a bit in a
    > table. However, if this isn't true for some reason, there is
    > nothing stopping us from implementing for instance CAP_SYS_RAWIO
    > by removing iopl and ioperm from the system call table of the
    > process.

    ... and adding an additional entry in the list of capabilities, making
    things even less efficient.

    > [...]
    > > The other way to abuse the program is that the attacker installs the
    > > syscall capability that contains execve() by itself before calling
    > > execve(). But this means that the attacker must have such a capability.
    > > And because it can't just produce one by itself, and because it can't
    > > get one from the system (it can only get a copy of the currently
    > > installed one) the only way to get it is by stealing it from the
    > > attacked process (and to do that it must know exactly where the attacked
    > > process holds it), which complicates things even more.
    > If you want it to be difficult to steal the capability from the
    > running process, you will have to _design_ it to be difficult. Until I
    > see some evidence suggesting it is difficult, I'll assume it is as
    > easy as stealing POSIX capabilities.

    Can you please explain to me how you can steal a file descriptor in


    Andrej Presern,

    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.037 / U:254.920 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site