Alternative to PAGs

From: David Howells (dhowells@redhat.com)
Date: Thu May 15 2003 - 09:15:49 EST


Hi Linus,

Okay, starting with a clean slate and writing PAGs off as a bad idea, how
about trying to work out what is required first? As I see it:

THE REQUIREMENTS
================

  (1) Credentials/tokens/keys/whatever are held in a "keyring".

  (2) A keyring is destroyed when the last reference goes away (kernel
      resources are precious, though it may be possible to store credentials
      in swapspace somehow).

  (3) Every user has to have a default keyring that is created the first time
      they log in [Linus demands this].

  (4) A user has to be able to override the default keyring, such that they
      can, for instance, perform operations on a remote filesystem with a
      different credential.

  (5) A user has to be able to run a program with a reduced set of
      credentials.

  (6) A process must be able to pass a subset of its credentials to a second,
      already running process so that the second process can perform some
      service on its behalf.

      This gets tricky if the service process is performing services for a
      number of processes simultaneously, each of which has its own set of
      credentials.

  (7) A process should be able to discard any credential it has access to,
      particularly in conjunction with (6).

  (8) It must be possible to withdraw a credential.

  (9) The credentials governing access to a file must be associated with a
      struct file, not with the process context currently accessing a file.

 (10) A struct file will gain its credentials at the time it is opened.

POSSIBLE EXTENSIONS
===================

 (11) Threads should perhaps share a common set of credentials, but be able to
      adjust them on a per-thread basis (see (6)).

 (12) A SUID process should add the credentials it gains from its new user ID
      to those it inherited from its original context.

 (13) There's one place Win32 has an advantage, I think: calls for setting up
      handles (files, mutexes, etc) take security context parameters.

I think "groups" specific keyrings and arbitrary joinable keyrings are
superfluous (that's what ACLs are for) and a systems maintenance nightmare, so
I haven't included them.

SUGGESTED IMPLEMENTATION
========================

As far as implementation goes, perhaps each task_struct and each file should
point to a stack of keyrings:

                                         +------+
                                         | |
                  +--------------------->| USER |
                  | | |
                  | +------+
                  |
 +------+ +------+ +------+ +------+
 | | | | | | | |
 | TASK |----->| SUID |---->| PRIV |---->| USER |
 | | | | | | | |
 +------+ +------+ +------+ +------+
                  ^ ^
 +------+ | |
 | | | |
 | FILE |---------+ |
 | | |
 +------+ |
                               |
 +------+ |
 | | |
 | FILE |----------------------+
 | | ^
 +------+ |
                  |
 +------+ +------+ +------+
 | | | | | |
 | TASK |----->| FILE |----------------->| USER |
 | | | | | |
 +------+ +------+ +------+

The keyrings in the stack would then be refcounted, and the next pointers
would be immutable.

        struct keyring {
                struct keyring *next;
                struct keyring *conjunction;
                struct list_head keys;
                atomic_t usage;
                int type;
        #define KEYRING_USER 0
        #define KEYRING_PRIVATE 1
        #define KEYRING_SUID 2
        #define KEYRING_FD 3
        };

        struct key {
                struct list_head link;
                atomic_t usage;
                int type;
        #define KEY_POSITIVE 0
        #define KEY_NEGATIVE 1
                void *credential;
        };

And then add the following syscalls:

 (*) auth_clear_stack(int completely)

     Totally clear a process's stack (either completely or of everything but
     the user credentials).

 (*) auth_add_cred(const char *fs, const char *domain, void *data);

     Add a new credential to the TOS keyring. The key would be negative if
     data is NULL.

 (*) auth_push_empty()

     Push an empty keyring onto this process's stack.

 (*) auth_push_fdcreds(int fd)

     Push the credentials associated with fd onto the stack as a preferred
     alternative.

 (*) auth_pop()

     Pop the top credential off of the stack.

David
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu May 15 2003 - 22:00:57 EST