diff -NurpP --minimal linux-2.4.20/arch/alpha/kernel/entry.S linux-2.4.20-vs1.00/arch/alpha/kernel/entry.S
--- linux-2.4.20/arch/alpha/kernel/entry.S	Sat Aug  3 02:39:42 2002
+++ linux-2.4.20-vs1.00/arch/alpha/kernel/entry.S	Sat Nov  1 10:36:51 2003
@@ -1044,8 +1044,8 @@ sys_call_table:
 	.quad alpha_ni_syscall			/* 270 */
 	.quad alpha_ni_syscall
 	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
-	.quad alpha_ni_syscall
+	.quad sys_new_s_context			/* 273 sys_virtual_context */
+	.quad sys_set_ipv4root			/* 274 borrowed for now */
 	.quad alpha_ni_syscall			/* 275 */
 	.quad alpha_ni_syscall
 	.quad alpha_ni_syscall
diff -NurpP --minimal linux-2.4.20/arch/i386/kernel/entry.S linux-2.4.20-vs1.00/arch/i386/kernel/entry.S
--- linux-2.4.20/arch/i386/kernel/entry.S	Fri Nov 29 00:53:09 2002
+++ linux-2.4.20-vs1.00/arch/i386/kernel/entry.S	Sat Nov  1 10:36:51 2003
@@ -657,6 +657,28 @@ ENTRY(sys_call_table)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 250 sys_alloc_hugepages */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_free_hugepages */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_exit_group */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 255 */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 260 */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 265 */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 270 */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_new_s_context)	/* 273 sys_virtual_context */
+	.long SYMBOL_NAME(sys_set_ipv4root)	/* 274 borrowed */
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -NurpP --minimal linux-2.4.20/arch/i386/kernel/ptrace.c linux-2.4.20-vs1.00/arch/i386/kernel/ptrace.c
--- linux-2.4.20/arch/i386/kernel/ptrace.c	Sat Aug  3 02:39:42 2002
+++ linux-2.4.20-vs1.00/arch/i386/kernel/ptrace.c	Sat Nov  1 10:36:51 2003
@@ -170,7 +170,7 @@ asmlinkage int sys_ptrace(long request, 
 	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 -NurpP --minimal linux-2.4.20/arch/ppc/kernel/misc.S linux-2.4.20-vs1.00/arch/ppc/kernel/misc.S
--- linux-2.4.20/arch/ppc/kernel/misc.S	Fri Nov 29 00:53:11 2002
+++ linux-2.4.20-vs1.00/arch/ppc/kernel/misc.S	Sat Nov  1 10:36:51 2003
@@ -1184,6 +1184,49 @@ _GLOBAL(sys_call_table)
 	.long sys_ni_syscall 	/*	reserved for sys_io_getevents */
 	.long sys_ni_syscall 	/* 230	reserved for sys_io_submit */
 	.long sys_ni_syscall 	/*	reserved for sys_io_cancel */
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall	/* 235 */
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall	/* 240 */
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall	/* 245 */
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall	/* 250 */
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall	/* 255 */
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall	/* 260 */
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall	/* 265 */
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_ni_syscall	/* 270 */
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_new_s_context	/* 273 sys_virtual_context */
+	.long sys_set_ipv4root	/* 274 borrowed */
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
diff -NurpP --minimal linux-2.4.20/arch/ppc/kernel/ptrace.c linux-2.4.20-vs1.00/arch/ppc/kernel/ptrace.c
--- linux-2.4.20/arch/ppc/kernel/ptrace.c	Fri Nov 29 00:53:11 2002
+++ linux-2.4.20-vs1.00/arch/ppc/kernel/ptrace.c	Sat Nov  1 10:36:51 2003
@@ -178,7 +178,7 @@ int sys_ptrace(long request, long pid, l
 	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 -NurpP --minimal linux-2.4.20/arch/sparc/kernel/systbls.S linux-2.4.20-vs1.00/arch/sparc/kernel/systbls.S
--- linux-2.4.20/arch/sparc/kernel/systbls.S	Sat Aug  3 02:39:43 2002
+++ linux-2.4.20-vs1.00/arch/sparc/kernel/systbls.S	Sat Nov  1 10:36:51 2003
@@ -70,7 +70,10 @@ sys_call_table:
 /*240*/	.long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 /*245*/	.long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-/*255*/	.long sys_nis_syscall, sys_nis_syscall
+/*255*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*260*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*265*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*270*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_new_s_context, sys_set_ipv4root
 
 #ifdef CONFIG_SUNOS_EMUL
 	/* Now the SunOS syscall table. */
diff -NurpP --minimal linux-2.4.20/arch/sparc64/kernel/entry.S linux-2.4.20-vs1.00/arch/sparc64/kernel/entry.S
--- linux-2.4.20/arch/sparc64/kernel/entry.S	Fri Nov 29 00:53:12 2002
+++ linux-2.4.20-vs1.00/arch/sparc64/kernel/entry.S	Sat Nov  1 10:36:51 2003
@@ -25,7 +25,7 @@
 
 #define curptr      g6
 
-#define NR_SYSCALLS 256      /* Each OS is different... */
+#define NR_SYSCALLS 275      /* Each OS is different... */
 
 	.text
 	.align		32
diff -NurpP --minimal linux-2.4.20/arch/sparc64/kernel/ptrace.c linux-2.4.20-vs1.00/arch/sparc64/kernel/ptrace.c
--- linux-2.4.20/arch/sparc64/kernel/ptrace.c	Fri Nov 29 00:53:12 2002
+++ linux-2.4.20-vs1.00/arch/sparc64/kernel/ptrace.c	Sat Nov  1 10:36:51 2003
@@ -156,7 +156,7 @@ asmlinkage void do_ptrace(struct pt_regs
 		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 -NurpP --minimal linux-2.4.20/arch/sparc64/kernel/systbls.S linux-2.4.20-vs1.00/arch/sparc64/kernel/systbls.S
--- linux-2.4.20/arch/sparc64/kernel/systbls.S	Sat Aug  3 02:39:43 2002
+++ linux-2.4.20-vs1.00/arch/sparc64/kernel/systbls.S	Sat Nov  1 10:36:51 2003
@@ -70,7 +70,10 @@ sys_call_table32:
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
 /*250*/	.word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
-	.word sys_aplib
+	.word sys_aplib, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*260*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*270*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_new_s_context, sys_set_ipv4root
 
 	/* Now the 64-bit native Linux syscall table. */
 
@@ -129,7 +132,10 @@ sys_call_table:
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-	.word sys_aplib
+	.word sys_aplib, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*260*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*270*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_new_s_context, sys_set_ipv4root
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -225,5 +231,12 @@ sunos_sys_table:
 	.word sunos_nosys, sunos_nosys
 /*250*/	.word sunos_nosys, sunos_nosys, sunos_nosys
 	.word sunos_nosys, sunos_nosys, sys_aplib
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys
 
 #endif
diff -NurpP --minimal linux-2.4.20/arch/x86_64/ia32/ia32entry.S linux-2.4.20-vs1.00/arch/x86_64/ia32/ia32entry.S
--- linux-2.4.20/arch/x86_64/ia32/ia32entry.S	Fri Nov 29 00:53:12 2002
+++ linux-2.4.20-vs1.00/arch/x86_64/ia32/ia32entry.S	Sat Nov  1 10:36:51 2003
@@ -366,21 +366,43 @@ ia32_sys_call_table:
 	.quad sys_removexattr	/* 235 */
 	.quad sys_lremovexattr
 	.quad sys_fremovexattr
-	.quad sys_tkill		/* 238 */ 
+	.quad sys_tkill
 	.quad sys_ni_syscall	/* sendfile64 */
-	.quad sys_ni_syscall	/* futex */
+	.quad sys_ni_syscall	/* 240 futex */
 	.quad sys_ni_syscall	/* sched_setaffinity */
 	.quad sys_ni_syscall	/* sched_getaffinity */
 	.quad sys_ni_syscall	/* set_threadarea */
 	.quad sys_ni_syscall	/* get_threadarea */
-	.quad sys_ni_syscall	/* io_setup */
+	.quad sys_ni_syscall	/* 245 io_setup */
 	.quad sys_ni_syscall	/* io_destroy */
 	.quad sys_ni_syscall	/* io_getevents */
 	.quad sys_ni_syscall	/* io_submit */
 	.quad sys_ni_syscall	/* io_cancel */
-	.quad sys_ni_syscall	/* alloc_hugepages */
+	.quad sys_ni_syscall	/* 250 alloc_hugepages */
 	.quad sys_ni_syscall	/* free_hugepages */
 	.quad sys_ni_syscall	/* exit_group */
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall	/* 255 */
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall	/* 260 */
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall	/* 265 */
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall	/* 270 */
+	.quad sys_ni_syscall
+	.quad sys_ni_syscall
+	.quad sys_new_s_context /* 273 sys_virtual_context */
+	.quad sys_set_ipv4root  /* 274 borrowed for now */
 
 ia32_syscall_end:		
 	.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
diff -NurpP --minimal linux-2.4.20/fs/devpts/inode.c linux-2.4.20-vs1.00/fs/devpts/inode.c
--- linux-2.4.20/fs/devpts/inode.c	Thu Oct 25 09:02:26 2001
+++ linux-2.4.20-vs1.00/fs/devpts/inode.c	Sat Nov  1 10:36:51 2003
@@ -24,6 +24,7 @@
 #include <linux/tty.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
+#include <linux/sched.h>
 
 #include "devpts_i.h"
 
@@ -180,6 +181,18 @@ static int devpts_statfs(struct super_bl
 
 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 +211,8 @@ void devpts_pty_new(int number, kdev_t d
 	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 -NurpP --minimal linux-2.4.20/fs/devpts/root.c linux-2.4.20-vs1.00/fs/devpts/root.c
--- linux-2.4.20/fs/devpts/root.c	Fri Dec 21 18:41:55 2001
+++ linux-2.4.20-vs1.00/fs/devpts/root.c	Sat Nov  1 10:36:51 2003
@@ -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,9 @@ static int devpts_root_readdir(struct fi
 	default:
 		while ( nr - 2 < sbi->max_ptys ) {
 			int ptynr = nr - 2;
-			if ( sbi->inodes[ptynr] ) {
+			struct inode *inode = sbi->inodes[ptynr];
+			if (inode && (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 +103,7 @@ static struct dentry *devpts_root_lookup
 	unsigned int entry;
 	int i;
 	const char *p;
+	struct inode *inode;
 
 	dentry->d_op    = &devpts_dentry_operations;
 
@@ -126,10 +130,15 @@ static struct dentry *devpts_root_lookup
 	if ( entry >= sbi->max_ptys )
 		return NULL;
 
-	if ( sbi->inodes[entry] )
-		atomic_inc(&sbi->inodes[entry]->i_count);
+	inode = sbi->inodes[entry];
+	if (inode && 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 -NurpP --minimal linux-2.4.20/fs/dquot.c linux-2.4.20-vs1.00/fs/dquot.c
--- linux-2.4.20/fs/dquot.c	Sat Aug  3 02:39:45 2002
+++ linux-2.4.20-vs1.00/fs/dquot.c	Sat Nov  1 10:36:51 2003
@@ -1403,11 +1403,11 @@ asmlinkage long sys_quotactl(int cmd, co
 		case Q_GETQUOTA:
 			if (((type == USRQUOTA && current->euid != id) ||
 			     (type == GRPQUOTA && !in_egroup_p(id))) &&
-			    !capable(CAP_SYS_ADMIN))
+			    !capable(CAP_SYS_ADMIN) && !capable(CAP_QUOTACTL))
 				goto out;
 			break;
 		default:
-			if (!capable(CAP_SYS_ADMIN))
+			if (!capable(CAP_SYS_ADMIN) && !capable(CAP_QUOTACTL))
 				goto out;
 	}
 
diff -NurpP --minimal linux-2.4.20/fs/exec.c linux-2.4.20-vs1.00/fs/exec.c
--- linux-2.4.20/fs/exec.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/exec.c	Sat Nov  1 10:36:51 2003
@@ -705,7 +705,7 @@ void compute_creds(struct linux_binprm *
 	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 -NurpP --minimal linux-2.4.20/fs/ext2/ialloc.c linux-2.4.20-vs1.00/fs/ext2/ialloc.c
--- linux-2.4.20/fs/ext2/ialloc.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/ext2/ialloc.c	Sat Nov  1 10:36:51 2003
@@ -388,7 +388,7 @@ repeat:
 	inode->u.ext2_i.i_new_inode = 1;
 	inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags & ~EXT2_BTREE_FL;
 	if (S_ISLNK(mode))
-		inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);
+		inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FILE_FL|EXT2_IMMUTABLE_LINK_FL|EXT2_APPEND_FL);
 	inode->u.ext2_i.i_block_group = group;
 	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
 		inode->i_flags |= S_SYNC;
diff -NurpP --minimal linux-2.4.20/fs/ext2/inode.c linux-2.4.20-vs1.00/fs/ext2/inode.c
--- linux-2.4.20/fs/ext2/inode.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/ext2/inode.c	Sat Nov  1 10:36:51 2003
@@ -46,6 +46,8 @@ void ext2_put_inode (struct inode * inod
 	ext2_discard_prealloc (inode);
 }
 
+static void ext2_truncate_nocheck (struct inode * inode);
+
 /*
  * Called at the last iput() if i_nlink is zero.
  */
@@ -62,7 +64,7 @@ void ext2_delete_inode (struct inode * i
 	ext2_update_inode(inode, IS_SYNC(inode));
 	inode->i_size = 0;
 	if (inode->i_blocks)
-		ext2_truncate (inode);
+		ext2_truncate_nocheck (inode);
 	ext2_free_inode (inode);
 
 	unlock_kernel();
@@ -786,7 +788,7 @@ static void ext2_free_branches(struct in
 		ext2_free_data(inode, p, q);
 }
 
-void ext2_truncate (struct inode * inode)
+static void ext2_truncate_nocheck (struct inode * inode)
 {
 	u32 *i_data = inode->u.ext2_i.i_data;
 	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
@@ -801,8 +803,6 @@ void ext2_truncate (struct inode * inode
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 	    S_ISLNK(inode->i_mode)))
 		return;
-	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-		return;
 
 	ext2_discard_prealloc(inode);
 
@@ -877,6 +877,13 @@ do_indirects:
 	}
 }
 
+void ext2_truncate (struct inode * inode)
+{
+	if (IS_APPEND(inode) || IS_IMMUTABLE_FILE(inode))
+		return;
+	ext2_truncate_nocheck (inode);
+}
+
 void ext2_read_inode (struct inode * inode)
 {
 	struct buffer_head * bh;
@@ -1005,9 +1012,13 @@ void ext2_read_inode (struct inode * ino
 		inode->i_attr_flags |= ATTR_FLAG_APPEND;
 		inode->i_flags |= S_APPEND;
 	}
-	if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL) {
-		inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;
-		inode->i_flags |= S_IMMUTABLE;
+	if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FILE_FL) {
+		inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE_FILE;
+		inode->i_flags |= S_IMMUTABLE_FILE;
+	}
+	if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_LINK_FL) {
+		inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE_LINK;
+		inode->i_flags |= S_IMMUTABLE_LINK;
 	}
 	if (inode->u.ext2_i.i_flags & EXT2_NOATIME_FL) {
 		inode->i_attr_flags |= ATTR_FLAG_NOATIME;
diff -NurpP --minimal linux-2.4.20/fs/ext2/ioctl.c linux-2.4.20-vs1.00/fs/ext2/ioctl.c
--- linux-2.4.20/fs/ext2/ioctl.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/ext2/ioctl.c	Sat Nov  1 10:36:51 2003
@@ -39,12 +39,12 @@ int ext2_ioctl (struct inode * inode, st
 		oldflags = inode->u.ext2_i.i_flags;
 
 		/*
-		 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
-		 * the relevant capability.
+		 * The IMMUTABLE_* and APPEND_ONLY flags can only be changed
+		 * by the relevant capability.
 		 *
 		 * This test looks nicer. Thanks to Pauline Middelink
 		 */
-		if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) {
+		if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FILE_FL | EXT2_IMMUTABLE_LINK_FL)) {
 			if (!capable(CAP_LINUX_IMMUTABLE))
 				return -EPERM;
 		}
@@ -61,10 +61,14 @@ int ext2_ioctl (struct inode * inode, st
 			inode->i_flags |= S_APPEND;
 		else
 			inode->i_flags &= ~S_APPEND;
-		if (flags & EXT2_IMMUTABLE_FL)
-			inode->i_flags |= S_IMMUTABLE;
+		if (flags & EXT2_IMMUTABLE_FILE_FL)
+			inode->i_flags |= S_IMMUTABLE_FILE;
 		else
-			inode->i_flags &= ~S_IMMUTABLE;
+			inode->i_flags &= ~S_IMMUTABLE_FILE;
+		if (flags & EXT2_IMMUTABLE_LINK_FL)
+			inode->i_flags |= S_IMMUTABLE_LINK;
+		else
+			inode->i_flags &= ~S_IMMUTABLE_LINK;
 		if (flags & EXT2_NOATIME_FL)
 			inode->i_flags |= S_NOATIME;
 		else
diff -NurpP --minimal linux-2.4.20/fs/ext3/ialloc.c linux-2.4.20-vs1.00/fs/ext3/ialloc.c
--- linux-2.4.20/fs/ext3/ialloc.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/ext3/ialloc.c	Sat Nov  1 10:36:51 2003
@@ -485,7 +485,7 @@ repeat:
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->u.ext3_i.i_flags = dir->u.ext3_i.i_flags & ~EXT3_INDEX_FL;
 	if (S_ISLNK(mode))
-		inode->u.ext3_i.i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL);
+		inode->u.ext3_i.i_flags &= ~(EXT3_IMMUTABLE_FILE_FL|EXT3_IMMUTABLE_LINK_FL|EXT3_APPEND_FL);
 #ifdef EXT3_FRAGMENTS
 	inode->u.ext3_i.i_faddr = 0;
 	inode->u.ext3_i.i_frag_no = 0;
diff -NurpP --minimal linux-2.4.20/fs/ext3/inode.c linux-2.4.20-vs1.00/fs/ext3/inode.c
--- linux-2.4.20/fs/ext3/inode.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/ext3/inode.c	Sat Nov  1 10:36:51 2003
@@ -157,6 +157,7 @@ void ext3_put_inode (struct inode * inod
 	ext3_discard_prealloc (inode);
 }
 
+static void ext3_truncate_nocheck (struct inode *inode);
 /*
  * Called at the last iput() if i_nlink is zero.
  */
@@ -186,7 +187,7 @@ void ext3_delete_inode (struct inode * i
 		handle->h_sync = 1;
 	inode->i_size = 0;
 	if (inode->i_blocks)
-		ext3_truncate(inode);
+		ext3_truncate_nocheck(inode);
 	/*
 	 * Kill off the orphan record which ext3_truncate created.
 	 * AKPM: I think this can be inside the above `if'.
@@ -1839,7 +1840,7 @@ static void ext3_free_branches(handle_t 
  * ext3_truncate() run will find them and release them.
  */
 
-void ext3_truncate(struct inode * inode)
+static void ext3_truncate_nocheck(struct inode * inode)
 {
 	handle_t *handle;
 	u32 *i_data = inode->u.ext3_i.i_data;
@@ -1855,8 +1856,6 @@ void ext3_truncate(struct inode * inode)
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 	    S_ISLNK(inode->i_mode)))
 		return;
-	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-		return;
 
 	ext3_discard_prealloc(inode);
 
@@ -1986,6 +1985,13 @@ out_stop:
 	ext3_journal_stop(handle, inode);
 }
 
+void ext3_truncate(struct inode * inode)
+{
+	if (IS_APPEND(inode) || IS_IMMUTABLE_FILE(inode))
+		return;
+	ext3_truncate_nocheck (inode);
+}
+
 /* 
  * ext3_get_inode_loc returns with an extra refcount against the
  * inode's underlying buffer_head on success. 
@@ -2159,9 +2165,13 @@ void ext3_read_inode(struct inode * inod
 		/* inode->i_attr_flags |= ATTR_FLAG_APPEND;	unused */
 		inode->i_flags |= S_APPEND;
 	}
-	if (inode->u.ext3_i.i_flags & EXT3_IMMUTABLE_FL) {
-		/* inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;	unused */
-		inode->i_flags |= S_IMMUTABLE;
+	if (inode->u.ext3_i.i_flags & EXT3_IMMUTABLE_FILE_FL) {
+		/* inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE_FILE;	unused */
+		inode->i_flags |= S_IMMUTABLE_FILE;
+	}
+	if (inode->u.ext3_i.i_flags & EXT3_IMMUTABLE_LINK_FL) {
+		/* inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE_LINK;	unused */
+		inode->i_flags |= S_IMMUTABLE_LINK;
 	}
 	if (inode->u.ext3_i.i_flags & EXT3_NOATIME_FL) {
 		/* inode->i_attr_flags |= ATTR_FLAG_NOATIME;	unused */
diff -NurpP --minimal linux-2.4.20/fs/ext3/ioctl.c linux-2.4.20-vs1.00/fs/ext3/ioctl.c
--- linux-2.4.20/fs/ext3/ioctl.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/ext3/ioctl.c	Sat Nov  1 10:36:51 2003
@@ -48,12 +48,12 @@ int ext3_ioctl (struct inode * inode, st
 		jflag = flags & EXT3_JOURNAL_DATA_FL;
 
 		/*
-		 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
-		 * the relevant capability.
+		 * The IMMUTABLE_* and APPEND_ONLY flags can only be changed
+		 * by the relevant capability.
 		 *
 		 * This test looks nicer. Thanks to Pauline Middelink
 		 */
-		if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) {
+		if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FILE_FL | EXT3_IMMUTABLE_LINK_FL)) {
 			if (!capable(CAP_LINUX_IMMUTABLE))
 				return -EPERM;
 		}
@@ -89,10 +89,14 @@ int ext3_ioctl (struct inode * inode, st
 			inode->i_flags |= S_APPEND;
 		else
 			inode->i_flags &= ~S_APPEND;
-		if (flags & EXT3_IMMUTABLE_FL)
-			inode->i_flags |= S_IMMUTABLE;
+		if (flags & EXT3_IMMUTABLE_FILE_FL)
+			inode->i_flags |= S_IMMUTABLE_FILE;
 		else
-			inode->i_flags &= ~S_IMMUTABLE;
+			inode->i_flags &= ~S_IMMUTABLE_FILE;
+		if (flags & EXT3_IMMUTABLE_LINK_FL)
+			inode->i_flags |= S_IMMUTABLE_LINK;
+		else
+			inode->i_flags &= ~S_IMMUTABLE_LINK;
 		if (flags & EXT3_NOATIME_FL)
 			inode->i_flags |= S_NOATIME;
 		else
diff -NurpP --minimal linux-2.4.20/fs/fat/file.c linux-2.4.20-vs1.00/fs/fat/file.c
--- linux-2.4.20/fs/fat/file.c	Sun Aug 12 19:56:56 2001
+++ linux-2.4.20-vs1.00/fs/fat/file.c	Sat Nov  1 10:36:51 2003
@@ -119,7 +119,7 @@ void fat_truncate(struct inode *inode)
 	/* Why no return value?  Surely the disk could fail... */
 	if (IS_RDONLY (inode))
 		return /* -EPERM */;
-	if (IS_IMMUTABLE(inode))
+	if (IS_IMMUTABLE_FILE(inode))
 		return /* -EPERM */;
 	cluster = 1 << sbi->cluster_bits;
 	/* 
diff -NurpP --minimal linux-2.4.20/fs/fat/inode.c linux-2.4.20-vs1.00/fs/fat/inode.c
--- linux-2.4.20/fs/fat/inode.c	Sat Aug  3 02:39:45 2002
+++ linux-2.4.20-vs1.00/fs/fat/inode.c	Sat Nov  1 10:36:51 2003
@@ -949,7 +949,7 @@ static void fat_fill_inode(struct inode 
 	}
 	if(de->attr & ATTR_SYS)
 		if (sbi->options.sys_immutable)
-			inode->i_flags |= S_IMMUTABLE;
+			inode->i_flags |= S_IMMUTABLE_FILE;
 	MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
 	/* this is as close to the truth as we can get ... */
 	inode->i_blksize = 1 << sbi->cluster_bits;
diff -NurpP --minimal linux-2.4.20/fs/hpfs/file.c linux-2.4.20-vs1.00/fs/hpfs/file.c
--- linux-2.4.20/fs/hpfs/file.c	Mon Aug 13 02:37:53 2001
+++ linux-2.4.20-vs1.00/fs/hpfs/file.c	Sat Nov  1 10:36:51 2003
@@ -60,7 +60,7 @@ secno hpfs_bmap(struct inode *inode, uns
 
 void hpfs_truncate(struct inode *i)
 {
-	if (IS_IMMUTABLE(i)) return /*-EPERM*/;
+	if (IS_IMMUTABLE_FILE(i)) return /*-EPERM*/;
 	i->i_hpfs_n_secs = 0;
 	i->i_blocks = 1 + ((i->i_size + 511) >> 9);
 	i->u.hpfs_i.mmu_private = i->i_size;
diff -NurpP --minimal linux-2.4.20/fs/intermezzo/vfs.c linux-2.4.20-vs1.00/fs/intermezzo/vfs.c
--- linux-2.4.20/fs/intermezzo/vfs.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/intermezzo/vfs.c	Sat Nov  1 10:36:51 2003
@@ -140,7 +140,7 @@ static inline int may_delete(struct inod
         if (IS_APPEND(dir))
                 return -EPERM;
         if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
-            IS_IMMUTABLE(victim->d_inode))
+            IS_IMMUTABLE_LINK(victim->d_inode))
                 return -EPERM;
         if (isdir) {
                 if (!S_ISDIR(victim->d_inode->i_mode))
@@ -262,7 +262,7 @@ int presto_settime(struct presto_file_se
                         return -EROFS;
                 }
 
-                if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+                if (IS_IMMUTABLE_FILE(inode) || IS_APPEND(inode)) {
                         EXIT;
                         return -EPERM;
                 }
@@ -377,7 +377,7 @@ int presto_do_setattr(struct presto_file
                 return -EROFS;
         }
 
-        if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+        if (IS_IMMUTABLE_FILE(inode) || IS_APPEND(inode)) {
                 EXIT;
                 return -EPERM;
         }
@@ -772,7 +772,7 @@ int presto_do_link(struct presto_file_se
          * A link to an append-only or immutable file cannot be created.
          */
         error = -EPERM;
-        if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) {
+        if (IS_APPEND(inode) || IS_IMMUTABLE_LINK(inode)) {
                 EXIT;
                 goto exit_lock;
         }
@@ -2362,7 +2362,7 @@ int presto_do_set_ext_attr(struct presto
                 return -EROFS;
         }
 
-        if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+        if (IS_IMMUTABLE_FILE(inode) || IS_APPEND(inode)) {
                 EXIT;
                 return -EPERM;
         }
diff -NurpP --minimal linux-2.4.20/fs/jfs/xattr.c linux-2.4.20-vs1.00/fs/jfs/xattr.c
--- linux-2.4.20/fs/jfs/xattr.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/jfs/xattr.c	Sat Nov  1 10:36:51 2003
@@ -646,7 +646,7 @@ static int can_set_xattr(struct inode *i
 	if (IS_RDONLY(inode))
 		return -EROFS;
 
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || S_ISLNK(inode->i_mode))
+	if (IS_IMMUTABLE_FILE(inode) || IS_APPEND(inode) || S_ISLNK(inode->i_mode))
 		return -EPERM;
 
 	if((strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) != 0) &&
diff -NurpP --minimal linux-2.4.20/fs/namei.c linux-2.4.20-vs1.00/fs/namei.c
--- linux-2.4.20/fs/namei.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/namei.c	Sat Nov  1 10:36:51 2003
@@ -152,6 +152,15 @@ int vfs_permission(struct inode * inode,
 {
 	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.
@@ -163,7 +172,7 @@ int vfs_permission(struct inode * inode,
 		/*
 		 * Nobody gets write access to an immutable file.
 		 */
-		if (IS_IMMUTABLE(inode))
+		if (IS_IMMUTABLE_FILE(inode))
 			return -EACCES;
 	}
 
@@ -902,8 +911,7 @@ static inline int may_delete(struct inod
 		return error;
 	if (IS_APPEND(dir))
 		return -EPERM;
-	if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
-	    IS_IMMUTABLE(victim->d_inode))
+	if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||IS_IMMUTABLE_LINK(victim->d_inode))
 		return -EPERM;
 	if (isdir) {
 		if (!S_ISDIR(victim->d_inode->i_mode))
@@ -1616,7 +1624,7 @@ int vfs_link(struct dentry *old_dentry, 
 	 * A link to an append-only or immutable file cannot be created.
 	 */
 	error = -EPERM;
-	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+	if (IS_APPEND(inode) || IS_IMMUTABLE_LINK(inode))
 		goto exit_lock;
 	if (!dir->i_op || !dir->i_op->link)
 		goto exit_lock;
diff -NurpP --minimal linux-2.4.20/fs/nfsd/vfs.c linux-2.4.20-vs1.00/fs/nfsd/vfs.c
--- linux-2.4.20/fs/nfsd/vfs.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/nfsd/vfs.c	Sat Nov  1 10:36:51 2003
@@ -1476,7 +1476,7 @@ nfsd_permission(struct svc_export *exp, 
 	if (acc == MAY_NOP)
 		return 0;
 #if 0
-	dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",
+	dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s%s\n",
 		acc,
 		(acc & MAY_READ)?	" read"  : "",
 		(acc & MAY_WRITE)?	" write" : "",
@@ -1486,7 +1486,8 @@ nfsd_permission(struct svc_export *exp, 
 		(acc & MAY_LOCK)?	" lock"  : "",
 		(acc & MAY_OWNER_OVERRIDE)? " owneroverride" : "",
 		inode->i_mode,
-		IS_IMMUTABLE(inode)?	" immut" : "",
+		IS_IMMUTABLE_FILE(inode)? " immut(F)" : "",
+		IS_IMMUTABLE_LINK(inode)? " immut(L)" : "",
 		IS_APPEND(inode)?	" append" : "",
 		IS_RDONLY(inode)?	" ro" : "");
 	dprintk("      owner %d/%d user %d/%d\n",
@@ -1505,7 +1506,7 @@ nfsd_permission(struct svc_export *exp, 
 	 && (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC))) {
 		if (EX_RDONLY(exp) || IS_RDONLY(inode))
 			return nfserr_rofs;
-		if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
+		if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE_FILE(inode))
 			return nfserr_perm;
 	}
 	if ((acc & MAY_TRUNC) && IS_APPEND(inode))
diff -NurpP --minimal linux-2.4.20/fs/open.c linux-2.4.20-vs1.00/fs/open.c
--- linux-2.4.20/fs/open.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/open.c	Sat Nov  1 10:36:51 2003
@@ -146,7 +146,7 @@ static inline long do_sys_truncate(const
 		goto dput_and_out;
 
 	error = -EPERM;
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+	if (IS_IMMUTABLE_FILE(inode) || IS_APPEND(inode))
 		goto dput_and_out;
 
 	/*
@@ -478,7 +478,7 @@ asmlinkage long sys_fchmod(unsigned int 
 	if (IS_RDONLY(inode))
 		goto out_putf;
 	err = -EPERM;
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+	if (IS_IMMUTABLE_FILE(inode) || IS_APPEND(inode))
 		goto out_putf;
 	if (mode == (mode_t) -1)
 		mode = inode->i_mode;
@@ -509,7 +509,7 @@ asmlinkage long sys_chmod(const char * f
 		goto dput_and_out;
 
 	error = -EPERM;
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+	if (IS_IMMUTABLE_FILE(inode) || IS_APPEND(inode))
 		goto dput_and_out;
 
 	if (mode == (mode_t) -1)
@@ -539,7 +539,7 @@ static int chown_common(struct dentry * 
 	if (IS_RDONLY(inode))
 		goto out;
 	error = -EPERM;
-	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+	if (IS_IMMUTABLE_FILE(inode) || IS_APPEND(inode))
 		goto out;
 	if (user == (uid_t) -1)
 		user = inode->i_uid;
diff -NurpP --minimal linux-2.4.20/fs/proc/array.c linux-2.4.20-vs1.00/fs/proc/array.c
--- linux-2.4.20/fs/proc/array.c	Sat Aug  3 02:39:45 2002
+++ linux-2.4.20-vs1.00/fs/proc/array.c	Sat Nov  1 10:36:51 2003
@@ -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 const char * get_task_stat
 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
+		&& current->s_info->initpid == ppid)
+		ppid = 1;
 	buffer += sprintf(buffer,
 		"State:\t%s\n"
 		"Tgid:\t%d\n"
@@ -158,7 +164,7 @@ static inline char * task_state(struct t
 		"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 @@ static inline char *task_cap(struct task
 {
     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 @@ int proc_pid_status(struct task_struct *
 	}
 	buffer = task_sig(task, buffer);
 	buffer = task_cap(task, buffer);
+#ifdef __NR_new_s_context
+	if (task->s_info) {
+		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) {
+		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"
+			,atomic_read(&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,8 @@ int proc_pid_stat(struct task_struct *ta
 
 	read_lock(&tasklist_lock);
 	ppid = task->pid ? task->p_opptr->pid : 0;
+	if (current->s_info && 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 -NurpP --minimal linux-2.4.20/fs/proc/base.c linux-2.4.20-vs1.00/fs/proc/base.c
--- linux-2.4.20/fs/proc/base.c	Sat Aug  3 02:39:45 2002
+++ linux-2.4.20-vs1.00/fs/proc/base.c	Sat Nov  1 10:36:51 2003
@@ -1019,6 +1019,11 @@ struct dentry *proc_pid_lookup(struct in
 	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);
@@ -1029,7 +1034,7 @@ struct dentry *proc_pid_lookup(struct in
 	inode->i_op = &proc_base_inode_operations;
 	inode->i_fop = &proc_base_operations;
 	inode->i_nlink = 3;
-	inode->i_flags|=S_IMMUTABLE;
+	inode->i_flags|=S_IMMUTABLE_FILE;
 
 	dentry->d_op = &pid_base_dentry_operations;
 	d_add(dentry, inode);
@@ -1064,6 +1069,20 @@ static int get_pid_list(int index, unsig
 	for_each_task(p) {
 		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 && current->s_info->initpid == pid)
 			continue;
 		if (--index >= 0)
 			continue;
diff -NurpP --minimal linux-2.4.20/fs/reiserfs/inode.c linux-2.4.20-vs1.00/fs/reiserfs/inode.c
--- linux-2.4.20/fs/reiserfs/inode.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/reiserfs/inode.c	Sat Nov  1 10:36:51 2003
@@ -1548,7 +1548,7 @@ struct inode * reiserfs_new_inode (struc
 
     /* symlink cannot be immutable or append only, right? */
     if( S_ISLNK( inode -> i_mode ) )
-	    inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND );
+	    inode -> i_flags &= ~ ( S_IMMUTABLE_FILE | S_APPEND );
 
     inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
     inode->i_size = i_size;
@@ -2082,10 +2082,14 @@ void sd_attrs_to_i_attrs( __u16 sd_attrs
 			inode -> i_flags |= S_SYNC;
 		else
 			inode -> i_flags &= ~S_SYNC;
-		if( sd_attrs & REISERFS_IMMUTABLE_FL )
-			inode -> i_flags |= S_IMMUTABLE;
+		if( sd_attrs & REISERFS_IMMUTABLE_FILE_FL )
+			inode -> i_flags |= S_IMMUTABLE_FILE;
 		else
-			inode -> i_flags &= ~S_IMMUTABLE;
+			inode -> i_flags &= ~S_IMMUTABLE_FILE;
+		if( sd_attrs & REISERFS_IMMUTABLE_LINK_FL )
+			inode -> i_flags |= S_IMMUTABLE_LINK;
+		else
+			inode -> i_flags &= ~S_IMMUTABLE_LINK;
 		if( sd_attrs & REISERFS_NOATIME_FL )
 			inode -> i_flags |= S_NOATIME;
 		else
@@ -2100,10 +2104,14 @@ void sd_attrs_to_i_attrs( __u16 sd_attrs
 void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs )
 {
 	if( reiserfs_attrs( inode -> i_sb ) ) {
-		if( inode -> i_flags & S_IMMUTABLE )
-			*sd_attrs |= REISERFS_IMMUTABLE_FL;
+		if( inode -> i_flags & S_IMMUTABLE_FILE )
+			*sd_attrs |= REISERFS_IMMUTABLE_FILE_FL;
 		else
-			*sd_attrs &= ~REISERFS_IMMUTABLE_FL;
+			*sd_attrs &= ~REISERFS_IMMUTABLE_FILE_FL;
+		if( inode -> i_flags & S_IMMUTABLE_LINK )
+			*sd_attrs |= REISERFS_IMMUTABLE_LINK_FL;
+		else
+			*sd_attrs &= ~REISERFS_IMMUTABLE_LINK_FL;
 		if( inode -> i_flags & S_SYNC )
 			*sd_attrs |= REISERFS_SYNC_FL;
 		else
diff -NurpP --minimal linux-2.4.20/fs/reiserfs/ioctl.c linux-2.4.20-vs1.00/fs/reiserfs/ioctl.c
--- linux-2.4.20/fs/reiserfs/ioctl.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/reiserfs/ioctl.c	Sat Nov  1 10:36:51 2003
@@ -51,7 +51,7 @@ int reiserfs_ioctl (struct inode * inode
 		if (get_user(flags, (int *) arg))
 			return -EFAULT;
 
-		if ( ( flags & REISERFS_IMMUTABLE_FL ) && 
+		if ( ( flags & (REISERFS_IMMUTABLE_FILE_FL | REISERFS_IMMUTABLE_LINK_FL)) &&
 		     !capable( CAP_LINUX_IMMUTABLE ) )
 			return -EPERM;
 			
diff -NurpP --minimal linux-2.4.20/fs/udf/inode.c linux-2.4.20-vs1.00/fs/udf/inode.c
--- linux-2.4.20/fs/udf/inode.c	Sat Aug  3 02:39:45 2002
+++ linux-2.4.20-vs1.00/fs/udf/inode.c	Sat Nov  1 10:36:51 2003
@@ -860,7 +860,7 @@ void udf_truncate(struct inode * inode)
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 			S_ISLNK(inode->i_mode)))
 		return;
-	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+	if (IS_APPEND(inode) || IS_IMMUTABLE_FILE(inode))
 		return;
 
 	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
diff -NurpP --minimal linux-2.4.20/fs/ufs/truncate.c linux-2.4.20-vs1.00/fs/ufs/truncate.c
--- linux-2.4.20/fs/ufs/truncate.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/fs/ufs/truncate.c	Sat Nov  1 10:36:51 2003
@@ -434,7 +434,7 @@ void ufs_truncate (struct inode * inode)
 
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
 		return;
-	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+	if (IS_APPEND(inode) || IS_IMMUTABLE_FILE(inode))
 		return;
 	while (1) {
 		retry = ufs_trunc_direct(inode);
diff -NurpP --minimal linux-2.4.20/include/asm-alpha/unistd.h linux-2.4.20-vs1.00/include/asm-alpha/unistd.h
--- linux-2.4.20/include/asm-alpha/unistd.h	Sat Aug  3 02:39:45 2002
+++ linux-2.4.20-vs1.00/include/asm-alpha/unistd.h	Sat Nov  1 10:36:51 2003
@@ -233,6 +233,8 @@
 #define __NR_osf_memcntl	260	/* not implemented */
 #define __NR_osf_fdatasync	261	/* not implemented */
 
+#define __NR_new_s_context	273
+#define __NR_set_ipv4root	274
 
 /*
  * Linux-specific system calls begin at 300
diff -NurpP --minimal linux-2.4.20/include/asm-i386/unistd.h linux-2.4.20-vs1.00/include/asm-i386/unistd.h
--- linux-2.4.20/include/asm-i386/unistd.h	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/include/asm-i386/unistd.h	Sat Nov  1 10:36:51 2003
@@ -257,6 +257,8 @@
 #define __NR_alloc_hugepages	250
 #define __NR_free_hugepages	251
 #define __NR_exit_group		252
+#define __NR_new_s_context      273
+#define __NR_set_ipv4root       274
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -NurpP --minimal linux-2.4.20/include/asm-ppc/unistd.h linux-2.4.20-vs1.00/include/asm-ppc/unistd.h
--- linux-2.4.20/include/asm-ppc/unistd.h	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/include/asm-ppc/unistd.h	Sat Nov  1 10:36:51 2003
@@ -241,6 +241,8 @@
 #define __NR_io_submit		230
 #define __NR_io_cancel		231
 #endif
+#define __NR_new_s_context      273
+#define __NR_set_ipv4root       274
 
 #define __NR(n)	#n
 
diff -NurpP --minimal linux-2.4.20/include/asm-sparc/unistd.h linux-2.4.20-vs1.00/include/asm-sparc/unistd.h
--- linux-2.4.20/include/asm-sparc/unistd.h	Sat Aug  3 02:39:45 2002
+++ linux-2.4.20-vs1.00/include/asm-sparc/unistd.h	Sat Nov  1 10:36:51 2003
@@ -271,6 +271,8 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
+#define __NR_new_s_context	273
+#define __NR_set_ipv4root	274
 
 #define _syscall0(type,name) \
 type name(void) \
diff -NurpP --minimal linux-2.4.20/include/asm-sparc64/unistd.h linux-2.4.20-vs1.00/include/asm-sparc64/unistd.h
--- linux-2.4.20/include/asm-sparc64/unistd.h	Sat Aug  3 02:39:45 2002
+++ linux-2.4.20-vs1.00/include/asm-sparc64/unistd.h	Sat Nov  1 10:36:51 2003
@@ -273,6 +273,8 @@
 #define __NR_fdatasync          253
 #define __NR_nfsservctl         254
 #define __NR_aplib              255
+#define __NR_new_s_context	273
+#define __NR_set_ipv4root	274
 
 #define _syscall0(type,name) \
 type name(void) \
diff -NurpP --minimal linux-2.4.20/include/asm-x86_64/unistd.h linux-2.4.20-vs1.00/include/asm-x86_64/unistd.h
--- linux-2.4.20/include/asm-x86_64/unistd.h	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/include/asm-x86_64/unistd.h	Sat Nov  1 10:36:51 2003
@@ -483,8 +483,12 @@ __SYSCALL(__NR_io_submit, sys_ni_syscall
 __SYSCALL(__NR_io_cancel, sys_ni_syscall)
 #define __NR_get_thread_area	211
 __SYSCALL(__NR_get_thread_area, sys_ni_syscall)
+#define __NR_new_s_context 273
+__SYSCALL(__NR_new_s_context, sys_new_s_context)
+#define __NR_set_ipv4root 274
+__SYSCALL(__NR_set_ipv4root, sys_set_ipv4root)
 
-#define __NR_syscall_max __NR_get_thread_area
+#define __NR_syscall_max __NR_set_ipv4root
 
 #ifndef __NO_STUBS
 
diff -NurpP --minimal linux-2.4.20/include/linux/capability.h linux-2.4.20-vs1.00/include/linux/capability.h
--- linux-2.4.20/include/linux/capability.h	Thu Nov 22 20:46:19 2001
+++ linux-2.4.20-vs1.00/include/linux/capability.h	Sat Nov  1 10:38:08 2003
@@ -130,7 +130,8 @@ typedef __u32 kernel_cap_t;
 
 #define CAP_SETPCAP          8
 
-/* Allow modification of S_IMMUTABLE and S_APPEND file attributes */
+/* Allow modification of S_IMMUTABLE_* and S_APPEND file
+   attributes */
 
 #define CAP_LINUX_IMMUTABLE  9
 
@@ -231,6 +232,7 @@ typedef __u32 kernel_cap_t;
 /* 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
 
@@ -278,6 +280,10 @@ typedef __u32 kernel_cap_t;
 /* Allow taking of leases on files */
 
 #define CAP_LEASE            28
+
+/* Allow quotactl */
+
+#define CAP_QUOTACTL         29
 
 #ifdef __KERNEL__
 /* 
diff -NurpP --minimal linux-2.4.20/include/linux/devpts_fs_info.h linux-2.4.20-vs1.00/include/linux/devpts_fs_info.h
--- linux-2.4.20/include/linux/devpts_fs_info.h	Thu Jan  1 01:00:00 1970
+++ linux-2.4.20-vs1.00/include/linux/devpts_fs_info.h	Sat Nov  1 10:36:51 2003
@@ -0,0 +1,4 @@
+struct devpts_inode_info {
+	int s_context;
+};
+
diff -NurpP --minimal linux-2.4.20/include/linux/ext2_fs.h linux-2.4.20-vs1.00/include/linux/ext2_fs.h
--- linux-2.4.20/include/linux/ext2_fs.h	Thu Nov 22 20:46:52 2001
+++ linux-2.4.20-vs1.00/include/linux/ext2_fs.h	Sat Nov  1 10:39:10 2003
@@ -187,7 +187,7 @@ struct ext2_group_desc
 #define	EXT2_UNRM_FL			0x00000002 /* Undelete */
 #define	EXT2_COMPR_FL			0x00000004 /* Compress file */
 #define EXT2_SYNC_FL			0x00000008 /* Synchronous updates */
-#define EXT2_IMMUTABLE_FL		0x00000010 /* Immutable file */
+#define EXT2_IMMUTABLE_FILE_FL		0x00000010 /* Immutable file */
 #define EXT2_APPEND_FL			0x00000020 /* writes to file may only append */
 #define EXT2_NODUMP_FL			0x00000040 /* do not dump file */
 #define EXT2_NOATIME_FL			0x00000080 /* do not update atime */
@@ -198,10 +198,11 @@ struct ext2_group_desc
 #define EXT2_ECOMPR_FL			0x00000800 /* Compression error */
 /* End compression flags --- maybe not all used */	
 #define EXT2_BTREE_FL			0x00001000 /* btree format dir */
+#define EXT2_IMMUTABLE_LINK_FL          0x00008000 /* Immutable link */
 #define EXT2_RESERVED_FL		0x80000000 /* reserved for ext2 lib */
 
-#define EXT2_FL_USER_VISIBLE		0x00001FFF /* User visible flags */
-#define EXT2_FL_USER_MODIFIABLE		0x000000FF /* User modifiable flags */
+#define EXT2_FL_USER_VISIBLE		0x00009FFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE		0x000080FF /* User modifiable flags */
 
 /*
  * ioctl commands
diff -NurpP --minimal linux-2.4.20/include/linux/ext3_fs.h linux-2.4.20-vs1.00/include/linux/ext3_fs.h
--- linux-2.4.20/include/linux/ext3_fs.h	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/include/linux/ext3_fs.h	Sat Nov  1 10:39:16 2003
@@ -190,7 +190,7 @@ struct ext3_group_desc
 #define	EXT3_UNRM_FL			0x00000002 /* Undelete */
 #define	EXT3_COMPR_FL			0x00000004 /* Compress file */
 #define EXT3_SYNC_FL			0x00000008 /* Synchronous updates */
-#define EXT3_IMMUTABLE_FL		0x00000010 /* Immutable file */
+#define EXT3_IMMUTABLE_FILE_FL		0x00000010 /* Immutable file */
 #define EXT3_APPEND_FL			0x00000020 /* writes to file may only append */
 #define EXT3_NODUMP_FL			0x00000040 /* do not dump file */
 #define EXT3_NOATIME_FL			0x00000080 /* do not update atime */
@@ -203,10 +203,11 @@ struct ext3_group_desc
 #define EXT3_INDEX_FL			0x00001000 /* hash-indexed directory */
 #define EXT3_IMAGIC_FL			0x00002000 /* AFS directory */
 #define EXT3_JOURNAL_DATA_FL		0x00004000 /* file data should be journaled */
+#define EXT3_IMMUTABLE_LINK_FL		0x00008000 /* Immutable link */
 #define EXT3_RESERVED_FL		0x80000000 /* reserved for ext3 lib */
 
-#define EXT3_FL_USER_VISIBLE		0x00005FFF /* User visible flags */
-#define EXT3_FL_USER_MODIFIABLE		0x000000FF /* User modifiable flags */
+#define EXT3_FL_USER_VISIBLE		0x0000DFFF /* User visible flags */
+#define EXT3_FL_USER_MODIFIABLE		0x000080FF /* User modifiable flags */
 
 /*
  * Inode dynamic state flags
diff -NurpP --minimal linux-2.4.20/include/linux/fs.h linux-2.4.20-vs1.00/include/linux/fs.h
--- linux-2.4.20/include/linux/fs.h	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/include/linux/fs.h	Sat Nov  1 10:38:08 2003
@@ -132,9 +132,10 @@ extern int leases_enable, dir_notify_ena
 #define S_NOATIME	2	/* Do not update access times */
 #define S_QUOTA		4	/* Quota initialized for file */
 #define S_APPEND	8	/* Append-only file */
-#define S_IMMUTABLE	16	/* Immutable file */
+#define S_IMMUTABLE_FILE	16	/* Immutable file */
 #define S_DEAD		32	/* removed, but still open directory */
 #define S_NOQUOTA	64	/* Inode is not counted to quota */
+#define S_IMMUTABLE_LINK	128	/* Immutable links */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -158,7 +159,8 @@ extern int leases_enable, dir_notify_ena
 #define IS_QUOTAINIT(inode)	((inode)->i_flags & S_QUOTA)
 #define IS_NOQUOTA(inode)	((inode)->i_flags & S_NOQUOTA)
 #define IS_APPEND(inode)	((inode)->i_flags & S_APPEND)
-#define IS_IMMUTABLE(inode)	((inode)->i_flags & S_IMMUTABLE)
+#define IS_IMMUTABLE_FILE(inode)	((inode)->i_flags & S_IMMUTABLE_FILE)
+#define IS_IMMUTABLE_LINK(inode) ((((inode)->i_flags & S_IMMUTABLE_FILE) << 3) ^ ((inode)->i_flags & S_IMMUTABLE_LINK) )
 #define IS_NOATIME(inode)	(__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME))
 #define IS_NODIRATIME(inode)	__IS_FLG(inode, MS_NODIRATIME)
 
@@ -320,6 +322,7 @@ extern void set_bh_page(struct buffer_he
 #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
@@ -364,8 +367,9 @@ struct iattr {
 #define ATTR_FLAG_SYNCRONOUS	1 	/* Syncronous write */
 #define ATTR_FLAG_NOATIME	2 	/* Don't update atime */
 #define ATTR_FLAG_APPEND	4 	/* Append-only file */
-#define ATTR_FLAG_IMMUTABLE	8 	/* Immutable file */
+#define ATTR_FLAG_IMMUTABLE_FILE	8	/* Immutable file */
 #define ATTR_FLAG_NODIRATIME	16 	/* Don't update atime for directory */
+#define ATTR_FLAG_IMMUTABLE_LINK	32	/* Immutable file */
 
 /*
  * Includes for diskquotas and mount structures.
@@ -510,6 +514,7 @@ struct inode {
 		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 -NurpP --minimal linux-2.4.20/include/linux/reiserfs_fs.h linux-2.4.20-vs1.00/include/linux/reiserfs_fs.h
--- linux-2.4.20/include/linux/reiserfs_fs.h	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/include/linux/reiserfs_fs.h	Sat Nov  1 10:40:14 2003
@@ -736,7 +736,8 @@ struct stat_data_v1
 
 /* we want common flags to have the same values as in ext2,
    so chattr(1) will work without problems */
-#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
+#define REISERFS_IMMUTABLE_FILE_FL EXT2_IMMUTABLE_FILE_FL
+#define REISERFS_IMMUTABLE_LINK_FL EXT2_IMMUTABLE_LINK_FL
 #define REISERFS_SYNC_FL      EXT2_SYNC_FL
 #define REISERFS_NOATIME_FL   EXT2_NOATIME_FL
 #define REISERFS_NODUMP_FL    EXT2_NODUMP_FL
@@ -752,7 +753,8 @@ struct stat_data_v1
 #define REISERFS_NOTAIL_FL    (0x00008000) /* EXT2_NOTAIL_FL */
 
 /* persistent flags that file inherits from the parent directory */
-#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL |	\
+#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FILE_FL |	\
+				REISERFS_IMMUTABLE_LINK_FL |	\
 				REISERFS_SYNC_FL |	\
 				REISERFS_NOATIME_FL |	\
 				REISERFS_NODUMP_FL |	\
diff -NurpP --minimal linux-2.4.20/include/linux/sched.h linux-2.4.20-vs1.00/include/linux/sched.h
--- linux-2.4.20/include/linux/sched.h	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/include/linux/sched.h	Sat Nov  1 10:38:08 2003
@@ -274,6 +274,7 @@ struct user_struct {
 	/* Hash table maintenance information */
 	struct user_struct *next, **pprev;
 	uid_t uid;
+	int s_context;
 };
 
 #define get_current_user() ({ 				\
@@ -281,6 +282,63 @@ struct user_struct {
 	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)
 
@@ -407,6 +465,12 @@ struct task_struct {
 	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;
 	
@@ -510,6 +574,7 @@ extern struct exec_domain	default_exec_d
     blocked:		{{0}},						\
     alloc_lock:		SPIN_LOCK_UNLOCKED,				\
     journal_info:	NULL,						\
+    cap_bset:		CAP_INIT_EFF_SET,				\
 }
 
 
@@ -574,7 +639,7 @@ static inline void task_release_cpu(stru
 }
 
 /* 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 *);
 
 #include <asm/current.h>
@@ -942,6 +1007,14 @@ static inline char * d_path(struct dentr
 	mntput(rootmnt);
 	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)
 {
diff -NurpP --minimal linux-2.4.20/include/linux/sys.h linux-2.4.20-vs1.00/include/linux/sys.h
--- linux-2.4.20/include/linux/sys.h	Mon Dec 11 05:56:37 1995
+++ linux-2.4.20-vs1.00/include/linux/sys.h	Sat Nov  1 10:36:51 2003
@@ -4,7 +4,7 @@
 /*
  * system call entry points ... but not all are defined
  */
-#define NR_syscalls 256
+#define NR_syscalls 275
 
 /*
  * These are system calls that will be removed at some time
diff -NurpP --minimal linux-2.4.20/include/net/route.h linux-2.4.20-vs1.00/include/net/route.h
--- linux-2.4.20/include/net/route.h	Sat Aug  3 02:39:46 2002
+++ linux-2.4.20-vs1.00/include/net/route.h	Sat Nov  1 10:40:05 2003
@@ -164,6 +164,44 @@ static inline char rt_tos2priority(u8 to
 static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif)
 {
 	int err;
+	struct iproot_info *ip_info = current->ip_info;
+	if (ip_info != NULL) {
+		__u32 ipv4root = ip_info->ipv4[0];
+		if (ipv4root != 0) {
+			int n=ip_info->nbipv4;
+			if (src == 0) {
+				if (n > 1) {
+					u32 foundsrc;
+					int i;
+					err = ip_route_output(rp, dst, src, tos, oif);
+					if (err) return err;
+					foundsrc = (*rp)->rt_src;
+					ip_rt_put(*rp);
+					for (i=0; i<n; i++){
+						u32 mask = ip_info->mask[i];
+						u32 ipv4 = ip_info->ipv4[i];
+						u32 netipv4 = ipv4 & mask;
+						if ((foundsrc & mask) == netipv4) {
+							src = ipv4;
+							break;
+						}
+					}
+				}
+				if (src == 0)
+					src = dst == 0x0100007f
+						? 0x0100007f: ipv4root;
+			} else {
+				int i;
+				for (i=0; i<n; i++) {
+					if (ip_info->ipv4[i] == src) break;
+				}
+				if (i==n)
+					return -EPERM;
+			}
+			if (dst == 0x0100007f && current->s_context != 0)
+				dst = ipv4root;
+		}
+	}
 	err = ip_route_output(rp, dst, src, tos, oif);
 	if (err || (dst && src))
 		return err;
diff -NurpP --minimal linux-2.4.20/include/net/sock.h linux-2.4.20-vs1.00/include/net/sock.h
--- linux-2.4.20/include/net/sock.h	Sat Aug  3 02:39:46 2002
+++ linux-2.4.20-vs1.00/include/net/sock.h	Sat Nov  1 10:38:48 2003
@@ -487,6 +487,7 @@ do {	spin_lock_init(&((__sk)->lock.slock
 } while(0)
 
 struct sock {
+	/* See tcp.h comment on tcp_tw_bucket */
 	/* Socket demultiplex comparisons on incoming packets. */
 	__u32			daddr;		/* Foreign IPv4 addr			*/
 	__u32			rcv_saddr;	/* Bound local IPv4 addr		*/
@@ -508,6 +509,8 @@ struct sock {
 	unsigned char		reuse;		/* SO_REUSEADDR setting			*/
 	unsigned char		shutdown;
 	atomic_t		refcnt;		/* Reference count			*/
+	struct iproot_info	*ip_info;
+	/* End of common section with tcp_tw_bucket */
 
 	socket_lock_t		lock;		/* Synchronizer...			*/
 	int			rcvbuf;		/* Size of receive buffer in bytes	*/
@@ -525,6 +528,7 @@ struct sock {
 	__u32			saddr;		/* Sending source			*/
 	unsigned int		allocation;	/* Allocation mode			*/
 	int			sndbuf;		/* Size of send buffer in bytes		*/
+	__u32			rcv_saddr2;	/* Second bound ipv4 addr, for ipv4root */
 	struct sock		*prev;
 
 	/* Not all are volatile, but some are, so we might as well say they all are.
@@ -669,6 +673,9 @@ struct sock {
 	/* RPC layer private data */
 	void			*user_data;
   
+	/* Context of process creating this socket */
+	int			s_context;
+
 	/* Callbacks */
 	void			(*state_change)(struct sock *sk);
 	void			(*data_ready)(struct sock *sk,int bytes);
diff -NurpP --minimal linux-2.4.20/include/net/tcp.h linux-2.4.20-vs1.00/include/net/tcp.h
--- linux-2.4.20/include/net/tcp.h	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/include/net/tcp.h	Sat Nov  1 10:41:00 2003
@@ -172,6 +172,7 @@ struct tcp_tw_bucket {
 	unsigned char		reuse,
 				rcv_wscale; /* It is also TW bucket specific */
 	atomic_t		refcnt;
+	struct ipv4_info	*ip_info;
 
 	/* And these are ours. */
 	int			hashent;
@@ -190,6 +191,7 @@ struct tcp_tw_bucket {
 	struct in6_addr		v6_daddr;
 	struct in6_addr		v6_rcv_saddr;
 #endif
+	int			s_context;
 };
 
 extern kmem_cache_t *tcp_timewait_cachep;
diff -NurpP --minimal linux-2.4.20/ipc/util.c linux-2.4.20-vs1.00/ipc/util.c
--- linux-2.4.20/ipc/util.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/ipc/util.c	Sat Nov  1 10:36:51 2003
@@ -93,6 +93,8 @@ int ipc_findkey(struct ipc_ids* ids, key
 	struct kern_ipc_perm* p;
 
 	for (id = 0; id <= ids->max_id; id++) {
+		if (ids->entries[id].s_context != current->s_context)
+			continue;
 		p = ids->entries[id].p;
 		if(p==NULL)
 			continue;
@@ -167,6 +169,7 @@ found:
 
 	spin_lock(&ids->ary);
 	ids->entries[id].p = new;
+	ids->entries[id].s_context = current->s_context;
 	return id;
 }
 
diff -NurpP --minimal linux-2.4.20/ipc/util.h linux-2.4.20-vs1.00/ipc/util.h
--- linux-2.4.20/ipc/util.h	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/ipc/util.h	Sat Nov  1 10:36:51 2003
@@ -25,6 +25,7 @@ struct ipc_ids {
 
 struct ipc_id {
 	struct kern_ipc_perm* p;
+	int s_context;	// Context owning this ID
 };
 
 
@@ -74,8 +75,12 @@ extern inline struct kern_ipc_perm* ipc_
 
 	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 -NurpP --minimal linux-2.4.20/kernel/exit.c linux-2.4.20-vs1.00/kernel/exit.c
--- linux-2.4.20/kernel/exit.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/kernel/exit.c	Sat Nov  1 10:36:51 2003
@@ -66,6 +66,8 @@ static void release_task(struct task_str
 		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 int has_stopped_jobs(int p
 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) {
+		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 @@ static inline void forget_original_paren
 			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 -NurpP --minimal linux-2.4.20/kernel/fork.c linux-2.4.20-vs1.00/kernel/fork.c
--- linux-2.4.20/kernel/fork.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/kernel/fork.c	Sat Nov  1 10:36:51 2003
@@ -603,6 +603,10 @@ int do_fork(unsigned long clone_flags, u
 	*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
@@ -612,6 +616,9 @@ int do_fork(unsigned long clone_flags, u
 	if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur
 	              && !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 -NurpP --minimal linux-2.4.20/kernel/printk.c linux-2.4.20-vs1.00/kernel/printk.c
--- linux-2.4.20/kernel/printk.c	Sat Aug  3 02:39:46 2002
+++ linux-2.4.20-vs1.00/kernel/printk.c	Sat Nov  1 10:36:51 2003
@@ -172,6 +172,9 @@ int do_syslog(int type, char * buf, int 
 	char c;
 	int error = 0;
 
+	if (!capable(CAP_SYS_ADMIN) && (current->s_context != 0))
+		return -EPERM;
+
 	switch (type) {
 	case 0:		/* Close log */
 		break;
diff -NurpP --minimal linux-2.4.20/kernel/sched.c linux-2.4.20-vs1.00/kernel/sched.c
--- linux-2.4.20/kernel/sched.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/kernel/sched.c	Sat Nov  1 10:36:51 2003
@@ -165,7 +165,13 @@ static inline int goodness(struct task_s
 		 * Don't do any other calculations if the time slice is
 		 * over..
 		 */
-		weight = p->counter;
+		if (p->s_info != NULL
+			&& (p->s_info->flags & S_CTX_INFO_SCHED)) {
+			weight = atomic_read (&p->s_info->ticks)/p->s_info->refcount;
+			weight = (weight+p->counter)>>1;
+		} else {
+			weight = p->counter;
+		}
 		if (!weight)
 			goto out;
 			
@@ -618,8 +624,21 @@ repeat_schedule:
 
 		spin_unlock_irq(&runqueue_lock);
 		read_lock(&tasklist_lock);
-		for_each_task(p)
+		/*
+			Reset the s_info->ticks to the sum off all
+			member processes p->counter
+		*/
+		for_each_task(p) {
+			if (p->s_info != NULL
+				&& (p->s_info->flags & S_CTX_INFO_SCHED))
+				atomic_set (&p->s_info->ticks,0);
+		}
+		for_each_task(p) {
 			p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice);
+			if (p->s_info != NULL
+				&& (p->s_info->flags & S_CTX_INFO_SCHED))
+				atomic_add (p->counter,&p->s_info->ticks);
+		}
 		read_unlock(&tasklist_lock);
 		spin_lock_irq(&runqueue_lock);
 		goto repeat_schedule;
diff -NurpP --minimal linux-2.4.20/kernel/signal.c linux-2.4.20-vs1.00/kernel/signal.c
--- linux-2.4.20/kernel/signal.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/kernel/signal.c	Sat Nov  1 10:36:51 2003
@@ -596,7 +596,9 @@ kill_pg_info(int sig, struct siginfo *in
 		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;
@@ -650,7 +652,20 @@ kill_proc_info(int sig, struct siginfo *
                        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;
@@ -674,7 +689,8 @@ static int kill_something_info(int sig, 
 
 		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)
@@ -1298,3 +1314,142 @@ sys_signal(int sig, __sighandler_t handl
 	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) {
+					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) {
+				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)
+					current->s_info->flags |= flags;
+			}
+		}
+	}
+	return ret;
+}
+
diff -NurpP --minimal linux-2.4.20/kernel/sys.c linux-2.4.20-vs1.00/kernel/sys.c
--- linux-2.4.20/kernel/sys.c	Sat Aug  3 02:39:46 2002
+++ linux-2.4.20-vs1.00/kernel/sys.c	Sat Nov  1 10:36:51 2003
@@ -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>
@@ -499,7 +500,7 @@ static int set_user(uid_t new_ruid, int 
 	 * cheaply with the new uid cache, so if it matters
 	 * we should be checking for it.  -DaveM
 	 */
-	new_user = alloc_uid(new_ruid);
+	new_user = alloc_uid(current->s_context, new_ruid);
 	if (!new_user)
 		return -EAGAIN;
 	old_user = current->user;
@@ -1015,17 +1016,142 @@ DECLARE_RWSEM(uts_sem);
 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) {
+		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) {
+		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) {
+		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) {
+		if (atomic_dec_and_test(&ip_info->refcount)) {
+			if (ip_info->mark != 0xdeadbeef)
+				printk ("sys_release_ip_info: broken signature %08lx\n", ip_info->mark);
+			else
+				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) {
+		atomic_inc (&ip_info->refcount);
+		if (ip_info->mark != 0xdeadbeef)
+			printk ("sys_assign_ip_info: broken signature %08lx\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));
+
+	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;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -1033,8 +1159,11 @@ asmlinkage long sys_sethostname(char *na
 		return -EINVAL;
 	down_write(&uts_sem);
 	errno = -EFAULT;
-	if (!copy_from_user(system_utsname.nodename, name, len)) {
-		system_utsname.nodename[len] = 0;
+	nodename = system_utsname.nodename;
+	if (current->s_info)
+		nodename = current->s_info->nodename;
+	if (!copy_from_user(nodename, name, len)) {
+		nodename[len] = 0;
 		errno = 0;
 	}
 	up_write(&uts_sem);
@@ -1044,15 +1173,19 @@ asmlinkage long sys_sethostname(char *na
 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;
@@ -1065,6 +1198,7 @@ asmlinkage long sys_gethostname(char *na
 asmlinkage long sys_setdomainname(char *name, int len)
 {
 	int errno;
+	char *domainname;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -1072,10 +1206,13 @@ asmlinkage long sys_setdomainname(char *
 		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(system_utsname.domainname, name, len)) {
+	if (!copy_from_user(domainname, name, len)) {
+		domainname[len] = 0;
 		errno = 0;
-		system_utsname.domainname[len] = 0;
 	}
 	up_write(&uts_sem);
 	return errno;
diff -NurpP --minimal linux-2.4.20/kernel/sysctl.c linux-2.4.20-vs1.00/kernel/sysctl.c
--- linux-2.4.20/kernel/sysctl.c	Sat Aug  3 02:39:46 2002
+++ linux-2.4.20-vs1.00/kernel/sysctl.c	Sat Nov  1 10:36:51 2003
@@ -381,6 +381,8 @@ extern asmlinkage long sys_sysctl(struct
 
 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))
@@ -795,7 +797,17 @@ static int proc_doutsstring(ctl_table *t
 		  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 -NurpP --minimal linux-2.4.20/kernel/timer.c linux-2.4.20-vs1.00/kernel/timer.c
--- linux-2.4.20/kernel/timer.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/kernel/timer.c	Sat Nov  1 10:36:51 2003
@@ -599,6 +599,8 @@ void update_process_times(int user_tick)
 
 	update_one_process(p, user_tick, system, cpu);
 	if (p->pid) {
+		if (p->s_info && (p->s_info->flags & S_CTX_INFO_SCHED))
+			atomic_dec (&p->s_info->ticks);
 		if (--p->counter <= 0) {
 			p->counter = 0;
 			/*
@@ -752,6 +754,9 @@ asmlinkage unsigned long sys_alarm(unsig
  */
 asmlinkage long sys_getpid(void)
 {
+	if (current->s_info && current->s_info->initpid == current->tgid)
+		/* We are faking process 1 for this security context */
+		return 1;
 	return current->tgid;
 }
 
@@ -798,6 +803,10 @@ asmlinkage long sys_getppid(void)
 #endif
 		break;
 	}
+	if (pid && current->s_info
+		&& current->s_info->initpid == pid)
+		/* We are faking process 1 for this security context */
+		pid = 1;
 	return pid;
 }
 
diff -NurpP --minimal linux-2.4.20/kernel/user.c linux-2.4.20-vs1.00/kernel/user.c
--- linux-2.4.20/kernel/user.c	Wed Nov 29 07:43:39 2000
+++ linux-2.4.20-vs1.00/kernel/user.c	Sat Nov  1 10:36:51 2003
@@ -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 @@ static inline void uid_hash_remove(struc
 	*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 @@ static inline struct user_struct *uid_ha
 		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 @@ void free_uid(struct user_struct *up)
 	}
 }
 
-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 @@ struct user_struct * alloc_uid(uid_t uid
 		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 @@ struct user_struct * alloc_uid(uid_t uid
 		 * 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 {
diff -NurpP --minimal linux-2.4.20/net/ipv4/af_inet.c linux-2.4.20-vs1.00/net/ipv4/af_inet.c
--- linux-2.4.20/net/ipv4/af_inet.c	Sat Aug  3 02:39:46 2002
+++ linux-2.4.20-vs1.00/net/ipv4/af_inet.c	Sat Nov  1 10:36:51 2003
@@ -177,6 +177,8 @@ void inet_sock_destruct(struct sock *sk)
 
 	if (sk->protinfo.af_inet.opt)
 		kfree(sk->protinfo.af_inet.opt);
+	sys_release_ip_info(sk->ip_info);
+	sk->ip_info = NULL;
 	dst_release(sk->dst_cache);
 #ifdef INET_REFCNT_DEBUG
 	atomic_dec(&inet_sock_nr);
@@ -393,6 +395,9 @@ static int inet_create(struct socket *so
 	sk->protinfo.af_inet.mc_index	= 0;
 	sk->protinfo.af_inet.mc_list	= NULL;
 
+	sk->s_context = current->s_context;
+	sk->ip_info = NULL;
+
 #ifdef INET_REFCNT_DEBUG
 	atomic_inc(&inet_sock_nr);
 #endif
@@ -477,6 +482,11 @@ static int inet_bind(struct socket *sock
 	unsigned short snum;
 	int chk_addr_ret;
 	int err;
+	__u32 s_addr;	/* Address used for validation */
+	__u32 s_addr1;
+	__u32 s_addr2 = 0xffffffffl;	/* Optional address of the socket */
+					/* bcast in ipv4root world */
+	struct iproot_info *ip_info;
 
 	/* If the socket has its own bind function then use it. (RAW) */
 	if(sk->prot->bind)
@@ -485,7 +495,37 @@ static int inet_bind(struct socket *sock
 	if (addr_len < sizeof(struct sockaddr_in))
 		return -EINVAL;
 
-	chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
+	s_addr = s_addr1 = addr->sin_addr.s_addr;
+	ip_info = current->ip_info;
+	if (ip_info) {
+		__u32 v4_bcast = ip_info->v4_bcast;
+		__u32 ipv4root = ip_info->ipv4[0];
+		int nbipv4 = ip_info->nbipv4;
+		if (s_addr == 0) {
+			s_addr = ipv4root;
+			if (nbipv4 > 1)
+				s_addr1 = 0;
+			else {
+				s_addr1 = ipv4root;
+				ip_info = NULL;
+			}
+			s_addr2 = v4_bcast;
+		} else if (s_addr == 0x0100007f) {
+			s_addr = s_addr1 = ipv4root;
+			ip_info = NULL;
+		} else if (s_addr != v4_bcast
+			&& s_addr != ipv4root) {
+			int i;
+			for (i=0; i<nbipv4; i++) {
+				if (s_addr == ip_info->ipv4[i])
+					break;
+			}
+			if (i == nbipv4)
+				return -EADDRNOTAVAIL;
+			ip_info = NULL;
+		}
+	}
+	chk_addr_ret = inet_addr_type(s_addr);
 
 	/* Not specified by any standard per-se, however it breaks too
 	 * many applications when removed.  It is unfortunate since
@@ -496,7 +536,7 @@ static int inet_bind(struct socket *sock
 	 */
 	if (sysctl_ip_nonlocal_bind == 0 && 
 	    sk->protinfo.af_inet.freebind == 0 &&
-	    addr->sin_addr.s_addr != INADDR_ANY &&
+	    s_addr != INADDR_ANY &&
 	    chk_addr_ret != RTN_LOCAL &&
 	    chk_addr_ret != RTN_MULTICAST &&
 	    chk_addr_ret != RTN_BROADCAST)
@@ -521,13 +561,19 @@ static int inet_bind(struct socket *sock
 	    (sk->num != 0))
 		goto out;
 
-	sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;
+	sk->rcv_saddr = sk->saddr = s_addr1;
+	sk->rcv_saddr2 = s_addr2;
+	sk->ip_info = ip_info;
+	if (ip_info)
+		sys_assign_ip_info(ip_info);
 	if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
 		sk->saddr = 0;  /* Use device */
 
 	/* Make sure we are allowed to bind here. */
 	if (sk->prot->get_port(sk, snum) != 0) {
 		sk->saddr = sk->rcv_saddr = 0;
+		sk->ip_info = NULL;
+		sys_release_ip_info(ip_info);
 		err = -EADDRINUSE;
 		goto out;
 	}
diff -NurpP --minimal linux-2.4.20/net/ipv4/devinet.c linux-2.4.20-vs1.00/net/ipv4/devinet.c
--- linux-2.4.20/net/ipv4/devinet.c	Sat Aug  3 02:39:46 2002
+++ linux-2.4.20-vs1.00/net/ipv4/devinet.c	Sat Nov  1 10:36:51 2003
@@ -455,6 +455,32 @@ static __inline__ int inet_abc_len(u32 a
   	return -1;
 }
 
+/*
+	Check that a device is not member of the ipv4root assigned to the process
+	Return true if this is the case
+
+	If the process is not bound to specific IP, then it returns 0 (all
+	interface are fine).
+*/
+static int devinet_notiproot (struct in_ifaddr *ifa)
+{
+	int ret = 0;
+	struct iproot_info *info = current->ip_info;
+	if (current->s_context && info) {
+		int i;
+		int nbip = info->nbipv4;
+		__u32 addr = ifa->ifa_local;
+		ret = 1;
+		for (i=0; i<nbip; i++) {
+			if(info->ipv4[i] == addr) {
+				ret = 0;
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
 
 int devinet_ioctl(unsigned int cmd, void *arg)
 {
@@ -558,7 +584,11 @@ int devinet_ioctl(unsigned int cmd, void
 		ret = -EADDRNOTAVAIL;
 		goto done;
 	}
-
+	if (ifa != NULL
+		&& devinet_notiproot(ifa)) {
+		ret = -EADDRNOTAVAIL;
+		goto done;
+	}
 	switch(cmd) {
 		case SIOCGIFADDR:	/* Get interface address */
 			sin->sin_addr.s_addr = ifa->ifa_local;
@@ -691,6 +721,9 @@ inet_gifconf(struct net_device *dev, cha
 		return 0;
 
 	for ( ; ifa; ifa = ifa->ifa_next) {
+		// We do not show other IP devices to vservers
+		if (devinet_notiproot(ifa))
+			continue;
 		if (!buf) {
 			done += sizeof(ifr);
 			continue;
@@ -908,6 +941,8 @@ static int inet_dump_ifaddr(struct sk_bu
 		read_lock(&in_dev->lock);
 		for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
 		     ifa = ifa->ifa_next, ip_idx++) {
+			if (devinet_notiproot(ifa))
+				continue;
 			if (ip_idx < s_ip_idx)
 				continue;
 			if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
diff -NurpP --minimal linux-2.4.20/net/ipv4/raw.c linux-2.4.20-vs1.00/net/ipv4/raw.c
--- linux-2.4.20/net/ipv4/raw.c	Sat Aug  3 02:39:46 2002
+++ linux-2.4.20-vs1.00/net/ipv4/raw.c	Sat Nov  1 10:36:51 2003
@@ -96,16 +96,47 @@ static void raw_v4_unhash(struct sock *s
 	write_unlock_bh(&raw_v4_lock);
 }
 
+
+/*
+	Check if an address is in the list
+*/
+static inline int raw_addr_in_list (
+	u32 rcv_saddr1,
+	u32 rcv_saddr2,
+	u32 loc_addr,
+	struct iproot_info *ip_info)
+{
+	int ret = 0;
+	if (loc_addr != 0 &&
+		(rcv_saddr1 == loc_addr || rcv_saddr2 == loc_addr))
+		ret = 1;
+	else if (rcv_saddr1 == 0) {
+		/* Accept any address or only the one in the list */
+		if (ip_info == NULL)
+			ret = 1;
+		else {
+			int n = ip_info->nbipv4;
+			int i;
+			for (i=0; i<n; i++) {
+				if (ip_info->ipv4[i] == loc_addr) {
+					ret = 1;
+					break;
+				}
+			}
+		}
+	}
+	return ret;
+}
+
 struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
 			     unsigned long raddr, unsigned long laddr,
 			     int dif)
 {
 	struct sock *s = sk;
-
 	for (s = sk; s; s = s->next) {
 		if (s->num == num 				&&
 		    !(s->daddr && s->daddr != raddr) 		&&
-		    !(s->rcv_saddr && s->rcv_saddr != laddr)	&&
+		    raw_addr_in_list(s->rcv_saddr,s->rcv_saddr2,laddr,s->ip_info) &&
 		    !(s->bound_dev_if && s->bound_dev_if != dif))
 			break; /* gotcha */
 	}
@@ -657,7 +688,7 @@ int raw_get_info(char *buffer, char **st
 		struct sock *sk;
 
 		for (sk = raw_v4_htable[i]; sk; sk = sk->next, num++) {
-			if (sk->family != PF_INET)
+			if (sk->family != PF_INET || (current->s_context != 1 && sk->s_context != current->s_context))
 				continue;
 			pos += 128;
 			if (pos <= offset)
diff -NurpP --minimal linux-2.4.20/net/ipv4/tcp_ipv4.c linux-2.4.20-vs1.00/net/ipv4/tcp_ipv4.c
--- linux-2.4.20/net/ipv4/tcp_ipv4.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/net/ipv4/tcp_ipv4.c	Sat Nov  1 10:36:51 2003
@@ -174,6 +174,49 @@ static inline void tcp_bind_hash(struct 
 	sk->prev = (struct sock *) tb;
 }
 
+/*
+	Return 1 if addr match the socket IP list
+	or the socket is INADDR_ANY
+*/
+static inline int tcp_in_list (struct sock *sk, u32 addr)
+{
+	struct iproot_info *ip_info = sk->ip_info;
+
+	if (ip_info) {
+		int n = ip_info->nbipv4;
+		int i;
+		for (i=0; i<n; i++)
+			if (ip_info->ipv4[i] == addr)
+				return 1;
+	}
+	else if (!sk->rcv_saddr || sk->rcv_saddr == addr)
+		return 1;
+	return 0;
+}
+	
+/*
+	Check if the addresses in sk1 conflict with those in sk2
+*/
+int tcp_ipv4_addr_conflict (struct sock *sk1, struct sock *sk2)
+{
+	int ret = 0;
+	if (sk1->rcv_saddr)
+		/* Bind to one address only */
+		ret = tcp_in_list (sk2,sk1->rcv_saddr);
+	else if (sk1->ip_info) {
+		/* A restricted bind(any) */
+		struct iproot_info *ip_info = sk1->ip_info;
+		int n = ip_info->nbipv4;
+		int i;
+		for (i=0; i<n; i++)
+			if (tcp_in_list (sk2,ip_info->ipv4[i]))
+				return 1;
+	}
+	else	/* A bind(any) do not allow other bind on the same port */
+		return 1;
+	return 0;
+}
+
 static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
 {
 	struct sock *sk2 = tb->owners;
@@ -186,9 +229,7 @@ static inline int tcp_bind_conflict(stru
 			if (!sk_reuse	||
 			    !sk2->reuse	||
 			    sk2->state == TCP_LISTEN) {
-				if (!sk2->rcv_saddr	||
-				    !sk->rcv_saddr	||
-				    (sk2->rcv_saddr == sk->rcv_saddr))
+				if (tcp_ipv4_addr_conflict(sk,sk2))
 					break;
 			}
 		}
@@ -407,6 +448,32 @@ void tcp_unhash(struct sock *sk)
 		wake_up(&tcp_lhash_wait);
 }
 
+/*
+	Check if an address is in the list
+*/
+static inline int tcp_addr_in_list (
+	u32 rcv_saddr,
+	u32 daddr,
+	struct iproot_info *ip_info)
+{
+	if (rcv_saddr == daddr)
+		return 1;
+	else if (rcv_saddr == 0) {
+		/* Accept any address or only the one in the list */
+		if (ip_info) {
+			int n = ip_info->nbipv4;
+			int i;
+			for (i=0; i<n; i++)
+				if (ip_info->ipv4[i] == daddr)
+					return 1;
+		}
+		else return 1;
+	}
+	return 0;
+}
+
+
+
 /* Don't inline this cruft.  Here are some nice properties to
  * exploit here.  The BSD API does not allow a listening TCP
  * to specify the remote port nor the remote address for the
@@ -424,11 +491,10 @@ static struct sock *__tcp_v4_lookup_list
 			__u32 rcv_saddr = sk->rcv_saddr;
 
 			score = 1;
-			if(rcv_saddr) {
-				if (rcv_saddr != daddr)
-					continue;
+			if (tcp_addr_in_list(rcv_saddr,daddr,sk->ip_info))
 				score++;
-			}
+			else
+				continue;
 			if (sk->bound_dev_if) {
 				if (sk->bound_dev_if != dif)
 					continue;
@@ -455,7 +521,7 @@ __inline__ struct sock *tcp_v4_lookup_li
 	if (sk) {
 		if (sk->num == hnum &&
 		    sk->next == NULL &&
-		    (!sk->rcv_saddr || sk->rcv_saddr == daddr) &&
+		    tcp_addr_in_list(sk->rcv_saddr,daddr,sk->ip_info) &&
 		    !sk->bound_dev_if)
 			goto sherry_cache;
 		sk = __tcp_v4_lookup_listener(sk, daddr, hnum, dif);
@@ -2183,6 +2249,9 @@ int tcp_get_info(char *buffer, char **st
 			int uid;
 			struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
+			if (current->s_context != 1 && sk->s_context != current->s_context)
+				continue;
+			
 			if (!TCP_INET_FAMILY(sk->family))
 				goto skip_listen;
 
@@ -2236,7 +2305,8 @@ skip_listen:
 
 		read_lock(&head->lock);
 		for(sk = head->chain; sk; sk = sk->next, num++) {
-			if (!TCP_INET_FAMILY(sk->family))
+			if (!TCP_INET_FAMILY(sk->family) ||
+				(current->s_context != 1 && sk->s_context != current->s_context))
 				continue;
 			pos += TMPSZ;
 			if (pos <= offset)
@@ -2251,7 +2321,8 @@ skip_listen:
 		for (tw = (struct tcp_tw_bucket *)tcp_ehash[i+tcp_ehash_size].chain;
 		     tw != NULL;
 		     tw = (struct tcp_tw_bucket *)tw->next, num++) {
-			if (!TCP_INET_FAMILY(tw->family))
+			if (!TCP_INET_FAMILY(tw->family) ||
+				(current->s_context != 1 && tw->s_context != current->s_context))
 				continue;
 			pos += TMPSZ;
 			if (pos <= offset)
diff -NurpP --minimal linux-2.4.20/net/ipv4/tcp_minisocks.c linux-2.4.20-vs1.00/net/ipv4/tcp_minisocks.c
--- linux-2.4.20/net/ipv4/tcp_minisocks.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/net/ipv4/tcp_minisocks.c	Sat Nov  1 10:36:51 2003
@@ -380,6 +380,9 @@ void tcp_time_wait(struct sock *sk, int 
 		tw->ts_recent_stamp= tp->ts_recent_stamp;
 		tw->pprev_death = NULL;
 
+		tw->s_context	= sk->s_context;
+		tw->ip_info	= NULL;
+
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 		if(tw->family == PF_INET6) {
 			memcpy(&tw->v6_daddr,
@@ -649,6 +652,7 @@ struct sock *tcp_create_openreq_child(st
 #endif
 
 		memcpy(newsk, sk, sizeof(*newsk));
+		sys_assign_ip_info(newsk->ip_info);
 		newsk->state = TCP_SYN_RECV;
 
 		/* SANITY */
diff -NurpP --minimal linux-2.4.20/net/ipv4/udp.c linux-2.4.20-vs1.00/net/ipv4/udp.c
--- linux-2.4.20/net/ipv4/udp.c	Sat Aug  3 02:39:46 2002
+++ linux-2.4.20-vs1.00/net/ipv4/udp.c	Sat Nov  1 10:36:51 2003
@@ -106,6 +106,9 @@ rwlock_t udp_hash_lock = RW_LOCK_UNLOCKE
 /* Shared by v4/v6 udp. */
 int udp_port_rover;
 
+int tcp_ipv4_addr_conflict (struct sock *sk1, struct sock *sk2);
+
+
 static int udp_v4_get_port(struct sock *sk, unsigned short snum)
 {
 	write_lock_bh(&udp_hash_lock);
@@ -160,9 +163,7 @@ gotit:
 			if (sk2->num == snum &&
 			    sk2 != sk &&
 			    sk2->bound_dev_if == sk->bound_dev_if &&
-			    (!sk2->rcv_saddr ||
-			     !sk->rcv_saddr ||
-			     sk2->rcv_saddr == sk->rcv_saddr) &&
+			    tcp_ipv4_addr_conflict (sk2,sk) &&
 			    (!sk2->reuse || !sk->reuse))
 				goto fail;
 		}
@@ -205,6 +206,20 @@ static void udp_v4_unhash(struct sock *s
 	write_unlock_bh(&udp_hash_lock);
 }
 
+static int udp_in_list (struct iproot_info *ip_info, u32 addr)
+{
+	int ret = 0;
+	int n = ip_info->nbipv4;
+	int i;
+	for (i=0; i<n; i++) {
+		if (ip_info->ipv4[i] == addr) {
+			ret = 1;
+			break;
+		}
+	}
+	return ret;
+}
+
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
  * harder than this. -DaveM
  */
@@ -221,6 +236,11 @@ struct sock *udp_v4_lookup_longway(u32 s
 				if(sk->rcv_saddr != daddr)
 					continue;
 				score++;
+			} else if (sk->ip_info) {
+				if (udp_in_list (sk->ip_info,daddr))
+					score++;
+				else
+					continue;
 			}
 			if(sk->daddr) {
 				if(sk->daddr != saddr)
@@ -272,7 +292,7 @@ static inline struct sock *udp_v4_mcast_
 		if ((s->num != hnum)					||
 		    (s->daddr && s->daddr!=rmt_addr)			||
 		    (s->dport != rmt_port && s->dport != 0)			||
-		    (s->rcv_saddr  && s->rcv_saddr != loc_addr)		||
+		    (s->rcv_saddr  && s->rcv_saddr != loc_addr && s->rcv_saddr2 != loc_addr)	||
 		    (s->bound_dev_if && s->bound_dev_if != dif))
 			continue;
 		break;
@@ -517,6 +537,16 @@ int udp_sendmsg(struct sock *sk, struct 
 		rt = (struct rtable*)sk_dst_check(sk, 0);
 
 	if (rt == NULL) {
+		struct iproot_info *ip_info = current->ip_info;
+		if (ip_info != NULL) {
+			__u32 ipv4root = ip_info->ipv4[0];
+			if (ipv4root) {
+				if (daddr == 0x0100007f && current->s_context != 0)
+					daddr = ipv4root;
+				if (ufh.saddr == 0)
+					ufh.saddr = ipv4root;
+			}
+		}
 		err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif);
 		if (err)
 			goto out;
@@ -1004,7 +1034,8 @@ int udp_get_info(char *buffer, char **st
 		struct sock *sk;
 
 		for (sk = udp_hash[i]; sk; sk = sk->next, num++) {
-			if (sk->family != PF_INET)
+			if (sk->family != PF_INET ||
+				(current->s_context != 1 && sk->s_context != current->s_context))
 				continue;
 			pos += 128;
 			if (pos <= offset)
diff -NurpP --minimal linux-2.4.20/net/ipv6/raw.c linux-2.4.20-vs1.00/net/ipv6/raw.c
--- linux-2.4.20/net/ipv6/raw.c	Sat Aug  3 02:39:46 2002
+++ linux-2.4.20-vs1.00/net/ipv6/raw.c	Sat Nov  1 10:36:51 2003
@@ -879,7 +879,8 @@ int raw6_get_info(char *buffer, char **s
 		struct sock *sk;
 
 		for (sk = raw_v6_htable[i]; sk; sk = sk->next, num++) {
-			if (sk->family != PF_INET6)
+			if (sk->family != PF_INET6 ||
+				(current->s_context != 1 && sk->s_context != current->s_context))
 				continue;
 			pos += LINE_LEN+1;
 			if (pos <= offset)
diff -NurpP --minimal linux-2.4.20/net/ipv6/tcp_ipv6.c linux-2.4.20-vs1.00/net/ipv6/tcp_ipv6.c
--- linux-2.4.20/net/ipv6/tcp_ipv6.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/net/ipv6/tcp_ipv6.c	Sat Nov  1 10:36:51 2003
@@ -2006,7 +2006,8 @@ int tcp6_get_info(char *buffer, char **s
 			int uid;
 			struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
-			if (sk->family != PF_INET6)
+			if (sk->family != PF_INET6 ||
+				(current->s_context != 1 && sk->s_context != current->s_context))
 				continue;
 			pos += LINE_LEN+1;
 			if (pos >= offset) {
@@ -2056,7 +2057,8 @@ int tcp6_get_info(char *buffer, char **s
 
 		read_lock(&head->lock);
 		for(sk = head->chain; sk; sk = sk->next, num++) {
-			if (sk->family != PF_INET6)
+			if (sk->family != PF_INET6 ||
+				(current->s_context != 1 && sk->s_context != current->s_context))
 				continue;
 			pos += LINE_LEN+1;
 			if (pos <= offset)
@@ -2071,7 +2073,8 @@ int tcp6_get_info(char *buffer, char **s
 		for (tw = (struct tcp_tw_bucket *)tcp_ehash[i+tcp_ehash_size].chain;
 		     tw != NULL;
 		     tw = (struct tcp_tw_bucket *)tw->next, num++) {
-			if (tw->family != PF_INET6)
+			if (tw->family != PF_INET6 ||
+				(current->s_context != 1 && tw->s_context != current->s_context))
 				continue;
 			pos += LINE_LEN+1;
 			if (pos <= offset)
diff -NurpP --minimal linux-2.4.20/net/ipv6/udp.c linux-2.4.20-vs1.00/net/ipv6/udp.c
--- linux-2.4.20/net/ipv6/udp.c	Fri Nov 29 00:53:15 2002
+++ linux-2.4.20-vs1.00/net/ipv6/udp.c	Sat Nov  1 10:36:51 2003
@@ -957,7 +957,8 @@ int udp6_get_info(char *buffer, char **s
 		struct sock *sk;
 
 		for (sk = udp_hash[i]; sk; sk = sk->next, num++) {
-			if (sk->family != PF_INET6)
+			if (sk->family != PF_INET6 ||
+				(current->s_context != 1 && sk->s_context != current->s_context))
 				continue;
 			pos += LINE_LEN+1;
 			if (pos <= offset)
diff -NurpP --minimal linux-2.4.20/net/socket.c linux-2.4.20-vs1.00/net/socket.c
--- linux-2.4.20/net/socket.c	Fri Nov 29 00:53:16 2002
+++ linux-2.4.20-vs1.00/net/socket.c	Sat Nov  1 10:36:51 2003
@@ -1754,3 +1754,55 @@ int socket_get_info(char *buffer, char *
 		len = 0;
 	return len;
 }
+
+asmlinkage int sys_set_ipv4root (
+	__u32 ip[],
+	int nbip,
+	__u32 bcast,
+	__u32 mask[])
+{
+	int ret = -EPERM;
+	__u32 tbip[NB_IPV4ROOT];
+	__u32 tbmask[NB_IPV4ROOT];
+	struct iproot_info *ip_info = current->ip_info;
+	if (nbip < 0 || nbip > NB_IPV4ROOT)
+		ret = -EINVAL;
+	else if (copy_from_user(tbip,ip,nbip*sizeof(ip[0]))
+		|| copy_from_user(tbmask,mask,nbip*sizeof(ip[0])))
+		ret = -EFAULT;
+	else if (!ip_info
+		|| ip_info->ipv4[0] == 0
+		|| capable(CAP_NET_ADMIN))
+		// We are allowed to change everything
+		ret = 0;
+	else if (current->ip_info) {
+		// We are allowed to select a subset of the currently
+		// installed IP numbers. No new one allowed
+		// We can't change the broadcast address though
+		int i;
+		int found = 0;
+		for (i=0; i<nbip; i++) {
+			int j;
+			__u32 ipi = tbip[i];
+			for (j=0; j<ip_info->nbipv4; j++) {
+				if (ipi == ip_info->ipv4[j]) {
+					found++;
+					break;
+				}
+			}
+		}
+		if (found == nbip && bcast == ip_info->v4_bcast) {
+			ret = 0;
+		}
+
+	}
+	if (ret == 0) {
+		sys_alloc_ip_info();
+		current->ip_info->nbipv4 = nbip;
+		memcpy (current->ip_info->ipv4,tbip,nbip*sizeof(tbip[0]));
+		current->ip_info->v4_bcast = bcast;
+		memcpy (current->ip_info->mask,tbmask,nbip*sizeof(tbmask[0]));
+	}
+	return ret;
+}
+
diff -NurpP --minimal linux-2.4.20/net/unix/af_unix.c linux-2.4.20-vs1.00/net/unix/af_unix.c
--- linux-2.4.20/net/unix/af_unix.c	Fri Nov 29 00:53:16 2002
+++ linux-2.4.20-vs1.00/net/unix/af_unix.c	Sat Nov  1 10:36:51 2003
@@ -479,6 +479,8 @@ static struct sock * unix_create1(struct
 
 	sk->write_space		=	unix_write_space;
 
+	sk->s_context = current->s_context;
+
 	sk->max_ack_backlog = sysctl_unix_max_dgram_qlen;
 	sk->destruct = unix_sock_destructor;
 	sk->protinfo.af_unix.dentry=NULL;
@@ -1756,6 +1758,9 @@ static int unix_read_proc(char *buffer, 
 	read_lock(&unix_table_lock);
 	forall_unix_sockets (i,s)
 	{
+		if (current->s_context != 1 && s->s_context != current->s_context)
+			continue;
+
 		unix_state_rlock(s);
 
 		len+=sprintf(buffer+len,"%p: %08X %08X %08X %04X %02X %5lu",
