diff -rc2P linux-2.4.10/Makefile linux-2.4.10ctx/Makefile *** linux-2.4.10/Makefile Sun Sep 23 13:02:30 2001 --- linux-2.4.10ctx/Makefile Tue Sep 25 11:33:49 2001 *************** *** 2,6 **** PATCHLEVEL = 4 SUBLEVEL = 10 ! EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) --- 2,6 ---- PATCHLEVEL = 4 SUBLEVEL = 10 ! EXTRAVERSION =ctx KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -rc2P linux-2.4.10/arch/i386/kernel/entry.S linux-2.4.10ctx/arch/i386/kernel/entry.S *** linux-2.4.10/arch/i386/kernel/entry.S Sat Sep 8 15:02:32 2001 --- linux-2.4.10ctx/arch/i386/kernel/entry.S Mon Sep 24 21:31:13 2001 *************** *** 620,623 **** --- 620,625 ---- .long SYMBOL_NAME(sys_getdents64) /* 220 */ .long SYMBOL_NAME(sys_fcntl64) + .long SYMBOL_NAME(sys_new_s_context) + .long SYMBOL_NAME(sys_set_ipv4root) .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ diff -rc2P linux-2.4.10/arch/i386/kernel/ptrace.c linux-2.4.10ctx/arch/i386/kernel/ptrace.c *** linux-2.4.10/arch/i386/kernel/ptrace.c Tue Sep 18 20:04:23 2001 --- linux-2.4.10ctx/arch/i386/kernel/ptrace.c Mon Sep 24 21:31:13 2001 *************** *** 171,175 **** get_task_struct(child); read_unlock(&tasklist_lock); ! if (!child) goto out; --- 171,175 ---- get_task_struct(child); read_unlock(&tasklist_lock); ! if (!child || child->s_context != current->s_context) goto out; diff -rc2P linux-2.4.10/fs/exec.c linux-2.4.10ctx/fs/exec.c *** linux-2.4.10/fs/exec.c Tue Sep 18 16:39:32 2001 --- linux-2.4.10ctx/fs/exec.c Mon Sep 24 21:31:13 2001 *************** *** 685,689 **** int do_unlock = 0; ! new_permitted = cap_intersect(bprm->cap_permitted, cap_bset); working = cap_intersect(bprm->cap_inheritable, current->cap_inheritable); --- 685,689 ---- int do_unlock = 0; ! new_permitted = cap_intersect(bprm->cap_permitted, current->cap_bset); working = cap_intersect(bprm->cap_inheritable, current->cap_inheritable); diff -rc2P linux-2.4.10/fs/proc/array.c linux-2.4.10ctx/fs/proc/array.c *** linux-2.4.10/fs/proc/array.c Wed Sep 19 19:18:31 2001 --- linux-2.4.10ctx/fs/proc/array.c Mon Sep 24 21:31:13 2001 *************** *** 263,270 **** return buffer + sprintf(buffer, "CapInh:\t%016x\n" "CapPrm:\t%016x\n" ! "CapEff:\t%016x\n", cap_t(p->cap_inheritable), cap_t(p->cap_permitted), ! cap_t(p->cap_effective)); } --- 263,272 ---- return buffer + sprintf(buffer, "CapInh:\t%016x\n" "CapPrm:\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_bset)); } *************** *** 288,291 **** --- 290,295 ---- buffer = task_sig(task, buffer); buffer = task_cap(task, buffer); + buffer += sprintf (buffer,"s_context: %d\n",task->s_context); + buffer += sprintf (buffer,"ipv4root: %08lx\n",task->ipv4root); #if defined(CONFIG_ARCH_S390) buffer = task_show_regs(task, buffer); diff -rc2P linux-2.4.10/fs/proc/base.c linux-2.4.10ctx/fs/proc/base.c *** linux-2.4.10/fs/proc/base.c Fri Jul 20 15:39:56 2001 --- linux-2.4.10ctx/fs/proc/base.c Mon Sep 24 21:31:13 2001 *************** *** 1036,1039 **** --- 1036,1049 ---- 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; if (--index >= 0) continue; diff -rc2P linux-2.4.10/include/asm-i386/unistd.h linux-2.4.10ctx/include/asm-i386/unistd.h *** linux-2.4.10/include/asm-i386/unistd.h Fri Aug 11 17:39:23 2000 --- linux-2.4.10ctx/include/asm-i386/unistd.h Mon Sep 24 21:31:13 2001 *************** *** 228,231 **** --- 228,233 ---- #define __NR_getdents64 220 #define __NR_fcntl64 221 + #define __NR_new_s_context 222 + #define __NR_set_ipv4root 223 /* user-visible error numbers are in the range -1 - -124: see */ diff -rc2P linux-2.4.10/include/linux/capability.h linux-2.4.10ctx/include/linux/capability.h *** linux-2.4.10/include/linux/capability.h Sun Sep 23 13:31:02 2001 --- linux-2.4.10ctx/include/linux/capability.h Tue Sep 25 11:36:12 2001 *************** *** 232,235 **** --- 232,236 ---- arbitrary SCSI commands */ /* Allow setting encryption key on loopback filesystem */ + /* Allow the selection of a security context */ #define CAP_SYS_ADMIN 21 *************** *** 277,280 **** --- 278,285 ---- #define CAP_LEASE 28 + + /* Allow opening special device file */ + + #define CAP_OPENDEV 29 #ifdef __KERNEL__ diff -rc2P linux-2.4.10/include/linux/sched.h linux-2.4.10ctx/include/linux/sched.h *** linux-2.4.10/include/linux/sched.h Sun Sep 23 13:31:02 2001 --- linux-2.4.10ctx/include/linux/sched.h Thu Sep 27 14:36:33 2001 *************** *** 276,279 **** --- 276,293 ---- __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 + */ + struct context_info{ + int refcount; + int s_context; + char nodename[65]; + char domainname[65]; + }; + + extern struct user_struct root_user; #define INIT_USER (&root_user) *************** *** 400,403 **** --- 414,423 ---- /* Protection of (de-)allocation: mm, files, fs, tty */ spinlock_t alloc_lock; + /* 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 */ + unsigned long ipv4root; /* Process can only bind to this iP */ + struct context_info *s_info; }; *************** *** 486,490 **** pending: { NULL, &tsk.pending.head, {{0}}}, \ blocked: {{0}}, \ ! alloc_lock: SPIN_LOCK_UNLOCKED \ } --- 506,511 ---- pending: { NULL, &tsk.pending.head, {{0}}}, \ blocked: {{0}}, \ ! alloc_lock: SPIN_LOCK_UNLOCKED, \ ! cap_bset: CAP_INIT_EFF_SET, \ } *************** *** 899,902 **** --- 920,928 ---- 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); #endif /* __KERNEL__ */ diff -rc2P linux-2.4.10/include/net/route.h linux-2.4.10ctx/include/net/route.h *** linux-2.4.10/include/net/route.h Sun Sep 23 13:31:33 2001 --- linux-2.4.10ctx/include/net/route.h Thu Sep 27 14:42:00 2001 *************** *** 161,164 **** --- 161,171 ---- { int err; + if (current->ipv4root != 0){ + if (src == 0){ + src = current->ipv4root; + }else if (current->ipv4root != src){ + return -EPERM; + } + } err = ip_route_output(rp, dst, src, tos, oif); if (err || (dst && src)) diff -rc2P linux-2.4.10/kernel/exit.c linux-2.4.10ctx/kernel/exit.c *** linux-2.4.10/kernel/exit.c Mon Sep 10 16:04:33 2001 --- linux-2.4.10ctx/kernel/exit.c Thu Sep 27 07:31:28 2001 *************** *** 65,68 **** --- 65,69 ---- if (current->counter >= MAX_COUNTER) current->counter = MAX_COUNTER; + sys_release_s_info(p); p->pid = 0; free_task_struct(p); diff -rc2P linux-2.4.10/kernel/fork.c linux-2.4.10ctx/kernel/fork.c *** linux-2.4.10/kernel/fork.c Tue Sep 18 00:46:04 2001 --- linux-2.4.10ctx/kernel/fork.c Wed Sep 26 23:28:39 2001 *************** *** 584,587 **** --- 584,588 ---- *p = *current; + sys_assign_s_info (p); retval = -EAGAIN; diff -rc2P linux-2.4.10/kernel/signal.c linux-2.4.10ctx/kernel/signal.c *** linux-2.4.10/kernel/signal.c Mon Sep 17 19:40:01 2001 --- linux-2.4.10ctx/kernel/signal.c Thu Sep 27 08:10:25 2001 *************** *** 593,597 **** read_lock(&tasklist_lock); for_each_task(p) { ! if (p->pgrp == pgrp) { int err = send_sig_info(sig, info, p); if (retval) --- 593,597 ---- read_lock(&tasklist_lock); for_each_task(p) { ! if (p->pgrp == pgrp && p->s_context == current->s_context) { int err = send_sig_info(sig, info, p); if (retval) *************** *** 640,644 **** p = find_task_by_pid(pid); error = -ESRCH; ! if (p) error = send_sig_info(sig, info, p); read_unlock(&tasklist_lock); --- 640,644 ---- p = find_task_by_pid(pid); error = -ESRCH; ! if (p && p->s_context == current->s_context) error = send_sig_info(sig, info, p); read_unlock(&tasklist_lock); *************** *** 664,668 **** read_lock(&tasklist_lock); for_each_task(p) { ! if (p->pid > 1 && p != current) { int err = send_sig_info(sig, info, p); ++count; --- 664,668 ---- read_lock(&tasklist_lock); for_each_task(p) { ! if (p->pid > 1 && p != current && p->s_context == current->s_context) { int err = send_sig_info(sig, info, p); ++count; *************** *** 1257,1258 **** --- 1257,1331 ---- } #endif /* !alpha && !__ia64__ && !defined(__mips__) */ + + /* + 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) + { + #define MAX_S_CONTEXT 65535 /* Arbitrary limit */ + int ret = -EPERM; + if (ctx == -1){ + /* 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; + } + current->s_context = alloc_ctx; + current->cap_bset &= (~remove_cap); + ret = alloc_ctx; + sys_alloc_s_info(); + spin_unlock(&alloc_ctx_lock); + }else if (ctx == -2){ + /* We keep the same s_context, but lower the capabilities */ + current->cap_bset &= (~remove_cap); + ret = current->s_context; + }else if (ctx < 0 || ctx > MAX_S_CONTEXT){ + ret = -EINVAL; + }else if (current->s_context == 0 && capable(CAP_SYS_ADMIN)){ + /* The root context can become any context it wants */ + int found = 0; + struct task_struct *p; + current->s_context = ctx; + current->cap_bset &= (~remove_cap); + /* Check if in use so we reuse the same context_info */ + read_lock(&tasklist_lock); + for_each_task(p) { + if (p->s_context == ctx){ + found = 1; + sys_release_s_info(current); + current->s_info = p->s_info; + sys_assign_s_info (current); + break; + } + } + read_unlock(&tasklist_lock); + if (!found) sys_alloc_s_info(); + ret = ctx; + } + return ret; + } + diff -rc2P linux-2.4.10/kernel/sys.c linux-2.4.10ctx/kernel/sys.c *** linux-2.4.10/kernel/sys.c Tue Sep 18 17:10:43 2001 --- linux-2.4.10ctx/kernel/sys.c Thu Sep 27 16:54:18 2001 *************** *** 1016,1022 **** { int errno = 0; down_read(&uts_sem); ! if (copy_to_user(name,&system_utsname,sizeof *name)) errno = -EFAULT; up_read(&uts_sem); --- 1016,1031 ---- { int errno = 0; + struct new_utsname tmp,*pttmp; down_read(&uts_sem); ! 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); *************** *** 1024,1030 **** --- 1033,1080 ---- } + /* + 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) + { + 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; + } + } + } + /* + Increase the reference count on the context_info member of a task + */ + void sys_assign_s_info (struct task_struct *p) + { + if (p->s_info != NULL) p->s_info->refcount++; + } + + void sys_alloc_s_info() + { + struct context_info *s_info = vmalloc(sizeof(struct context_info)); + // printk ("new s_info %d\n",current->pid); + s_info->s_context = current->s_context; + 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); + } + s_info->refcount = 1; + sys_release_s_info (current); + current->s_info = s_info; + } + asmlinkage long sys_sethostname(char *name, int len) { int errno; + char *nodename; if (!capable(CAP_SYS_ADMIN)) *************** *** 1034,1039 **** down_write(&uts_sem); errno = -EFAULT; ! if (!copy_from_user(system_utsname.nodename, name, len)) { ! system_utsname.nodename[len] = 0; errno = 0; } --- 1084,1091 ---- down_write(&uts_sem); errno = -EFAULT; ! 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; } *************** *** 1045,1057 **** { int i, errno; if (len < 0) return -EINVAL; down_read(&uts_sem); ! i = 1 + strlen(system_utsname.nodename); if (i > len) i = len; errno = 0; ! if (copy_to_user(name, system_utsname.nodename, i)) errno = -EFAULT; up_read(&uts_sem); --- 1097,1112 ---- { int i, errno; + char *nodename; if (len < 0) return -EINVAL; down_read(&uts_sem); ! 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, nodename, i)) errno = -EFAULT; up_read(&uts_sem); *************** *** 1066,1069 **** --- 1121,1125 ---- { int errno; + char *domainname; if (!capable(CAP_SYS_ADMIN)) *************** *** 1073,1080 **** down_write(&uts_sem); errno = -EFAULT; ! if (!copy_from_user(system_utsname.domainname, name, len)) { errno = 0; ! system_utsname.domainname[len] = 0; } up_write(&uts_sem); --- 1129,1138 ---- down_write(&uts_sem); + domainname = system_utsname.domainname; + if (current->s_info) domainname = current->s_info->domainname; errno = -EFAULT; ! if (!copy_from_user(domainname, name, len)) { errno = 0; ! domainname[len] = 0; } up_write(&uts_sem); diff -rc2P linux-2.4.10/kernel/sysctl.c linux-2.4.10ctx/kernel/sysctl.c *** linux-2.4.10/kernel/sysctl.c Tue Sep 18 17:10:43 2001 --- linux-2.4.10ctx/kernel/sysctl.c Thu Sep 27 16:48:22 2001 *************** *** 789,793 **** --- 789,804 ---- { 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); diff -rc2P linux-2.4.10/net/ipv4/af_inet.c linux-2.4.10ctx/net/ipv4/af_inet.c *** linux-2.4.10/net/ipv4/af_inet.c Tue Aug 7 11:30:50 2001 --- linux-2.4.10ctx/net/ipv4/af_inet.c Mon Sep 24 21:31:13 2001 *************** *** 474,477 **** --- 474,478 ---- int chk_addr_ret; int err; + __u32 s_addr; /* If the socket has its own bind function then use it. (RAW) */ *************** *** 482,486 **** return -EINVAL; ! chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); /* Not specified by any standard per-se, however it breaks too --- 483,497 ---- return -EINVAL; ! s_addr = addr->sin_addr.s_addr; ! if (current->ipv4root != 0){ ! // printk ("ipv4root0 %08lx %08x\n",current->ipv4root,s_addr); ! if (s_addr == 0){ ! s_addr = current->ipv4root; ! }else if (s_addr != current->ipv4root){ ! return -EADDRNOTAVAIL; ! } ! } ! chk_addr_ret = inet_addr_type(s_addr); ! // printk ("ipv4root %08lx %08x %d\n",current->ipv4root,s_addr,chk_addr_ret); /* Not specified by any standard per-se, however it breaks too *************** *** 493,497 **** if (sysctl_ip_nonlocal_bind == 0 && sk->protinfo.af_inet.freebind == 0 && ! addr->sin_addr.s_addr != INADDR_ANY && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && --- 504,508 ---- if (sysctl_ip_nonlocal_bind == 0 && sk->protinfo.af_inet.freebind == 0 && ! s_addr != INADDR_ANY && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && *************** *** 518,522 **** goto out; ! sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr; if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) sk->saddr = 0; /* Use device */ --- 529,533 ---- goto out; ! sk->rcv_saddr = sk->saddr = s_addr; if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) sk->saddr = 0; /* Use device */ diff -rc2P linux-2.4.10/net/socket.c linux-2.4.10ctx/net/socket.c *** linux-2.4.10/net/socket.c Tue Aug 28 13:56:06 2001 --- linux-2.4.10ctx/net/socket.c Thu Sep 27 00:48:13 2001 *************** *** 1766,1767 **** --- 1766,1779 ---- return len; } + + asmlinkage int sys_set_ipv4root (unsigned long ip) + { + int ret = -EPERM; + if (current->ipv4root == 0 + || capable(CAP_SYS_ADMIN)){ + ret = 0; + current->ipv4root = ip; + } + return ret; + } +