Re: [PATCH] in-core AFS multiplexor and PAG support

David Howells
2003-05-13T17:30:19Z

Linux Torvalds wrote:
> I htink the table-driven approach is just generally pretty nasty, even if
> it's clever and concise. I personally prefer a table of function pointers
> over a table of constraints.

I assume you're talking about the AFS mux. I'm dropping that for the moment as
it's provoking a touch of dissatisfaction.

> The Linux way of doing things is to have a per-object "operations
> structure", which is not an anonymous table (array of identical entries),

I'd prefer to add a pioctl method to inode_operations, but I don't think Al
Viro would go for it.

I'd also like to totally redefine the AFS syscall interface (which is _very_
messy as you can see), but that would involve changing both OpenAFS and Arla
userpsaces as well... Oh well, I'll save the flamebait for another day
(wouldn't want Christoph to get bored now:-).

> > Maybe... There are arguments either way, but if the token ring is kept in
> > struct user, a task can't detach from it and pass a token-less set of keys
> > onto another process it wants to run.
>
> Oh, but it can.

Your suggesting having multiple user structs with the same UID?

> The pointer should be kept at two places: the "struct task_struct" contains
> the initial pre-process value, and at file open time that pointer should get
> copied (and the user count incremented) and put into the "struct file".

The pointer to what? The user struct? I've put a pointer to the PAG struct in
the task_struct, and a pointer to the particular token governing that file
access point in struct file. I did this because I don't want to have to search
the token ring every time readpage is called for instance.

> So you can pass the set of keys the way UNIX _always_ passes rights -
> through the file descriptor.

Surely you'd only want the minimum set of credentials (preferably a single
token) attached to the file descriptor rather than the whole ring to avoid
having to needlessly repeat searches.

> > Also, using a separate PAG structure means that you can lend your keys to
> > an SUID program and conversely it means a SUID program can't so easily
> > gain access to keys it didn't inherit from its caller.
>
> "task->user" always follows uid ("real uid"), and as such you can always
> switch back and forth by just changing uid.

So anyone who has the ability to get root on a box can immediately use other
peoples keys with su... OTOH, the ability to get root would normally permit
someone sufficiently motivated to get this anyway.

> The advantage of associating the PAG with the real uid rather than make it
> per-process is that it's a lot easier to administer that way, I think. You
> don't need to log out or anything like that to have changes take effect
> for your session, and it is very natural to say "this user now gets key
> X". Which is what I think you really want when you do something like enter
> a key to an encrypted filesystem, for example.

It's not per-process. If a process calls setpag(-1) to create a new PAG (the
sort of thing PAM would do for login), then all processes that it creates and
their children, and their children's children, etc. would share in that PAG
unless they themselves called setpag() to leave it.

So you wouldn't have to log out for an additional token to take effect.

Normally a PAG would be coincident with a login session. It might be worth
making SUID programs automatically invest in an empty PAG, but with a way to
revert to the original PAG.

> Put another way: you'd usually add the PAG's at filesystem _mount_ time,
> no? And at that point you'd usually want to add it "retroactively" to the
> session processes that caused the mount to happen, no? Not just to the
> children of the mount.

You'd want to be able to do it before, during and/or after. PAGs permit this.

I have a further suggestion for some new system calls specifically for
managing tokens. I'd like to add the following:

(1) settok(const char *fs, const char *key, size_t size, const void *data)

Present data to the named filesystem as being the authentication token
for the specified key (eg: an AFS cell). If accepted, this token should
be stored in the PAG to which the calling process belongs.

(2) gettok(const char *fs, const char *key, size_t size, void *buffer)

Get a copy of an authentication token.

(3) deltok(const char *fs, const char *key)

Delete an authentication token.

(4) cleartoks(const char *fs)

Clear all the tokens belonging to a particular filesystem.

These would work by calling operations in struct file_system_type for (1) at
least and either doing that for (2) - (4) or by dealing with the PAG (or
whatever) directly.

David