Re: In-kernel Authentication Tokens (PAGs)

From: David Howells
Date: Wed Jun 23 2004 - 07:32:07 EST



Kyle Moffett <mrmacman_g4@xxxxxxx> wrote:
> You are referring to the attachment point from the UID to key-ring or
> process to key-ring. I was referring to your method of telling the key-ring
> what is attached to it, though I could have misread your code. Of course a
> task_struct should have a key-ring pointer, but the key-ring shouldn't need
> to know what points to it, just how many things point to it (ref count).

A keyring doesn't know what points to it, only the keys that it holds. The key
part of the keyring keeps track of the refcount.

A keyring does have a name, though, but it is arbitrary and otherwise ignored.

> I see, we're going about this different ways. For me, the ideal search path
> within a single key-ring: keyring, keyring->parent, keyring->parent->parent,
> etc.

So you're thinking of a credential stack? That gets tricky when su is thrown
into the mix. Not that I'm saying my method is precisely simple then either.

Actually, you don't need the concept of a parent at all. If the process had a
current credential TOS pointer, you could push another keyring by adding the
TOS pointer as a child of the new keyring, and then redirecting the TOS
pointer. Basically, the old TOS becomes a child of the new TOS.

I've suggested a stack before, but it got rejected for various reasons.

> That way we wouldn't even need a "session" key-ring in the kernel, a PAM
> module could join processes to the appropriate key-ring when you login.
> That way if I login several times on different console virtual terminals it
> can share a key-ring across all of them, but not when I login remotely.

True. You would still have a "session" keyring, but it would be entirely
defined and governed by userspace (PAM) as to what it meant.

I sort of like that idea. The kernel could still pin keyrings for groups and
users, and PAM could bolt them together, so upon login PAM could create:

TOS
|
+--> Session keyring
|
+--> UID keyring
+--> GID keyring
+--> Supplementary Group keyring
+--> Supplementary Group keyring
+--> Supplementary Group keyring

And then a process or a thread that wanted its own private keys could stack a
new ring:

TOS
|
+--> Thread keyring
|
+--> Process keyring
|
+--> Session keyring

However, you have a number of problems to contend with:

(*) How do you handle setuid() and co?

(*) How do you handle setgid() and co?

(*) How do you handle setgroups()?

(*) How do you handle S_SUID?

This last could be handled in three ways: stack a new credential on the
front; have a second TOS pointer (similar to UIDs); or start a new stack.

If having a second TOS pointer, you could have setresuid() clear it if
setting all UIDs to non-zero.

(*) There needs to be a limit on recursion.

> Let's allow user programs to *request* (Could be overridden) that certain
> keys be swappable, and we could always allow them to be in highmem, as long
> as we can ensure that certain keys won't be swapped. There are advantages
> to not allowing keys to be swapped.

I'm not sure making keys swappable is necessarily easy.

> > Plus, should there be a quota system?
>
> Definitely, by limiting the amount of memory allocated per security context.
> We should make sure that the extra key-ring struct data also counts, so the
> user can't just allocate thousands of empty keys.

Put a counter in "struct user".

> Are the serial numbers unique within a key-ring or within the entire
> subsystem?

The latter.

> Perhaps we should allow user-space to "allocate" a key-type dynamically,
> something >=1024, while <1024 is reserved for kernel-registered
> key-types.
> Key-types should be mappable name=>number and number=>name.

Why?

> Are the types numbers? That would seem simpler and allow differing
> user-space and kernel-space key-type allocation. Then it would be:
> type: KEYTYPE_KRB5 (1042 or some such user-space allocated number)
> desc: "krbtgt/MY.REALM@xxxxxxxx"

No. The types are names. I suppose they could be made numeric too, but I don't
think there's a need for that. I could just decree that all userspace type
names begin with a '+' or something.

> > Some of this could be done by link and rename.
> Yeah, but carefully.

Actually, symlink() would probably be better. Though Al Viro might kill me for
abusing it:-)

> > mkdir would be nice, but the key manager supplies the ID.
> How about a key-ring id directory "-1" that can be opendir()ed to generate a
> new key-ring. Then once you have that you can just use IOCTLs to find out
> what key-ring ID it has. That gives you a directory file-handle and makes
> the retain count management a little simpler. If they don't use the
> key-ring and just close the dir handle then the retain count becomes zero
> and it disappears.

Let's try not to bend the VFS layer too far. Just add another syscall or
prctl() for that.

> I think we are referring to the same ability here, you just referenced it as
> "child" key-rings, whereas I referenced them as "parent" key-rings. Both
> have the same behavior. I think I like the multiple inheritance idea
> better. What we do need is a way to make a

Make a what?

> Yeah, but I think the payload should be accessible through read(), write(),
> etc so that cat can be used to get a dump of the keys, it makes it easier on
> sysadmins who are trying to debug things. Perhaps we could have two files
> for each key in a kernel-registered key-type:

Perhaps it'd be better to make each key a directory, whether or not it's a
keyring:

/proc/keys/
types
keys/
<keyID>/
type
state
description
payload
<keyringID>/
type
state
description
<keyID> => ../<keyID> [symlink]

> Or something like that. That way key filenames stay the same, are easy to
> locate and use in scripts, and give detailed information just in the
> directories.

> We can also store sub-key-rings that way. Here "unlink()" of a directory
> could be permitted.

I don't think you can unlink() a directory, and rmdir() might not work if it's
got contents.

Add a syscall or a prctl().

Perhaps we need a keyctl() syscall...

long keyctl(KEYCTL_NEW, keyid_t keyring,
char *type, char *desc, void *payload);

long keyctl(KEYCTL_UPDATE, keyid_t key,
char *type, void *desc, void *payload);

long keyctl(KEYCTL_LINK, keyid_t keyring, keyid_t key);

long keyctl(KEYCTL_UNLINK, keyid_t keyring, keyid_t key);

long keyctl(KEYCTL_CLEAR, keyid_t keyring);

long keyctl(KEYCTL_REVOKE, keyid_t key);

long keyctl(KEYCTL_FIND, keyid_t keyring, char *type, char *desc);

Some prctls()...

long prctl(PR_GET_KEYID, keyid_t keyring);

long prctl(PR_NEW_SESSION_KEYRING);

With some special keyIDs:

0xABCD0001 - This thread's keyring
0xABCD0002 - This process's keyring
0xABCD0003 - This session's keyring
0xABCD0004 - This UID's keyring
0xABCD0005 - This GID's keyring

New rlimits:

RLIMIT_KEYS - Amount of memory consumed by a user's keys.

And a new filesystem in which extant keys (including keyrings) can be viewed
to a greater or a lesser extent.

> Yeah. We ought to have equivalent IOCTLs so that mostly atomic updates can
> be done to key-rings, possibly even setting up a mandatory flock() for key
> and key-ring file-handles. Opening a file-handle would be enough to make
> sure it doesn't go away, but flocking it would protect against other kinds
> of operations.

We don't want to add ioctls if we can avoid it... And I don't think you want
to try mixing flock() in.

What you're suggesting makes filesystem key searching tricky... what happens
when it is running in softirq context and encounters a locked keyring?

> As for the first two operations, looking up key-rings, we could just add a
> hard-link or soft-link /proc/<pid>/keyring/process/thread, though we'd want
> sys-calls as well, since the UID and group ones aren't mapped in proc. I
> don't expect those will be used as much, though.

hard-link or soft-link to what? Keyrings are directories on another
filesystem, and we can only assume that it's mounted on /proc/keys. Besides,
you can't hard-link directories.

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