Coda File System

process authentication groups (resent)

From: Peter J. Braam <>
Date: Tue, 12 May 1998 15:46:45 -0400 (EDT)

Many Unices have a "setpag" (I called it "newpag") system call through
which a process puts itself into a new process authentication group - a
new field in process structure. Mostly setpag is called by "login-type"
programs, and inherited by fork. This serves authentication which is
not necessarily uid based. 

Filesystems like AFS and Coda like this system for authentication and
SMBFS etc could equally use it to their advantage. 

Will you consider this mini patch which gives us "newpag" and "getpag"
system calls, implemented by the students cc'd above?  It puts an extra
unsigned long in the process structure and defines two mini syscalls and
an entry in the /proc/status output.

This design was discussed extensively with Ted Ts'o and others, like Bill
joined in.   There was no protest apart from those who had misunderstood.
A fuller motivation is below. 

I do not know what numbers to assign for sparc, alpha and others.  Is
lock_kernel() the right way to increment an integer? 

/**** NOTE ****/
--------> Even if you don't take it note that it patches two little bugs:

-       .long SYMBOL_NAME(sys_chown)
+       .long SYMBOL_NAME(sys_lchown)

and the syscall numbering was off by one. 

Below is a fuller motivation.  Will you let me know if this is worthy? 

- Peter -

Process Authentication Groups (PAGs)

Peter Braam (
Tue, 17 Feb 1998 22:24:39 -0500 (EST)

Process Authentication Groups

Coda as well as other system services want to implement a stricter
form of protection and authentication. Unix authorizes processes
based on their uid -- the uid defines a partition of the set of
processes. Coda finds this partition into protection groups based on
uid too coarse; the sets of processes it wants to authorize should be

For example smbfs and ncpfs need subsets of processes to allow more
than one authenticated session to an NT or Novel server, much like
Coda. Another example, is that root is not to be trusted lightly but
can change its uid easily -- systems based on the Kerberos model don't
like this. A further worry arises when telnetd is serving two
sessions for the same uid, it is good practice to ask each of these
sessions to authenticate.

The smaller group of processes for which authentication should give
access is called a PAG, a process authentication group. Hopefully
defined by the following:
- Every process should belong to a pag
- Pag's are inherited by fork
- at boottime init has a zero pag
- when process executes a login related operation (preferrably
through a PAM module) this login process would execute a "newpag"
system call which places the process in a new PAG.
- any process can execute newpag and thereby leave an
authentication group of which is was a member
- the kernel can return a list of PAG's in use (a la "ps") so that
processes holding resources indexed by PAGs can garbage collect
resources for PAGS that have gone away. This list will include
the pags found under "SAVED_IDS".

PAG's are different from process groups and session groups. These
change more often and are meant for job control.


The Andrew project used PAGs for AFS authentication. They were
"hacked" in the sense that they used 2 fields in the groups array.
Root can fairly easily change fields in the group array on some
systems -- so this doesn't look so nice. I have no idea what the
second field was used for.

They called the system call "setpag", but "newpag" seems to better
convey semantics. Finally there was/is a special value of pag which
was meant to be ignored. I haven't seen the need for this.


The simplest is to assign a PAGid just like the pid when newpag is
executed. This costs one "int" field in the process structure. The
PAG can be made increasing and will always be new. Newpag will be a
simple system call increasing a global variable maxpag and assigning
this to the PAG field in the process structure. We could use
/proc/pags to hold a list of pags.

One may argue that kernel subsystems may want to hold data related to
a PAG and that using a pointer to some kernel data structure - which
we can extend as need arises - is more efficient. The worry I have
about this is that this pointer may be re-used for a different PAG and
that it might be difficult to update all user level processing holding
data related to a PAG.

How would Coda use PAGS?

The following discussion summarizes our ideas about using PAGs for

When a system call reaches the Coda kernel code, Coda queries Venus
for access by giving it the PAG as part of the Coda credentials of the
process. Venus checks if it has a token for this pag and bases access
on this. To get a token a process in the same PAG would use the
"clog" (Coda login) program. This negotiates a session key with the
auth server (perhaps using Kerberos) and asks the kernel to pass Venus
the session key and PAG -- from this moment Venus associates a PAG
with a session key.

A) session keys for root

There are a few interesting issues which relate to root and PAGS.
Since PAGS are inherited by fork, it could be very dangerous for a
root process to have a session key. Imagine that root has a session
key and starts a deamon process. The deamon process would inherit the
permissions root has through it's PAG and session key and possibly
pass such permissions to any user process requesting service from the

In contrast with this, it is highly desirable that root can start
processes which have session keys: however we don't want to give the
current PAG those session keys since that could be risky. We propose
the following solution:

1) clog will not acquire token for the root user without a further
2) clog can be given a "-e" (for execute) flag. If one were to
clog braam -e program
Clog would:
in the child:
get a session key

If roots want a Coda authenticated shell with a key for user moose she
would execute:
clog moose -e bash

B) weaker authentication for special programs

Imagine that we are running an NFS server on machine A, and that A is
a coda client. We want this nfs server to export /coda to machine B.

We assume that the nfs server is well behaved and changes its fsuid to
that of the user on behalf of which it is servicing a request.

To make this useful we would want a user U on B to telnet to A and
create an "unsafe" session key there with "clog --unsafe U". A
session key would be given to Venus with a sloppy flag which enables
the following:

When Venus decides access permissions to serve a request coming from
the NFS server, it fails to find a PAG key for the PAG passed by the
NFS server. It continues searching for a sloppy key matching the
fsuid of the NFS server and grants permissions based on that.

- Peter Braam -

diff -uNr linux-2.1.100b2.orig/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- linux-2.1.100b2.orig/arch/i386/kernel/entry.S	Thu Apr 30 18:17:16 1998
+++ linux/arch/i386/kernel/entry.S	Tue May  5 17:54:30 1998
@@ -542,9 +542,11 @@
 	.long SYMBOL_NAME(sys_rt_sigsuspend)
 	.long SYMBOL_NAME(sys_pread)		/* 180 */
 	.long SYMBOL_NAME(sys_pwrite)
-	.long SYMBOL_NAME(sys_chown)
+	.long SYMBOL_NAME(sys_lchown)
 	.long SYMBOL_NAME(sys_getcwd)
-	.rept NR_syscalls-182
+	.long SYMBOL_NAME(sys_newpag)
+	.long SYMBOL_NAME(sys_getpag)
+	.rept NR_syscalls-185
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -uNr linux-2.1.100b2.orig/fs/proc/array.c linux/fs/proc/array.c
--- linux-2.1.100b2.orig/fs/proc/array.c	Wed Mar 11 18:53:18 1998
+++ linux/fs/proc/array.c	Tue May  5 17:50:03 1998
@@ -657,10 +657,12 @@
-		"Gid:\t%d\t%d\t%d\t%d\n",
+		"Gid:\t%d\t%d\t%d\t%d\n"
+		"Pag:\t%d\n",
 		p->pid, p->p_pptr->pid,
 		p->uid, p->euid, p->suid, p->fsuid,
-		p->gid, p->egid, p->sgid, p->fsgid);
+		p->gid, p->egid, p->sgid, p->fsgid,
+		p->pag);
 	return buffer;
@@ -833,7 +835,7 @@
 	return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
-%lu %s %s %s %s %lu %lu %lu\n",
+%lu %s %s %s %s %lu %lu %lu %lu\n",
@@ -870,7 +872,8 @@
-		tsk->cnswap);
+		tsk->cnswap,
+		tsk->pag);
 static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
diff -uNr linux-2.1.100b2.orig/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- linux-2.1.100b2.orig/include/asm-i386/unistd.h	Tue Apr  7 11:05:05 1998
+++ linux/include/asm-i386/unistd.h	Tue May  5 17:51:55 1998
@@ -189,6 +189,8 @@
 #define __NR_pwrite		181
 #define __NR_chown		182
 #define __NR_getcwd		183
+#define __NR_newpag		184
+#define __NR_getpag		185
 /* user-visible error numbers are in the range -1 - -122: see <asm-i386/errno.h> */
diff -uNr linux-2.1.100b2.orig/include/linux/pag.h linux/include/linux/pag.h
--- linux-2.1.100b2.orig/include/linux/pag.h	Wed Dec 31 19:00:00 1969
+++ linux/include/linux/pag.h	Tue May  5 17:45:48 1998
@@ -0,0 +1,6 @@
+#include <linux/unistd.h>
+_syscall0(unsigned long, newpag);
+_syscall0(unsigned long, getpag);
diff -uNr linux-2.1.100b2.orig/include/linux/sched.h linux/include/linux/sched.h
--- linux-2.1.100b2.orig/include/linux/sched.h	Thu Apr 30 15:51:34 1998
+++ linux/include/linux/sched.h	Tue May  5 17:45:48 1998
@@ -212,6 +212,7 @@
 	long debugreg[8];  /* Hardware debugging registers */
 	long counter;
 	long priority;
+	unsigned long pag;          /* Process authentication group */
 	struct linux_binfmt *binfmt;
 	struct task_struct *next_task, *prev_task;
 	struct task_struct *next_run,  *prev_run;
@@ -337,6 +338,7 @@
 /* state etc */	{ 0,0,0,KERNEL_DS,&default_exec_domain, \
 /* debugregs */ { 0, },            \
+/* pag */	0, \
 /* binfmt */	NULL, \
 /* schedlink */	&init_task,&init_task, &init_task, &init_task, \
 /* ec,brk... */	0,0,0,0,0,0, \
diff -uNr linux-2.1.100b2.orig/kernel/Makefile linux/kernel/Makefile
--- linux-2.1.100b2.orig/kernel/Makefile	Tue Mar 10 17:43:13 1998
+++ linux/kernel/Makefile	Tue May  5 17:45:48 1998
@@ -12,7 +12,7 @@
 O_TARGET := kernel.o
 O_OBJS    = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
-	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
+	    module.o exit.o itimer.o info.o pag.o time.o softirq.o resource.o \
 	    sysctl.o acct.o
 OX_OBJS  += signal.o
diff -uNr linux-2.1.100b2.orig/kernel/pag.c linux/kernel/pag.c
--- linux-2.1.100b2.orig/kernel/pag.c	Wed Dec 31 19:00:00 1969
+++ linux/kernel/pag.c	Tue May  5 17:45:48 1998
@@ -0,0 +1,39 @@
+ *  linux/kernel/pag.c
+ *
+ */
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/module.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/mmu_context.h>
+unsigned long int total_pags=1;
+asmlinkage unsigned long sys_newpag(void)
+  lock_kernel();
+  current->pag = total_pags++;
+  unlock_kernel();
+  return 0;
+asmlinkage unsigned long sys_getpag(void)
+  return current->pag;
Received on 1998-05-12 15:48:08