diff -urN linux-2.4.20/Makefile linux-2.4.20ctx17/Makefile --- linux-2.4.20/Makefile Tue Jan 7 15:50:24 2003 +++ linux-2.4.20ctx17/Makefile Fri May 9 12:31:43 2003 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 20 -EXTRAVERSION = +EXTRAVERSION =ctx-17 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -urN linux-2.4.20/arch/i386/kernel/entry.S linux-2.4.20ctx17/arch/i386/kernel/entry.S --- linux-2.4.20/arch/i386/kernel/entry.S Tue Jan 7 15:50:24 2003 +++ linux-2.4.20ctx17/arch/i386/kernel/entry.S Fri May 9 12:31:43 2003 @@ -657,6 +657,8 @@ .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_new_s_context) + .long SYMBOL_NAME(sys_set_ipv4root) .rept NR_syscalls-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall) diff -urN linux-2.4.20/arch/i386/kernel/ptrace.c linux-2.4.20ctx17/arch/i386/kernel/ptrace.c --- linux-2.4.20/arch/i386/kernel/ptrace.c Tue Jan 7 15:49:51 2003 +++ linux-2.4.20ctx17/arch/i386/kernel/ptrace.c Fri May 9 12:31:43 2003 @@ -170,7 +170,7 @@ if (child) get_task_struct(child); read_unlock(&tasklist_lock); - if (!child) + if (!child || child->s_context != current->s_context) goto out; ret = -EPERM; diff -urN linux-2.4.20/arch/ppc/kernel/misc.S linux-2.4.20ctx17/arch/ppc/kernel/misc.S --- linux-2.4.20/arch/ppc/kernel/misc.S Tue Jan 7 15:50:26 2003 +++ linux-2.4.20ctx17/arch/ppc/kernel/misc.S Fri May 9 12:31:43 2003 @@ -1184,6 +1184,8 @@ .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_new_s_context + .long sys_set_ipv4root .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall diff -urN linux-2.4.20/arch/ppc/kernel/ptrace.c linux-2.4.20ctx17/arch/ppc/kernel/ptrace.c --- linux-2.4.20/arch/ppc/kernel/ptrace.c Tue Jan 7 15:50:29 2003 +++ linux-2.4.20ctx17/arch/ppc/kernel/ptrace.c Fri May 9 12:31:43 2003 @@ -178,7 +178,7 @@ if (child) get_task_struct(child); read_unlock(&tasklist_lock); - if (!child) + if (!child || child->s_context != current->s_context) goto out; ret = -EPERM; diff -urN linux-2.4.20/arch/sparc/kernel/systbls.S linux-2.4.20ctx17/arch/sparc/kernel/systbls.S --- linux-2.4.20/arch/sparc/kernel/systbls.S Tue Jan 7 15:49:59 2003 +++ linux-2.4.20ctx17/arch/sparc/kernel/systbls.S Fri May 9 12:31:43 2003 @@ -70,7 +70,9 @@ /*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 + .long sys_new_s_context + .long sys_set_ipv4root #ifdef CONFIG_SUNOS_EMUL /* Now the SunOS syscall table. */ diff -urN linux-2.4.20/arch/sparc64/kernel/entry.S linux-2.4.20ctx17/arch/sparc64/kernel/entry.S --- linux-2.4.20/arch/sparc64/kernel/entry.S Tue Jan 7 15:50:29 2003 +++ linux-2.4.20ctx17/arch/sparc64/kernel/entry.S Fri May 9 12:31:43 2003 @@ -25,7 +25,7 @@ #define curptr g6 -#define NR_SYSCALLS 256 /* Each OS is different... */ +#define NR_SYSCALLS 258 /* Each OS is different... */ .text .align 32 diff -urN linux-2.4.20/arch/sparc64/kernel/ptrace.c linux-2.4.20ctx17/arch/sparc64/kernel/ptrace.c --- linux-2.4.20/arch/sparc64/kernel/ptrace.c Tue Jan 7 15:50:29 2003 +++ linux-2.4.20ctx17/arch/sparc64/kernel/ptrace.c Fri May 9 12:31:43 2003 @@ -156,7 +156,7 @@ get_task_struct(child); read_unlock(&tasklist_lock); - if (!child) { + if (!child || child->s_context != current->s_context) { pt_error_return(regs, ESRCH); goto out; } diff -urN linux-2.4.20/arch/sparc64/kernel/systbls.S linux-2.4.20ctx17/arch/sparc64/kernel/systbls.S --- linux-2.4.20/arch/sparc64/kernel/systbls.S Tue Jan 7 15:49:59 2003 +++ linux-2.4.20ctx17/arch/sparc64/kernel/systbls.S Fri May 9 12:31:43 2003 @@ -71,6 +71,8 @@ .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_new_s_context + .word sys_set_ipv4root /* Now the 64-bit native Linux syscall table. */ @@ -130,6 +132,8 @@ .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_new_s_context + .word sys_set_ipv4root #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ defined(CONFIG_SOLARIS_EMUL_MODULE) @@ -225,5 +229,6 @@ .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 #endif diff -urN linux-2.4.20/fs/devpts/inode.c linux-2.4.20ctx17/fs/devpts/inode.c --- linux-2.4.20/fs/devpts/inode.c Thu Oct 25 09:02:26 2001 +++ linux-2.4.20ctx17/fs/devpts/inode.c Fri May 9 12:31:43 2003 @@ -24,6 +24,7 @@ #include #include #include +#include #include "devpts_i.h" @@ -152,7 +153,6 @@ inode->i_op = &devpts_root_inode_operations; inode->i_fop = &devpts_root_operations; inode->i_nlink = 2; - s->u.generic_sbp = (void *) sbi; s->s_blocksize = 1024; s->s_blocksize_bits = 10; @@ -180,6 +180,19 @@ 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 @@ 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 -urN linux-2.4.20/fs/devpts/root.c linux-2.4.20ctx17/fs/devpts/root.c --- linux-2.4.20/fs/devpts/root.c Fri Dec 21 18:41:55 2001 +++ linux-2.4.20ctx17/fs/devpts/root.c Fri May 9 12:31:43 2003 @@ -14,6 +14,7 @@ #include #include #include +#include #include "devpts_i.h" static int devpts_root_readdir(struct file *,void *,filldir_t); @@ -64,7 +65,10 @@ default: while ( nr - 2 < sbi->max_ptys ) { int ptynr = nr - 2; - if ( sbi->inodes[ptynr] ) { + struct inode *inode = sbi->inodes[ptynr]; + if ( inode != NULL + && (current->s_context == 1 + || inode->u.devpts_i.s_context == current->s_context)) { genptsname(numbuf, ptynr); if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_CHR) < 0 ) return 0; @@ -100,6 +104,7 @@ unsigned int entry; int i; const char *p; + struct inode *inode; dentry->d_op = &devpts_dentry_operations; @@ -126,10 +131,17 @@ if ( entry >= sbi->max_ptys ) return NULL; - if ( sbi->inodes[entry] ) - atomic_inc(&sbi->inodes[entry]->i_count); + inode = sbi->inodes[entry]; + if (inode != NULL + && inode->u.devpts_i.s_context == current->s_context){ + atomic_inc(&inode->i_count); + }else{ + inode = NULL; + } - d_add(dentry, sbi->inodes[entry]); + d_add(dentry, inode); return NULL; } + + diff -urN linux-2.4.20/fs/exec.c linux-2.4.20ctx17/fs/exec.c --- linux-2.4.20/fs/exec.c Tue Jan 7 15:50:40 2003 +++ linux-2.4.20ctx17/fs/exec.c Fri May 9 12:31:43 2003 @@ -705,7 +705,7 @@ kernel_cap_t new_permitted, working; int do_unlock = 0; - new_permitted = cap_intersect(bprm->cap_permitted, cap_bset); + new_permitted = cap_intersect(bprm->cap_permitted, current->cap_bset); working = cap_intersect(bprm->cap_inheritable, current->cap_inheritable); new_permitted = cap_combine(new_permitted, working); diff -urN linux-2.4.20/fs/ext2/ialloc.c linux-2.4.20ctx17/fs/ext2/ialloc.c --- linux-2.4.20/fs/ext2/ialloc.c Tue Jan 7 15:50:40 2003 +++ linux-2.4.20ctx17/fs/ext2/ialloc.c Fri May 9 12:31:43 2003 @@ -388,7 +388,7 @@ 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 -urN linux-2.4.20/fs/ext2/inode.c linux-2.4.20ctx17/fs/ext2/inode.c --- linux-2.4.20/fs/ext2/inode.c Tue Jan 7 15:50:40 2003 +++ linux-2.4.20ctx17/fs/ext2/inode.c Fri May 9 12:31:43 2003 @@ -46,6 +46,8 @@ 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 @@ 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 @@ 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 @@ 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); @@ -876,6 +876,12 @@ mark_inode_dirty(inode); } } +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) { @@ -1005,9 +1011,13 @@ 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 -urN linux-2.4.20/fs/ext2/ioctl.c linux-2.4.20ctx17/fs/ext2/ioctl.c --- linux-2.4.20/fs/ext2/ioctl.c Tue Jan 7 15:50:41 2003 +++ linux-2.4.20ctx17/fs/ext2/ioctl.c Fri May 9 12:31:43 2003 @@ -44,7 +44,7 @@ * * 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,17 @@ 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_FILE; + + if (flags & EXT2_IMMUTABLE_LINK_FL) + inode->i_flags |= S_IMMUTABLE_LINK; else - inode->i_flags &= ~S_IMMUTABLE; + inode->i_flags &= ~S_IMMUTABLE_LINK; + if (flags & EXT2_NOATIME_FL) inode->i_flags |= S_NOATIME; else diff -urN linux-2.4.20/fs/ext3/ialloc.c linux-2.4.20ctx17/fs/ext3/ialloc.c --- linux-2.4.20/fs/ext3/ialloc.c Tue Jan 7 15:50:41 2003 +++ linux-2.4.20ctx17/fs/ext3/ialloc.c Fri May 9 12:31:43 2003 @@ -485,7 +485,7 @@ 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 -urN linux-2.4.20/fs/ext3/inode.c linux-2.4.20ctx17/fs/ext3/inode.c --- linux-2.4.20/fs/ext3/inode.c Tue Jan 7 15:50:41 2003 +++ linux-2.4.20ctx17/fs/ext3/inode.c Fri May 9 12:31:43 2003 @@ -157,6 +157,7 @@ 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 @@ 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 @@ * 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 @@ 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 @@ 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,12 @@ /* inode->i_attr_flags |= ATTR_FLAG_APPEND; unused */ inode->i_flags |= S_APPEND; } - if (inode->u.ext3_i.i_flags & EXT3_IMMUTABLE_FL) { + if (inode->u.ext3_i.i_flags & EXT3_IMMUTABLE_FILE_FL) { /* inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE; unused */ - inode->i_flags |= S_IMMUTABLE; + inode->i_flags |= S_IMMUTABLE_FILE; + } + if (inode->u.ext3_i.i_flags & EXT3_IMMUTABLE_LINK_FL) { + 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 -urN linux-2.4.20/fs/ext3/ioctl.c linux-2.4.20ctx17/fs/ext3/ioctl.c --- linux-2.4.20/fs/ext3/ioctl.c Tue Jan 7 15:50:41 2003 +++ linux-2.4.20ctx17/fs/ext3/ioctl.c Fri May 9 12:31:43 2003 @@ -53,7 +53,7 @@ * * 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 @@ 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 -urN linux-2.4.20/fs/fat/file.c linux-2.4.20ctx17/fs/fat/file.c --- linux-2.4.20/fs/fat/file.c Sun Aug 12 19:56:56 2001 +++ linux-2.4.20ctx17/fs/fat/file.c Fri May 9 12:31:43 2003 @@ -119,7 +119,7 @@ /* 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 -urN linux-2.4.20/fs/fat/inode.c linux-2.4.20ctx17/fs/fat/inode.c --- linux-2.4.20/fs/fat/inode.c Tue Jan 7 15:50:13 2003 +++ linux-2.4.20ctx17/fs/fat/inode.c Fri May 9 12:31:43 2003 @@ -949,7 +949,7 @@ } 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 -urN linux-2.4.20/fs/hpfs/file.c linux-2.4.20ctx17/fs/hpfs/file.c --- linux-2.4.20/fs/hpfs/file.c Mon Aug 13 02:37:53 2001 +++ linux-2.4.20ctx17/fs/hpfs/file.c Fri May 9 12:31:43 2003 @@ -60,7 +60,7 @@ 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 -urN linux-2.4.20/fs/intermezzo/vfs.c linux-2.4.20ctx17/fs/intermezzo/vfs.c --- linux-2.4.20/fs/intermezzo/vfs.c Tue Jan 7 15:50:41 2003 +++ linux-2.4.20ctx17/fs/intermezzo/vfs.c Fri May 9 12:31:43 2003 @@ -140,7 +140,7 @@ 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 @@ return -EROFS; } - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { + if (IS_IMMUTABLE_FILE(inode) || IS_APPEND(inode)) { EXIT; return -EPERM; } @@ -377,7 +377,7 @@ return -EROFS; } - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { + if (IS_IMMUTABLE_FILE(inode) || IS_APPEND(inode)) { EXIT; return -EPERM; } @@ -772,7 +772,7 @@ * 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 @@ return -EROFS; } - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { + if (IS_IMMUTABLE_FILE(inode) || IS_APPEND(inode)) { EXIT; return -EPERM; } diff -urN linux-2.4.20/fs/namei.c linux-2.4.20ctx17/fs/namei.c --- linux-2.4.20/fs/namei.c Tue Jan 7 15:50:41 2003 +++ linux-2.4.20ctx17/fs/namei.c Fri May 9 12:31:43 2003 @@ -152,6 +152,15 @@ { umode_t mode = inode->i_mode; + /* + A dir with permission bit all 0s is a dead zone for + process running in a vserver. By doing + chmod 000 /vservers + you fix the "escape from chroot" bug. + */ + if ((mode & 0777) == 0 + && S_ISDIR(mode) + && current->s_context != 0) return -EACCES; if (mask & MAY_WRITE) { /* * Nobody gets write access to a read-only fs. @@ -163,7 +172,7 @@ /* * Nobody gets write access to an immutable file. */ - if (IS_IMMUTABLE(inode)) + if (IS_IMMUTABLE_FILE(inode)) return -EACCES; } @@ -902,8 +911,7 @@ 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 @@ * 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 -urN linux-2.4.20/fs/nfsd/vfs.c linux-2.4.20ctx17/fs/nfsd/vfs.c --- linux-2.4.20/fs/nfsd/vfs.c Tue Jan 7 15:50:41 2003 +++ linux-2.4.20ctx17/fs/nfsd/vfs.c Fri May 9 12:31:43 2003 @@ -1476,7 +1476,7 @@ 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 @@ (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 @@ && (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 -urN linux-2.4.20/fs/open.c linux-2.4.20ctx17/fs/open.c --- linux-2.4.20/fs/open.c Tue Jan 7 15:50:41 2003 +++ linux-2.4.20ctx17/fs/open.c Fri May 9 12:31:43 2003 @@ -146,7 +146,7 @@ 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 @@ 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 @@ 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 @@ 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 -urN linux-2.4.20/fs/proc/array.c linux-2.4.20ctx17/fs/proc/array.c --- linux-2.4.20/fs/proc/array.c Tue Jan 7 15:50:14 2003 +++ linux-2.4.20ctx17/fs/proc/array.c Fri May 9 12:31:43 2003 @@ -75,6 +75,7 @@ #include #include #include +#include /* Gcc optimizes away "strlen(x)" for constant x */ #define ADDBUF(buffer, string) \ @@ -147,8 +148,12 @@ static inline char * task_state(struct task_struct *p, char *buffer) { int g; - + pid_t ppid; read_lock(&tasklist_lock); + ppid = p->p_opptr->pid; + if (ppid != 0 + && current->s_info != NULL + && current->s_info->initpid == ppid) ppid = 1; buffer += sprintf(buffer, "State:\t%s\n" "Tgid:\t%d\n" @@ -158,7 +163,7 @@ "Uid:\t%d\t%d\t%d\t%d\n" "Gid:\t%d\t%d\t%d\t%d\n", get_task_state(p), p->tgid, - p->pid, p->pid ? p->p_opptr->pid : 0, 0, + p->pid, p->pid ? ppid : 0, 0, p->uid, p->euid, p->suid, p->fsuid, p->gid, p->egid, p->sgid, p->fsgid); read_unlock(&tasklist_lock); @@ -266,10 +271,12 @@ { return buffer + sprintf(buffer, "CapInh:\t%016x\n" "CapPrm:\t%016x\n" - "CapEff:\t%016x\n", + "CapEff:\t%016x\n" + "CapBset:\t%016x\n", cap_t(p->cap_inheritable), cap_t(p->cap_permitted), - cap_t(p->cap_effective)); + cap_t(p->cap_effective), + cap_t(p->cap_bset)); } @@ -291,6 +298,49 @@ } buffer = task_sig(task, buffer); buffer = task_cap(task, buffer); +#ifdef __NR_new_s_context + if (task->s_info != NULL){ + int i; + buffer += sprintf (buffer,"s_context: %d [",task->s_context); + for (i=0; is_info->s_context[i]; + if (ctx == 0) break; + buffer += sprintf (buffer," %d",ctx); + } + *buffer++ = ']'; + *buffer++ = '\n'; + buffer += sprintf (buffer,"ctxticks: %d %ld %d\n" + ,atomic_read(&task->s_info->ticks),task->counter + ,task->s_info->refcount); + buffer += sprintf (buffer,"ctxflags: %d\n" + ,task->s_info->flags); + buffer += sprintf (buffer,"initpid: %d\n" + ,task->s_info->initpid); + }else{ + buffer += sprintf (buffer,"s_context: %d\n",task->s_context); + buffer += sprintf (buffer,"ctxticks: none\n"); + buffer += sprintf (buffer,"ctxflags: none\n"); + buffer += sprintf (buffer,"initpid: none\n"); + } + if (task->ip_info != NULL){ + int i; + buffer += sprintf (buffer,"ipv4root:"); + for (i=0; iip_info->nbipv4; i++){ + buffer += sprintf (buffer," %08x" + ,task->ip_info->ipv4[i]); + } + *buffer++ = '\n'; + buffer += sprintf (buffer,"ipv4root_bcast: %08x\n" + ,task->ip_info->v4_bcast); + buffer += sprintf (buffer,"ipv4root_refcnt: %d\n" + ,task->ip_info->refcount); + }else{ + buffer += sprintf (buffer,"ipv4root: 0\n"); + buffer += sprintf (buffer,"ipv4root_bcast: 0\n"); + } + buffer += sprintf (buffer,"__NR_new_s_context: %d\n",__NR_new_s_context); + buffer += sprintf (buffer,"__NR_set_ipv4root: %d rev2\n",__NR_set_ipv4root); +#endif #if defined(CONFIG_ARCH_S390) buffer = task_show_regs(task, buffer); #endif @@ -344,6 +394,8 @@ read_lock(&tasklist_lock); ppid = task->pid ? task->p_opptr->pid : 0; + if (current->s_info != NULL + && current->s_info->initpid == ppid) ppid = 1; read_unlock(&tasklist_lock); res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \ diff -urN linux-2.4.20/fs/proc/base.c linux-2.4.20ctx17/fs/proc/base.c --- linux-2.4.20/fs/proc/base.c Tue Jan 7 15:50:14 2003 +++ linux-2.4.20ctx17/fs/proc/base.c Fri May 9 12:31:43 2003 @@ -1019,6 +1019,12 @@ if (!task) goto out; + if (pid != 1 + && current->s_context != 1 + && task->s_context != current->s_context){ + free_task_struct(task); + goto out; + } inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_INO); free_task_struct(task); @@ -1029,7 +1035,7 @@ 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); @@ -1065,6 +1071,19 @@ int pid = p->pid; if (!pid) continue; + /* Even if the pid 1 is not part of the security context */ + /* we show it anyway. This makes the security box */ + /* more standard (and helps pstree do its job) */ + /* So current process "knows" pid 1 exist anyway and can't */ + /* send any signal either */ + + /* A process with security context 1 can see all processes */ + if (pid != 1 + && current->s_context != 1 + && p->s_context != current->s_context) continue; + /* We hide the fakeinit process since we show it as process 1 */ + if (current->s_info != NULL + && current->s_info->initpid == pid) continue; if (--index >= 0) continue; pids[nr_pids] = pid; diff -urN linux-2.4.20/fs/reiserfs/inode.c linux-2.4.20ctx17/fs/reiserfs/inode.c --- linux-2.4.20/fs/reiserfs/inode.c Tue Jan 7 15:50:41 2003 +++ linux-2.4.20ctx17/fs/reiserfs/inode.c Fri May 9 12:31:43 2003 @@ -1548,7 +1548,7 @@ /* 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 @@ 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 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_FILE_FL; + if( inode -> i_flags & S_IMMUTABLE_LINK ) + *sd_attrs |= REISERFS_IMMUTABLE_LINK_FL; else - *sd_attrs &= ~REISERFS_IMMUTABLE_FL; + *sd_attrs &= ~REISERFS_IMMUTABLE_LINK_FL; if( inode -> i_flags & S_SYNC ) *sd_attrs |= REISERFS_SYNC_FL; else diff -urN linux-2.4.20/fs/reiserfs/ioctl.c linux-2.4.20ctx17/fs/reiserfs/ioctl.c --- linux-2.4.20/fs/reiserfs/ioctl.c Tue Jan 7 15:50:41 2003 +++ linux-2.4.20ctx17/fs/reiserfs/ioctl.c Fri May 9 12:31:43 2003 @@ -51,7 +51,7 @@ 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 -urN linux-2.4.20/fs/udf/inode.c linux-2.4.20ctx17/fs/udf/inode.c --- linux-2.4.20/fs/udf/inode.c Tue Jan 7 15:50:14 2003 +++ linux-2.4.20ctx17/fs/udf/inode.c Fri May 9 12:31:43 2003 @@ -860,7 +860,7 @@ 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 -urN linux-2.4.20/fs/ufs/truncate.c linux-2.4.20ctx17/fs/ufs/truncate.c --- linux-2.4.20/fs/ufs/truncate.c Tue Jan 7 15:50:41 2003 +++ linux-2.4.20ctx17/fs/ufs/truncate.c Fri May 9 12:31:43 2003 @@ -434,7 +434,7 @@ 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 -urN linux-2.4.20/include/asm-i386/unistd.h linux-2.4.20ctx17/include/asm-i386/unistd.h --- linux-2.4.20/include/asm-i386/unistd.h Tue Jan 7 15:50:42 2003 +++ linux-2.4.20ctx17/include/asm-i386/unistd.h Fri May 9 12:31:43 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 253 +#define __NR_set_ipv4root 254 /* user-visible error numbers are in the range -1 - -124: see */ diff -urN linux-2.4.20/include/asm-ppc/unistd.h linux-2.4.20ctx17/include/asm-ppc/unistd.h --- linux-2.4.20/include/asm-ppc/unistd.h Tue Jan 7 15:50:46 2003 +++ linux-2.4.20ctx17/include/asm-ppc/unistd.h Fri May 9 12:31:43 2003 @@ -241,6 +241,8 @@ #define __NR_io_submit 230 #define __NR_io_cancel 231 #endif +#define __NR_new_s_context 232 +#define __NR_set_ipv4root 233 #define __NR(n) #n diff -urN linux-2.4.20/include/asm-sparc/unistd.h linux-2.4.20ctx17/include/asm-sparc/unistd.h --- linux-2.4.20/include/asm-sparc/unistd.h Tue Jan 7 15:50:20 2003 +++ linux-2.4.20ctx17/include/asm-sparc/unistd.h Fri May 9 12:31:43 2003 @@ -271,6 +271,8 @@ #define __NR_fdatasync 253 #define __NR_nfsservctl 254 #define __NR_aplib 255 +#define __NR_new_s_context 256 +#define __NR_set_ipv4root 257 #define _syscall0(type,name) \ type name(void) \ diff -urN linux-2.4.20/include/asm-sparc64/unistd.h linux-2.4.20ctx17/include/asm-sparc64/unistd.h --- linux-2.4.20/include/asm-sparc64/unistd.h Tue Jan 7 15:50:20 2003 +++ linux-2.4.20ctx17/include/asm-sparc64/unistd.h Fri May 9 12:31:43 2003 @@ -273,6 +273,8 @@ #define __NR_fdatasync 253 #define __NR_nfsservctl 254 #define __NR_aplib 255 +#define __NR_new_s_context 256 +#define __NR_set_ipv4root 257 #define _syscall0(type,name) \ type name(void) \ diff -urN linux-2.4.20/include/linux/capability.h linux-2.4.20ctx17/include/linux/capability.h --- linux-2.4.20/include/linux/capability.h Thu May 8 20:22:12 2003 +++ linux-2.4.20ctx17/include/linux/capability.h Fri May 9 12:31:43 2003 @@ -231,6 +231,7 @@ /* Allow enabling/disabling tagged queuing on SCSI controllers and sending arbitrary SCSI commands */ /* Allow setting encryption key on loopback filesystem */ +/* Allow the selection of a security context */ #define CAP_SYS_ADMIN 21 @@ -278,6 +279,10 @@ /* Allow taking of leases on files */ #define CAP_LEASE 28 + +/* Allow opening special device file */ + +#define CAP_OPENDEV 29 #ifdef __KERNEL__ /* diff -urN linux-2.4.20/include/linux/devpts_fs_info.h linux-2.4.20ctx17/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.20ctx17/include/linux/devpts_fs_info.h Fri May 9 12:31:43 2003 @@ -0,0 +1,4 @@ +struct devpts_inode_info{ + int s_context; +}; + diff -urN linux-2.4.20/include/linux/ext2_fs.h linux-2.4.20ctx17/include/linux/ext2_fs.h --- linux-2.4.20/include/linux/ext2_fs.h Thu Mar 6 22:00:04 2003 +++ linux-2.4.20ctx17/include/linux/ext2_fs.h Fri May 9 12:31:43 2003 @@ -187,7 +187,7 @@ #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 @@ #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 -urN linux-2.4.20/include/linux/ext3_fs.h linux-2.4.20ctx17/include/linux/ext3_fs.h --- linux-2.4.20/include/linux/ext3_fs.h Tue Jan 7 15:50:46 2003 +++ linux-2.4.20ctx17/include/linux/ext3_fs.h Fri May 9 12:31:43 2003 @@ -190,7 +190,7 @@ #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 @@ #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 -urN linux-2.4.20/include/linux/fs.h linux-2.4.20ctx17/include/linux/fs.h --- linux-2.4.20/include/linux/fs.h Tue Jan 7 15:50:46 2003 +++ linux-2.4.20ctx17/include/linux/fs.h Fri May 9 12:31:43 2003 @@ -128,13 +128,14 @@ /* Inode flags - they have nothing to superblock flags now */ -#define S_SYNC 1 /* Writes are synced at once */ -#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_DEAD 32 /* removed, but still open directory */ -#define S_NOQUOTA 64 /* Inode is not counted to quota */ +#define S_SYNC 1 /* Writes are synced at once */ +#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_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 @@ #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 @@ #include #include #include +#include /* * Attribute flags. These should be or-ed together to figure out what @@ -361,11 +364,12 @@ /* * This is the inode attributes flag definitions */ -#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_NODIRATIME 16 /* Don't update atime for directory */ +#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_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 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 -urN linux-2.4.20/include/linux/reiserfs_fs.h linux-2.4.20ctx17/include/linux/reiserfs_fs.h --- linux-2.4.20/include/linux/reiserfs_fs.h Fri Jan 24 07:55:53 2003 +++ linux-2.4.20ctx17/include/linux/reiserfs_fs.h Fri May 9 12:31:43 2003 @@ -736,7 +736,8 @@ /* 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 @@ #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 -urN linux-2.4.20/include/linux/sched.h linux-2.4.20ctx17/include/linux/sched.h --- linux-2.4.20/include/linux/sched.h Tue Jan 7 15:50:47 2003 +++ linux-2.4.20ctx17/include/linux/sched.h Fri May 9 12:31:43 2003 @@ -274,6 +274,7 @@ /* Hash table maintenance information */ struct user_struct *next, **pprev; uid_t uid; + int s_context; }; #define get_current_user() ({ \ @@ -281,6 +282,60 @@ 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 v4_bcast; /* Broadcast address used to receive UDP packets */ +}; + + extern struct user_struct root_user; #define INIT_USER (&root_user) @@ -407,6 +462,12 @@ unsigned long sas_ss_sp; size_t sas_ss_size; int (*notifier)(void *priv); +/* Field to make virtual server running in chroot more isolated */ + int s_context; /* Process can only deal with other processes */ + /* with the same s_context */ + __u32 cap_bset; /* Maximum capability of this process and children */ + struct context_info *s_info; + struct iproot_info *ip_info; void *notifier_data; sigset_t *notifier_mask; @@ -510,6 +571,7 @@ blocked: {{0}}, \ alloc_lock: SPIN_LOCK_UNLOCKED, \ journal_info: NULL, \ + cap_bset: CAP_INIT_EFF_SET, \ } @@ -574,7 +636,7 @@ } /* per-UID process charging. */ -extern struct user_struct * alloc_uid(uid_t); +extern struct user_struct * alloc_uid(int, uid_t); extern void free_uid(struct user_struct *); #include @@ -942,6 +1004,14 @@ 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 -urN linux-2.4.20/include/net/route.h linux-2.4.20ctx17/include/net/route.h --- linux-2.4.20/include/net/route.h Wed Apr 23 16:17:56 2003 +++ linux-2.4.20ctx17/include/net/route.h Fri May 9 12:31:43 2003 @@ -164,6 +164,26 @@ 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){ + if (src == 0){ + src = dst == 0x0100007f + ? 0x0100007f: ipv4root; + }else{ + int n=ip_info->nbipv4; + int i; + for (i=0; iipv4[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 -urN linux-2.4.20/include/net/sock.h linux-2.4.20ctx17/include/net/sock.h --- linux-2.4.20/include/net/sock.h Tue Jan 7 15:50:21 2003 +++ linux-2.4.20ctx17/include/net/sock.h Fri May 9 12:31:43 2003 @@ -487,6 +487,7 @@ } 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 @@ 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 @@ __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. @@ -668,7 +672,10 @@ /* 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 -urN linux-2.4.20/include/net/tcp.h linux-2.4.20ctx17/include/net/tcp.h --- linux-2.4.20/include/net/tcp.h Tue Jan 7 15:50:48 2003 +++ linux-2.4.20ctx17/include/net/tcp.h Fri May 9 12:31:43 2003 @@ -172,6 +172,7 @@ 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 in6_addr v6_daddr; struct in6_addr v6_rcv_saddr; #endif + int s_context; }; extern kmem_cache_t *tcp_timewait_cachep; diff -urN linux-2.4.20/ipc/util.c linux-2.4.20ctx17/ipc/util.c --- linux-2.4.20/ipc/util.c Tue Jan 7 15:50:48 2003 +++ linux-2.4.20ctx17/ipc/util.c Fri May 9 12:31:43 2003 @@ -93,6 +93,7 @@ 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 +168,7 @@ spin_lock(&ids->ary); ids->entries[id].p = new; + ids->entries[id].s_context = current->s_context; return id; } diff -urN linux-2.4.20/ipc/util.h linux-2.4.20ctx17/ipc/util.h --- linux-2.4.20/ipc/util.h Tue Jan 7 15:50:48 2003 +++ linux-2.4.20ctx17/ipc/util.h Fri May 9 12:31:43 2003 @@ -25,6 +25,7 @@ struct ipc_id { struct kern_ipc_perm* p; + int s_context; // Context owning this ID }; @@ -74,8 +75,12 @@ spin_lock(&ids->ary); out = ids->entries[lid].p; - if(out==NULL) + if(out==NULL + || (ids->entries[lid].s_context != current->s_context + && current->s_context != 1)){ spin_unlock(&ids->ary); + out = NULL; + } return out; } diff -urN linux-2.4.20/kernel/exit.c linux-2.4.20ctx17/kernel/exit.c --- linux-2.4.20/kernel/exit.c Tue Jan 7 15:50:48 2003 +++ linux-2.4.20ctx17/kernel/exit.c Fri May 9 12:31:43 2003 @@ -66,6 +66,8 @@ current->counter += p->counter; if (current->counter >= MAX_COUNTER) current->counter = MAX_COUNTER; + sys_release_s_info(p); + sys_release_ip_info(p->ip_info); p->pid = 0; free_task_struct(p); } else { @@ -159,8 +161,17 @@ static inline void forget_original_parent(struct task_struct * father) { struct task_struct * p; + struct task_struct *vchild_reaper = child_reaper; read_lock(&tasklist_lock); + if (father->s_info != NULL){ + pid_t initpid = father->s_info->initpid; + if (initpid != 0 + && father->pid != initpid){ + struct task_struct *r = find_task_by_pid(initpid); + if (r != NULL) vchild_reaper = r; + } + } for_each_task(p) { if (p->p_opptr == father) { @@ -169,7 +180,7 @@ p->self_exec_id++; /* Make sure we're not reparenting to ourselves */ - p->p_opptr = child_reaper; + p->p_opptr = vchild_reaper; if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0); } diff -urN linux-2.4.20/kernel/fork.c linux-2.4.20ctx17/kernel/fork.c --- linux-2.4.20/kernel/fork.c Tue Jan 7 15:50:48 2003 +++ linux-2.4.20ctx17/kernel/fork.c Fri May 9 12:31:43 2003 @@ -603,6 +603,10 @@ *p = *current; retval = -EAGAIN; + if (p->s_info != NULL && (p->s_info->flags & S_CTX_INFO_NPROC)!=0){ + 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 @@ 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 -urN linux-2.4.20/kernel/printk.c linux-2.4.20ctx17/kernel/printk.c --- linux-2.4.20/kernel/printk.c Tue Jan 7 15:50:21 2003 +++ linux-2.4.20ctx17/kernel/printk.c Fri May 9 12:31:43 2003 @@ -172,6 +172,8 @@ char c; int error = 0; + if (!capable(CAP_SYS_ADMIN) && current->s_context != 0) return -EPERM; + switch (type) { case 0: /* Close log */ break; diff -urN linux-2.4.20/kernel/sched.c linux-2.4.20ctx17/kernel/sched.c --- linux-2.4.20/kernel/sched.c Tue Jan 7 15:50:48 2003 +++ linux-2.4.20ctx17/kernel/sched.c Fri May 9 12:31:43 2003 @@ -165,7 +165,13 @@ * 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)!=0){ + 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,23 @@ 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)!=0){ + 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)!=0){ + atomic_add (p->counter,&p->s_info->ticks); + } + } read_unlock(&tasklist_lock); spin_lock_irq(&runqueue_lock); goto repeat_schedule; diff -urN linux-2.4.20/kernel/signal.c linux-2.4.20ctx17/kernel/signal.c --- linux-2.4.20/kernel/signal.c Tue Jan 7 15:50:48 2003 +++ linux-2.4.20ctx17/kernel/signal.c Fri May 9 12:31:43 2003 @@ -596,7 +596,9 @@ retval = -ESRCH; read_lock(&tasklist_lock); for_each_task(p) { - if (p->pgrp == pgrp && thread_group_leader(p)) { + if (p->pgrp == pgrp && thread_group_leader(p) + && ((long)info==1 + || p->s_context == current->s_context)) { int err = send_sig_info(sig, info, p); if (retval) retval = err; @@ -650,7 +652,22 @@ 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 +691,8 @@ read_lock(&tasklist_lock); for_each_task(p) { - if (p->pid > 1 && p != current && thread_group_leader(p)) { + if (p->pid > 1 && p != current && thread_group_leader(p) + && p->s_context == current->s_context) { int err = send_sig_info(sig, info, p); ++count; if (err != -EPERM) @@ -1298,3 +1316,147 @@ 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)!=0){ + 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) == 0){ + /* Ok we allocate a new context. For now, we just increase */ + /* it. Wrap around possible, so we loop */ + static int alloc_ctx=1; + static spinlock_t alloc_ctx_lock = SPIN_LOCK_UNLOCKED; + spin_lock(&alloc_ctx_lock); + while (1){ + int found = 0; + struct task_struct *p; + alloc_ctx++; + /* The s_context 1 is special. It sess all processes */ + if (alloc_ctx == 1){ + alloc_ctx++; + }else if (alloc_ctx > MAX_S_CONTEXT){ + // No need to grow and grow + alloc_ctx = 2; + } + /* Check if in use */ + read_lock(&tasklist_lock); + for_each_task(p) { + if (p->s_context == alloc_ctx){ + found = 1; + break; + } + } + read_unlock(&tasklist_lock); + if (!found) break; + } + ret = switch_user_struct(alloc_ctx); + if (ret == 0) { + current->s_context = alloc_ctx; + current->cap_bset &= (~remove_cap); + ret = alloc_ctx; + sys_alloc_s_info(); + if (current->s_info != NULL) { + set_initpid (flags); + current->s_info->flags |= flags; + } + } + spin_unlock(&alloc_ctx_lock); + } + }else if (ctx == -2){ + ret = set_initpid(flags); + if (ret == 0){ + /* We keep the same s_context, but lower the capabilities */ + current->cap_bset &= (~remove_cap); + ret = current->s_context; + if (current->s_info != NULL){ + if ((flags & S_CTX_INFO_INIT)!=0){ + 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)==0){ + sys_release_s_info(current); + sys_assign_s_info (p); + current->s_info = p->s_info; + }else{ + ret = -EPERM; + } + break; + } + } + read_unlock(&tasklist_lock); + if (ret == ctx) { + ret = switch_user_struct(ctx); + if (ret == 0) { + current->s_context = ctx; + current->cap_bset &= (~remove_cap); + if (!found) { + sys_alloc_s_info(); + } + if (current->s_info != NULL) { + current->s_info->flags |= flags; + } + } + } + } + return ret; +} + diff -urN linux-2.4.20/kernel/sys.c linux-2.4.20ctx17/kernel/sys.c --- linux-2.4.20/kernel/sys.c Tue Jan 7 15:50:21 2003 +++ linux-2.4.20ctx17/kernel/sys.c Fri May 9 12:31:43 2003 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -499,7 +500,7 @@ * 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,147 @@ asmlinkage long sys_newuname(struct new_utsname * name) { int errno = 0; + struct new_utsname tmp,*pttmp; down_read(&uts_sem); - if (copy_to_user(name,&system_utsname,sizeof *name)) + if (current->s_info != NULL){ + tmp = system_utsname; + strcpy (tmp.nodename,current->s_info->nodename); + strcpy (tmp.domainname,current->s_info->domainname); + pttmp = &tmp; + }else{ + pttmp = &system_utsname; + } + if (copy_to_user(name,pttmp,sizeof *name)) errno = -EFAULT; up_read(&uts_sem); return errno; } +/* + Decrease the reference count on the context_info member of a task + Free the struct if the reference count reach 0. +*/ +void sys_release_s_info (struct task_struct *p) +{ + down_write (&uts_sem); + if (p->s_info != NULL){ + p->s_info->refcount--; + if (p->s_info->refcount == 0){ + // printk ("vfree s_info %d\n",p->pid); + 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 != NULL) p->s_info->refcount++; + up_write (&uts_sem); +} + +/* + Alloc a new s_info to the current process and release + the one currently owned by the current process. +*/ +void sys_alloc_s_info() +{ + struct context_info *s_info = vmalloc(sizeof(struct context_info)); + if (s_info != NULL){ + int i; + memset (s_info,0,sizeof(*s_info)); + // printk ("new s_info %d\n",current->pid); + 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; irlim[i] = 0xffffffff; + atomic_set (&s_info->res[i],0); + } + down_read (&uts_sem); + if (current->s_info != NULL){ + 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(¤t->files->count)); + // printk ("new s_info ctx=%d file->count %d\n",current->s_context + // ,atomic_read (&s_info->res[RLIMIT_NOFILE])); + } +} + +/* + Decrease the reference count on the ip_info struct + Free the struct if the reference count reach 0. +*/ +void sys_release_ip_info (struct iproot_info *ip_info) +{ + if (ip_info != NULL){ + if (atomic_dec_and_test(&ip_info->refcount)){ + if (ip_info->mark != 0xdeadbeef){ + printk ("sys_release_ip_info: broken signature %08lx, tell jack@solucorp.qc.ca\n",ip_info->mark); + }else{ + // printk ("vfree s_info %d\n",p->pid); + vfree (ip_info); + } + } + } +} +/* + Increase the reference count on the ip_info member of a task +*/ +void sys_assign_ip_info (struct iproot_info *ip_info) +{ + if (ip_info != NULL){ + atomic_inc (&ip_info->refcount); + if (ip_info->mark != 0xdeadbeef){ + printk ("sys_assign_ip_info: broken signature %08lx, tell jack@solucorp.qc.ca\n",ip_info->mark); + } + } +} + +/* + Alloc a new ip_info to the current process and release + the one currently owned by the current process. +*/ +void sys_alloc_ip_info() +{ + struct iproot_info *ip_info = vmalloc(sizeof(struct iproot_info)); + // printk ("new s_info %d\n",current->pid); + memset (ip_info,0,sizeof(*ip_info)); + ip_info->mark = 0xdeadbeef; + atomic_set (&ip_info->refcount,1); + sys_release_ip_info (current->ip_info); + current->ip_info = ip_info; +} + + asmlinkage long sys_sethostname(char *name, int len) { int errno; + char *nodename; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1033,8 +1164,10 @@ 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 +1177,18 @@ 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 != NULL) 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 +1201,7 @@ asmlinkage long sys_setdomainname(char *name, int len) { int errno; + char *domainname; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1072,10 +1209,12 @@ return -EINVAL; down_write(&uts_sem); + domainname = system_utsname.domainname; + if (current->s_info) domainname = current->s_info->domainname; errno = -EFAULT; - if (!copy_from_user(system_utsname.domainname, name, len)) { + if (!copy_from_user(domainname, name, len)) { errno = 0; - system_utsname.domainname[len] = 0; + domainname[len] = 0; } up_write(&uts_sem); return errno; diff -urN linux-2.4.20/kernel/sysctl.c linux-2.4.20ctx17/kernel/sysctl.c --- linux-2.4.20/kernel/sysctl.c Tue Jan 7 15:50:21 2003 +++ linux-2.4.20ctx17/kernel/sysctl.c Fri May 9 12:31:43 2003 @@ -381,6 +381,7 @@ 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 +796,18 @@ void *buffer, size_t *lenp) { int r; + ctl_table tmp; + /* HACK for per s_context hostname and domainname */ + if (current->s_info != NULL){ + tmp = *table; + table = &tmp; + if (table->data == (void*)&system_utsname.nodename){ + tmp.data = ¤t->s_info->nodename; + }else if (table->data == (void*)&system_utsname.domainname){ + tmp.data = ¤t->s_info->domainname; + } + } if (!write) { down_read(&uts_sem); r=proc_dostring(table,0,filp,buffer,lenp); diff -urN linux-2.4.20/kernel/timer.c linux-2.4.20ctx17/kernel/timer.c --- linux-2.4.20/kernel/timer.c Tue Jan 7 15:50:48 2003 +++ linux-2.4.20ctx17/kernel/timer.c Fri May 9 12:31:43 2003 @@ -599,6 +599,11 @@ update_one_process(p, user_tick, system, cpu); if (p->pid) { + if (p->s_info != NULL + && (p->s_info->flags & S_CTX_INFO_SCHED)!=0){ + // atomic_sub (ticks*p->s_info->refcount, &p->s_info->ticks); + atomic_dec (&p->s_info->ticks); + } if (--p->counter <= 0) { p->counter = 0; /* @@ -752,6 +757,11 @@ */ asmlinkage long sys_getpid(void) { + if (current->s_info != NULL + && current->s_info->initpid == current->tgid){ + /* We are faking process 1 for this security context */ + return 1; + } return current->tgid; } @@ -797,6 +807,12 @@ } #endif break; + } + if (pid != 0 + && current->s_info != NULL + && current->s_info->initpid == pid){ + /* We are faking process 1 for this security context */ + pid = 1; } return pid; } diff -urN linux-2.4.20/kernel/user.c linux-2.4.20ctx17/kernel/user.c --- linux-2.4.20/kernel/user.c Wed Nov 29 07:43:39 2000 +++ linux-2.4.20ctx17/kernel/user.c Fri May 9 12:31:43 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 @@ -56,7 +69,7 @@ *pprev = next; } -static inline struct user_struct *uid_hash_find(uid_t uid, struct user_struct **hashent) +static inline struct user_struct *uid_hash_find(int s_context, uid_t uid, struct user_struct **hashent) { struct user_struct *next; @@ -65,7 +78,7 @@ struct user_struct *up = next; if (next) { next = up->next; - if (up->uid != uid) + if (up->uid != uid || up->s_context != s_context) continue; atomic_inc(&up->__count); } @@ -82,13 +95,13 @@ } } -struct user_struct * alloc_uid(uid_t uid) +struct user_struct * alloc_uid(int s_context, uid_t uid) { struct user_struct **hashent = uidhashentry(uid); struct user_struct *up; spin_lock(&uidhash_lock); - up = uid_hash_find(uid, hashent); + up = uid_hash_find(s_context, uid, hashent); spin_unlock(&uidhash_lock); if (!up) { @@ -98,6 +111,7 @@ if (!new) return NULL; new->uid = uid; + new->s_context = s_context; atomic_set(&new->__count, 1); atomic_set(&new->processes, 0); atomic_set(&new->files, 0); @@ -107,7 +121,7 @@ * on adding the same user already.. */ spin_lock(&uidhash_lock); - up = uid_hash_find(uid, hashent); + up = uid_hash_find(s_context, uid, hashent); if (up) { kmem_cache_free(uid_cachep, new); } else { diff -urN linux-2.4.20/net/ipv4/af_inet.c linux-2.4.20ctx17/net/ipv4/af_inet.c --- linux-2.4.20/net/ipv4/af_inet.c Tue Jan 7 15:50:21 2003 +++ linux-2.4.20ctx17/net/ipv4/af_inet.c Fri May 9 12:31:43 2003 @@ -177,6 +177,8 @@ 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 @@ 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 @@ 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,40 @@ 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 != NULL){ + __u32 v4_bcast = ip_info->v4_bcast; + __u32 ipv4root = ip_info->ipv4[0]; + int nbipv4 = ip_info->nbipv4; + // printk ("ipv4root0 %08lx %08x\n",ipv4root,s_addr); + 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; iipv4[i]){ + break; + } + } + if (i == nbipv4) return -EADDRNOTAVAIL; + ip_info = NULL; + } + //printk ("bind: ip_info != NULL, s_addr %x, s_addr1 %x, s_addr2 %x\n" + // ,s_addr,s_addr1,s_addr2); + } + 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 +539,7 @@ */ 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 +564,18 @@ (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 != NULL) 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 -urN linux-2.4.20/net/ipv4/devinet.c linux-2.4.20ctx17/net/ipv4/devinet.c --- linux-2.4.20/net/ipv4/devinet.c Tue Jan 7 15:50:21 2003 +++ linux-2.4.20ctx17/net/ipv4/devinet.c Fri May 9 12:31:43 2003 @@ -455,6 +455,32 @@ 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 != 0 && info != NULL){ + int i; + int nbip = info->nbipv4; + __u32 addr = ifa->ifa_local; + ret = 1; + for (i=0; iipv4[i] == addr){ + ret = 0; + break; + } + } + } + return ret; +} + int devinet_ioctl(unsigned int cmd, void *arg) { @@ -558,7 +584,11 @@ 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,8 @@ 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 +940,7 @@ 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 -urN linux-2.4.20/net/ipv4/raw.c linux-2.4.20ctx17/net/ipv4/raw.c --- linux-2.4.20/net/ipv4/raw.c Tue Jan 7 15:50:23 2003 +++ linux-2.4.20ctx17/net/ipv4/raw.c Fri May 9 12:31:43 2003 @@ -96,16 +96,48 @@ 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; iipv4[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->rcv_saddr && s->rcv_saddr != laddr) && !(s->bound_dev_if && s->bound_dev_if != dif)) break; /* gotcha */ } @@ -657,7 +689,7 @@ 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 -urN linux-2.4.20/net/ipv4/tcp_ipv4.c linux-2.4.20ctx17/net/ipv4/tcp_ipv4.c --- linux-2.4.20/net/ipv4/tcp_ipv4.c Tue Jan 7 15:50:49 2003 +++ linux-2.4.20ctx17/net/ipv4/tcp_ipv4.c Fri May 9 12:31:43 2003 @@ -174,6 +174,56 @@ 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) +{ + int ret = 0; + struct iproot_info *ip_info = sk->ip_info; + if (ip_info != NULL){ + int n = ip_info->nbipv4; + int i; + for (i=0; iipv4[i] == addr){ + ret = 1; + break; + } + } + }else if (!sk->rcv_saddr || sk->rcv_saddr == addr){ + ret = 1; + } + return ret; +} + +/* + 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 != NULL){ + /* A restricted bind(any) */ + struct iproot_info *ip_info = sk1->ip_info; + int n = ip_info->nbipv4; + int i; + for (i=0; iipv4[i])){ + ret = 1; + break; + } + } + }else{ + /* A bind(any) do not allow other bind on the same port */ + ret = 1; + } + return ret; +} + static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb) { struct sock *sk2 = tb->owners; @@ -186,9 +236,7 @@ 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 +455,37 @@ 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) +{ + int ret = 0; + if (rcv_saddr == daddr){ + ret = 1; + }else if (rcv_saddr == 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; iipv4[i] == daddr){ + ret = 1; + break; + } + } + } + } + return ret; +} + + + /* 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,10 +503,10 @@ __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) @@ -455,7 +534,7 @@ 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 +2262,9 @@ 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 +2318,7 @@ 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 +2333,7 @@ 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 -urN linux-2.4.20/net/ipv4/tcp_minisocks.c linux-2.4.20ctx17/net/ipv4/tcp_minisocks.c --- linux-2.4.20/net/ipv4/tcp_minisocks.c Tue Jan 7 15:50:49 2003 +++ linux-2.4.20ctx17/net/ipv4/tcp_minisocks.c Fri May 9 12:31:43 2003 @@ -380,6 +380,9 @@ 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 @@ #endif memcpy(newsk, sk, sizeof(*newsk)); + sys_assign_ip_info (newsk->ip_info); newsk->state = TCP_SYN_RECV; /* SANITY */ diff -urN linux-2.4.20/net/ipv4/udp.c linux-2.4.20ctx17/net/ipv4/udp.c --- linux-2.4.20/net/ipv4/udp.c Tue Jan 7 15:50:23 2003 +++ linux-2.4.20ctx17/net/ipv4/udp.c Fri May 9 12:31:43 2003 @@ -106,6 +106,9 @@ /* 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 @@ 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 @@ 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; iipv4[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,12 @@ if(sk->rcv_saddr != daddr) continue; score++; + }else if (sk->ip_info != NULL){ + if (udp_in_list (sk->ip_info,daddr)){ + score++; + }else{ + continue; + } } if(sk->daddr) { if(sk->daddr != saddr) @@ -261,6 +282,7 @@ return sk; } + static inline struct sock *udp_v4_mcast_next(struct sock *sk, u16 loc_port, u32 loc_addr, u16 rmt_port, u32 rmt_addr, @@ -272,7 +294,7 @@ 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 +539,24 @@ 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 != 0){ + if (daddr == 0x0100007f && current->s_context != 0){ + daddr = ipv4root; + } + if (ufh.saddr == 0){ + ufh.saddr = ipv4root; + } + #if 0 + else if (!udp_in_list(ip_info,ufh.saddr)){ + err = EADDRNOTAVAIL; + goto out; + } + #endif + } + } err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif); if (err) goto out; @@ -1004,7 +1044,7 @@ 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 -urN linux-2.4.20/net/ipv6/raw.c linux-2.4.20ctx17/net/ipv6/raw.c --- linux-2.4.20/net/ipv6/raw.c Tue Jan 7 15:50:23 2003 +++ linux-2.4.20ctx17/net/ipv6/raw.c Fri May 9 12:31:43 2003 @@ -879,7 +879,7 @@ 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 -urN linux-2.4.20/net/ipv6/tcp_ipv6.c linux-2.4.20ctx17/net/ipv6/tcp_ipv6.c --- linux-2.4.20/net/ipv6/tcp_ipv6.c Tue Jan 7 15:50:49 2003 +++ linux-2.4.20ctx17/net/ipv6/tcp_ipv6.c Fri May 9 12:31:43 2003 @@ -2006,7 +2006,7 @@ 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 +2056,7 @@ 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 +2071,7 @@ 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 -urN linux-2.4.20/net/ipv6/udp.c linux-2.4.20ctx17/net/ipv6/udp.c --- linux-2.4.20/net/ipv6/udp.c Tue Jan 7 15:50:49 2003 +++ linux-2.4.20ctx17/net/ipv6/udp.c Fri May 9 12:31:43 2003 @@ -957,7 +957,7 @@ 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 -urN linux-2.4.20/net/socket.c linux-2.4.20ctx17/net/socket.c --- linux-2.4.20/net/socket.c Tue Jan 7 15:50:49 2003 +++ linux-2.4.20ctx17/net/socket.c Fri May 9 12:31:43 2003 @@ -1754,3 +1754,48 @@ len = 0; return len; } + +asmlinkage int sys_set_ipv4root (__u32 ip[], int nbip, __u32 bcast) +{ + int ret = -EPERM; + __u32 tbip[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]))!=0){ + ret = -EFAULT; + }else if (ip_info == NULL + || ip_info->ipv4[0] == 0 + || capable(CAP_NET_ADMIN)){ + // We are allowed to change everything + ret = 0; + }else if (current->ip_info != NULL){ + // 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; inbipv4; 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; + } + return ret; +} + diff -urN linux-2.4.20/net/unix/af_unix.c linux-2.4.20ctx17/net/unix/af_unix.c --- linux-2.4.20/net/unix/af_unix.c Tue Jan 7 15:50:49 2003 +++ linux-2.4.20ctx17/net/unix/af_unix.c Fri May 9 12:31:43 2003 @@ -479,6 +479,8 @@ 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 @@ 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",