diff -NurP --minimal linux-2.4.23-pre4/Makefile linux-2.4.23-pre4-ctx17d/Makefile
--- linux-2.4.23-pre4/Makefile	2003-09-13 00:50:14.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/Makefile	2003-09-13 15:24:22.000000000 +0200
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 23
-EXTRAVERSION = -pre4
+EXTRAVERSION = -pre4-ctx17a
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -NurP --minimal linux-2.4.23-pre4/arch/i386/kernel/ptrace.c linux-2.4.23-pre4-ctx17d/arch/i386/kernel/ptrace.c
--- linux-2.4.23-pre4/arch/i386/kernel/ptrace.c	2002-08-03 02:39:42.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/arch/i386/kernel/ptrace.c	2003-09-13 15:24:22.000000000 +0200
@@ -170,7 +170,7 @@
 	if (child)
 		get_task_struct(child);
 	read_unlock(&tasklist_lock);
-	if (!child)
+	if (!child || child->s_context != current->s_context)
 		goto out;
 
 	ret = -EPERM;
diff -NurP --minimal linux-2.4.23-pre4/arch/ppc/kernel/ptrace.c linux-2.4.23-pre4-ctx17d/arch/ppc/kernel/ptrace.c
--- linux-2.4.23-pre4/arch/ppc/kernel/ptrace.c	2003-08-25 20:32:08.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/arch/ppc/kernel/ptrace.c	2003-09-13 15:24:22.000000000 +0200
@@ -188,7 +188,7 @@
 	if (child)
 		get_task_struct(child);
 	read_unlock(&tasklist_lock);
-	if (!child)
+	if (!child || child->s_context != current->s_context)
 		goto out;
 
 	ret = -EPERM;
diff -NurP --minimal linux-2.4.23-pre4/arch/sparc64/kernel/ptrace.c linux-2.4.23-pre4-ctx17d/arch/sparc64/kernel/ptrace.c
--- linux-2.4.23-pre4/arch/sparc64/kernel/ptrace.c	2002-11-29 00:53:12.000000000 +0100
+++ linux-2.4.23-pre4-ctx17d/arch/sparc64/kernel/ptrace.c	2003-09-13 15:24:22.000000000 +0200
@@ -156,7 +156,7 @@
 		get_task_struct(child);
 	read_unlock(&tasklist_lock);
 
-	if (!child) {
+	if (!child || child->s_context != current->s_context) {
 		pt_error_return(regs, ESRCH);
 		goto out;
 	}
diff -NurP --minimal linux-2.4.23-pre4/fs/devpts/inode.c linux-2.4.23-pre4-ctx17d/fs/devpts/inode.c
--- linux-2.4.23-pre4/fs/devpts/inode.c	2001-10-25 09:02:26.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/fs/devpts/inode.c	2003-09-13 17:19:02.000000000 +0200
@@ -24,6 +24,7 @@
 #include <linux/tty.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
+#include <linux/sched.h>
 
 #include "devpts_i.h"
 
@@ -152,7 +153,6 @@
 	inode->i_op = &devpts_root_inode_operations;
 	inode->i_fop = &devpts_root_operations;
 	inode->i_nlink = 2;
-
 	s->u.generic_sbp = (void *) sbi;
 	s->s_blocksize = 1024;
 	s->s_blocksize_bits = 10;
@@ -180,6 +180,18 @@
 
 static DECLARE_FSTYPE(devpts_fs_type, "devpts", devpts_read_super, FS_SINGLE);
 
+static int devpts_tty_permission(struct inode *inode, int mask)
+{
+	int ret = -EACCES;
+	if (current->s_context == inode->u.devpts_i.s_context)
+		ret = vfs_permission(inode, mask);
+	return ret;
+}
+
+struct inode_operations devpts_tty_inode_operations = {
+	permission:	devpts_tty_permission,
+};
+
 void devpts_pty_new(int number, kdev_t device)
 {
 	struct super_block *sb = devpts_mnt->mnt_sb;
@@ -198,6 +210,8 @@
 	inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid;
 	inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	inode->u.devpts_i.s_context = current->s_context;
+	inode->i_op = &devpts_tty_inode_operations;
 	init_special_inode(inode, S_IFCHR|sbi->mode, kdev_t_to_nr(device));
 
 	if ( sbi->inodes[number] ) {
diff -NurP --minimal linux-2.4.23-pre4/fs/devpts/root.c linux-2.4.23-pre4-ctx17d/fs/devpts/root.c
--- linux-2.4.23-pre4/fs/devpts/root.c	2001-12-21 18:41:55.000000000 +0100
+++ linux-2.4.23-pre4-ctx17d/fs/devpts/root.c	2003-09-13 17:19:02.000000000 +0200
@@ -14,6 +14,7 @@
 #include <linux/stat.h>
 #include <linux/param.h>
 #include <linux/string.h>
+#include <linux/sched.h>
 #include "devpts_i.h"
 
 static int devpts_root_readdir(struct file *,void *,filldir_t);
@@ -64,7 +65,10 @@
 	default:
 		while ( nr - 2 < sbi->max_ptys ) {
 			int ptynr = nr - 2;
-			if ( sbi->inodes[ptynr] ) {
+			struct inode *inode = sbi->inodes[ptynr];
+			if ( inode != NULL
+				&& (current->s_context == 1
+				|| inode->u.devpts_i.s_context == current->s_context)) {
 				genptsname(numbuf, ptynr);
 				if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_CHR) < 0 )
 					return 0;
@@ -100,6 +104,7 @@
 	unsigned int entry;
 	int i;
 	const char *p;
+	struct inode *inode;
 
 	dentry->d_op    = &devpts_dentry_operations;
 
@@ -126,10 +131,17 @@
 	if ( entry >= sbi->max_ptys )
 		return NULL;
 
-	if ( sbi->inodes[entry] )
-		atomic_inc(&sbi->inodes[entry]->i_count);
+	inode = sbi->inodes[entry];
+	if (inode != NULL
+		&& inode->u.devpts_i.s_context == current->s_context) {
+		atomic_inc(&inode->i_count);
+	} else {
+		inode = NULL;
+	}
 	
-	d_add(dentry, sbi->inodes[entry]);
+	d_add(dentry, inode);
 
 	return NULL;
 }
+
+
diff -NurP --minimal linux-2.4.23-pre4/fs/exec.c linux-2.4.23-pre4-ctx17d/fs/exec.c
--- linux-2.4.23-pre4/fs/exec.c	2003-09-13 00:50:16.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/fs/exec.c	2003-09-13 15:24:22.000000000 +0200
@@ -734,7 +734,7 @@
 	kernel_cap_t new_permitted, working;
 	int do_unlock = 0;
 
-	new_permitted = cap_intersect(bprm->cap_permitted, cap_bset);
+	new_permitted = cap_intersect(bprm->cap_permitted, current->cap_bset);
 	working = cap_intersect(bprm->cap_inheritable,
 				current->cap_inheritable);
 	new_permitted = cap_combine(new_permitted, working);
diff -NurP --minimal linux-2.4.23-pre4/fs/namei.c linux-2.4.23-pre4-ctx17d/fs/namei.c
--- linux-2.4.23-pre4/fs/namei.c	2003-08-25 20:32:19.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/fs/namei.c	2003-09-13 15:24:22.000000000 +0200
@@ -152,6 +152,15 @@
 {
 	umode_t			mode = inode->i_mode;
 
+	/*
+		A dir with permission bit all 0s is a dead zone for
+		process running in a vserver. By doing
+			chmod 000 /vservers
+		you fix the "escape from chroot" bug.
+	*/
+	if ((mode & 0777) == 0
+		&& S_ISDIR(mode)
+		&& current->s_context != 0) return -EACCES;
 	if (mask & MAY_WRITE) {
 		/*
 		 * Nobody gets write access to a read-only fs.
diff -NurP --minimal linux-2.4.23-pre4/fs/proc/array.c linux-2.4.23-pre4-ctx17d/fs/proc/array.c
--- linux-2.4.23-pre4/fs/proc/array.c	2003-06-13 16:51:37.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/fs/proc/array.c	2003-09-13 17:19:02.000000000 +0200
@@ -75,6 +75,7 @@
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/processor.h>
+#include <asm/unistd.h>
 
 /* Gcc optimizes away "strlen(x)" for constant x */
 #define ADDBUF(buffer, string) \
@@ -147,8 +148,13 @@
 static inline char * task_state(struct task_struct *p, char *buffer)
 {
 	int g;
-
+	pid_t ppid;
 	read_lock(&tasklist_lock);
+	ppid = p->p_opptr->pid;
+	if (ppid != 0
+		&& current->s_info != NULL
+		&& current->s_info->initpid == ppid)
+		ppid = 1;
 	buffer += sprintf(buffer,
 		"State:\t%s\n"
 		"Tgid:\t%d\n"
@@ -158,7 +164,7 @@
 		"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,
-		p->pid, p->pid ? p->p_opptr->pid : 0, 0,
+		p->pid, p->pid ? ppid : 0, 0,
 		p->uid, p->euid, p->suid, p->fsuid,
 		p->gid, p->egid, p->sgid, p->fsgid);
 	read_unlock(&tasklist_lock);	
@@ -266,10 +272,12 @@
 {
     return buffer + sprintf(buffer, "CapInh:\t%016x\n"
 			    "CapPrm:\t%016x\n"
-			    "CapEff:\t%016x\n",
+			    "CapEff:\t%016x\n"
+			    "CapBset:\t%016x\n",
 			    cap_t(p->cap_inheritable),
 			    cap_t(p->cap_permitted),
-			    cap_t(p->cap_effective));
+			    cap_t(p->cap_effective),
+			    cap_t(p->cap_bset));
 }
 
 
@@ -291,6 +299,50 @@
 	}
 	buffer = task_sig(task, buffer);
 	buffer = task_cap(task, buffer);
+#ifdef __NR_new_s_context
+	if (task->s_info != NULL) {
+		int i;
+		buffer += sprintf (buffer,"s_context: %d [",task->s_context);
+		for (i=0; i<NB_S_CONTEXT; i++) {
+			short int ctx = task->s_info->s_context[i];
+			if (ctx == 0) break;
+			buffer += sprintf (buffer," %d",ctx);
+		}
+		*buffer++ = ']';
+		*buffer++ = '\n';
+		buffer += sprintf (buffer,"ctxticks: %d %ld %d\n"
+			,atomic_read(&task->s_info->ticks),task->counter
+			,task->s_info->refcount);
+		buffer += sprintf (buffer,"ctxflags: %d\n"
+			,task->s_info->flags);
+		buffer += sprintf (buffer,"initpid: %d\n"
+			,task->s_info->initpid);
+	}else{
+		buffer += sprintf (buffer,"s_context: %d\n",task->s_context);
+		buffer += sprintf (buffer,"ctxticks: none\n");
+		buffer += sprintf (buffer,"ctxflags: none\n");
+		buffer += sprintf (buffer,"initpid: none\n");
+	}
+	if (task->ip_info != NULL){
+		int i;
+		buffer += sprintf (buffer,"ipv4root:");
+		for (i=0; i<task->ip_info->nbipv4; i++){
+			buffer += sprintf (buffer," %08x/%08x"
+				,task->ip_info->ipv4[i]
+				,task->ip_info->mask[i]);
+		}
+		*buffer++ = '\n';
+		buffer += sprintf (buffer,"ipv4root_bcast: %08x\n"
+			,task->ip_info->v4_bcast);
+		buffer += sprintf (buffer,"ipv4root_refcnt: %d\n"
+			,task->ip_info->refcount);
+	}else{
+		buffer += sprintf (buffer,"ipv4root: 0\n");
+		buffer += sprintf (buffer,"ipv4root_bcast: 0\n");
+	}
+	buffer += sprintf (buffer,"__NR_new_s_context: %d\n",__NR_new_s_context);
+	buffer += sprintf (buffer,"__NR_set_ipv4root: %d rev3\n",__NR_set_ipv4root);
+#endif
 #if defined(CONFIG_ARCH_S390)
 	buffer = task_show_regs(task, buffer);
 #endif
@@ -344,6 +396,9 @@
 
 	read_lock(&tasklist_lock);
 	ppid = task->pid ? task->p_opptr->pid : 0;
+	if (current->s_info != NULL
+		&& current->s_info->initpid == ppid)
+		ppid = 1;
 	read_unlock(&tasklist_lock);
 	res = 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 \
diff -NurP --minimal linux-2.4.23-pre4/fs/proc/base.c linux-2.4.23-pre4-ctx17d/fs/proc/base.c
--- linux-2.4.23-pre4/fs/proc/base.c	2003-08-25 20:32:19.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/fs/proc/base.c	2003-09-13 17:19:02.000000000 +0200
@@ -1056,6 +1056,12 @@
 	if (!task)
 		goto out;
 
+	if (pid != 1
+		&& current->s_context != 1
+		&& task->s_context != current->s_context) {
+		free_task_struct(task);
+		goto out;
+	}
 	inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_INO);
 
 	free_task_struct(task);
@@ -1102,6 +1108,21 @@
 		int pid = p->pid;
 		if (!pid)
 			continue;
+		/* Even if the pid 1 is not part of the security context */
+		/* we show it anyway. This makes the security box */
+		/* more standard (and helps pstree do its job) */
+		/* So current process "knows" pid 1 exist anyway and can't */
+		/* send any signal either */
+
+		/* A process with security context 1 can see all processes */
+		if (pid != 1
+			&& current->s_context != 1
+			&& p->s_context != current->s_context)
+			continue;
+		/* We hide the fakeinit process since we show it as process 1 */
+		if (current->s_info != NULL
+			&& current->s_info->initpid == pid)
+			continue;
 		if (--index >= 0)
 			continue;
 		pids[nr_pids] = pid;
diff -NurP --minimal linux-2.4.23-pre4/include/linux/capability.h linux-2.4.23-pre4-ctx17d/include/linux/capability.h
--- linux-2.4.23-pre4/include/linux/capability.h	2003-08-15 01:24:52.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/include/linux/capability.h	2003-09-13 17:19:02.000000000 +0200
@@ -231,6 +232,7 @@
 /* Allow enabling/disabling tagged queuing on SCSI controllers and sending
    arbitrary SCSI commands */
 /* Allow setting encryption key on loopback filesystem */
+/* Allow the selection of a security context */
 
 #define CAP_SYS_ADMIN        21
 
diff -NurP --minimal linux-2.4.23-pre4/include/linux/devpts_fs_info.h linux-2.4.23-pre4-ctx17d/include/linux/devpts_fs_info.h
--- linux-2.4.23-pre4/include/linux/devpts_fs_info.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.23-pre4-ctx17d/include/linux/devpts_fs_info.h	2003-09-13 17:19:02.000000000 +0200
@@ -0,0 +1,4 @@
+struct devpts_inode_info {
+	int s_context;
+};
+
diff -NurP --minimal linux-2.4.23-pre4/include/linux/fs.h linux-2.4.23-pre4-ctx17d/include/linux/fs.h
--- linux-2.4.23-pre4/include/linux/fs.h	2003-08-25 20:32:20.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/include/linux/fs.h	2003-09-13 15:52:46.000000000 +0200
@@ -322,6 +324,7 @@
 #include <linux/usbdev_fs_i.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/cramfs_fs_sb.h>
+#include <linux/devpts_fs_info.h>
 
 /*
  * Attribute flags.  These should be or-ed together to figure out what
@@ -517,6 +521,7 @@
 		struct socket			socket_i;
 		struct usbdev_inode_info        usbdev_i;
 		struct jffs2_inode_info		jffs2_i;
+		struct devpts_inode_info	devpts_i;
 		void				*generic_ip;
 	} u;
 };
diff -NurP --minimal linux-2.4.23-pre4/include/linux/sched.h linux-2.4.23-pre4-ctx17d/include/linux/sched.h
--- linux-2.4.23-pre4/include/linux/sched.h	2003-09-13 00:50:17.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/include/linux/sched.h	2003-09-13 17:19:02.000000000 +0200
@@ -270,6 +270,7 @@
 	/* Hash table maintenance information */
 	struct user_struct *next, **pprev;
 	uid_t uid;
+	int s_context;
 };
 
 #define get_current_user() ({ 				\
@@ -277,6 +278,63 @@
 	atomic_inc(&__user->__count);			\
 	__user; })
 
+
+/*
+	We may have a different domainname and nodename for each security
+	context. By default, a security context share the same as its
+	parent, potentially the information in system_utsname
+*/
+#define S_CTX_INFO_LOCK		1	/* Can't request a new s_context */
+#define S_CTX_INFO_SCHED	2	/* All process in the s_context */
+					/* Contribute to the schedular */
+#define S_CTX_INFO_NPROC	4	/* Limit number of processes in a context */
+#define S_CTX_INFO_PRIVATE	8	/* Noone can join this security context */
+#define S_CTX_INFO_INIT		16	/* This process wants to become the */
+					/* logical process 1 of the security */
+					/* context */
+#define S_CTX_INFO_HIDEINFO	32	/* Hide some information in /proc */
+#define S_CTX_INFO_ULIMIT	64	/* Use ulimit of the current process */
+					/* to become the global limits */
+					/* of the context */
+
+#define NB_IPV4ROOT	16
+#define NB_S_CONTEXT	16
+
+struct context_info {
+	int refcount;
+	short int s_context[NB_S_CONTEXT];/* root is allowed to switch the current */
+				/* security context using any in this table */
+	unsigned long rlim[RLIM_NLIMITS];	/* Per context limit */
+	atomic_t res[RLIM_NLIMITS];	/* Current value */
+	char nodename[65];
+	char domainname[65];
+	int flags;		/* S_CTX_INFO_xxx */
+	atomic_t ticks;		/* Number of ticks used by all process */
+				/* in the s_context */
+	int initpid;		/* PID of the logical process 1 of the */
+				/* of the context */
+	void *data1;
+	void *data2;
+	void *data3;
+	void *data4;
+};
+
+struct iproot_info {
+	unsigned long mark;	/* Special signature for debugging */
+	atomic_t refcount;
+	int nbipv4;
+	__u32 ipv4[NB_IPV4ROOT];/* Process can only bind to these IPs */
+				/* The first one is used to connect */
+				/* and for bind any service */
+				/* The other must be used explicity when */
+				/* binding */
+	__u32 mask[NB_IPV4ROOT];/* Netmask for each ipv4 */
+				/* Used to select the proper source address */
+				/* for sockets */
+	__u32 v4_bcast;	/* Broadcast address used to receive UDP packets */
+};
+
+
 extern struct user_struct root_user;
 #define INIT_USER (&root_user)
 
@@ -404,6 +462,12 @@
 	unsigned long sas_ss_sp;
 	size_t sas_ss_size;
 	int (*notifier)(void *priv);
+/* Field to make virtual server running in chroot more  isolated */
+	int s_context;	/* Process can only deal with other processes */
+			/* with the same s_context */
+	__u32 cap_bset;	/* Maximum capability of this process and children */
+	struct context_info *s_info;
+	struct iproot_info *ip_info;
 	void *notifier_data;
 	sigset_t *notifier_mask;
 	
@@ -508,6 +572,7 @@
     blocked:		{{0}},						\
     alloc_lock:		SPIN_LOCK_UNLOCKED,				\
     journal_info:	NULL,						\
+    cap_bset:		CAP_INIT_EFF_SET,				\
 }
 
 
@@ -572,7 +637,7 @@
 }
 
 /* per-UID process charging. */
-extern struct user_struct * alloc_uid(uid_t);
+extern struct user_struct * alloc_uid(int, uid_t);
 extern void free_uid(struct user_struct *);
 extern void switch_uid(struct user_struct *);
 
@@ -944,6 +1009,14 @@
 	return res;
 }
 
+/* Manage the reference count of the context_info pointer */
+void sys_release_s_info (struct task_struct *);
+void sys_assign_s_info (struct task_struct *);
+void sys_alloc_s_info (void);
+void sys_release_ip_info (struct iproot_info *);
+void sys_assign_ip_info (struct iproot_info *);
+void sys_alloc_ip_info (void);
+
 static inline int need_resched(void)
 {
 	return (unlikely(current->need_resched));
diff -NurP --minimal linux-2.4.23-pre4/ipc/util.h linux-2.4.23-pre4-ctx17d/ipc/util.h
--- linux-2.4.23-pre4/ipc/util.h	2002-11-29 00:53:15.000000000 +0100
+++ linux-2.4.23-pre4-ctx17d/ipc/util.h	2003-09-13 17:19:02.000000000 +0200
@@ -25,6 +25,7 @@
 
 struct ipc_id {
 	struct kern_ipc_perm* p;
+	int s_context;	// Context owning this ID
 };
 
 
@@ -74,8 +75,12 @@
 
 	spin_lock(&ids->ary);
 	out = ids->entries[lid].p;
-	if(out==NULL)
+	if (out==NULL
+		|| (ids->entries[lid].s_context != current->s_context
+			&& current->s_context != 1)) {
 		spin_unlock(&ids->ary);
+		out = NULL;
+	}
 	return out;
 }
 
diff -NurP --minimal linux-2.4.23-pre4/kernel/exit.c linux-2.4.23-pre4-ctx17d/kernel/exit.c
--- linux-2.4.23-pre4/kernel/exit.c	2002-11-29 00:53:15.000000000 +0100
+++ linux-2.4.23-pre4-ctx17d/kernel/exit.c	2003-09-13 17:19:02.000000000 +0200
@@ -66,6 +66,8 @@
 		current->counter += p->counter;
 		if (current->counter >= MAX_COUNTER)
 			current->counter = MAX_COUNTER;
+		sys_release_s_info(p);
+		sys_release_ip_info(p->ip_info);
 		p->pid = 0;
 		free_task_struct(p);
 	} else {
@@ -159,8 +161,17 @@
 static inline void forget_original_parent(struct task_struct * father)
 {
 	struct task_struct * p;
+	struct task_struct *vchild_reaper = child_reaper;
 
 	read_lock(&tasklist_lock);
+	if (father->s_info != NULL) {
+		pid_t initpid = father->s_info->initpid;
+		if ((initpid != 0) && (father->pid != initpid)) {
+			struct task_struct *r = find_task_by_pid(initpid);
+			if (r != NULL)
+				vchild_reaper = r;
+		}
+	}
 
 	for_each_task(p) {
 		if (p->p_opptr == father) {
@@ -169,7 +180,7 @@
 			p->self_exec_id++;
 
 			/* Make sure we're not reparenting to ourselves */
-			p->p_opptr = child_reaper;
+			p->p_opptr = vchild_reaper;
 
 			if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0);
 		}
diff -NurP --minimal linux-2.4.23-pre4/kernel/fork.c linux-2.4.23-pre4-ctx17d/kernel/fork.c
--- linux-2.4.23-pre4/kernel/fork.c	2003-09-13 00:50:17.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/kernel/fork.c	2003-09-13 17:19:02.000000000 +0200
@@ -662,6 +662,10 @@
 	*p = *current;
 
 	retval = -EAGAIN;
+	if (p->s_info && (p->s_info->flags & S_CTX_INFO_NPROC)) {
+		if (p->s_info->refcount >= p->rlim[RLIMIT_NPROC].rlim_max)
+			goto bad_fork_free;
+	}
 	/*
 	 * Check if we are over our maximum process limit, but be sure to
 	 * exclude root. This is needed to make it possible for login and
@@ -672,6 +676,9 @@
 	              && !capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE))
 		goto bad_fork_free;
 
+	sys_assign_s_info(p);
+	sys_assign_ip_info(p->ip_info);
+
 	atomic_inc(&p->user->__count);
 	atomic_inc(&p->user->processes);
 
diff -NurP --minimal linux-2.4.23-pre4/kernel/printk.c linux-2.4.23-pre4-ctx17d/kernel/printk.c
--- linux-2.4.23-pre4/kernel/printk.c	2003-09-13 00:50:17.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/kernel/printk.c	2003-09-13 17:19:02.000000000 +0200
@@ -176,6 +176,9 @@
 	char c;
 	int error = 0;
 
+	if (!capable(CAP_SYS_ADMIN) && (current->s_context != 0))
+		return -EPERM;
+
 	switch (type) {
 	case 0:		/* Close log */
 		break;
diff -NurP --minimal linux-2.4.23-pre4/kernel/signal.c linux-2.4.23-pre4-ctx17d/kernel/signal.c
--- linux-2.4.23-pre4/kernel/signal.c	2003-06-13 16:51:39.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/kernel/signal.c	2003-09-13 17:19:02.000000000 +0200
@@ -621,7 +621,9 @@
 		retval = -ESRCH;
 		read_lock(&tasklist_lock);
 		for_each_task(p) {
-			if (p->pgrp == pgrp && thread_group_leader(p)) {
+			if (p->pgrp == pgrp && thread_group_leader(p)
+				&& ((long)info==1
+					|| p->s_context == current->s_context)) {
 				int err = send_sig_info(sig, info, p);
 				if (retval)
 					retval = err;
@@ -675,7 +677,20 @@
                        if (tg)
                                p = tg;
                 }
-		error = send_sig_info(sig, info, p);
+		switch ((unsigned long)info) {
+		case 0:
+			if (p->s_context == current->s_context)
+				error = send_sig_info(sig, info, p);
+			break;
+		case 1:
+			error = send_sig_info(sig, info, p);
+			break;
+		default:
+			if( info->si_code == SI_KERNEL
+				|| p->s_context == current->s_context)
+				error = send_sig_info(sig, info, p);
+			break;
+		}
 	}
 	read_unlock(&tasklist_lock);
 	return error;
@@ -699,7 +714,8 @@
 
 		read_lock(&tasklist_lock);
 		for_each_task(p) {
-			if (p->pid > 1 && p != current && thread_group_leader(p)) {
+			if (p->pid > 1 && p != current && thread_group_leader(p)
+				&& p->s_context == current->s_context) {
 				int err = send_sig_info(sig, info, p);
 				++count;
 				if (err != -EPERM)
@@ -1323,3 +1339,142 @@
 	return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
 }
 #endif /* !alpha && !__ia64__ && !defined(__mips__) */
+
+static int set_initpid (int flags)
+{
+	int ret = 0;
+	if (flags & S_CTX_INFO_INIT) {
+		if (current->s_info == NULL)
+			ret = -EINVAL;
+		else if (current->s_info->initpid != 0)
+			ret = -EPERM;
+		else
+			current->s_info->initpid = current->tgid;
+	}
+	return ret;
+}
+
+static inline int switch_user_struct(int new_context)
+{
+	struct user_struct *new_user;
+
+	new_user = alloc_uid(new_context, current->uid);
+	if (!new_user)
+		return -ENOMEM;
+
+	if (new_user != current->user) {
+		struct user_struct *old_user = current->user;
+
+		atomic_inc(&new_user->processes);
+		atomic_dec(&old_user->processes);
+		current->user = new_user;
+		free_uid(old_user);
+	}
+	return 0;
+}
+
+/*
+	Change to a new security context and reduce the capability
+	basic set of the current process
+*/
+asmlinkage int
+sys_new_s_context(int ctx, __u32 remove_cap, int flags)
+{
+	#define MAX_S_CONTEXT 65535	/* Arbitrary limit */
+	int ret = -EPERM;
+	if (ctx == -1) {
+		if (current->s_info == NULL
+			|| !(current->s_info->flags & S_CTX_INFO_LOCK)) {
+			/* Ok we allocate a new context. For now, we just increase */
+			/* it. Wrap around possible, so we loop */
+			static int alloc_ctx=1;
+			static spinlock_t alloc_ctx_lock = SPIN_LOCK_UNLOCKED;
+			spin_lock(&alloc_ctx_lock);
+			while (1) {
+				int found = 0;
+				struct task_struct *p;
+				alloc_ctx++;
+				/* The s_context 1 is special. It sess all processes */
+				if (alloc_ctx == 1)
+					alloc_ctx++;
+				else if (alloc_ctx > MAX_S_CONTEXT) {
+					// No need to grow and grow
+					alloc_ctx = 2;
+				/* Check if in use */
+				read_lock(&tasklist_lock);
+				for_each_task(p) {
+					if (p->s_context == alloc_ctx){
+						found = 1;
+						break;
+					}
+				}
+				read_unlock(&tasklist_lock);
+				if (!found) break;
+			}
+			ret = switch_user_struct(alloc_ctx);
+			if (ret == 0) {
+				current->s_context = alloc_ctx;
+				current->cap_bset &= (~remove_cap);
+				ret = alloc_ctx;
+				sys_alloc_s_info();
+				if (current->s_info != NULL) {
+					set_initpid (flags);
+					current->s_info->flags |= flags;
+				}
+			}
+			spin_unlock(&alloc_ctx_lock);
+		}
+	} else if (ctx == -2) {
+		ret = set_initpid(flags);
+		if (ret == 0) {
+			/* We keep the same s_context, but lower the capabilities */
+			current->cap_bset &= (~remove_cap);
+			ret = current->s_context;
+			if (current->s_info != NULL) {
+				if (flags & S_CTX_INFO_INIT)
+					current->s_info->initpid = current->tgid;
+				current->s_info->flags |= flags;
+			}
+		}
+	} else if (ctx <= 0 || ctx > MAX_S_CONTEXT) {
+		ret = -EINVAL;
+	} else if (current->s_context == 0
+		&& capable(CAP_SYS_ADMIN)
+		&& (current->s_info == NULL
+			||(current->s_info->flags & S_CTX_INFO_LOCK) == 0)) {
+		/* The root context can become any context it wants */
+		int found = 0;
+		struct task_struct *p;
+		/* Check if in use so we reuse the same context_info */
+		read_lock(&tasklist_lock);
+		ret = ctx;
+		for_each_task(p) {
+			if (p->s_context == ctx) {
+				found = 1;
+				if (p->s_info == NULL
+					|| !(p->s_info->flags & S_CTX_INFO_PRIVATE)) {
+					sys_release_s_info(current);
+					sys_assign_s_info (p);
+					current->s_info = p->s_info;
+				}
+				else
+					ret = -EPERM;
+				break;
+			}
+		}
+		read_unlock(&tasklist_lock);
+		if (ret == ctx) {
+			ret = switch_user_struct(ctx);
+			if (ret == 0) {
+				current->s_context = ctx;
+				current->cap_bset &= (~remove_cap);
+				if (!found)
+					sys_alloc_s_info();
+				if (current->s_info != NULL)
+					current->s_info->flags |= flags;
+			}
+		}
+	}
+	return ret;
+}
+
diff -NurP --minimal linux-2.4.23-pre4/kernel/sys.c linux-2.4.23-pre4-ctx17d/kernel/sys.c
--- linux-2.4.23-pre4/kernel/sys.c	2003-09-13 00:50:17.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/kernel/sys.c	2003-09-13 17:19:02.000000000 +0200
@@ -6,6 +6,7 @@
 
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/vmalloc.h>
 #include <linux/utsname.h>
 #include <linux/mman.h>
 #include <linux/smp_lock.h>
@@ -513,7 +514,7 @@
 {
 	struct user_struct *new_user;
 
-	new_user = alloc_uid(new_ruid);
+	new_user = alloc_uid(current->s_context, new_ruid);
 	if (!new_user)
 		return -EAGAIN;
 	switch_uid(new_user);
@@ -1025,17 +1026,144 @@
 asmlinkage long sys_newuname(struct new_utsname * name)
 {
 	int errno = 0;
+	struct new_utsname tmp,*pttmp;
 
 	down_read(&uts_sem);
-	if (copy_to_user(name,&system_utsname,sizeof *name))
+	if (current->s_info != NULL) {
+		tmp = system_utsname;
+		strcpy (tmp.nodename,current->s_info->nodename);
+		strcpy (tmp.domainname,current->s_info->domainname);
+		pttmp = &tmp;
+	}
+	else
+		pttmp = &system_utsname;
+	if (copy_to_user(name,pttmp,sizeof *name))
 		errno = -EFAULT;
 	up_read(&uts_sem);
 	return errno;
 }
 
+/*
+	Decrease the reference count on the context_info member of a task
+	Free the struct if the reference count reach 0.
+*/
+void sys_release_s_info (struct task_struct *p)
+{
+	down_write (&uts_sem);
+	if (p->s_info != NULL) {
+		p->s_info->refcount--;
+		if (p->s_info->refcount == 0) {
+			vfree (p->s_info);
+			p->s_info = NULL;
+		}
+	}
+	up_write (&uts_sem);
+}
+/*
+	Increase the reference count on the context_info member of a task
+*/
+void sys_assign_s_info (struct task_struct *p)
+{
+	down_write (&uts_sem);
+	if (p->s_info)
+		p->s_info->refcount++;
+	up_write (&uts_sem);
+}
+
+/*
+	Alloc a new s_info to the current process and release
+	the one currently owned by the current process.
+*/
+void sys_alloc_s_info()
+{
+	struct context_info *s_info = vmalloc(sizeof(struct context_info));
+	if (s_info != NULL){
+		int i;
+		memset (s_info,0,sizeof(*s_info));
+		s_info->s_context[0] = current->s_context;
+		s_info->refcount = 1;
+		atomic_set (&s_info->ticks,current->counter);
+		s_info->flags = 0;
+		s_info->initpid = 0;
+		for (i=0; i<RLIM_NLIMITS; i++) {
+			s_info->rlim[i] = 0xffffffff;
+			atomic_set (&s_info->res[i],0);
+		}
+		down_read (&uts_sem);
+		if (current->s_info) {
+			strcpy (s_info->nodename,current->s_info->nodename);
+			strcpy (s_info->domainname,current->s_info->domainname);
+		} else {
+			strcpy (s_info->nodename,system_utsname.nodename);
+			strcpy (s_info->domainname,system_utsname.domainname);
+		}
+		up_read (&uts_sem);
+		sys_release_s_info (current);	
+		current->s_info = s_info;
+		/*
+			The current process is switching to a new context
+			so we preset the open file counter with
+			the file currently open by that process.
+			Some of those files may have been opened by
+			a parent, so do not strictly belong to this
+			process, so we kind of over bill the current process
+			but it is minimal.
+		*/
+		atomic_set (&s_info->res[RLIMIT_NOFILE]
+			,atomic_read(&current->files->count));
+	}
+}
+
+/*
+	Decrease the reference count on the ip_info struct
+	Free the struct if the reference count reach 0.
+*/
+void sys_release_ip_info (struct iproot_info *ip_info)
+{
+	if (ip_info != NULL){
+		if (atomic_dec_and_test(&ip_info->refcount)){
+			if (ip_info->mark != 0xdeadbeef){
+				printk ("sys_release_ip_info: broken signature %08lx, tell jack@solucorp.qc.ca\n",ip_info->mark);
+			}else{
+				// printk ("vfree s_info %d\n",p->pid);
+				vfree (ip_info);
+			}
+		}
+	}
+}
+/*
+	Increase the reference count on the ip_info member of a task
+*/
+void sys_assign_ip_info (struct iproot_info *ip_info)
+{
+	if (ip_info != NULL){
+		atomic_inc (&ip_info->refcount);
+		if (ip_info->mark != 0xdeadbeef){
+			printk ("sys_assign_ip_info: broken signature %08lx, tell jack@solucorp.qc.ca\n",ip_info->mark);
+		}
+	}
+}
+
+/*
+	Alloc a new ip_info to the current process and release
+	the one currently owned by the current process.
+*/
+void sys_alloc_ip_info()
+{
+	struct iproot_info *ip_info = vmalloc(sizeof(struct iproot_info));
+	// printk ("new s_info %d\n",current->pid);
+	memset (ip_info,0,sizeof(*ip_info));
+	ip_info->mark = 0xdeadbeef;
+	atomic_set (&ip_info->refcount,1);
+	sys_release_ip_info (current->ip_info);	
+	current->ip_info = ip_info;
+}
+
+
 asmlinkage long sys_sethostname(char *name, int len)
 {
 	int errno;
+	char *nodename;
 	char tmp[__NEW_UTS_LEN];
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -1044,9 +1172,12 @@
 		return -EINVAL;
 	down_write(&uts_sem);
 	errno = -EFAULT;
+	nodename = system_utsname.nodename;
+	if (current->s_info)
+		nodename = current->s_info->nodename;
 	if (!copy_from_user(tmp, name, len)) {
-		memcpy(system_utsname.nodename, tmp, len);
-		system_utsname.nodename[len] = 0;
+		memcpy(nodename, tmp, len);
+		nodename[len] = 0;
 		errno = 0;
 	}
 	up_write(&uts_sem);
@@ -1056,15 +1187,19 @@
 asmlinkage long sys_gethostname(char *name, int len)
 {
 	int i, errno;
+	char *nodename;
 
 	if (len < 0)
 		return -EINVAL;
 	down_read(&uts_sem);
-	i = 1 + strlen(system_utsname.nodename);
+	nodename = system_utsname.nodename;
+	if (current->s_info)
+		nodename = current->s_info->nodename;
+	i = 1 + strlen(nodename);
 	if (i > len)
 		i = len;
 	errno = 0;
-	if (copy_to_user(name, system_utsname.nodename, i))
+	if (copy_to_user(name, nodename, i))
 		errno = -EFAULT;
 	up_read(&uts_sem);
 	return errno;
@@ -1077,6 +1212,7 @@
 asmlinkage long sys_setdomainname(char *name, int len)
 {
 	int errno;
+	char *domainname;
 	char tmp[__NEW_UTS_LEN];
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -1085,10 +1221,12 @@
 		return -EINVAL;
 
 	down_write(&uts_sem);
+	domainname = system_utsname.domainname;
+	if (current->s_info) domainname = current->s_info->domainname;
 	errno = -EFAULT;
 	if (!copy_from_user(tmp, name, len)) {
-		memcpy(system_utsname.domainname, tmp, len);
-		system_utsname.domainname[len] = 0;
+		memcpy(domainname, tmp, len);
+		domainname[len] = 0;
 		errno = 0;
 	}
 	up_write(&uts_sem);
diff -NurP --minimal linux-2.4.23-pre4/kernel/sysctl.c linux-2.4.23-pre4-ctx17d/kernel/sysctl.c
--- linux-2.4.23-pre4/kernel/sysctl.c	2003-09-13 00:50:17.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/kernel/sysctl.c	2003-09-13 17:19:02.000000000 +0200
@@ -408,6 +408,8 @@
 
 static int test_perm(int mode, int op)
 {
+	if (!capable(CAP_SYS_ADMIN))
+		mode &= ~(0222);
 	if (!current->euid)
 		mode >>= 6;
 	else if (in_egroup_p(0))
@@ -823,7 +825,17 @@
 		  void *buffer, size_t *lenp)
 {
 	int r;
+	ctl_table tmp;
 
+	/* HACK for per s_context hostname and domainname */
+	if (current->s_info) {
+		tmp = *table;
+		table = &tmp;
+		if (table->data == (void*)&system_utsname.nodename)
+			tmp.data = &current->s_info->nodename;
+		else if (table->data == (void*)&system_utsname.domainname)
+			tmp.data = &current->s_info->domainname;
+	}
 	if (!write) {
 		down_read(&uts_sem);
 		r=proc_dostring(table,0,filp,buffer,lenp);
diff -NurP --minimal linux-2.4.23-pre4/kernel/timer.c linux-2.4.23-pre4-ctx17d/kernel/timer.c
--- linux-2.4.23-pre4/kernel/timer.c	2002-11-29 00:53:15.000000000 +0100
+++ linux-2.4.23-pre4-ctx17d/kernel/timer.c	2003-09-13 17:19:02.000000000 +0200
@@ -599,6 +599,10 @@
 
 	update_one_process(p, user_tick, system, cpu);
 	if (p->pid) {
+		if (p->s_info
+			&& (p->s_info->flags & S_CTX_INFO_SCHED) != 0)
+			atomic_dec (&p->s_info->ticks);
+		}
 		if (--p->counter <= 0) {
 			p->counter = 0;
 			/*
@@ -752,6 +756,10 @@
  */
 asmlinkage long sys_getpid(void)
 {
+	if (current->s_info != NULL
+		&& current->s_info->initpid == current->tgid)
+		/* We are faking process 1 for this security context */
+		return 1;
 	return current->tgid;
 }
 
@@ -798,6 +806,11 @@
 #endif
 		break;
 	}
+	if (pid != 0
+		&& current->s_info != NULL
+		&& current->s_info->initpid == pid)
+		/* We are faking process 1 for this security context */
+		pid = 1;
 	return pid;
 }
 
diff -NurP --minimal linux-2.4.23-pre4/kernel/user.c linux-2.4.23-pre4-ctx17d/kernel/user.c
--- linux-2.4.23-pre4/kernel/user.c	2003-09-13 00:50:17.000000000 +0200
+++ linux-2.4.23-pre4-ctx17d/kernel/user.c	2003-09-13 15:24:22.000000000 +0200
@@ -6,6 +6,19 @@
  * We have a per-user structure to keep track of how many
  * processes, files etc the user has claimed, in order to be
  * able to have per-user limits for system resources. 
+ *
+ * For the vserver project, the key is extended from UID to (SC,UID),
+ * with SC being the security context ID. Thus, each security context
+ * has independant per-UID resource usage counters.
+ *
+ * As a consequence, even if two UIDs are the same, the 'struct user *'
+ * in their task_struct could be different. I don't think any code cares.
+ *
+ * (vserver modifications done Sun Jan 13 08:48:45 CET 2002 by bof@bof.de)
+ *
+ * NOTE: For now, the hash function is unmodified: the same uid in several
+ * security contexts, will always sit on the same hash chain. This could
+ * be changed easily.
  */
 
 #include <linux/init.h>
@@ -56,7 +69,7 @@
 	*pprev = next;
 }
 
-static inline struct user_struct *uid_hash_find(uid_t uid, struct user_struct **hashent)
+static inline struct user_struct *uid_hash_find(int s_context, uid_t uid, struct user_struct **hashent)
 {
 	struct user_struct *next;
 
@@ -65,7 +78,7 @@
 		struct user_struct *up = next;
 		if (next) {
 			next = up->next;
-			if (up->uid != uid)
+			if (up->uid != uid || up->s_context != s_context)
 				continue;
 			atomic_inc(&up->__count);
 		}
@@ -82,13 +95,13 @@
 	}
 }
 
-struct user_struct * alloc_uid(uid_t uid)
+struct user_struct * alloc_uid(int s_context, uid_t uid)
 {
 	struct user_struct **hashent = uidhashentry(uid);
 	struct user_struct *up;
 
 	spin_lock(&uidhash_lock);
-	up = uid_hash_find(uid, hashent);
+	up = uid_hash_find(s_context, uid, hashent);
 	spin_unlock(&uidhash_lock);
 
 	if (!up) {
@@ -98,6 +111,7 @@
 		if (!new)
 			return NULL;
 		new->uid = uid;
+		new->s_context = s_context;
 		atomic_set(&new->__count, 1);
 		atomic_set(&new->processes, 0);
 		atomic_set(&new->files, 0);
@@ -107,7 +121,7 @@
 		 * on adding the same user already..
 		 */
 		spin_lock(&uidhash_lock);
-		up = uid_hash_find(uid, hashent);
+		up = uid_hash_find(s_context, uid, hashent);
 		if (up) {
 			kmem_cache_free(uid_cachep, new);
 		} else {
