lkml.org 
[lkml]   [1998]   [Apr]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: [patch 2.1.97] more capabilities support
Alexander Kjeldaas wrote:
> As I said, I don't have anything against pure capabilities. However, I
> don't see pure capabilities being implemented in Linux this year and
> not next year either. That makes me conclude that the discussion on
> "pure vs POSIX" capabilities is a non-issue. One of them has been
> implemented and will improve security, the other one is at most at the
> design stage.
>
> The pragmatic in me tells me that the software that will actually
> _use_ the POSIX capability interface will be quite low. So if you, in
> 3 years time, come up with an implementation of pure capabilities in
> Linux it will not be a huge task to change a few programs to use a new
> interface. It won't even be difficult to support the old interface.
>
> _That_ is a win-win situation.

Theodore Y. Ts'o wrote:
>
> Date: Thu, 23 Apr 1998 20:51:31 +0200
> From: Andrej Presern <andrejp@luz.fe.uni-lj.si>
>
> Besides, I really don't see a good reason why a clearly superior design
> should not be implemented, especially considering the fact that both ACL
> and capability list designs can be implemented on top of it, ensuring
> compatibility with existing standards and old programs. Pure capability
> based systems have been running commercial and military security aware
> applications for over 20 years and have even been implemented on off the
> shelf technology (such as IA32) for a number of times.
>
> How about the fact that in order to do pure capability systems, you'd
> have to rev the interface of every single system call to take a
> capability argument (just as file I/O syscalls now take a file
> descriptor)?

Not neccessarily.

I know that requests for massive changes of the kernel won't even be
considered and I wouldn't even think of proposing the idea if I didn't
think that massive changes are actually not required to at least
minimally support pure capabilities.

The path that I would propose is to add minimal support. Currently,
processes can assume that they can call every non privileged system call
- those that the process actually needs and those that the process
doesn't need also. To get the ball rolling, I would propose a
modification of this mechanism, so that a process is able to restrict
itself to only a subset of system calls, thus throwing away the
superfluous authority that can be abused if the program contains a bug.

An example use of such a basic and primitive extension would be that a
suid program can throw away its authority to execve() system call, if it
doesn't need it. This alone would make it quite difficult for the hacker
to produce a root shell by means of stack smashing for example, and
would make it difficult to do so for all time, not just until the next
bug in argument handling code (of the program or libraries) is found. If
the program would actually need such authority, it can get a copy of the
existing capability (which is all syscalls by default for beginning),
modify it so that it drops execve() and then use one of the two
capabilities as appropriate in sections where execve() is needed and
where execve() is not needed, thus restricting the amount of risky code
arbitrarily (the application can install the with_execve() capability
just before execve() is called and install without_execve() capability
where processing user arguments for example).

Of course, it would be much better if such capabilities could be
attached to the program image residing on the disk. In this case the
suid app would not need to be changed at all because the syscall
capability would be loaded from the disk at startup time automatically,
plus we could also prevent a troyan login program (that wouldn't want to
throw away authority by itself) from storing intercepted passwords on
the disk by not giving it the ability to do write() (another stupid
example). But this would require changes to the file subsystem, which
means quite a bit of changes so I don't think its appropriate right now.

The reason why such an extension would be usefull lies in the principle
of the least authority. If the program doesn't have the authority it
doesn't need, such authority cannot be abused. Not now, not ever.

Of course, because Linux is not a pure capability system by default,
such an extension would have some impact on the system. If we don't want
to make it so that the process has to pass the syscall capability at
call time, the change to IDT (or the system call table or the
system_call function) would need to be made at process switch time. The
other impact would be in the use of kernel memory, because every
different syscall capability would require some storage. Although only a
few running tasks would want to have a modified syscall table, such
tasks would eat up a few hundred extra bytes of non swappable memory for
their private syscall table which would impact all running programs.

On the other hand, POSIX capabilities also take up extra space. They do
so with programs residing on the disk, and they do so with running
tasks, the difference with pure capabilities being that pure
capabilities only take up space if they are given to an object while
POSIX capabilities do so always.

If the whole sys_call_table would need to be allocated that will hold an
alternative syscall mask, that would mean approximatelly 173*4 bytes (if
I recall the current number of system calls in 2.1.x kernels correctly)
wasted by every process that wants to hold different syscall sets, plus
a small modification of system_call in arch/x/kernel/entry.S so that it
is possible to change the location of sys_call_table (a pointer is
needed instead of hardcoding it into the kernel). Unfortunatelly, some
means would be needed to perform the change of the sys_call_table for
the current process and I am not sure if it would be better to use a new
syscall or to do it in some other way. Because we're still in the
beginning and want to keep changes small, we won't make this capability
passable in any direction (not even parent -> child), so we can free
alternative sys_call_tables when the process that requested them exits.

So, for a slow start, I would like to see these pure capabilities in the
system:
1) create a duplicate of current sys_call_table and return it to me
2) disable a syscall in the current sys_call_table
3) install a sys_call_table

This way, the process can't get any more syscall authority than it has
by default (making room for future extensions), but it gets the ability
to disable potentially dangerous system calls that could be abused if
the application is invaded by some foreign code (ie as with stack
smashing).

I will try to write some code that does this, but I hope I won't mess
something up in the kernel, because I'm still a newbie to the Linux
kernel source:)

> You could set a global capability for the process, and switch between
> capabilitiy sets, but at that point you've lost most of the advantages
> of a pure capability system. (You might as well raise and lower POSIX
> capaibilities.)

Switching between capability sets is not pure capabilities, it's
capability lists, ie. POSIX capabilities. If authority can be attached
to a program flow instead of the program (that is, it can be passed
between objects), you don't have to switch but only always use the same
authority that has been given to you by the object at the other end of
the input channel. If an operation cannot be performed it's because
input object didn't give you enough authority.


+-- object border -----------------------+
| |
obj1 -+-> exec. flow with auth. given by obj1 -+-> output 1
| |
obj2 -+-> exec. flow with auth. given by obj2 -+-> output 2
+----------------------------------------+


If the authority is not separated from the object, the object must
switch between different sets of authority within itself. In this case,
the object is responsible for making a distinction between input objects
1 and 2. Input objects 1 and 2 are the same at the border and it's up to
the program to make a distinction between them and use propper
authority, making program more complex as the number of different
authorities rises.


+-- object border -------------------------+
| |
obj1 + | +-- obj1 ------------------+-> output 1
+-+-> exec. flow -+ (auth. of obj1 or obj22?)|
obj2 + | +-- obj2 ------------------+-> output 2
+------------------------------------------+


Anyway, because in the end it always comes to Linus saying yes or no, I
would like to hear what Linus thinks about the idea. I don't want to
waste any more time of any of you (and mine) trying to explain something
that is not even going to be considered (for whatever reason). I am
aware that what I am proposing is in the end not a small thing. I am
also aware of the fact that my current knowledge of Linux internals is
not sufficient to be able to provide a complete design for Linux that
will prove the concept, which has been asked of me for a number of
times. I have not yet heard any opinions, arguments or comments from
neither Linus nor Andrew Morgan who also expressed interest, so I guess
this is what I am asking for right now.

Andrej

--
Andrej Presern, andrejp@luz.fe.uni-lj.si


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu

\
 
 \ /
  Last update: 2005-03-22 13:42    [W:0.112 / U:1.416 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site