2004-06-12 02:37:39

by Kyle Moffett

[permalink] [raw]
Subject: In-kernel Authentication Tokens (PAGs)

I am working on a generic PAG subsystem for the kernel, something that
handles BLOB PAG data and could be used for OpenAFS, Coda, NFSv4, etc.
I have a patch, but it is not well tested yet. Here is an overview of
the
architecture:

Each process has a PAG, and each PAG has a parent PAG. Users are
allowed to make new PAGs associated with their UID and modify ones that
are already associated with their UID. Each PAG consists of a set of
tokens,
each uniquely identified by an integral "type" and a string "realm."
The
search for a token by any subsystem is done starting at the immediate
parent
and proceeds upward. Tokens are in kernel memory and so are not ever
swapped out.

Each PAG is represented in user-space as an integer. Here are the
sys-calls
that I propose:

sys_get_pag
sys_set_pag
These manipulate the PAG associated with a given PID.

sys_get_pag_parent
sys_set_pag_parent
These manipulate the parent PAG of a given PAG

sys_get_pag_uid
sys_set_pag_uid
These manipulate the UID which "owns" a PAG

sys_get_pag_token
sys_set_pag_token
These manipulate tokens within a specific PAG

sys_search_pag_token
This executes the search process as described above

Cheers,
Kyle Moffett


2004-06-12 03:13:23

by Andy Lutomirski

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

Kyle Moffett wrote:

> I am working on a generic PAG subsystem for the kernel, something that
> handles BLOB PAG data and could be used for OpenAFS, Coda, NFSv4, etc.
> I have a patch, but it is not well tested yet. Here is an overview of the
> architecture:
>
> Each process has a PAG, and each PAG has a parent PAG. Users are
> allowed to make new PAGs associated with their UID and modify ones that
> are already associated with their UID. Each PAG consists of a set of
> tokens,
> each uniquely identified by an integral "type" and a string "realm." The
> search for a token by any subsystem is done starting at the immediate
> parent
> and proceeds upward. Tokens are in kernel memory and so are not ever
> swapped out.
>
> ...

I like the idea of having some kernel support for tokens.

But why PAGs? I imagine tokens as being independent objects without any
hierarchy. A token group is a set of tokens. The operations on tokens are:

read: read the raw value of the token
write: change the value of the token
execute: "use" the token (i.e. for VFS, pass over UNIX socket (to a
privileged process, I guess).

Which gives an interesting thought: there are "anonymous" and named tokens.
Anonymous ones are just fds. Named ones live in /cred/tokens.

/cred/tokens: a named token
/cred/groups/all: a magic group which has everything
/cred/groups/whatever: contains symlinks to tokens it can access

/proc/12345/tokengroup: symlink to my token group

To avoid information leaks, /cred/tokens would be readable and executable
only by root. You can only create symlinks to tokens you have access to.
And you have a syscall to select a token group.

AFS's pagsh (or whatever it's called) creates a new token group and selects it.

If you really need a hierarchy, then you could allow token groups to
contain other token groups, with the rule that the whole thing must be acyclic.

Now, if I only knew how to write filesystems...

--Andy

2004-06-12 03:15:30

by Chris Wright

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

* Kyle Moffett ([email protected]) wrote:
> I am working on a generic PAG subsystem for the kernel, something that
> handles BLOB PAG data and could be used for OpenAFS, Coda, NFSv4, etc.
> I have a patch, but it is not well tested yet. Here is an overview of
> the
> architecture:
>
> Each process has a PAG, and each PAG has a parent PAG. Users are
> allowed to make new PAGs associated with their UID and modify ones that
> are already associated with their UID. Each PAG consists of a set of

Hrm. Wouldn't it be possible that two processes with same uid have
authenticated in different domains, and as such shouldn't be allowed to
touch each other's PAGs? Or is this not allowed?

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-06-12 04:48:42

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 11, 2004, at 23:15, Chris Wright wrote:
> Hrm. Wouldn't it be possible that two processes with same uid have
> authenticated in different domains, and as such shouldn't be allowed to
> touch each other's PAGs? Or is this not allowed?

Linux doesn't really support the idea that a process should not be able
to
affect another process in the same UID. There's too many things that
would break or become horribly insecure if we tried to assume that. For
example, just attach a debugger to a process that you want the keys of.
Then just insert a few system calls to retrieve the data, and leave.
Linux
assumes atomicity of a user/UID and it's not practical to change that.

Cheers,
Kyle Moffett

2004-06-12 04:57:19

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 11, 2004, at 23:13, Andy Lutomirski wrote:
> I like the idea of having some kernel support for tokens.
>
> But why PAGs? I imagine tokens as being independent objects without
> any hierarchy. A token group is a set of tokens. The operations on
> tokens
> are:
>
> [...snip...]
>
> If you really need a hierarchy, then you could allow token groups to
> contain
> other token groups, with the rule that the whole thing must be acyclic.

I think my vocabulary here is confusing, what you refer to as a token
group, I refer to as a PAG. The idea for the hierarchy is that it is
frequently desirable to start a sub-shell with a temporarily different
set of tokens, or to mask out only a certain token without modifying
the rest. For example, let's say that I login at my school, which gets
Kerberos tokens and AFS tickets. Now I want to perform some Kerberos
administration activities, so I run "pagsh" or something to create a
new shell with a new PAG, one with a parent of the original PAG. When
I do filesystem access the search process finds the old AFS tokens, but
the kmoffett/[email protected] Kerberos TGT token hides the old
[email protected] Kerberos TGT, without replacing it. That means that
all the old shells operate normally, nothing has changed for them, but
the new shell has the extra layer with the new Kerberos tickets, so I
can administrate Kerberos without changing my AFS tokens to admin ones.

Cheers,
Kyle Moffett

2004-06-12 05:34:40

by Andy Lutomirski

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

Kyle Moffett wrote:

> On Jun 11, 2004, at 23:13, Andy Lutomirski wrote:
>
>> I like the idea of having some kernel support for tokens.
>>
>> But why PAGs? I imagine tokens as being independent objects without
>> any hierarchy. A token group is a set of tokens. The operations on
>> tokens
>> are:
>>
>> [...snip...]
>>
>> If you really need a hierarchy, then you could allow token groups to
>> contain
>> other token groups, with the rule that the whole thing must be acyclic.
>
>
> I think my vocabulary here is confusing, what you refer to as a token
> group, I refer to as a PAG. The idea for the hierarchy is that it is
> frequently desirable to start a sub-shell with a temporarily different
> set of tokens, or to mask out only a certain token without modifying the
> rest.

Right. But I think it would be desirable to do other things -- for
example, a program might want to forward one token over to a daemon to do
some work. It doesn't make much sense here to have a hierarchial structure.

BTW, does AFS even have this hierarchy, or does pagsh just create a copy?
I can't find any manpage for it...


--Andy

2004-06-12 12:52:04

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 12, 2004, at 01:34, Andy Lutomirski wrote:
> Right. But I think it would be desirable to do other things -- for
> example, a program might want to forward one token over to a daemon to
> do some work. It doesn't make much sense here to have a hierarchial
> structure.

So you disagree with the hierarchical structure because you believe
that there are other things that are more important that conflict with
it. I see no reason why both cannot be accommodated. For me, I would
really desire a hierarchical structure because it would make it very
simple to have a token set for the entire session and one for each
instance (shell), and ones for subshells where convenient.

You want to sent a token to some daemon over a UNIX socket? Just copy
the token data and write it out to the socket, the same as if you had
some external token store (Like in MIT Kerberos) and wanted to send the
token to somewhere without the environment variables. This system
would allow several existing token cache mechanisms to be converted to
this alternative store without much work at all.

Perhaps the syscalls should be changed to allow better protection
against race conditions when two processes are using token groups.

sys_tokgrp_open
Returns a tokgrp_handle associated with a token group id. Implies
that the tokgrp will not go away until this handle is closed

sys_tokgrp_pid_open
Returns a tokgrp_handle associated with the token group currently
controlled by a given PID.

sys_tokgrp_close
Releases a tokgrp_handle

sys_tokgrp_get{parent,uid,token}
sys_tokgrp_set{parent,uid,token}
These operate the same as earlier, except on tokgrp_handles instead of
tokgrp IDs.

Then perhaps we could arrange for a tokgrp_handle to be a special kind
of filehandle, and perhaps the set* and get* functions could be IOCTLs
or something. That would allow a tokgrp_handle to be passed around
between processes, although a suitably privileged process could just
run sys_tokgrp_pid_open on the PID of the other process. That way also
close-on-exec and such work as expected.

> BTW, does AFS even have this hierarchy, or does pagsh just create a
> copy? I can't find any manpage for it...

AFS in 2.4 has these magic high-numbered groups that it dynamically
allocates. The way a new set of tokens is created is by changing magic
groups to a new set. That whole system is just a massive hack and I'd
rather it stop at 2.4 I don't know about 2.6, I think they might be
ready for a beta, but I don't know how their auth tokens work.

Cheers,
Kyle Moffett

2004-06-12 15:37:36

by Andy Lutomirski

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

Kyle Moffett wrote:

> On Jun 12, 2004, at 01:34, Andy Lutomirski wrote:
>
>> Right. But I think it would be desirable to do other things -- for
>> example, a program might want to forward one token over to a daemon to
>> do some work. It doesn't make much sense here to have a hierarchial
>> structure.
>
>
> So you disagree with the hierarchical structure because you believe that
> there are other things that are more important that conflict with it. I
> see no reason why both cannot be accommodated. For me, I would really
> desire a hierarchical structure because it would make it very simple to
> have a token set for the entire session and one for each instance
> (shell), and ones for subshells where convenient.

OK.

>
> You want to sent a token to some daemon over a UNIX socket? Just copy
> the token data and write it out to the socket, the same as if you had
> some external token store (Like in MIT Kerberos) and wanted to send the
> token to somewhere without the environment variables. This system would
> allow several existing token cache mechanisms to be converted to this
> alternative store without much work at all.

Except I'd like non-root users to have tokens that they _cannot_ read, but
that they can still pass over unix sockets. I have no objection to also
allowing user-readable tokens.

This way I could have a server with, say, a Kerberos service token such
that a compromise of the server process does not compromise the service
token. (You still have a gotcha in that the kerberosd this would require
would, for performance reasons, want to handle only ticket-granting
traffic. Still, you just mark the TGT unreadable and the individual
session tickets readable, so that the damage of a compromise is limited to
a few hours until the sessions expire.)

Yes, this would be a _lot_ more work than just blindly porting Kerberos'
ticket cache, but it has security benefits.

And I really want a good token system in Linux -- that way the OpenAFS
people will stop bitching and I might be able to use it again.

--Andy

2004-06-12 17:15:54

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 12, 2004, at 11:37, Andy Lutomirski wrote:
> Kyle Moffett wrote:
>> You want to sent a token to some daemon over a UNIX socket? Just
>> copy the token data and write it out to the socket, the same as if
>> you had some external token store (Like in MIT Kerberos) and wanted
>> to send the token to somewhere without the environment variables.
>> This system would allow several existing token cache mechanisms to be
>> converted to this alternative store without much work at all.
>
> Except I'd like non-root users to have tokens that they _cannot_ read,
> but that they can still pass over unix sockets. I have no objection
> to also allowing user-readable tokens.

Ok, that makes a lot of sense, I really should have thought of that
earlier. So how about we add an extra flag to a token identifying
whether it's readable by someone with it's UID or only by someone with
CAP_LINUX_TOKGRP. How about the following interface:

The special files "/proc/tokgrp/<tokgrp-id>/group" represent token
groups. They cannot be read or written, but they utilize file modes
(I'm not sure how yet). Opening one of them prevents it from going
away until it is closed. There should be symlinks named
"/proc/<pid>/tokgrp" to the appropriate dir in "/proc/tokgrp/".
Perhaps there should be symlinks as "/proc/tokgrp/<tokgrp_id>/parent"
to the appropriate parent tokgrp directory. Those would not exist if
it did not have a parent.

IOCTLs:
tokgrp_{get,set}_pid: Manipulates the PID of a token group
tokgrp_{get,set}_parent: Manipulates the parent of a token group

Tokens are uniquely identified within a token group by an integral
"type" and a string "realm". A specific token is mapped to
"/proc/tokgrp/<id>/<typenum>/<realm>". They can be read or written
according to file modes, and the execute permission means the ability
to execute in-kernel operations on the token (depending on the type)
using IOCTLs. All tokens (As long as the process is in the same UID
and/or has CAP_LINUX_PAG) can be opened and the filehandles passed
around using UNIX sockets.

> This way I could have a server with, say, a Kerberos service token
> such that a compromise of the server process does not compromise the
> service token. (You still have a gotcha in that the kerberosd this
> would require would, for performance reasons, want to handle only
> ticket-granting traffic. Still, you just mark the TGT unreadable and
> the individual session tickets readable, so that the damage of a
> compromise is limited to a few hours until the sessions expire.)

Since we have in-kernel crypto we could even put some of the token
operations into the kernel and use those operations to work with the
ticket (decrypt, etc). That would mean that in certain cases we could
keep the tickets completely out of reach of exposed software.

> Yes, this would be a _lot_ more work than just blindly porting
> Kerberos' ticket cache, but it has security benefits.

Definitely

> And I really want a good token system in Linux -- that way the OpenAFS
> people will stop bitching and I might be able to use it again.

Yeah, I know. If we do it well enough and make it modular enough then
OpenAFS, Coda, NFSv4, Kerberos, OpenSSH (RSA keys) etc can all use the
same implementation. This could also be steps in the right direction
of making Linux more TCB-ish.

Cheers,
Kyle Moffett

2004-06-12 20:53:06

by Chris Wright

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

* Kyle Moffett ([email protected]) wrote:
> On Jun 11, 2004, at 23:15, Chris Wright wrote:
> > Hrm. Wouldn't it be possible that two processes with same uid have
> > authenticated in different domains, and as such shouldn't be allowed to
> > touch each other's PAGs? Or is this not allowed?
>
> Linux doesn't really support the idea that a process should not be able
> to
> affect another process in the same UID. There's too many things that

Actually that's not the case. The UID is currently insufficient to
describe the security domain that a process is running in. The whole
of the LSM infrastructure is designed with this in mind. So somehting
like SELinux may enforce a security domain change (w/out a UID change)
across an execve() of pagsh. I was simply trying to ascertain if you
were storing this within task->user which I think would be wrong.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-06-12 21:15:52

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 12, 2004, at 16:53, Chris Wright wrote:
> Actually that's not the case. The UID is currently insufficient to
> describe the security domain that a process is running in. The whole
> of the LSM infrastructure is designed with this in mind. So somehting
> like SELinux may enforce a security domain change (w/out a UID change)
> across an execve() of pagsh. I was simply trying to ascertain if you
> were storing this within task->user which I think would be wrong.

Ahh, ok, I myself have no experience with LSM, so there will likely be
some
need to change my implementation. Currently the only field that I add
to
existing structures in the kernel is a pag field in the task_struct.
PAG
structures themselves need some way of determining if the calling task
is in the same "grouping" as a stored "grouping" within the PAG. My
implementation uses UIDs, but I would be very glad if you could tell me
what I should use instead. I need some kind of structure or pointer
that I
can embed within a PAG and a token, and some kind of equality test.

The other thing that needs to be implemented is some kind of limit that
restricts how many PAGs/tokens and how much memory can be allocated
in the kernel per user and per process. Do you have any information on
where would be the best place to store that information?

Cheers,
Kyle Moffett

2004-06-12 21:45:00

by Chris Wright

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

* Kyle Moffett ([email protected]) wrote:
> On Jun 12, 2004, at 16:53, Chris Wright wrote:
> > Actually that's not the case. The UID is currently insufficient to
> > describe the security domain that a process is running in. The whole
> > of the LSM infrastructure is designed with this in mind. So somehting
> > like SELinux may enforce a security domain change (w/out a UID change)
> > across an execve() of pagsh. I was simply trying to ascertain if you
> > were storing this within task->user which I think would be wrong.
>
> Ahh, ok, I myself have no experience with LSM, so there will likely be
> some
> need to change my implementation. Currently the only field that I add
> to
> existing structures in the kernel is a pag field in the task_struct.
> PAG
> structures themselves need some way of determining if the calling task
> is in the same "grouping" as a stored "grouping" within the PAG. My
> implementation uses UIDs, but I would be very glad if you could tell me
> what I should use instead. I need some kind of structure or pointer
> that I
> can embed within a PAG and a token, and some kind of equality test.

Typically, objects that LSM cares about include a pointer to opaque
data (security blob) which describes the security domain for the object.
See task->security as an example. It's not clear to me if task->security
is sufficient and you only need a back pointer to the task or if each
PAG needs it's own security blob.

> The other thing that needs to be implemented is some kind of limit that
> restricts how many PAGs/tokens and how much memory can be allocated
> in the kernel per user and per process. Do you have any information on
> where would be the best place to store that information?

Sounds like an extension to rlimits. The counters could be stored in
->user to limit the userwide number of tokens.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-06-12 21:58:37

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 12, 2004, at 17:44, Chris Wright wrote:
> Typically, objects that LSM cares about include a pointer to opaque
> data (security blob) which describes the security domain for the
> object.
> See task->security as an example. It's not clear to me if
> task->security
> is sufficient and you only need a back pointer to the task or if each
> PAG needs it's own security blob.

Ahh, ok. In this case, a PAG is an independent object, not directly
associated with any specific task or other PAG, so therefore it will
likely
need its own security blob. Currently, in the creation of my PAG I just
copy over the UID from the calling task. If I was to convert it to use
LSM,
I guess I should just leave out the UID entirely, and just have a
pointer
to a security blob. What is the best way to portray the security blob
to
user-space, in terms of sys-calls? I need a way for user-space apps to
change the security context in a similar way as it is changed for a task
or process. Do you have a link to some documentation on the kernel
API for LSM? I basically need to copy the current task's security blob
into a new one and be able to compare two contexts to see if one
can affect the other. Thanks!

> Sounds like an extension to rlimits. The counters could be stored in
> ->user to limit the userwide number of tokens.

Ok, thank you very much, that's exactly what I need. I am somewhat
new to kernel development, so finding my way around the structs is
somewhat difficult. Is there a good guide somewhere on the net that
you can point me to?

Cheers,
Kyle Moffett

2004-06-12 22:51:08

by Trond Myklebust

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

P? fr , 11/06/2004 klokka 22:37, skreiv Kyle Moffett:
> I am working on a generic PAG subsystem for the kernel,

It's been done.

See the thread on

http://marc.theaimsgroup.com/?l=linux-fsdevel&m=105290906118164&w=2

on why Linus vetoed the idea of PAGs for Linux.

Cheers,
Trond

2004-06-12 22:51:28

by Chris Wright

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

* Kyle Moffett ([email protected]) wrote:
> On Jun 12, 2004, at 17:44, Chris Wright wrote:
> > Typically, objects that LSM cares about include a pointer to opaque
> > data (security blob) which describes the security domain for the
> > object.
> > See task->security as an example. It's not clear to me if
> > task->security
> > is sufficient and you only need a back pointer to the task or if each
> > PAG needs it's own security blob.
>
> Ahh, ok. In this case, a PAG is an independent object, not directly
> associated with any specific task or other PAG, so therefore it will
> likely
> need its own security blob. Currently, in the creation of my PAG I just
> copy over the UID from the calling task. If I was to convert it to use
> LSM,
> I guess I should just leave out the UID entirely, and just have a
> pointer
> to a security blob. What is the best way to portray the security blob
> to
> user-space, in terms of sys-calls? I need a way for user-space apps to
> change the security context in a similar way as it is changed for a task
> or process. Do you have a link to some documentation on the kernel
> API for LSM? I basically need to copy the current task's security blob
> into a new one and be able to compare two contexts to see if one
> can affect the other. Thanks!

I don't have a good feel for the PAG data structure, perhaps the
above would turn out as overkill. The security api is commented in
include/linux/security.h, take a gander there. The blobs are specific
to the security model, and I don't yet see a need to display them to
userspace for each PAG.

> > Sounds like an extension to rlimits. The counters could be stored in
> > ->user to limit the userwide number of tokens.
>
> Ok, thank you very much, that's exactly what I need. I am somewhat
> new to kernel development, so finding my way around the structs is
> somewhat difficult. Is there a good guide somewhere on the net that
> you can point me to?

Hmm, not really. The source is best.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-06-12 23:33:09

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 12, 2004, at 18:51, Trond Myklebust wrote:
> It's been done.
>
> See the thread on
>
> http://marc.theaimsgroup.com/?l=linux-fsdevel&m=105290906118164&w=2
>
> on why Linus vetoed the idea of PAGs for Linux.

He didn't veto PAGs, he only vetoed that particular implementation.
I've
read his criticisms before and I believe that my proposal neatly handles
most of them, which is why I'm posting it. Another nice feature of my
system
is that it does not break anything if it is completely ignored by some
tasks
and used by others. In fact, most processes shouldn't care, only stuff
that
actually needs to use or modify the tokens in user-space should care.

I really should change the term "PAG". My implementation does not
operate
at all like the posted one did. His implementation is tied in very
strongly with
the concept of a user, 1 user => 1 PAG. In my code the two are
completely
separate, a PAG is a generic object with a few properties: a security
context,
a list of tokens, and a parent. Linus' criticisms are:


- Designed for AFS

I designed this because I would like to see a ticket/token storage
mechanism
in the kernel. I would like this to be something that could be a
Kerberos V5
credentials cache, an RSA key storage agent (like ssh-agent), and a
generic
remote filesystem token storage.


- A token can only be on one PAG

True in my design, but in order to access the token you open() it,
which returns
a filehandle that can be passed to any other program over a UNIX socket.
This could be easily extended to allow the original user to
invalidate/close the
other user's filehandle. Also, the design allows each PAG to have a
parent,
so it forms a tree (Must be non-cyclic). This allows multiple
processes to share
a set of global tokens in a parent PAG, and each have their own sub-PAGs
that they can work in without disturbing the global token set. Linus
even
mentions that perhaps a list of PAGs could handle that issue, but with
that the
priority is unintuitive, whereas with a tree one can match the process
tree
much more accurately and without much effort. Even still, my design
makes it
simple to add the ability for a token to be in more than one PAG.


- pag_t is too small

This doesn't apply, because I don't map a PAG to a user, it stands on
its own,
in an allocation namespace separate from anything else.


- Desire for "group" PAGs.

I don't have any feature that allows for a "group" PAG, but I think
that should be
handled elsewhere. If I want special file access because I am in a
group, then
that should be handled by the filesystem based on my _user_ token. It
knows
who I am and can figure out my group list from that. If it is truly a
desire to have
all members share a token or set of tokens (I don't know of any
circumstances
where this would be desirable, please tell me if you have any
examples), then
each group could have a PAG tree associated with it, which would be
searched
*after* the PAG tree associated with a process when looking for tokens.


Cheers,
Kyle Moffett

2004-06-12 23:40:46

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 12, 2004, at 18:51, Chris Wright wrote:
> I don't have a good feel for the PAG data structure, perhaps the
> above would turn out as overkill. The security api is commented in
> include/linux/security.h, take a gander there. The blobs are specific
> to the security model, and I don't yet see a need to display them to
> userspace for each PAG.

Ok, well perhaps what I actually need are some extra callbacks for
security modules then. A token-group (I'm changing the term because
PAG is confused with an older patch) needs to have an access spec
indicating who can read/modify the token-group as a whole and who
can read/modify each token within it. In my emails with Andy
Lutomirski we have thought about the idea of putting the token-groups
in /proc and running all access through that way. If we do that, then
it
would be very practical to just use file permissions and POSIX ACLs
to control access, in which case each token-group and token could
just use the same access-control mechanisms that are used for other
files in /proc. That would likely be the easiest path

>> Ok, thank you very much, that's exactly what I need. I am somewhat
>> new to kernel development, so finding my way around the structs is
>> somewhat difficult. Is there a good guide somewhere on the net that
>> you can point me to?
> Hmm, not really. The source is best.
Ok, well thanks for pointing out linux/security.h anyway.

Thanks very much for your help!

Cheers,
Kyle Moffett

2004-06-12 23:58:59

by Trond Myklebust

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

P? lau , 12/06/2004 klokka 19:33, skreiv Kyle Moffett:

> - Designed for AFS
>
> I designed this because I would like to see a ticket/token storage
> mechanism
> in the kernel. I would like this to be something that could be a
> Kerberos V5
> credentials cache, an RSA key storage agent (like ssh-agent), and a
> generic
> remote filesystem token storage.

So this would be more like an in-kernel keyring then?

> - A token can only be on one PAG
>
> True in my design, but in order to access the token you open() it,
> which returns
> a filehandle that can be passed to any other program over a UNIX socket.
> This could be easily extended to allow the original user to
> invalidate/close the
> other user's filehandle. Also, the design allows each PAG to have a
> parent,
> so it forms a tree (Must be non-cyclic). This allows multiple
> processes to share
> a set of global tokens in a parent PAG, and each have their own sub-PAGs
> that they can work in without disturbing the global token set. Linus
> even
> mentions that perhaps a list of PAGs could handle that issue, but with
> that the
> priority is unintuitive, whereas with a tree one can match the process
> tree
> much more accurately and without much effort. Even still, my design
> makes it
> simple to add the ability for a token to be in more than one PAG.

How does it cope with lifetime issues such as token renewal and
invalidation?

Does it provide for notifiers in case of invalidation, renewal or token
expiration?

For NFSv4 for instance, this is important, since the client will want to
evict all state if the user's credential expires.

Cheers,
Trond

2004-06-13 00:23:19

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 12, 2004, at 19:58, Trond Myklebust wrote:
> So this would be more like an in-kernel keyring then?
Yeah, that seems about right.

> How does it cope with lifetime issues such as token renewal and
> invalidation?
My design is token-type independent, it merely implements a generic
token BLOB handling facility that maps a process to a set of tokens.
The usage of tokens should be a completely separate issue. For
example, I auth to a Kerberos server and put the retrieved ticket into
the kernel token system. When that token is later used, the user
(NFSv4, in this case) must verify if the token has expired or not. A
variety of actions may be taken after that point, one of which may be
to just delete the token. If NFSv4 later tried to use the token handle
(Basically a filehandle), then it would get an error indicating that the
token was deleted, and could clean up. If NFSv4 was the first one
that discovered the token was expired, then _it_ could delete the
token and clean up the state.

> Does it provide for notifiers in case of invalidation, renewal or token
> expiration?
That is a token-type specific matter, and should be handled by a
module targeting a specific token type. All tokens have a type and a
service. The "type" is an integer, representing the format of the
token.
It could be TOKEN_RSA, or TOKEN_DSA, or TOKEN_KRB4, or
TOKEN_KRB5, or TOKEN_AES. The "service" is a string that ids
a token uniquely within its type and token group. A user program
could presumably create a token with any binary data and type arg
at all and just stick it into the kernel. It would deduct from the
user's
space and token limit, but it could be done and would work fine. If
some token type needs special kernel handling then that could be
a module with some custom IOCTLs on the token filehandle.

Cheers,
Kyle Moffett


2004-06-15 06:31:35

by Blair Strang

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

Kyle Moffett <[email protected]> writes:

> On Jun 12, 2004, at 19:58, Trond Myklebust wrote:
> > So this would be more like an in-kernel keyring then?
> Yeah, that seems about right.
>

Hi,

Disclaimer: I haven't looked at the LSM stuff.

Surely the only logical reason to tag a process with extra security
information /in the kernel/ is because that information is going to be
used /by the kernel/. I can't think of a good reason to put a
generalised keystore in the kernel.

Distributed filesystem credentials are a sensible thing to associate
with a process because then they can be easily used by the filesystem
code. Keeping this information per-uid would be easier, but PAGs are
more general.

>From that point of view, AFS PAGs boil down to the idea of annotating
processes with authorisation tokens that can be easily used by the
kernel. IIRC, in AFS, they just tack on a couple of magic
supplementary GIDs. It is good if the "annotation" can be carried out
by a userspace process.

To be most useful for distributed filesystems, PAG ids should be
per-process and inherited across fork/exec.

This is somewhat different from the genereal idea of a keystore, or
capabilities ala http://www.cap-lore.com/CapTheory/.

So that you can see where I'm coming from (and tell me I'm wrong :)
here's my braindead idea of what generic PAG support would look like.
I would be very surprised if there were not some more generic
mechanism of which this is a subset. LSM?

=====

There needs to be some capability set to allow trusted processes to
grant a PAG id to a process. In a simple implementation, say,
CAP_PAG_ALLOCATE allows you to assign them. In some cases, the kernel
might attach a PAG id to a process.

Each process may have a list of PAG ids.

A PAG id list entry has two important parts, a pag_domain [which might
be PAG_DOMAIN_AFS or PAG_DOMAIN_CODA, whatever -- it just identifies
the kernel subsystem to which the PAG is meaningful] and a pag_id,
which is considered opaque.

You might also have CAP_PAG_GIVEAWAY to allow giveaways by processes
with PAG ids. I haven't thought that part through very well.

A pag-er (allocator) needs at least:

* some way to give a process a unique PAG id.
* some subsystem specific support to associate more data with that PAG id.

And the pag-ee needs at least:

* some (allocator specific) way to ask for a PAG id. this happens in
userspace
* some way to enumerate PAG ids.
* some way to get rid of PAG ids.
* perhaps some way to give PAG ids away.

Regards,

Blair.

--
Hello. Just walk along and try NOT to think about your INTESTINES
being almost FORTY YARDS LONG!! ; C-u M-x yow

2004-06-15 07:03:18

by Trond Myklebust

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

P? ty , 15/06/2004 klokka 02:38, skreiv Blair Strang:

> Surely the only logical reason to tag a process with extra security
> information /in the kernel/ is because that information is going to be
> used /by the kernel/. I can't think of a good reason to put a
> generalised keystore in the kernel.

Here are three good reasons.

- You want the key lifetime to be the same as your process lifetime
- You want the key to be readable ONLY by that one process.
- The kernel wants to supports multiple security realms and mechanisms.
Not everybody is happy with just kerberosV credentials, and we already
have beta code for the SPKM mechanism in RPCSEC_GSS.


As for the AFS PAG idea: it's already been shot down. See the
linux-fsdevel thread I referred to earlier.

Cheers,
Trond

2004-06-15 09:38:49

by David Howells

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)


> > Surely the only logical reason to tag a process with extra security
> > information /in the kernel/ is because that information is going to be
> > used /by the kernel/. I can't think of a good reason to put a
> > generalised keystore in the kernel.
>
> Here are three good reasons.
>
> - You want the key lifetime to be the same as your process lifetime
> - You want the key to be readable ONLY by that one process.
> - The kernel wants to supports multiple security realms and mechanisms.
> Not everybody is happy with just kerberosV credentials, and we already
> have beta code for the SPKM mechanism in RPCSEC_GSS.
>
>
> As for the AFS PAG idea: it's already been shot down. See the
> linux-fsdevel thread I referred to earlier.

You might want to look at this patch. It's what I've come up with to support
kafs, but it's general, and should work for anything. It's been built along
Linus's guidelines, and has Linus's approval, contingent on something actually
using it fully.

You can use the session keyring number as a PAG ID if you wish.

I've a sample aklog program (key submission) should you be interested.

David


Attachments:
keys-266.diff (46.82 kB)

2004-06-15 19:00:16

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 15, 2004, at 05:36, David Howells wrote:
> You might want to look at this patch. It's what I've come up with to
> support
> kafs, but it's general, and should work for anything. It's been built
> along
> Linus's guidelines, and has Linus's approval, contingent on something
> actually
> using it fully.
>
> You can use the session keyring number as a PAG ID if you wish.
>
> I've a sample aklog program (key submission) should you be interested.

One thing that I would very much like to have is the ability to create
a new
shell with a new keyring, such that I can still see and use the old
keyring,
but I can create new keys without modifying the old keyring, even to the
extent of masking out keys in the old keyring without modifying them for
other processes. From my brief glance at your patch, that's not a
feature
you have implemented. I would also like the ability to mark a key as
unreadable except by kernel threads or processes with CAP_KEYRING.
If I can pass key "handles" of some sort over UNIX sockets, then I can
also pass an unreadable key to a daemon process which uses it to
access my files until I revoke the key.

Cheers,
Kyle Moffett

2004-06-15 22:07:33

by Chris Wright

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

* Kyle Moffett ([email protected]) wrote:
> One thing that I would very much like to have is the ability to create
> a new
> shell with a new keyring, such that I can still see and use the old
> keyring,
> but I can create new keys without modifying the old keyring, even to the
> extent of masking out keys in the old keyring without modifying them for
> other processes. From my brief glance at your patch, that's not a
> feature you have implemented.

Sounds like a CLONE_KEYRING flag?

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-06-15 22:29:15

by Chris Wright

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

* David Howells ([email protected]) wrote:
> You might want to look at this patch. It's what I've come up with to support
> kafs, but it's general, and should work for anything. It's been built along
> Linus's guidelines, and has Linus's approval, contingent on something actually
> using it fully.
>
> You can use the session keyring number as a PAG ID if you wish.
>
> I've a sample aklog program (key submission) should you be interested.

I'd be intereseted. BTW, I just took a brief look and had a quick
question.

> + if (bprm->e_uid != current->uid)
> + suid_keys(current);
> + exec_keys(current);
> +

would the security module be expected update/revoke keys if the thing changes
security domains on exec?

> task_lock(current);
> unsafe = unsafe_exec(current);
> security_bprm_apply_creds(bprm, unsafe);

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-06-15 23:51:53

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 15, 2004, at 18:07, Chris Wright wrote:
> * Kyle Moffett ([email protected]) wrote:
>> One thing that I would very much like to have is the ability to create
>> a new
>> shell with a new keyring, such that I can still see and use the old
>> keyring,
>> but I can create new keys without modifying the old keyring, even to
>> the
>> extent of masking out keys in the old keyring without modifying them
>> for
>> other processes. From my brief glance at your patch, that's not a
>> feature you have implemented.
> Sounds like a CLONE_KEYRING flag?

I think the two concepts are unrelated. You should not be required
to create a new thread/process/task in order to give yourself a
separate key-ring, and it would be plain stupid to have one mode
of the clone() syscall that doesn't create a new task but instead
changes key-rings Take Apache and suexec PHP for example: it
would be very useful to be able to have a key-ring owned by the
root user that contains the AFS keys Apache uses to access files.
Then when it runs a suexec PHP script, it adds a new key-ring
owned by "someuser" to the process (without doing a clone()).
It does a seteuid("someuser"), then proceeds with the PHP code.
That gives the user's PHP its own key-ring context, and protects
the parent's key-ring. When done it removes "someuser"'s keys
and does seteuid(0).

Cheers,
Kyle Moffett

2004-06-15 23:59:28

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 15, 2004, at 05:36, David Howells wrote:
> You might want to look at this patch. It's what I've come up with to
> support
> kafs, but it's general, and should work for anything. It's been built
> along
> Linus's guidelines, and has Linus's approval, contingent on something
> actually
> using it fully.

One other thing that I'm not certain about in this patch is if there
is actually an important difference between "process" and
"session" key-rings. I believe that the "session" distinction
should be left up to user-space software like PAM to determine
which key-ring "session" a process should belong to. The user
and group key-rings are a good idea, so I guess the order with
which key-rings are checked for keys is:
Thread
Process
Session???
User
Group

Cheers,
Kyle Moffett

2004-06-16 00:01:19

by Chris Wright

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

* Kyle Moffett ([email protected]) wrote:
> On Jun 15, 2004, at 18:07, Chris Wright wrote:
> > * Kyle Moffett ([email protected]) wrote:
> >> One thing that I would very much like to have is the ability to create
> >> a new
> >> shell with a new keyring, such that I can still see and use the old
> >> keyring,
> >> but I can create new keys without modifying the old keyring, even to
> >> the
> >> extent of masking out keys in the old keyring without modifying them
> >> for
> >> other processes. From my brief glance at your patch, that's not a
> >> feature you have implemented.
> > Sounds like a CLONE_KEYRING flag?
>
> I think the two concepts are unrelated. You should not be required
> to create a new thread/process/task in order to give yourself a

Just commenting on your desire to "create a new shell with a new
keyring.." This had clone() implicit in it.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-06-16 00:07:02

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 15, 2004, at 20:01, Chris Wright wrote:
> Just commenting on your desire to "create a new shell with a new
> keyring.." This had clone() implicit in it.

Ah, it did indeed. Sorry for the confusion! :-D

Cheers,
Kyle Moffett

2004-06-16 14:22:58

by David Howells

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)


> One thing that I would very much like to have is the ability to create a new
> shell with a new keyring, such that I can still see and use the old keyring,
> but I can create new keys without modifying the old keyring, even to the
> extent of masking out keys in the old keyring without modifying them for
> other processes. From my brief glance at your patch, that's not a feature
> you have implemented.

Hmmm... What exactly are you wanting to do? Each task theoretically subscribes
to five keyrings (the group one isn't yet there) in this model; three of which
are transferred across a fork, and four across CLONE_THREAD.

The five keyrings are:

- Group (associated with primary GID)
- User (associated with UID)
- Session (voluntarily discarded)
- Process (shared between threads in a process)
- Thread (one per thread)

> I would also like the ability to mark a key as unreadable except by kernel
> threads or processes with CAP_KEYRING.

What do you mean by "unreadable"?

Currently, userspace can't see the data attached to a key. It can only see the
description, and only then through /proc/keys.

> If I can pass key "handles" of some sort over UNIX sockets, then I can also
> pass an unreadable key to a daemon process which uses it to access my files
> until I revoke the key.

I can see what you're getting at.

I think I need to create some more operations:

(*) Retire/Revoke key

(*) Add key to another keyring

(*) Remove key from keyring

(*) List keyring

(*) Describe key

(*) Read key (if not protected)

(*) Create keyring

I have pondered representing keyspace with some sort of filesystem interface
(using vfs ops to represent the operations), but that could require hardlinked
directories (keyrings) to pull off - either that or symlinks.

Also, there's the problem of security on the operations themselves. How do you
determine what a process is allowed to do?

Either I should only allow access to keys and keyrings to which a process is
subscribed, or I should attach UID/GID/MASK values to every key and keyring.

David

2004-06-16 14:40:40

by David Howells

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)


> > I've a sample aklog program (key submission) should you be interested.
>
> I'd be intereseted. BTW, I just took a brief look and had a quick
> question.

Please see attached files.

key_afs.c Rudimentary kAFS filesystem token handling
afsutil.h }
kernel.c } aklog program
aklog.c }

> > + if (bprm->e_uid != current->uid)
> > + suid_keys(current);
> > + exec_keys(current);
> > +
>
> would the security module be expected update/revoke keys if the thing changes
> security domains on exec?

I don't know. Currently this patch replaces the old session keyring in favour
of a new empty one upon SUID exec. I suspect that depends on the policy set by
the administrator.

If you've a better suggestion than what I've done, feel free to make it.

> > task_lock(current);
> > unsafe = unsafe_exec(current);
> > security_bprm_apply_creds(bprm, unsafe);

David


Attachments:
key_afs.c (3.01 kB)
afsutil.h (762.00 B)
kernel.c (2.47 kB)
aklog.c (5.49 kB)
Download all attachments

2004-06-16 14:49:34

by David Howells

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)


> One other thing that I'm not certain about in this patch is if there
> is actually an important difference between "process" and
> "session" key-rings. I believe that the "session" distinction
> should be left up to user-space software like PAM to determine
> which key-ring "session" a process should belong to.

Well, userspace can decide that a process should begin a new session. I'd
envision this as a user gets a session keyring for each login, and so are able
to use these to hold different sets of credentials that don't interfere with
each other.

A UID keyring would be too pervasive - a key in there would affect _every_
process owned by that user - which might be undesirable.

A process keyring wouldn't be pervasive enough. You couldn't, for example, run
aklog in your shell to get you an AFS token attached to the session, use that
token several times by running programs and then quit the shell to dispose of
the token. Each process wanting the token would have to get itself a new token
by contacting the Kerberos server.

> The user and group key-rings are a good idea, so I guess the order with
> which key-rings are checked for keys is:
> Thread
> Process
> Session???
> User
> Group

That's about it, yes. Group keyrings don't currently actually exist.

David

2004-06-17 01:14:04

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 16, 2004, at 10:49, David Howells wrote:
> Well, userspace can decide that a process should begin a new session.
> I'd
> envision this as a user gets a session keyring for each login, and so
> are able
> to use these to hold different sets of credentials that don't
> interfere with
> each other.
>
> A UID keyring would be too pervasive - a key in there would affect
> _every_
> process owned by that user - which might be undesirable.
>
> A process keyring wouldn't be pervasive enough. You couldn't, for
> example, run
> aklog in your shell to get you an AFS token attached to the session,
> use that
> token several times by running programs and then quit the shell to
> dispose of
> the token. Each process wanting the token would have to get itself a
> new token
> by contacting the Kerberos server.

What if we leave the concept of a key-ring as completely general in
nature,
such that it can be associated with any object without needing to know
what
that object is. Then additional key-ring contexts could be created as
needed
for LSM modules or such.

I gave reasons earlier in this thread of why it is very useful to have
nested
key-rings, so perhaps we can give each key-ring a "parent" which
happens to
be an additional key-ring association. As long as we avoid cyclic
graphs, that
should give a great increase in flexibility without security problems.

Another complexity is the access control issue. I would rather not add
more
LSM hooks if we can avoid it, just to keep the complexity down, so I'm
thinking
that we could just represent all the information through the filesystem
and file
descriptors, with a couple of convenient IOCTLs. That way we could use
the
existing LSM hooks for filesystem access, and avoid giving sysadmins
another
system that they must start all over learning to secure.

I've looked at your patch, and it doesn't seem to be general enough to
allow
user-space to store arbitrary keys in the kernel, one of the features
that others
have expressed a desire for (see Andy Lutomirski's emails). With such a
system the most critical aspect to get first is the most flexible way
to manipulate
such keys without creating too much complexity.

It's essential to be able to tell the difference between different
types of keys,
especially if we want to let user-space use this to store other kinds
of keys. We
also need to be able to identify keys by "service" of some sort. I
think that
would probably be a key-type specific parameter, but for a Kerberos TGT
it
could be something like "krbtgt/[email protected]". With a type based
system we could even allow modules that implement additional
functionality
for certain types (IE something that uses CryptoAPI to do AES in-kernel
for
extra security).

Hmm, so going along with these ideas, how about this?
/proc/keyring/
MODE = 555
DESC = keyringfs, contains keyring metadata

<id>/
MODE = Access control for entire keyring
DESC = A keyring entry, referenced by number
opendir = Increments the ref count to make sure it won't go away.

parent => ../<id>
DESC = A symlink or hardlink to the parent keyring

<typeid>/
MODE = 555
DESC = A numerical "key-type" (KEYTYPE_KRB5)

<service>
MODE = Access control for a single key
DESC = The key, accessed as a file.

<typename> => <typeid>/
DESC = A symlink or hardlink to a type number from
a type name. These types could be registered
by modules that implement them.

There would be IOCTLs on the key-ring dir handles for getting the
key-ring
number, adding new keys, etc. On key handles there would be IOCTLs for
deleting the key, revoking access, etc. We'd also need a few syscalls
for
creating new key-rings.

Cheers,
Kyle Moffett

2004-06-17 11:48:55

by David Howells

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)


Kyle Moffett <[email protected]> wrote:
> What if we leave the concept of a key-ring as completely general in nature,
> such that it can be associated with any object without needing to know what
> that object is. Then additional key-ring contexts could be created as
> needed for LSM modules or such.

The main reason that there are attachment points for keyrings on UIDs,
processes, etc, is that there needs to be some way for things like open() to
find them without adding an equivalent syscalls that take a key as well.

In a way, you could look at it as these attachment points are like the PATH
variable - they describe a search path. You still need one of those.

LSM modules can always create keyrings and subscribe one of the five keyrings
a task has to them so that they become accessible.

> I gave reasons earlier in this thread of why it is very useful to have
> nested key-rings, so perhaps we can give each key-ring a "parent" which
> happens to be an additional key-ring association. As long as we avoid
> cyclic graphs, that should give a great increase in flexibility without
> security problems.

It supports nested keyrings - up to a certain depth anyway - and when you add
one keyring into another it checks to see you're not trying to create a cycle
(at least, you can from the kernel... you can't from userspace yet).

I'm not keen on the "parent" idea. I'm not sure what you are thinking of
exactly - a keyring can have multiple parents, and also this sounds like it
may cause a cycle.

> Another complexity is the access control issue. I would rather not add more
> LSM hooks if we can avoid it, just to keep the complexity down, so I'm
> thinking that we could just represent all the information through the
> filesystem and file descriptors, with a couple of convenient IOCTLs. That
> way we could use the existing LSM hooks for filesystem access, and avoid
> giving sysadmins another system that they must start all over learning to
> secure.

Using LSM hooks could represent a chicken vs egg scenario if you want to use
these keys to represent LSM security data (which you might reasonably want to
do).

> I've looked at your patch, and it doesn't seem to be general enough to allow
> user-space to store arbitrary keys in the kernel, one of the features that
> others have expressed a desire for (see Andy Lutomirski's emails). With
> such a system the most critical aspect to get first is the most flexible way
> to manipulate such keys without creating too much complexity.

It could be made such that arbitrary keys can be stored there (just another
keytype)... it's just that the keys eat into the kernel low memory region. It
may be better to permit such keys to be stored in highmem or swap somehow.

Plus, should there be a quota system?

> It's essential to be able to tell the difference between different types of
> keys, especially if we want to let user-space use this to store other kinds
> of keys. We also need to be able to identify keys by "service" of some sort.

Keys have a serial number, a type, a description and a payload. Currently the
types can't be arbitrary - a kernel driver or whatever must have registered
that type for it to be used. If that driver unregisters its key type, all keys
of that type are immediately withdrawn.

For instance, my kafs module registers an "afs" key type in which it can store
a Krb5 ticket. Having a type management system like this allows the type to
have operations to validate, match and pretty-print key descriptions. The
first one is the most important, I feel, because we can validate a key upon
addition.

It might be possible to make this more flexible. Have userspace upload a
"potential" key with arbitrary type, description and payload; and then have,
say, a kafs's file open routine locate a candidate key and render it into
parsed key form. Hmmm...

One thing I want to avoid is having to have the filesystem (or whatever)
validate the key every time it looks at it.

> I think that would probably be a key-type specific parameter, but for a
> Kerberos TGT it could be something like "krbtgt/[email protected]". With a
> type based system we could even allow modules that implement additional
> functionality for certain types (IE something that uses CryptoAPI to do AES
> in-kernel for extra security).

In this example, you might have something like:

type krbtgt
desc [email protected]

Or:

type user
desc krbtgt/[email protected]

But you'd have to provide the kernel with a type registration for the key type
in question.

> Hmm, so going along with these ideas, how about this?
> /proc/keyring/
> MODE = 555
> DESC = keyringfs, contains keyring metadata

I presume you mean keyringfs or keyfs mounted on /proc/keyring/ (or /proc/keys/).

> <id>/
> MODE = Access control for entire keyring
> DESC = A keyring entry, referenced by number
> opendir = Increments the ref count to make sure it won't go away.
>
> parent => ../<id>
> DESC = A symlink or hardlink to the parent keyring
>
> <typeid>/
> MODE = 555
> DESC = A numerical "key-type" (KEYTYPE_KRB5)
>
> <service>
> MODE = Access control for a single key
> DESC = The key, accessed as a file.
>
> <typename> => <typeid>/
> DESC = A symlink or hardlink to a type number from
> a type name. These types could be registered
> by modules that implement them.
>
> There would be IOCTLs on the key-ring dir handles for getting the key-ring
> number

Why? That's the filename of the keyring dir.

> adding new keys, etc.

Some of this could be done by link and rename.

> On key handles there would be IOCTLs for deleting the key,

unlink.

> revoking access, etc.

> We'd also need a few syscalls for creating new key-rings.

mkdir would be nice, but the key manager supplies the ID.


I think I'd make the filesystem look like:

/proc/keys/
types
keys/
<keyID>
<keyringID>/
<keyID>
<keyringID> => ../<keyringID> [symlink]
<keyID>
<keyID> [hardlink to keyID]
<keyringID>/
<keyID>
<keyID>
<keyringID>/
<keyringID>/
<keyID>


Each key would then have a UID, GID and umask which behave like for normal
files. Reading key files would then get you a summary of the key contents and
state. getxattr could be used also. The payload would only be accessible
through getxattr.

I might even permit the use of link() and rename(), provided the keys
filenames stay the same, and unlink().

However, I think I'd prefer to extend the syscall interface some more.

I've got four prctls:

(*) Get process subscribed keyring ID (choose which of the five).

(*) Clear process subscribed keyring ID (choose which of the five).

(*) Request new session keyring for this process.

(*) Add key to process subscribed keyring ID (choose which of the five).

I could then add some more syscalls:

(*) Add key to arbitrary keyring.

(*) Update key.

(*) Retire key.

(*) Get list of key IDs from keyring.

(*) Get type of key.

(*) Get description of key.

(*) Get payload of key.

(*) Link key to keyring.

(*) Unlink key from keyring.

All but the first two are trivially easy to do with a keyfs using standard
operations.

David

2004-06-17 19:07:29

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 17, 2004, at 07:48, David Howells wrote:
> The main reason that there are attachment points for keyrings on UIDs,
> processes, etc, is that there needs to be some way for things like
> open() to
> find them without adding an equivalent syscalls that take a key as
> well.
>
> In a way, you could look at it as these attachment points are like the
> PATH
> variable - they describe a search path. You still need one of those.
>
> LSM modules can always create keyrings and subscribe one of the five
> keyrings
> a task has to them so that they become accessible.

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

> It supports nested keyrings - up to a certain depth anyway - and when
> you add
> one keyring into another it checks to see you're not trying to create
> a cycle
> (at least, you can from the kernel... you can't from userspace yet).

Ahh, that's basically what I was thinking about, I must have missed it
in your patch.

> I'm not keen on the "parent" idea. I'm not sure what you are thinking
> of
> exactly - a keyring can have multiple parents, and also this sounds
> like it
> may cause a cycle.

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

> Using LSM hooks could represent a chicken vs egg scenario if you want
> to use
> these keys to represent LSM security data (which you might reasonably
> want to
> do).

It just means that LSM modules that want to use keys to hold LSM
security data
must be careful about their access to key-ring FS objects. Besides,
there's no
requirements that LSM use the user-space interfaces, we'd probably need
a
set of kernel-space functions that could ignore the access check if
requested,
and most LSM modules would just use unreadable/unwritable/unusable keys
and ignore the access checks.

> It could be made such that arbitrary keys can be stored there (just
> another
> keytype)... it's just that the keys eat into the kernel low memory
> region. It
> may be better to permit such keys to be stored in highmem or swap
> somehow.

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.

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

> Keys have a serial number, a type, a description and a payload.
> Currently the
> types can't be arbitrary - a kernel driver or whatever must have
> registered
> that type for it to be used. If that driver unregisters its key type,
> all keys
> of that type are immediately withdrawn.

Are the serial numbers unique within a key-ring or within the entire
subsystem?
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.

> For instance, my kafs module registers an "afs" key type in which it
> can store
> a Krb5 ticket. Having a type management system like this allows the
> type to
> have operations to validate, match and pretty-print key descriptions.
> The
> first one is the most important, I feel, because we can validate a key
> upon
> addition.

Kernel-registered key-types should definitely be validated by the
kernel.

> It might be possible to make this more flexible. Have userspace upload
> a
> "potential" key with arbitrary type, description and payload; and then
> have,
> say, a kafs's file open routine locate a candidate key and render it
> into
> parsed key form. Hmmm...

User-space should be required to parse the key as much as possible, so
that we can keep clutter out of kernel-space. But it's not an issue if
all AFS
ever does with the key is just perform mathematical operations on it and
it happens to be corrupted, as long as it doesn't break the kernel. If
we
allow user-space key-type allocations then we should allow arbitrary
data
to be stored there, up to quota.

> One thing I want to avoid is having to have the filesystem (or
> whatever)
> validate the key every time it looks at it.

No kidding. Once it's added (And validated if needed), we only need to
check it again if it's modified.

> In this example, you might have something like:
>
> type krbtgt
> desc [email protected]
>
> Or:
>
> type user
> desc krbtgt/[email protected]
>
> But you'd have to provide the kernel with a type registration for the
> key type
> in question.

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/[email protected]"

>> Hmm, so going along with these ideas, how about this?
>> /proc/keyring/
>> MODE = 555
>> DESC = keyringfs, contains keyring metadata
> I presume you mean keyringfs or keyfs mounted on /proc/keyring/ (or
> /proc/keys/).
Of course

>> <id>/
>> MODE = Access control for entire keyring
>> DESC = A keyring entry, referenced by number
>> opendir = Increments the ref count to make sure it won't go away.
>>
>> parent => ../<id>
>> DESC = A symlink or hardlink to the parent keyring
>>
>> <typeid>/
>> MODE = 555
>> DESC = A numerical "key-type" (KEYTYPE_KRB5)
>>
>> <service>
>> MODE = Access control for a single key
>> DESC = The key, accessed as a file.
>>
>> <typename> => <typeid>/
>> DESC = A symlink or hardlink to a type number from
>> a type name. These types could be registered
>> by modules that implement them.
>>
>> There would be IOCTLs on the key-ring dir handles for getting the
>> key-ring
>> number
> Why? That's the filename of the keyring dir.
If you were passed a key-ring handle and told to do something with it,
how
would you find out what number the keyring is?

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

>> On key handles there would be IOCTLs for deleting the key,
> unlink.
Duh, I feel stupid now.

>> revoking access, etc.
>
>> We'd also need a few syscalls for creating new key-rings.
>
> 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.

> I think I'd make the filesystem look like:
>
> /proc/keys/
> types
> keys/
> <keyID>
> <keyringID>/
> <keyID>
> <keyringID> => ../<keyringID> [symlink]
> <keyID>
> <keyID> [hardlink to keyID]
> <keyringID>/
> <keyID>
> <keyID>
> <keyringID>/
> <keyringID>/
> <keyID>

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

> Each key would then have a UID, GID and umask which behave like for
> normal
> files. Reading key files would then get you a summary of the key
> contents and
> state. getxattr could be used also. The payload would only be
> accessible
> through getxattr.

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:
"123" => summary of key, from kernel handler
"123-raw" => raw binary data of key, if accessible
User-mode key-types wouldn't have kernel functions, and so would only
have a
"123-raw" file.

> I might even permit the use of link() and rename(), provided the keys
> filenames stay the same, and unlink().
What if we have:
<keyring-id>/
0/ => These are sub-key-rings (type=0,desc=<key-ring ID string>)
<keyring-no>
<keyring-no>
<key-type>/
<key-desc>
<key-type>_raw/
<key-desc>
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. If it's a primary key-ring entry then we just remove it
from the
visible database but not from anything that references it (Like
unlink() on an
open file).

> However, I think I'd prefer to extend the syscall interface some more.
> I've got four prctls:
>
> (*) Get process subscribed keyring ID (choose which of the five).
>
> (*) Clear process subscribed keyring ID (choose which of the five).
>
> (*) Request new session keyring for this process.
>
> (*) Add key to process subscribed keyring ID (choose which of the
> five).
>
> I could then add some more syscalls:
>
> (*) Add key to arbitrary keyring.
>
> (*) Update key.
>
> (*) Retire key.
>
> (*) Get list of key IDs from keyring.
>
> (*) Get type of key.
>
> (*) Get description of key.
>
> (*) Get payload of key.
>
> (*) Link key to keyring.
>
> (*) Unlink key from keyring.
>
> All but the first two are trivially easy to do with a keyfs using
> standard
> operations.

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.

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.

Cheers,
Kyle Moffett

2004-06-23 12:30:36

by David Howells

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)


Kyle Moffett <[email protected]> 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/[email protected]"

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

2004-06-23 21:03:26

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

On Jun 23, 2004, at 08:29, David Howells wrote:
> Kyle Moffett <[email protected]> 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/[email protected]"
>
> 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

2004-06-29 17:08:55

by Kyle Moffett

[permalink] [raw]
Subject: Re: In-kernel Authentication Tokens (PAGs)

Ok, I have some free time this week to code up a patch. To start with
everything
will rely on being in process context just to make things simple.
Here's a short
summary of everything we've agreed upon so far:

1) A key-ring is an object independent of what uses it. It supports
operations
to read, modify, and search it.

2) When a key-ring is searched for a particular key by name and type,
first
it checks all keys of the specified type within said key-ring. If it
does not find it
there, then it proceeds with all sub-key-rings.

3) Keys and key-rings are allocated and referenced through an
independent
number space (Somewhat like the PID allocator)

4) Key and key-ring access should be controlled using permissions and
POSIX ACLs as though they were files. In this case, however, the
"execute"
permission bit is used to control in-kernel operations on the keys (EX:
AES
encrypting a block of data using CryptoAPI without being able to read
the key.

5) Key-rings should be automatically associated with the following
things.
This is also the search order when looking for a key.
Thread
Process
Process Group
Session
User
Group

6) User process with the appropriate privileges (Perhaps a new
capability
CAP_LINUX_KEYS or something) can modify/search/link/whatever any/all
keyrings. (I'm still not quite sure how much should be allowed.)

7) All algorithms working with keys and keyrings should be iterative,
not
recursive, and should be run it process context.

8) Graphs of nested key-rings must be non-circular.

9) All memory allocated for key-rings and keys should be counted from
various limits associated with users/processes/etc.

10) All kernel key-types should begin with a "+" character, and
user-space
cannot use an unregistered key-type that begins with a "+" character.
(This
means that all keys having a key-type beginning with a "+" character
have
been validated by kernel code.

11) A key-ring filesystem should be mounted on /proc/keys:
types
keys/
<keyID>/
control
type
description
state
<keyringID>/
control
type
description
state
<keyID> => ../<keyID> [symlink]

12) It should be impossible to look up keys by number unless said key
filesystem is mounted. The "control" entries in the key filesystem can
be
open()ed to get the kind of file handle that KETCTL manipulates.

13) A new syscall "keyctl":

KEYCTL_NEW_RING: Creates a new key-ring and returns its fd
Returns: int filedesc
Params:
char *desc
int *subkeys
long subkey_count

KEYCTL_NEW_KEY: Creates a new key and returns its fd
Returns: int filedesc
Params:
char *type
char *desc
void *data

KEYCTL_SHLOCK
KEYCTL_EXLOCK
KEYCTL_UNLOCK: A mandatory lock on the key/key-ring
Returns: int error
Params:
int filedesc
int flags

KEYCTL_TYPE: Retrieves the "type" field
Returns: long bytes_left
Params:
char *desc
long size

KEYCTL_DESC: Retrieves the "desc" field
Returns: long bytes_left
Params:
char *desc
long size

KEYCTL_READ: Retrieves the "data" field
Returns: long bytes_left
Params:
char *data
long size

KEYCTL_WRITE: Modifies the "data" field
Returns: int error
Params:
char *data
long size

KEYCTL_GET: Retrieves the current key fd
Returns: int filedesc
Params:
int type
KEY_THREAD
KEY_PROCESS
KEY_PGROUP
KEY_SESSION
KEY_USER
KEY_GROUP

KEYCTL_SET: Modifies the current key fd
Returns: int error
Params:
int type
<See above KEYCTL_GET_KEY>
int filedesc

KEYCTL_ENUM: Enumerates through all keys. NOTE: This must only be
called with a KEYCTL_SHLOCK, otherwise it might skip keys or repeat
keys.
Returns: int error
Params:
int keyring_fd
int *key_fd

KEYCTL_LOOKUP: Look for a key by type, but don't recurse
Returns: int filedesc

KEYCTL_SEARCH: Searches for a specific key by type
Returns: int filedesc
Params:
char *type
char *desc

KEYCTL_ADD: Adds a key to a key-ring
Returns: int error
Params:
int keyring_fd
int key_fd

KEYCTL_REMOVE: Removes a key from a key-ring
Returns: int error
Params:
int keyring_fd
int key_fd

KEYCTL_CLEAR: Removes all keys from a key-ring
Returns: int error
Params:
int keyring_fd

KEYCTL_REVOKE: Revokes a specific key file descriptor and any key
file descriptors it spawned. This should even apply to keyrings!
Returns: int error
Params:
int filedesc


I think that's just about everything. Let me know if I got something
wrong
or have another problem with the above.

Cheers,
Kyle Moffett