Re: [patch 2.1.97] more capabilities support

Andrej Presern (andrejp@luz.fe.uni-lj.si)
Sat, 02 May 1998 01:59:28 +0200


Alexander Kjeldaas wrote:
> Yes, this is a nice idea. You separate checking authority to a single
> place, or if possible use hardware mechanisms to catch a fault. We use
> this when copying information to/from user-land. Other than the
> user-land/kernel border, there are a lot of "almost" borders in the
> kernel. We have a common permission() routine in the VFS layer and we
> have common implementations of all struct file_operations routines so
> you don't have to duplicate unnecessary authority checks. When
> possible, it is of course in everybody's interest to simplify the
> logic needed to check for authority.
>
> But whether you call it a "border of authority" or not, somewhere you
> have to check for authority, and in the Linux kernel you have to deal
> with an existing design. POSIX capabilities are designed to deal with
> the typical UNIX design - all you [basically] do is change suser()
> calls to capable() calls [the backwards compatibility stuff is needed
> no matter how this is implemented]. System call capabilities must be
> only a small part of your overall design, because you can't use them

They are.

> to express some of the important privileged operations the kernel
> provides. I want to know how you will support expressing those
> operations - which means at least representing the POSIX
> capabilities. Some important capabilities:
>
> CAP_DAC_READ_SEARCH - capability needed to take backup
> CAP_SYS_TIME - capability needed for xntpd.
> CAP_KILL - kill any process
> CAP_NET_BIND_SERVICE - any well-known service
> CAP_NET_RAW - tcpdump
> CAP_SYS_RAWIO - X server
> CAP_SYS_RESOURCE - important daemons
>
> Of these, CAP_SYS_RAWIO can be caught by the system call filter. If
> you comment on nothing else in this mail, _please_ tell me how you
> will to implement the other capabilities above.

I really don't see why you want to keep broken interfaces. You can
emulate them on top of capabilities if you want (and are willing to
sacrifice some storage for the sake of performance, such as in the
syscall example) but I don't think there will be many applications using
them if you'll want to keep the system very secure. Security aware
applications will surely turn to better alternative methods when they
show up in the system, even though that might mean changing some code -
and those that won't will be left to the discretion of the administrator
to decide if they should be given too much authority or not.

I'm not talking about dropping ACLs or capability lists. Just to also
provide superior interfaces to applications that need them. Why should
we force an application to create its own subset of syscalls? We can
leave that to its author to decide if it's worth the effort to change
the utility, and the user to decide if the (not) changed utility meets
his security standards.

I hope we are still talking about concepts and not how I'm going to
tailor Linux for this particular design. I am just proposing that new
interfaces are created that use the capability approach because it is
more efficient.

> > 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.
>
> This isn't useful information to me. The expressiveness depends on the
> implementation. You don't have "arbitrary amount of expressiveness".

Conceptually, you do.

> > 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.
> >
>
> But then we're back to where we started! We both try to be backwards
> compatible and we both come up with a lists design! It's just that the

I can be backward compatible for all the old programs. But that doesn't
mean that I can't create new interfaces that would replace old,
inefficient ones. I've only come back to emulating a lists design
because I _have to_ support syscalls the way they are now in order to
maintain backward compatibility with compiled software. If this
additional functionality of being able to control which individual
syscalls are available to the application is not desired, I can as well
extend personality() to drop to capability-only mode, turning off
syscalls completely. But because this would probably not be desired, I
proposed the syscall capability.

> expressiveness differ. Your design can express things that the POSIX
> one cannot do without additional checks (CAP_EXEC, CAP_NETWORK
> etc). Your design cannot implement things that the POSIX one can. Both
> are nice, but it is my belief that being able to precisely express
> privileged operations is more important since abuse of privileged
> operations is what causes most trouble on our systems.

We can emulate POSIX to do things the way POSIX does them, together with
all deficiencies. But I can't make POSIX better than it is conceptually.
I can only propose alternative concepts and interfaces that do the same
thing POSIX capabilities do, only that they do it different (and
better).

> [explanation of why sys_call_table is faster]
>
> I'm aware of how this would work. It might be faster, it might be
> slower, you'll have to test to find out. Both techniques are pretty
> fast. The capable() requires two instructions and a branch, yours

With a small capability list, yes. What about a bit larger one?

> > 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.
>
> A simple change to the system call invocation path could check the
> bitmap I proposed instead of having to deal with an actual pointer
> array, and would save memory. But this is details.

You still have to waste CPU time to check the bitmap. This is details
also.

> >
> > > [...]
> > > > 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
> > Linux?
> >
>
> We must be misunderstanding each other here. Using a file descriptor
> in a buffer overflow exploit is done by either knowing the the file
> descriptor number [since the assignment rules are *easily* guessable],
> or fetching one from the stack or some variable. A similar technique

I mentioned that possibility in the mail. I also mentioned the
implications of doing that.

> could be used with capabilities. There's nothing inherently difficult
> with stealing a capability for an attacker compared to stealing any
> other data the process might hold. This is obvious until there is some

If you know where to look for it (ie if you know the source, if you know
the binary and if you're sure that you're attacking a binary that
doesn't differ from the one you used to produce the attack), which is
not very easy and not very reliable (you're patching a running program
from within, remember?).

> remarkable design proving something else.

The design is: make two objects out of it and have a real border between
them.

-- 
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