lkml.org 
[lkml]   [2004]   [Jun]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
From
SubjectRe: In-kernel Authentication Tokens (PAGs)
Date
On Jun 23, 2004, at 08:29, David Howells wrote:
> Kyle Moffett <mrmacman_g4@mac.com> 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.

Ok, that makes sense, I just confused myself when I read your code.
Could we
just use numbers? Possibly a port of the PID allocator would make that
easier.

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

We've been looking at this from different perspectives. My search
system was
to have a special "parent" that is searched if a key cannot be found in
the
current key-ring. Your search systeam appears to be to have a bunch of
"children" that are just an extra collection of more keys that are
searched after
the key-ring.

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

I really like that idea, but perhaps it could be made more extendable.
Maybe
we could use a system like this:

Searching a key-ring involves searching its keys, then searching its
children,
(Child order is undefined). When a task begins a search operation it
searches
the following key-rings in this order:

Thread
Process
User
Primary Group
Secondary Group(s) (Undefined order)

The recommended way to join a process to a session is to change its
process
key-ring to something like the following:
Process
|
+---New empty process key-ring
|
+---"Session" key-ring

> However, you have a number of problems to contend with:
>
> (*) How do you handle setuid() and co?

By default the init process receives a NULL key-ring (No key-ring at
all). This
means that new processes spawned by init receive a NULL key-ring. These
are NULL key-ring pointers, not empty key-rings, so no data/keys are
shared.
If a process tries to create keys in a NULL key-ring, it will fail.
Then setuid(),
etc. merely change the uid, etc. If a daemon is explicitly given a
keyring at
startup it will retain that keyring. This preserves maximum
compatibility even
though there are no changes to libc.

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

The same way as setuid().

> (*) How do you handle setgroups()?

The same way as setgid().

> (*) 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.

As long as we're careful to do all key-ring operations within an
interruptible task
context, and only use a locking iterative search, we don't need to care
about
tree depth. If the user creates too deep of a child structure, it just
gets credited to
their process time and user limits. Iterative searches eliminate the
stack usage
problems and make it simple to fit in a 4k stack limit.

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

So in the initial implementation of the key-ring system all requests
for swappable
keys would be overridden to be not swappable. After all, it's only a
*request* :-D

> Put a counter in "struct user".

Possibly also per-process or per-thread limits. Maybe even per-group
limits, if we
want to go all the way. Those are relatively simple, though.

>> Are the serial numbers unique within a key-ring or within the entire
>> subsystem?
> The latter.
That makes it much easier to move keys around between key-rings, I
guess.

>> 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@MY.REALM"
>
> 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.

I suppose that makes sense. I think at one point I had a technical
reason for why
types should be numbers but it seems to have gone away. Oh well :-)

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

We want to be careful to give processes a way to prevent race conditions
when accessing/modifying key-rings.

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

Yeah. Generally we want to give them a file or directory handle
instead of a
key-ring ID. That way we have a simple way to detect when they're done
using it.

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

I like this idea. It's a simple shallow directory tree.

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

Yes, but unlink would only be needed on the symlinks, which is what we
need. The keys and key-rings themselves would go away when all
references to them have been destroyed.

> 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

Why not just have separate keyctl calls to set thread, process, UID,
and GID
keyrings for specific threads/processes/UIDs/GIDs. That way a process
with
the appropriate capabilities can manipulate keys as needed. It also
frees
us from the need to worry about not allocating those particular IDs.

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

Is there anything that needs to run in softirq context that should be
accessing
key-rings there? Perhaps one condition on key-ring access would be to
require that it be done from interruptible task context. We could
re-implement
the flock operation for our particular key filesystem to be a mandatory
key lock.
That would prevent race conditions in priv'ed processes manipulating the
key-rings by allowing atomic modifications on a large scale.

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

Ahh, sorry, I was thinking and got lost. Nevermind :-D
Perhaps we should add a few /proc/<pid>/keyring/{thread,process,...}
"files"
to allow the sysadmin to view what key-rings are currently used by a
particular
process.

Cheers,
Kyle Moffett

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

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