Skip to contentSkip to conversation

in-core AFS multiplexor and PAG support

PATCH In review David Howells 14 participants 30 messages May 13, 2003 – May 18, 2003

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 in-core AFS multiplexor and PAG support

Hi Linus,

Here's a patch to add three things that are required for AFS and that may be of use to other stuff (such as NFSv4 and Samba):

(1) PAG (Process Authentication Group) support. A PAG is ID'd by a unique number, and is represented in memory as a structure that has a ring of associated authentication tokens.

Each process can either be part of a PAG, or it can PAG-less - in which case it has no authentication tokens.

Two new syscalls are added: setpag and getpag.

(2) Authentication token support. An authentication token is a blob of binary data that is keyed by filesystem name and fs-specific key (such as AFS cell name or SMB workgroup).

These are retained in two places: each PAG has a ring of tokens appropriate to the group of processes within that PAG; and each struct file has a pointer to the single token governing that file (if there is one).

(3) AFS multiplexor support. Not complete at the moment, but implemented far enough to provide access to the PAG mechanism. Further patches will be forthcoming to make this fully functional.

It is my intention to add Trond's vfs_cred stuff in at some point, but that has a lot greater impact than this patch (which has negligible impact).

David

arch/i386/kernel/entry.S +3 -2
diff -uNr linux-2.5.69/arch/i386/kernel/entry.S linux-2.5.69-cred/arch/i386/kernel/entry.S
@@ -721,7 +721,7 @@
 	.long sys_bdflush
 	.long sys_sysfs		/* 135 */
 	.long sys_personality
-	.long sys_ni_syscall	/* reserved for afs_syscall */
+	.long sys_afs
 	.long sys_setfsuid16
 	.long sys_setfsgid16
 	.long sys_llseek	/* 140 */
@@ -852,6 +852,7 @@
  	.long sys_clock_gettime		/* 265 */
  	.long sys_clock_getres
  	.long sys_clock_nanosleep
- 
+	.long sys_setpag
+	.long sys_getpag
  
 nr_syscalls=(.-sys_call_table)/4
fs/afssyscall.c +223 -0

223 lines not on this page · raw message

fs/file_table.c +1 -0
diff -uNr linux-2.5.69/fs/file_table.c linux-2.5.69-cred/fs/file_table.c
@@ -166,6 +166,7 @@
 	if (file->f_op && file->f_op->release)
 		file->f_op->release(inode, file);
 	security_file_free(file);
+	if (file->f_token) vfs_token_put(file->f_token);
 	fops_put(file->f_op);
 	if (file->f_mode & FMODE_WRITE)
 		put_write_access(inode);
fs/Makefile +2 -1
diff -uNr linux-2.5.69/fs/Makefile linux-2.5.69-cred/fs/Makefile
@@ -10,7 +10,8 @@
 		namei.o fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
 		dcache.o inode.o attr.o bad_inode.o file.o dnotify.o \
 		filesystems.o namespace.o seq_file.o xattr.o libfs.o \
-		fs-writeback.o mpage.o direct-io.o aio.o eventpoll.o
+		fs-writeback.o mpage.o direct-io.o aio.o eventpoll.o \
+		afssyscall.o
 
 obj-$(CONFIG_COMPAT) += compat.o
 
fs/open.c +1 -1
diff -uNr linux-2.5.69/fs/open.c linux-2.5.69-cred/fs/open.c
@@ -46,7 +46,7 @@
 	struct nameidata nd;
 	int error;
 
-	error = user_path_walk(path, &nd);
+	error = user_path_walk(path,&nd);
 	if (!error) {
 		struct statfs tmp;
 		error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp);
fs/proc/array.c +2 -1
diff -uNr linux-2.5.69/fs/proc/array.c linux-2.5.69-cred/fs/proc/array.c
@@ -154,13 +154,14 @@
 	read_lock(&tasklist_lock);
 	buffer += sprintf(buffer,
 		"State:\t%s\n"
+		"Pag:\t%d\n"
 		"Tgid:\t%d\n"
 		"Pid:\t%d\n"
 		"PPid:\t%d\n"
 		"TracerPid:\t%d\n"
 		"Uid:\t%d\t%d\t%d\t%d\n"
 		"Gid:\t%d\t%d\t%d\t%d\n",
-		get_task_state(p), p->tgid,
+		get_task_state(p), p->vfspag ? p->vfspag->pag : 0, p->tgid,
 		p->pid, p->pid ? p->real_parent->pid : 0,
 		p->pid && p->ptrace ? p->parent->pid : 0,
 		p->uid, p->euid, p->suid, p->fsuid,
include/asm-i386/posix_types.h +1 -0
diff -uNr linux-2.5.69/include/asm-i386/posix_types.h linux-2.5.69-cred/include/asm-i386/posix_types.h
@@ -13,6 +13,7 @@
 typedef unsigned short	__kernel_nlink_t;
 typedef long		__kernel_off_t;
 typedef int		__kernel_pid_t;
+typedef int		__kernel_pag_t;
 typedef unsigned short	__kernel_ipc_pid_t;
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
include/asm-i386/unistd.h +3 -1
diff -uNr linux-2.5.69/include/asm-i386/unistd.h linux-2.5.69-cred/include/asm-i386/unistd.h
@@ -273,8 +273,10 @@
 #define __NR_clock_gettime	(__NR_timer_create+6)
 #define __NR_clock_getres	(__NR_timer_create+7)
 #define __NR_clock_nanosleep	(__NR_timer_create+8)
+#define __NR_setpag		268
+#define __NR_getpag		269
 
-#define NR_syscalls 268
+#define NR_syscalls 270
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
include/linux/afs_syscall.h +159 -0

159 lines not on this page · raw message

include/linux/cred.h +79 -0

79 lines not on this page · raw message

include/linux/fs.h +1 -0
diff -uNr linux-2.5.69/include/linux/fs.h linux-2.5.69-cred/include/linux/fs.h
@@ -430,6 +430,7 @@
 	mode_t			f_mode;
 	loff_t			f_pos;
 	struct fown_struct	f_owner;
+	struct vfs_token	*f_token;	/* governing credential */
 	unsigned int		f_uid, f_gid;
 	int			f_error;
 	struct file_ra_state	f_ra;
include/linux/sched.h +2 -0
diff -uNr linux-2.5.69/include/linux/sched.h linux-2.5.69-cred/include/linux/sched.h
@@ -28,6 +28,7 @@
 #include <linux/completion.h>
 #include <linux/pid.h>
 #include <linux/percpu.h>
+#include <linux/cred.h>
 
 struct exec_domain;
 
@@ -387,6 +388,7 @@
 	gid_t gid,egid,sgid,fsgid;
 	int ngroups;
 	gid_t	groups[NGROUPS];
+	struct vfs_pag *vfspag;
 	kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
 	int keep_capabilities:1;
 	struct user_struct *user;
include/linux/types.h +1 -0
diff -uNr linux-2.5.69/include/linux/types.h linux-2.5.69-cred/include/linux/types.h
@@ -24,6 +24,7 @@
 typedef __kernel_nlink_t	nlink_t;
 typedef __kernel_off_t		off_t;
 typedef __kernel_pid_t		pid_t;
+typedef __kernel_pag_t		pag_t;
 typedef __kernel_daddr_t	daddr_t;
 typedef __kernel_key_t		key_t;
 typedef __kernel_suseconds_t	suseconds_t;
init/main.c +2 -0
diff -uNr linux-2.5.69/init/main.c linux-2.5.69-cred/init/main.c
@@ -80,6 +80,7 @@
 extern void pidhash_init(void);
 extern void pidmap_init(void);
 extern void pte_chain_init(void);
+extern void credentials_init(void);
 extern void radix_tree_init(void);
 extern void free_initmem(void);
 extern void populate_rootfs(void);
@@ -434,6 +435,7 @@
 	pidmap_init();
 	pgtable_cache_init();
 	pte_chain_init();
+	credentials_init();
 	fork_init(num_physpages);
 	proc_caches_init();
 	security_scaffolding_startup();
kernel/cred.c +367 -0

367 lines not on this page · raw message

kernel/fork.c +3 -0
diff -uNr linux-2.5.69/kernel/fork.c linux-2.5.69-cred/kernel/fork.c
@@ -884,6 +884,9 @@
 
 	if (clone_flags & CLONE_CHILD_SETTID)
 		p->set_child_tid = child_tidptr;
+
+	if (p->vfspag) vfs_pag_get(p->vfspag);
+
 	/*
 	 * Clear TID on mm_release()?
 	 */
kernel/Makefile +1 -1
diff -uNr linux-2.5.69/kernel/Makefile linux-2.5.69-cred/kernel/Makefile
@@ -3,7 +3,7 @@
 #
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
-	    exit.o itimer.o time.o softirq.o resource.o \
+	    cred.o exit.o itimer.o time.o softirq.o resource.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o futex.o pid.o \
 	    rcupdate.o intermodule.o extable.o params.o posix-timers.o
#1 lore raw
Quoted 9 lines · David Howells

(1) PAG (Process Authentication Group) support. A PAG is ID'd by a unique number, and is represented in memory as a structure that has a ring of associated authentication tokens.

Each process can either be part of a PAG, or it can PAG-less - in which case it has no authentication tokens.

Two new syscalls are added: setpag and getpag.

I think the code looks pretty horrible, but I think we'll need something like this to keep track of keys. However, I'm not sure we should make this a new structure - I think we should make the current "tsk->user" thing _be_ the "PAG".

Linus

#2 lore raw
Quoted 4 lines · Linus Torvalds

I think the code looks pretty horrible, but I think we'll need something like this to keep track of keys. However, I'm not sure we should make this a new structure - I think we should make the current "tsk->user" thing _be_ the "PAG".

With something like SELinux a PAG may belong to a role not to a user even though other limits like processes probably belong to the user as a whole.

How does AFS currently handle this, can two logins of the same user have seperate PAGs ?

#3 lore raw
Quoted 6 lines · Alan Cox
Quoted 4 lines · Linus Torvalds

I think the code looks pretty horrible, but I think we'll need something like this to keep track of keys. However, I'm not sure we should make this a new structure - I think we should make the current "tsk->user" thing _be_ the "PAG".

Quoted 6 lines

With something like SELinux a PAG may belong to a role not to a user even though other limits like processes probably belong to the user as a whole.

How does AFS currently handle this, can two logins of the same user have seperate PAGs ?

Yes, easily and it is useful.

I can start an xterm a new PAG that has administrative rights. Or various system daemons all running with uid 0, but with different access rights (sendmail/webserver).

It also goes the other way around, different uid's using the same PAG, if I run a setuid application it can still access my files.

Jan

#4 lore raw
In reply to Alan Cox
Quoted 4 lines · Alan Cox

With something like SELinux a PAG may belong to a role not to a user even though other limits like processes probably belong to the user as a whole.

Hmm.. That doesn't make a lot of sense to me.

A "user" is by definition what the unix filesystem considers to be the "atom of security". In fact, a "user" has no other meaning - except for the notion of "root", which is obviously special and has meaning outside of the scope of filesystems (and even here capabilities have tried to separate out that meaning from the "user" definition).

But if we want to split up users into "roles", then sure, we can have a "role" that is shared across processes. But I think that for _usability_ we really want that to be _shared_ by default, and anybody who wants to split it should have to work at it. Exactly so that when you log in, and use your private key to mount some encrypted volume, _all_ your processes should by default get access to it. Even if the other ones were independent logins (another window with another ssh session to that machine).

In other words: I really think usability should count very high on the list of requirements. Much higher than SELinux.

Linus

#5 lore raw
Quoted 5 lines · Linus Torvalds

A "user" is by definition what the unix filesystem considers to be the "atom of security". In fact, a "user" has no other meaning - except for the notion of "root", which is obviously special and has meaning outside of the scope of filesystems (and even here capabilities have tried to separate out that meaning from the "user" definition).

This has been untrue since the security hooks went in, and in some senses before that (capabilities mean multiple "root"'s)

Quoted 10 lines

"role" that is shared across processes. But I think that for _usability_ we really want that to be _shared_ by default, and anybody who wants to split it should have to work at it. Exactly so that when you log in, and use your private key to mount some encrypted volume, _all_ your processes should by default get access to it. Even if the other ones were independent logins (another window with another ssh session to that machine).

In other words: I really think usability should count very high on the list of requirements. Much higher than SELinux.

Sounds right. PAM can certainly do the splitting providing the functionality is there to do it

#6 lore raw
In reply to Alan Cox
Quoted 2 lines · Alan Cox

How does AFS currently handle this, can two logins of the same user have seperate PAGs ?

Yes. In fact, that's the default situation and it requires some work to get two logins of the same user into the same PAG.

AFS currently handles PAGs by creating "random" high-numbered groups and putting the user into them, and then associating the token with that group in the kernel.

One could debate whether it's best to put a user into the same PAG as their other logins by default, but it's imperative that a user be able to create a separate PAG when they wish to (so, for example, they can acquire separate credentials in that new PAG without affecting the credentials and PAG for their other running processes).

Signature · 1 line
Russ Allbery ([email protected])             <http://www.eyrie.org/~eagle/>
#7 lore raw
In reply to Alan Cox
Quoted 2 lines · Alan Cox

How does AFS currently handle this, can two logins of the same user have seperate PAGs ?

Yes. Indeed, individual logins usually DO have separate PAGs (as the login program runs setpag() to create a new pag). Moreover, there is a program called "pagsh" which allows a user to create a shell in a new PAG -- allowing multiple PAGs even in one login session for a single "user".

-derek

Signature · 4 lines
       Derek Atkins, SB '93 MIT EE, SM '95 MIT Media Laboratory
       Member, MIT Student Information Processing Board  (SIPB)
       URL: http://web.mit.edu/warlord/    PP-ASEL-IA     N1NWH
       [email protected]                        PGP key available
#8 lore raw
In reply to Linus Torvalds
Quoted 6 lines · Linus Torvalds
Quoted 5 lines · David Howells

(1) PAG (Process Authentication Group) support. A PAG is ID'd by a unique number, and is represented in memory as a structure that has a ring of associated authentication tokens.

Quoted 6 lines
Quoted 4 lines

Each process can either be part of a PAG, or it can PAG-less - in which case it has no authentication tokens.

Two new syscalls are added: setpag and getpag.

I think the code looks pretty horrible,

Any particular bits?

Quoted 3 lines

but I think we'll need something like this to keep track of keys. However, I'm not sure we should make this a new structure - I think we should make the current "tsk->user" thing _be_ the "PAG".

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.

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.

I'm not sure that the ability to arbitrarily join a PAG should be permitted, but it was requested.

David

#9 lore raw
Quoted 3 lines · David Howells

I'm not sure that the ability to arbitrarily join a PAG should be permitted, but it was requested.

This was a very handy feature which could be used with DCE/DFS. It is especially nice if the cost of obtaining credentials is high, vs the amount of processing being done, for example if the user is running a script, and doing multiple kerberos rsh commands to a host, if the rshd could join a PAG, it would not need to received delegated credentials for each connection, as it could use the credentials that where delegated earlier.

It could can also be used as a way to refresh credentials.

Quoted 6 lines

David
_______________________________________________
OpenAFS-devel mailing list
[email protected]
https://lists.openafs.org/mailman/listinfo/openafs-devel

Signature · 5 lines
 Douglas E. Engert  <[email protected]>
 Argonne National Laboratory
 9700 South Cass Avenue
 Argonne, Illinois  60439 
 (630) 252-5444
#10 lore raw
In reply to David Howells
Quoted 4 lines · David Howells
Quoted 2 lines

I think the code looks pretty horrible,

Any particular bits?

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.

Right now you have one table of constraints, and then later on when you actually implement the code that _does_ anything, you'll end up having another table (or switch statment) per filesystem of actual actions. And neither with any kind of compile-time type checking, since the actual interfaces to pass stuff around are just extended ioctls.

The Linux way of doing things is to have a per-object "operations structure", which is not an anonymous table (array of identical entries), but a list of unique entries (a structure of strongly typed function pointers). And then you never de-multiplex (which inherently loses type information), or you at least do it only _once_ and make sure that you stronly type things at that point so that any downstream stuff is typed.

Quoted 3 lines

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

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

Quoted 3 lines

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.

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.

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.

Linus

#11 lore raw
Quoted 11 lines · Linus Torvalds
Quoted 3 lines

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

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

Right, if some process/user opens a file and then passes the descriptor to another process/user which closes it. The close should operate under the same permissions as the original opener.

Simple example when this happens is when a setuid application is started and the stdout/stderr is redirected to a file. 'ping foo >out 2>&1'. The shell opens the file under my uid, but the setuid application closes it under the new uid.

Quoted 6 lines

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.

The local user id is not a 'trusted' identity for a distributed filesystem. Any user still have to prove his identity by obtaining tokens.

If someone obtains my user id on in any way (i.e. weak password/ bufferoverflow/ root exploit), he should not be allowed to use or access my tokens as he hasn't proven his identity. In this case he would either still be in his original process authentication group, or a new and empty PAG. But definitely not in any of my authentication groups.

Which is also why joining a PAG should never be allowed.

Any arguments about 'it avoids the cost of obtaining credentials' are stupid because that cost is exactly what it takes to prove that a new session is in fact associated with a specific user. If our identity already was proven beyond reasonable doubt, we clearly already have our 'token' and the additional cost to associate this with the new PAG is zero.

Jan

#12 lore raw
Quoted 4 lines

Right, if some process/user opens a file and then passes the descriptor to another process/user which closes it. The close should operate under the same permissions as the original opener.

As long as the token isn't explicitly withdrawn. With my token structure, I've defined it such that if the list_head in the token struct is ever empty, then the token is withdrawn.

Furthermore, I'm considering it such that the the filesystem will select a token from the PAG's token ring in the file_operations->open method and will attach it to the file->f_token at that point for quick reference later.

Quoted 7 lines

If someone obtains my user id on in any way (i.e. weak password/ bufferoverflow/ root exploit), he should not be allowed to use or access my tokens as he hasn't proven his identity. In this case he would either still be in his original process authentication group, or a new and empty PAG. But definitely not in any of my authentication groups.

Which is also why joining a PAG should never be allowed.

Someone asked for it, but I suspect if allowed at all it may be best that this ability is governed by its own capability bit and also that the security interface should be consulted.

David

#13 lore raw
In reply to Jan Harkes
Quoted 11 lines · Jan Harkes

The local user id is not a 'trusted' identity for a distributed filesystem. Any user still have to prove his identity by obtaining tokens.

If someone obtains my user id on in any way (i.e. weak password/ bufferoverflow/ root exploit), he should not be allowed to use or access my tokens as he hasn't proven his identity. In this case he would either still be in his original process authentication group, or a new and empty PAG. But definitely not in any of my authentication groups.

Which is also why joining a PAG should never be allowed.

Joining a PAG can be allowed, if the connecting process can prove its identify to the owner of the PAG. This does not imply that using a weak password gets you access to a PAG that was instituted via some more secure method.
In the example I used of Kerberized rsh, the rshd running as root, would only allow a second connection to join the PAG if the second connection was also authenticated via the same Kerberos user.

Quoted 4 lines

Any arguments about 'it avoids the cost of obtaining credentials' are stupid because that cost is exactly what it takes to prove that a new session is in fact associated with a specific user.

No that is not true. In a Kerberos example, the client needs a service ticket, to prove its identity to the server, and then it delegates a forwardable TGT to the server so the server can act on behalf of the user. The server can then use the forwarded TGT to obtain additional tickets for AFS for example.

Since each invocation of the server would be placed into its own PAG, (sort of by definition of a PAG) then each invocation of the server would have to get a new AFS token.

What I am looking for is that the server can verify the identity, of the client, then use previously forwarded credentials, such as a TGT or AFS token, so it does not have to get a new token., i.e. it joins the existing PAG.

Note that the ability to join a PAG requires root access to place the new process in the existing PAG. A user process can not on its own join a PAG.

Quoted 1 line

If our identity already was proven beyond reasonable doubt,

Maybe to the local system, but not to a third party.

Quoted 3 lines

we clearly already have our
'token' and the additional cost to associate this with the new PAG is zero.

I would say the "token" is in the PAG, so the new process would join the existing PAG. We may be saying the same thing, just describing how PAGs are used. Traditionally a PAG was created for a process and inherited by its children. I am saying root processes could add additional processes to the existing PAG, such as in the rshd example.

Quoted 7 lines

Jan

_______________________________________________
OpenAFS-devel mailing list
[email protected]
https://lists.openafs.org/mailman/listinfo/openafs-devel

Signature · 5 lines
 Douglas E. Engert  <[email protected]>
 Argonne National Laboratory
 9700 South Cass Avenue
 Argonne, Illinois  60439 
 (630) 252-5444
#14 lore raw
Quoted 3 lines · Douglas E. Engert
Quoted 2 lines · Jan Harkes

The local user id is not a 'trusted' identity for a distributed filesystem. Any user still have to prove his identity by obtaining tokens.

...

Quoted 9 lines
Quoted 1 line

Which is also why joining a PAG should never be allowed.

Joining a PAG can be allowed, if the connecting process can prove its identify to the owner of the PAG. This does not imply that using a weak password gets you access to a PAG that was instituted via some more secure method.
In the example I used of Kerberized rsh, the rshd running as root, would only allow a second connection to join the PAG if the second connection was also authenticated via the same Kerberos user.

The kernel doesn't know whether you got into the system using a kerberized rsh, ssh, telnet, or by a buffer-overflow.

The 'authenticated' user in fact already got his kerberos tokens on the system he is logging in from. The kerberized rshd simply adds the token used as authentication to the new session, if it is a TGT it can be used to obtain AFS and other credentials either from within the daemon or through commands in a .login script (using afslog or aklog or something).

Quoted 3 lines

Since each invocation of the server would be placed into its own PAG, (sort of by definition of a PAG) then each invocation of the server would have to get a new AFS token.

Which actually seems logical to me.

Quoted 3 lines

What I am looking for is that the server can verify the identity, of the client, then use previously forwarded credentials, such as a TGT or AFS token, so it does not have to get a new token., i.e. it joins the existing PAG.

You could have the kerberized rshd remember the tokens it obtained during a previous login or were forwarded by the client and associate them with the new PAG. No need to join an existing PAG.

What you propose has completely different behaviour depending on whether the user happens to have a secondary permanent connection to the target host or not. If there is no permanent session there will be no PAG to join and each rsh invocation will have to reauthenticate anyways.

Jan

#15 lore raw
Quoted 16 lines · Jan Harkes
Quoted 3 lines · Douglas E. Engert
Quoted 2 lines · Jan Harkes

The local user id is not a 'trusted' identity for a distributed filesystem. Any user still have to prove his identity by obtaining tokens.

...

Quoted 9 lines
Quoted 1 line

Which is also why joining a PAG should never be allowed.

Joining a PAG can be allowed, if the connecting process can prove its identify to the owner of the PAG. This does not imply that using a weak password gets you access to a PAG that was instituted via some more secure method.
In the example I used of Kerberized rsh, the rshd running as root, would only allow a second connection to join the PAG if the second connection was also authenticated via the same Kerberos user.

Quoted 2 lines

The kernel doesn't know whether you got into the system using a kerberized rsh, ssh, telnet, or by a buffer-overflow.

No, but the sshd, or rshd can look at the credentials and determine if you are establishing a new connection, and then let this process join the previous PAG, i.e. share the credentials if appropriate.

Quoted 6 lines

The 'authenticated' user in fact already got his kerberos tokens on the system he is logging in from. The kerberized rshd simply adds the token used as authentication to the new session, if it is a TGT it can be used to obtain AFS and other credentials either from within the daemon or through commands in a .login script (using afslog or aklog or something).

True but I am saying that you don't want to have to call aklog to get new AFS tokens for each connection, but would rather use the existing AFS token or credentials already present from the previous session.

When we did this back in 1997 we did this with the DFS PAG as the overhead of getting a DCE context could be quite large, requiring many tickets Here are some comments forom the k5dcecon.c program:

/*
* k5dcecon - Program to convert a K5 TGT to a DCE context,
* for use with DFS and its PAG.
*
* The program is designed to be called as a sub process,
* and return via stdout the name of the cache which implies
* the PAG which should be used. This program itself does not
* use the cache or PAG itself, so the PAG in the kernel for
* this program may not be set.
*
* The calling program can then use the name of the cache
* to set the KRB5CCNAME and PAG for its self and its children. *
* If no ticket was passed, an attemplt to join an existing
* PAG will be made.
*
* If a forwarded K5 TGT is passed in, either a new DCE
* context will be created, or an existing one will be updated.
* If the same ticket was already used to create an existing
* context, it will be joined instead.
*
* Parts of this program are based on k5dceauth,c which was
* given to me by HP and by the k5dcelogin.c which I developed.
* A slightly different version of k5dcelogin.c, was added to
* DCE 1.2.2
*
* D. E. Engert 6/17/97 ANL
*/

Quoted 7 lines
Quoted 4 lines

Since each invocation of the server would be placed into its own PAG, (sort of by definition of a PAG) then each invocation of the server would have to get a new AFS token.

Which actually seems logical to me.

Quoted 7 lines
Quoted 3 lines

What I am looking for is that the server can verify the identity, of the client, then use previously forwarded credentials, such as a TGT or AFS token, so it does not have to get a new token., i.e. it joins the existing PAG.

You could have the kerberized rshd remember the tokens it obtained during a previous login or were forwarded by the client and associate them with the new PAG. No need to join an existing PAG.

We maybe saying the same thing. I would say the PAG is where this information is stored. One may define the PAG as a kernel only concept which is destroyed when the last process ends, where I am also saying it includes cached credentials which may persist longer.

Quoted 5 lines

What you propose has completely different behaviour depending on whether the user happens to have a secondary permanent connection to the target host or not. If there is no permanent session there will be no PAG to join and each rsh invocation will have to reauthenticate anyways.

It is possible that the credential can be kept around for some time, as was the case with the k5dcecon, so previous credentials could be reused. In the case of the DCE, there where three files, one of which was the kerberos cache. The filenames has the PAG number as part of the file name.

The DFS cache manager process would assist the kernel in getting additional tickets and use these files.

This was not possible with AFS, since the AFS token was only in the kernel, and would be destroyed when the last process in the PAG finished. (To bad, as we have seen problems if a user saves a big file, then logs off, and the token is destroyed before the cache manager writes the file ac to the server.)

Quoted 2 lines

Jan

Signature · 5 lines
 Douglas E. Engert  <[email protected]>
 Argonne National Laboratory
 9700 South Cass Avenue
 Argonne, Illinois  60439 
 (630) 252-5444
#16 lore raw
Quoted 7 lines · Douglas E. Engert
Quoted 2 lines · Jan Harkes

The kernel doesn't know whether you got into the system using a kerberized rsh, ssh, telnet, or by a buffer-overflow.

No, but the sshd, or rshd can look at the credentials and determine if you are establishing a new connection, and then let this process join the previous PAG, i.e. share the credentials if appropriate.

PAG != tokens.

PAG is a simple unique session identifier. AFS, Coda and DCE/DFS happen associate credentials with a session.

But there is no reason why multiple PAG's can't map to the same set of credentials. You still don't 'join' a PAG, it is up to some filesystem specific policy how PAGs are mapped to credentials.

Quoted 8 lines
Quoted 3 lines

You could have the kerberized rshd remember the tokens it obtained during a previous login or were forwarded by the client and associate them with the new PAG. No need to join an existing PAG.

We maybe saying the same thing. I would say the PAG is where this information is stored. One may define the PAG as a kernel only concept which is destroyed when the last process ends, where I am also saying it includes cached credentials which may persist longer.

I think we are saying the same thing. But abstract at a different level.

Yes, a new session could use the same credentials as an existing session. But it is still a new session.

Quoted 9 lines
Quoted 4 lines

What you propose has completely different behaviour depending on whether the user happens to have a secondary permanent connection to the target host or not. If there is no permanent session there will be no PAG to join and each rsh invocation will have to reauthenticate anyways.

It is possible that the credential can be kept around for some time, as was the case with the k5dcecon, so previous credentials could be reused. In the case of the DCE, there where three files, one of which was the kerberos cache. The filenames has the PAG number as part of the file name.

How long should the credentials be kept around? The kernel doesn't know the difference between a Kerberos ticket, an AFS or Coda token, or a DCE security context. In my case only the Coda servers can reliably tell us whether the token is valid at all.

Quoted 5 lines

This was not possible with AFS, since the AFS token was only in the kernel, and would be destroyed when the last process in the PAG finished. (To bad, as we have seen problems if a user saves a big file, then logs off, and the token is destroyed before the cache manager writes the file ac to the server.)

That seems to be more an implementation issue, the token (or actually PAG) has to be associated with the open file handle. Logging out doesn't matter, except if the user explicitly flushes all tokens associated with his PAG.

Jan

#17 lore raw
Quoted 10 lines · Jan Harkes
Quoted 7 lines · Douglas E. Engert
Quoted 2 lines · Jan Harkes

The kernel doesn't know whether you got into the system using a kerberized rsh, ssh, telnet, or by a buffer-overflow.

No, but the sshd, or rshd can look at the credentials and determine if you are establishing a new connection, and then let this process join the previous PAG, i.e. share the credentials if appropriate.

Quoted 7 lines

PAG != tokens.

PAG is a simple unique session identifier. AFS, Coda and DCE/DFS happen associate credentials with a session.

But there is no reason why multiple PAG's can't map to the same set of credentials.

True. But traditionally with AFS or DCE at lest they have not. Each had its own set of credentials, and the PAG was only defined to allow the credentials to be shared.

Quoted 2 lines

You still don't 'join' a PAG, it is up to some filesystem specific policy how PAGs are mapped to credentials.

Not sure what you mean here, isn't it the other way around, the file system uses the credentials, which happen to belong to a PAG. In the past the credentials only belonged to one PAG, so "joining" was a way to use the same credentials.

Quoted 11 lines
Quoted 9 lines
Quoted 4 lines

You could have the kerberized rshd remember the tokens it obtained during a previous login or were forwarded by the client and associate them with the new PAG. No need to join an existing PAG.

We maybe saying the same thing. I would say the PAG is where this information is stored. One may define the PAG as a kernel only concept which is destroyed when the last process ends, where I am also saying it includes cached credentials which may persist longer.

I think we are saying the same thing. But abstract at a different level.

Yes I agree.

Quoted 14 lines

Yes, a new session could use the same credentials as an existing session. But it is still a new session.

Quoted 9 lines
Quoted 4 lines

What you propose has completely different behaviour depending on whether the user happens to have a secondary permanent connection to the target host or not. If there is no permanent session there will be no PAG to join and each rsh invocation will have to reauthenticate anyways.

It is possible that the credential can be kept around for some time, as was the case with the k5dcecon, so previous credentials could be reused. In the case of the DCE, there where three files, one of which was the kerberos cache. The filenames has the PAG number as part of the file name.

Quoted 4 lines

How long should the credentials be kept around? The kernel doesn't know the difference between a Kerberos ticket, an AFS or Coda token, or a DCE security context. In my case only the Coda servers can reliably tell us whether the token is valid at all.

How long? Not sure.

It comes down to what is a "session" A user may say "I will be contacting this system for the next four hour, so hold on to any credentials I send you now, even though I don't have an open connection or an active process." A user could do something similiar with a sshd and port forwarding, or a VPN, to keep a session running but they should not have to resort to these methods if possible.

Quoted 11 lines
Quoted 6 lines

This was not possible with AFS, since the AFS token was only in the kernel, and would be destroyed when the last process in the PAG finished. (To bad, as we have seen problems if a user saves a big file, then logs off, and the token is destroyed before the cache manager writes the file ac to the server.)

That seems to be more an implementation issue, the token (or actually PAG) has to be associated with the open file handle. Logging out doesn't matter, except if the user explicitly flushes all tokens associated with his PAG.

Yes its an implementation issue.

Quoted 2 lines

Jan

Signature · 5 lines
 Douglas E. Engert  <[email protected]>
 Argonne National Laboratory
 9700 South Cass Avenue
 Argonne, Illinois  60439 
 (630) 252-5444
#18 lore raw
Quoted 6 lines · Douglas E. Engert
Quoted 5 lines · Jan Harkes

PAG != tokens.

PAG is a simple unique session identifier. AFS, Coda and DCE/DFS happen associate credentials with a session.

Quoted 6 lines
Quoted 2 lines

But there is no reason why multiple PAG's can't map to the same set of credentials.

True. But traditionally with AFS or DCE at lest they have not. Each had its own set of credentials, and the PAG was only defined to allow the credentials to be shared.

Actually, the PAG was defined to temporarily disable membership in one or more groups. Every process would normally run in PAG 0, and the credentials were shared based on the uid. When a user wanted to 'restrict' rights he would initiate a new PAG which provided a more limited environment.

This is my interpretation of the AFS paper that documents the original security policies of AFS as it was initially deployed on November 11, 1986.

Integrating Security in a Large Distributed System (# 12) Satyanarayanan, M.
ACM Transactions on Computer Systems
Aug. 1989, Vol. 7, No. 3, pp. 247-280

http://www-2.cs.cmu.edu/afs/cs/project/coda-www/ResearchWebPages/docdir/sec89.pdf

The process authentication group is described on pages 22-23 in the pdf, 268-269 in the original ACM publication.

Jan

#19 lore raw
In reply to Jan Harkes

Hi!

Quoted 7 lines
Quoted 6 lines

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.

Quoted 6 lines

The local user id is not a 'trusted' identity for a distributed filesystem. Any user still have to prove his identity by obtaining tokens.

If someone obtains my user id on in any way (i.e. weak password/ bufferoverflow/ root exploit), he should not be allowed to use or access my tokens as he hasn't proven his identity. In this case he would either

? If he has same uid as you *and* you
have >=1 process running, what prevents
him from gdb attach <that process>,
and force it to do whatever he needs
by forcing syscall?
Pavel

Signature · 2 lines
				Pavel
Written on sharp zaurus, because my Velo1 broke. If you have Velo you don't need...
#20 lore raw
Quoted 6 lines

? If he has same uid as you *and* you
have >=1 process running, what prevents
him from gdb attach <that process>,
and force it to do whatever he needs
by forcing syscall?
Pavel

That's a good point, and perhaps it should be an option to not allow ptrace or other potentially dangerous operations between processes in different pags. But leave that optional, as it might still be useful - for example, logging in and diagnosing a daemon running in a separate pag.

It's not clear if this would be best as a per-pag flag or a global one though.

-- Nathan

------------------------------------------------------------
Nathan Neulinger EMail: [email protected]
University of Missouri - Rolla Phone: (573) 341-4841
Computing Services Fax: (573) 341-4216

#21 lore raw
Quoted 7 lines
Quoted 6 lines

? If he has same uid as you *and* you
have >=1 process running, what prevents
him from gdb attach <that process>,
and force it to do whatever he needs
by forcing syscall?
Pavel

Quoted 8 lines

That's a good point, and perhaps it should be an option to not allow ptrace or other potentially dangerous operations between processes in different pags. But leave that optional, as it might still be useful - for example, logging in and diagnosing a daemon running in a separate pag.

It's not clear if this would be best as a per-pag flag or a global one though.

Well, at that point you are getting quite far away from unix.... And this decision is pretty fundamental.

Quoted 7 lines

-- Nathan

------------------------------------------------------------
Nathan Neulinger EMail: [email protected]
University of Missouri - Rolla Phone: (573) 341-4841
Computing Services Fax: (573) 341-4216

Signature · 2 lines
Horseback riding is like software...
...vgf orggre jura vgf serr.
#22 lore raw
In reply to Linus Torvalds
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

" " == Linus Torvalds <[email protected]> writes:

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

Think of PAGs as "session"-style management of credentials. If you want to add/remove a credential without sharing that operation with all the other processes that are currently in the same session/PAG then you change PAGs.
Otherwise, the credential operation affects all processes in the same PAG.

Under normal circumstances, changing real uid/gid should involve changing your PAG, but it doesn't necessarily have to do so.

Cheers,
Trond

#23 lore raw
Quoted 2 lines · Trond Myklebust

Under normal circumstances, changing real uid/gid should involve changing your PAG, but it doesn't necessarily have to do so.

It should not change your PAG, because otherwise a key principle of PAGs (root is not able to get into a PAG with "su $UID") is lost.

Regards

Ingo Oeser

#24 lore raw
In reply to Linus Torvalds
Quoted 3 lines · Linux Torvalds

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.

Quoted 2 lines

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

Quoted 5 lines
Quoted 3 lines

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?

Quoted 3 lines

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.

Quoted 2 lines

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.

Quoted 6 lines
Quoted 3 lines

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.

Quoted 6 lines

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.

Quoted 4 lines

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

#25 lore raw
In reply to David Howells
Quoted 3 lines · David Howells

(3) AFS multiplexor support. Not complete at the moment, but implemented far enough to provide access to the PAG mechanism. Further patches will be forthcoming to make this fully functional.

This is broken. Please add individual syscalls instead of yet another broken multiplexer.

and do you really think this is a 2.6 thing?

#26 lore raw
Quoted 7 lines · David Howells
Quoted 3 lines

(3) AFS multiplexor support. Not complete at the moment, but implemented far enough to provide access to the PAG mechanism. Further patches will be forthcoming to make this fully functional.

This is broken. Please add individual syscalls instead of yet another broken multiplexer.

At what level? There're two levels of mux...

(1) four syscalls

(2) 30-ish pioctls, 40-ish control functions and 20-ish ICL functions.

If I go for (2) as I think you're suggesting, that's on the order of at least 90 new syscalls, probably more when Arla's additions are included...

Quoted 1 line

and do you really think this is a 2.6 thing?

Yes.

David

#27 lore raw
Quoted 8 lines · David Howells

At what level? There're two levels of mux...

(1) four syscalls

(2) 30-ish pioctls, 40-ish control functions and 20-ish ICL functions.

If I go for (2) as I think you're suggesting, that's on the order of at least 90 new syscalls, probably more when Arla's additions are included...

As a first patch two pag syscalls. After that please post an implementation for every additional syscall you need to this list (or groups thereof) after you moved most to an afsctl fs.

Quoted 3 lines
Quoted 1 line

and do you really think this is a 2.6 thing?

Yes.

Care to explain why?

#28 lore raw
In reply to Christoph Hellwig
Quoted 7 lines · Christoph Hellwig
Quoted 3 lines · David Howells

(3) AFS multiplexor support. Not complete at the moment, but implemented far enough to provide access to the PAG mechanism. Further patches will be forthcoming to make this fully functional.

This is broken. Please add individual syscalls instead of yet another broken multiplexer.

AFS is annoying and painful no matter how you look at it. :/

But I don't think 90+ new syscalls is the answer, even for 2.7.

File this under "design mistake we must live with", much like ioctl(2) itself.

Jeff

#29 lore raw
Quoted 4 lines

AFS is annoying and painful no matter how you look at it. :/

But I don't think 90+ new syscalls is the answer, even for 2.7.

I think it's going to be either

(1) try to maintain compatibility with OpenAFS and Arla's current syscall setup

(2) totally rewrite the interface and tell OpenAFS/Arla they have to change too.

In the case of (2), I think the AFS operations would best be emulated by a combination of the following means:

(1) Use the setpag() syscall in my patch.

(2) Add syscalls for managing tokens on a general filesystem-by-filesystem basis (only need four ops: set, get, delete and clear-all). These could work through operations in struct file_system_type.

(3) Work through sysfs files for fs-specific control functions. Things like adding cells would come into this category.

(4) Emulate as much as many of the inode-requiring pioctl calls as possible with xattr syscalls.

However, this leaves at least one that doesn't fit into any of the above categories. VIOC_STAT_MT_PT takes an inode, and so should come into (4) except that the xattr key size isn't sufficiently capacious.

There are two ways to deal with this:

(1) Add an actual pioctl syscall as a top-level syscall and make it either call a pioctl method in inode_operations or maybe have it fake a dentry and file and call file_operations->ioctl.

(2) Open the directory holding the mountpoint and make an ioctl that aims at the mountpoint in question.

David