diff -urNX nopatch linux-2.2.20/Documentation/Configure.help linux-2.2.20-medusa-0.9.0/Documentation/Configure.help --- linux-2.2.20/Documentation/Configure.help Fri Nov 2 17:39:05 2001 +++ linux-2.2.20-medusa-0.9.0/Documentation/Configure.help Wed Nov 21 14:43:43 2001 @@ -14423,6 +14423,58 @@ Saying M will compile this driver as a module (planb.o). +CONFIG_MEDUSA + This option provides a facility to improve overall security of + Linux by extending its standard security architecture, while + remaining fully transparent in terms of system API. Technically, + it's a kernel support of the user-space authorization server. + + For more info see README in the source package. + +CONFIG_MEDUSA_SYSCALL + This option allows the authorization server to check any system + call and its parameters. This is very low-level and it is + currently implemented only on the i386 architecture. + + Say Y here if want to have complete control of the user-space + processes actions. + +CONFIG_MEDUSA_FORCE + This powerful option makes it possible to force execution of the + arbitrary code to any process. This option currently works only + on the i386 architecture. + + Answer Y only if you really need it, otherwise answer N. + +CONFIG_MEDUSA_INIT_WRAPPER + Say Y here, if you want the kernel to execute the Constable + after bootup instead of the standard init. Note that Constable + have to be installed at /sbin, /etc or /bin. + +CONFIG_MEDUSA_ON_NFS + Enabling this allows you to use Medusa file redirections to NFS filesystem. + + Say Y only if you need to use file redirections to NFS filesystem. + +CONFIG_MEDUSA_QUIET + This option prevents Medusa from displaying any kernel messages. + + If you want to hide Medusa on your machine, answer Y. + +CONFIG_MEDUSA_FILE_CAPABILITIES + This option enables you to set POSIX capabilities for files. + Note that you can set process capabilities even with this option + turned off. Answer N, unless you really know what are you doing. + +CONFIG_MEDUSA_FILE_HIDING + + This option enables hiding directory entries depending on virtual spaces + setttings of processes and files. It required relatively big and dirty + changes to the kernel directory reading code and it greatly reduces + directory reading performance. + + Say N, unless you really need it. + # # ARM options # diff -urNX nopatch linux-2.2.20/Makefile linux-2.2.20-medusa-0.9.0/Makefile --- linux-2.2.20/Makefile Fri Nov 2 17:39:05 2001 +++ linux-2.2.20-medusa-0.9.0/Makefile Wed Nov 21 13:12:50 2001 @@ -124,6 +124,11 @@ LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib +ifdef CONFIG_MEDUSA +CORE_FILES := $(CORE_FILES) medusa/medusa.o +SUBDIRS := $(SUBDIRS) medusa +endif + ifdef CONFIG_NUBUS DRIVERS := $(DRIVERS) drivers/nubus/nubus.a endif diff -urNX nopatch linux-2.2.20/arch/i386/Makefile linux-2.2.20-medusa-0.9.0/arch/i386/Makefile --- linux-2.2.20/arch/i386/Makefile Sun Mar 25 18:31:45 2001 +++ linux-2.2.20-medusa-0.9.0/arch/i386/Makefile Wed Nov 21 13:12:50 2001 @@ -45,7 +45,7 @@ HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o -SUBDIRS := $(SUBDIRS) arch/i386/kernel arch/i386/mm arch/i386/lib +SUBDIRS := $(SUBDIRS) arch/i386/tools arch/i386/kernel arch/i386/mm arch/i386/lib CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES) LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a @@ -94,6 +94,7 @@ archclean: @$(MAKEBOOT) clean + @$(MAKE) -C arch/$(ARCH)/tools clean archmrproper: rm -f arch/i386/vmlinux.lds diff -urNX nopatch linux-2.2.20/arch/i386/config.in linux-2.2.20-medusa-0.9.0/arch/i386/config.in --- linux-2.2.20/arch/i386/config.in Fri Nov 2 17:39:05 2001 +++ linux-2.2.20-medusa-0.9.0/arch/i386/config.in Wed Nov 21 14:45:59 2001 @@ -48,6 +48,8 @@ bool 'Symmetric multi-processing support' CONFIG_SMP endmenu + source medusa/Config.in + mainmenu_option next_comment comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES diff -urNX nopatch linux-2.2.20/arch/i386/kernel/Makefile linux-2.2.20-medusa-0.9.0/arch/i386/kernel/Makefile --- linux-2.2.20/arch/i386/kernel/Makefile Sun Mar 25 18:37:29 2001 +++ linux-2.2.20-medusa-0.9.0/arch/i386/kernel/Makefile Wed Nov 21 13:12:50 2001 @@ -78,4 +78,11 @@ head.o: head.S $(TOPDIR)/include/linux/tasks.h $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o +entry.o: $(TOPDIR)/include/asm-i386/offsets.h + +$(TOPDIR)/include/asm-i386/offsets.h: $(TOPDIR)/arch/i386/tools/printoffset + +$(TOPDIR)/arch/i386/tools/printoffset: + $(MAKE) -C $(TOPDIR)/arch/i386/tools + include $(TOPDIR)/Rules.make diff -urNX nopatch linux-2.2.20/arch/i386/kernel/entry.S linux-2.2.20-medusa-0.9.0/arch/i386/kernel/entry.S --- linux-2.2.20/arch/i386/kernel/entry.S Fri Nov 2 17:39:05 2001 +++ linux-2.2.20-medusa-0.9.0/arch/i386/kernel/entry.S Wed Nov 21 13:12:50 2001 @@ -70,13 +70,8 @@ /* * these are offsets into the task-struct. */ -state = 0 -flags = 4 -sigpending = 8 -addr_limit = 12 -exec_domain = 16 -need_resched = 20 -ptrace = 24 + +#include ENOSYS = 38 @@ -175,10 +170,36 @@ GET_CURRENT(%ebx) cmpl $(NR_syscalls),%eax jae badsys - testb $0x02,ptrace(%ebx) # PT_TRACESYS + +#ifdef CONFIG_MEDUSA_SYSCALL + /* cannot change: eax=syscall, ebx=current */ + btl %eax,med_syscall(%ebx) + jnc 1f + pushl %ebx + pushl %eax + call SYMBOL_NAME(medusa_syscall_watch) + cmpl $1, %eax + popl %eax + popl %ebx + jc 3f + jne 2f +1: +#endif + + testb $0x02,ptrace(%ebx) # PT_TRACESYS jne tracesys - call *SYMBOL_NAME(sys_call_table)(,%eax,4) - movl %eax,EAX(%esp) # save the return value + +#ifdef CONFIG_MEDUSA_SYSCALL +2: +#endif + + call *SYMBOL_NAME(sys_call_table)(,%eax,4) + +#ifdef CONFIG_MEDUSA_SYSCALL +3: +#endif + + movl %eax,EAX(%esp) # save the return value ALIGN .globl ret_from_sys_call .globl ret_from_intr diff -urNX nopatch linux-2.2.20/arch/i386/kernel/process.c linux-2.2.20-medusa-0.9.0/arch/i386/kernel/process.c --- linux-2.2.20/arch/i386/kernel/process.c Fri Nov 2 17:39:05 2001 +++ linux-2.2.20-medusa-0.9.0/arch/i386/kernel/process.c Wed Nov 21 13:12:50 2001 @@ -46,6 +46,10 @@ #include "irq.h" +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED; asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); @@ -505,6 +509,14 @@ /* Load the argument into eax, and push it. That way, it does * not matter whether the called function is compiled with * -mregparm or not. */ +#ifdef CONFIG_MEDUSA + "pushl %%eax\n\tpushl %%ebx\n\tpushl %%ecx\n\tpushl %%edx\n\t" + "movl %5,%%eax\n\t" + "pushl %%eax\n\t" + "call medusa_kernel_thread\n\t" /* call medusa */ + "popl %%eax\n\t" + "popl %%edx\n\tpopl %%ecx\n\tpopl %%ebx\n\tpopl %%eax\n\t" +#endif /* CONFIG_MEDUSA */ "movl %4,%%eax\n\t" "pushl %%eax\n\t" "call *%5\n\t" /* call fn */ diff -urNX nopatch linux-2.2.20/arch/i386/kernel/ptrace.c linux-2.2.20-medusa-0.9.0/arch/i386/kernel/ptrace.c --- linux-2.2.20/arch/i386/kernel/ptrace.c Fri Nov 2 17:39:05 2001 +++ linux-2.2.20-medusa-0.9.0/arch/i386/kernel/ptrace.c Wed Nov 21 13:12:50 2001 @@ -13,6 +13,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + #include #include #include @@ -390,6 +394,12 @@ unsigned long flags; int i, ret; +#ifdef CONFIG_MEDUSA + if (request != PTRACE_TRACEME && + medusa_ptrace(current, find_task_by_pid(pid)) == MED_NO) + return -EPERM; +#endif /* CONFIG_MEDUSA */ + lock_kernel(); ret = -EPERM; if (request == PTRACE_TRACEME) { @@ -713,6 +723,12 @@ if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) != (PT_PTRACED|PT_TRACESYS)) return; + +#ifdef CONFIG_MEDUSA + if (medusa_ptrace(current->p_pptr, current) == MED_NO) + return; +#endif /* CONFIG_MEDUSA */ + current->exit_code = SIGTRAP; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); diff -urNX nopatch linux-2.2.20/arch/i386/kernel/signal.c linux-2.2.20-medusa-0.9.0/arch/i386/kernel/signal.c --- linux-2.2.20/arch/i386/kernel/signal.c Fri Nov 2 17:39:05 2001 +++ linux-2.2.20-medusa-0.9.0/arch/i386/kernel/signal.c Wed Nov 21 13:12:50 2001 @@ -19,6 +19,12 @@ #include #include #include + +#ifdef CONFIG_MEDUSA +#include +#include +#endif + #include #include @@ -408,11 +414,25 @@ struct sigframe *frame; int err = 0; +#ifdef CONFIG_MEDUSA_FORCE + if (sig < 0) + frame = (struct sigframe *)((regs->esp - sizeof(*frame) + sig) & -8ul); + else +#endif /* CONFIG_MEDUSA_FORCE */ frame = get_sigframe(ka, regs, sizeof(*frame)); +#ifdef CONFIG_MEDUSA_FORCE + if (sig < 0) { + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)-sig)) + goto give_sigsegv; + } else +#endif /* CONFIG_MEDUSA_FORCE */ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; +#ifdef CONFIG_MEDUSA_FORCE + if (sig >= 0) +#endif /* CONFIG_MEDUSA_FORCE */ err |= __put_user((current->exec_domain && current->exec_domain->signal_invmap && sig < 32 @@ -435,21 +455,34 @@ /* Set up to return from userspace. If provided, use a stub already in userspace. */ - if (ka->sa.sa_flags & SA_RESTORER) { +#ifdef CONFIG_MEDUSA_FORCE + if ((sig >= 0) && (ka->sa.sa_flags & SA_RESTORER)) +#else + if (ka->sa.sa_flags & SA_RESTORER) +#endif /* CONFIG_MEDUSA_FORCE */ err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); - } else { + else { err |= __put_user(frame->retcode, &frame->pretcode); /* This is popl %eax ; movl $,%eax ; int $0x80 */ err |= __put_user(0xb858, (short *)(frame->retcode+0)); err |= __put_user(__NR_sigreturn, (int *)(frame->retcode+2)); err |= __put_user(0x80cd, (short *)(frame->retcode+6)); } - +#ifdef CONFIG_MEDUSA_FORCE + if (sig < 0) { + err |= __copy_to_user((void *)((unsigned long)frame+sizeof(*frame)), (void *)ka, -sig); + } +#endif /* CONFIG_MEDUSA_FORCE */ if (err) goto give_sigsegv; /* Set up registers for signal handler */ regs->esp = (unsigned long) frame; +#ifdef CONFIG_MEDUSA_FORCE + if (sig < 0) + regs->eip = (unsigned long)frame+sizeof(*frame); + else +#endif /* CONFIG_MEDUSA_FORCE */ regs->eip = (unsigned long) ka->sa.sa_handler; set_fs(USER_DS); @@ -618,6 +651,46 @@ if (!oldset) oldset = ¤t->blocked; + +#ifdef CONFIG_MEDUSA_FORCE + if (current->med.force_code) { + void * force_code; + int force_len; + +/****** XXX STOLEN FROM THE CODE ABOVE ********/ + /* Are we from a system call? */ + if (regs->orig_eax >= 0) { + /* If so, check system call restarting.. */ + switch (regs->eax) { + case -ERESTARTNOHAND: + regs->eax = -EINTR; + break; + + case -ERESTARTSYS: /* restartne nam syscall */ + if (!(ka->sa.sa_flags & SA_RESTART)) { + regs->eax = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + regs->eax = regs->orig_eax; + regs->eip -= 2; + } + } +/****** END OF STOLEN CODE ********/ + spin_lock_irq(¤t->sigmask_lock); + force_code = current->med.force_code; + force_len = current->med.force_len; + current->med.force_code = NULL; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + /* we don't care about real-time processes */ + setup_frame(-force_len, force_code, oldset, regs); + kfree(force_code); + return 1; + } +#endif for (;;) { unsigned long signr; diff -urNX nopatch linux-2.2.20/arch/i386/tools/Makefile linux-2.2.20-medusa-0.9.0/arch/i386/tools/Makefile --- linux-2.2.20/arch/i386/tools/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.2.20-medusa-0.9.0/arch/i386/tools/Makefile Wed Nov 21 13:12:50 2001 @@ -0,0 +1,18 @@ +# Makefile for i386 kernel build tools + +TARGET=$(TOPDIR)/include/asm-$(ARCH)/offsets.h + +offsets all: $(TARGET) + +$(TARGET): printoffsets + ./printoffsets > $(TARGET) + +printoffsets: printoffsets.o + $(CC) $(CFLAGS) $^ -o $@ + +printoffsets.o: $(TOPDIR)/include/linux/sched.h + +clean: + rm -f $(TARGET) printoffsets + +include $(TOPDIR)/Rules.make diff -urNX nopatch linux-2.2.20/arch/i386/tools/printoffsets.c linux-2.2.20-medusa-0.9.0/arch/i386/tools/printoffsets.c --- linux-2.2.20/arch/i386/tools/printoffsets.c Thu Jan 1 01:00:00 1970 +++ linux-2.2.20-medusa-0.9.0/arch/i386/tools/printoffsets.c Wed Nov 21 13:12:50 2001 @@ -0,0 +1,39 @@ +#define _LOOSE_KERNEL_NAMES +#include +#include + +#define OFFSET(structure, member) ((unsigned long)(&(((structure *)NULL)->member))) + +struct i386_offset { + const char identifier[64]; + unsigned long value; +} offsets[] = { + { "state", OFFSET(struct task_struct, state) }, + { "flags", OFFSET(struct task_struct, flags) }, + { "sigpending", OFFSET(struct task_struct, sigpending) }, + { "addr_limit", OFFSET(struct task_struct, addr_limit) }, + { "exec_domain", OFFSET(struct task_struct, exec_domain) }, + { "need_resched", OFFSET(struct task_struct, need_resched) }, + { "ptrace", OFFSET(struct task_struct, ptrace) } +#ifdef CONFIG_MEDUSA_SYSCALL + , { "med_syscall", OFFSET(struct task_struct, med.med_syscall) } +#endif +}; + +extern int printf (const char *, ...); + +int main(int argc, char *argv[]) +{ + int i; + + printf("#ifndef _I386_OFFSETS_H_\n#define _I386_OFFSETS_H_\n\n"); + printf("/* \n"); + printf(" * offsets for i386\n"); + printf(" * DO NOT TOUCH\n"); + printf(" * generated by arch/i386/tools/print_offset.c\n"); + printf(" */\n\n"); + for(i = 0; i < (sizeof(offsets) / sizeof(struct i386_offset)); i++) + printf("%s =\t%lu\n", offsets[i].identifier, offsets[i].value); + printf("\n#endif\n"); + return 0; +} diff -urNX nopatch linux-2.2.20/fs/attr.c linux-2.2.20-medusa-0.9.0/fs/attr.c --- linux-2.2.20/fs/attr.c Sun Mar 25 18:30:59 2001 +++ linux-2.2.20-medusa-0.9.0/fs/attr.c Wed Nov 21 13:12:50 2001 @@ -9,6 +9,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* Taken over from the old code... */ /* POSIX UID/GID verification for setting inode attributes. */ @@ -91,6 +95,10 @@ if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; +#ifdef CONFIG_MEDUSA /* FIXME */ + if ((error = medusa_notify_change(dentry,attr)) == MED_NO) + return -EPERM; +#endif /* CONFIG_MEDUSA */ if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->notify_change) error = inode->i_sb->s_op->notify_change(dentry, attr); diff -urNX nopatch linux-2.2.20/fs/exec.c linux-2.2.20-medusa-0.9.0/fs/exec.c --- linux-2.2.20/fs/exec.c Fri Nov 2 17:39:08 2001 +++ linux-2.2.20-medusa-0.9.0/fs/exec.c Wed Nov 21 13:12:50 2001 @@ -42,6 +42,11 @@ #include #endif +#include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* * Here are the actual binaries that will be accepted: * add more with "register_binfmt()" if using modules... @@ -594,6 +599,11 @@ return -EACCES; if (!inode->i_sb) return -EACCES; +#ifdef CONFIG_MEDUSA + if ((retval = medusa_exec(&(bprm->dentry))) == MED_NO) + return -EPERM; + if (retval != MED_YES) +#endif /* CONFIG_MEDUSA */ if ((retval = permission(inode, MAY_EXEC)) != 0) return retval; /* better not execute files which are being written to */ @@ -623,10 +633,17 @@ id_change = 1; } +#ifndef CONFIG_MEDUSA_FILE_CAPABILITIES /* We don't have VFS support for capabilities yet */ cap_clear(bprm->cap_inheritable); cap_clear(bprm->cap_permitted); cap_clear(bprm->cap_effective); +#else + /* If the security daemon sets the file capabilities, use them */ + cap_t(bprm->cap_inheritable) = cap_t(inode->i_med.icap); + cap_t(bprm->cap_permitted) = cap_t(inode->i_med.pcap); + cap_t(bprm->cap_effective) = cap_t(inode->i_med.ecap); +#endif /* CONFIG_MEDUSA_FILE_CAPABILITIES */ /* To support inheritance of root-permissions and suid-root * executables under compatibility mode, we raise all three @@ -662,6 +679,22 @@ } } +#ifdef CONFIG_MEDUSA + if(id_change || cap_raised) { + if ((retval = medusa_sexec(bprm)) == MED_NO) + return -EPERM; + if (retval == MED_SKIP) { + bprm->e_uid = current->euid; + bprm->e_gid = current->egid; + id_change = 0; + cap_clear(bprm->cap_inheritable); + bprm->cap_permitted = current->cap_permitted; + cap_t(bprm->cap_effective) = cap_t(current->cap_effective); + cap_raised = 0; + } + } +#endif /* CONFIG_MEDUSA */ + bprm->priv_change = id_change || cap_raised; if (bprm->priv_change) { current->dumpable = 0; @@ -888,6 +921,11 @@ if (retval >= 0) retval = search_binary_handler(&bprm,regs); + +#ifdef CONFIG_MEDUSA + if (retval >= 0) + medusa_after_exec(filename, argv, envp); +#endif /* CONFIG_MEDUSA */ if (retval >= 0) { /* execve success */ diff -urNX nopatch linux-2.2.20/fs/inode.c linux-2.2.20-medusa-0.9.0/fs/inode.c --- linux-2.2.20/fs/inode.c Sun Mar 25 18:37:38 2001 +++ linux-2.2.20-medusa-0.9.0/fs/inode.c Wed Nov 21 13:12:50 2001 @@ -4,6 +4,10 @@ * (C) 1997 Linus Torvalds */ +#include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ #include #include #include @@ -571,6 +575,9 @@ inode->i_generation = 0; memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); sema_init(&inode->i_sem, 1); +#ifdef CONFIG_MEDUSA + medusa_clean_inode(inode); +#endif /* CONFIG_MEDUSA */ } /* diff -urNX nopatch linux-2.2.20/fs/namei.c linux-2.2.20-medusa-0.9.0/fs/namei.c --- linux-2.2.20/fs/namei.c Fri Nov 2 17:39:08 2001 +++ linux-2.2.20-medusa-0.9.0/fs/namei.c Wed Nov 21 13:12:50 2001 @@ -25,6 +25,11 @@ #include +#include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* This can be removed after the beta phase. */ #define CACHE_SUPERVISE /* debug the correctness of dcache entries */ #undef DEBUG /* some other debugging */ @@ -161,6 +166,15 @@ int permission(struct inode * inode,int mask) { +#ifdef CONFIG_MEDUSA + int r; + + if ((r = medusa_permission(inode, mask)) == MED_NO) + return -EACCES; + if (r == MED_YES) + return 0; +#endif /* CONFIG_MEDUSA */ + if (inode->i_op && inode->i_op->permission) return inode->i_op->permission(inode, mask); return vfs_permission(inode, mask); @@ -222,6 +236,9 @@ { struct dentry * dentry = d_lookup(parent, name); +#ifdef CONFIG_MEDUSA + medusa_get_dentry(parent); +#endif /* CONFIG_MEDUSA */ if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) { dput(dentry); @@ -419,6 +436,22 @@ } } +#ifdef CONFIG_MEDUSA + { + int ret; + if ((ret = medusa_lookup(base->d_inode, &dentry)) == MED_NO) { + dput(dentry); + dentry = ERR_PTR(-EPERM); + break; + } + if (ret == MED_SKIP) { + dput(dentry); + dentry = ERR_PTR(-ENOENT); + break; + } + } +#endif /* CONFIG_MEDUSA */ + /* Check mountpoints.. */ dentry = follow_mount(dentry); @@ -694,6 +727,17 @@ if (flag & O_CREAT) { struct dentry *dir; +#ifdef CONFIG_MEDUSA + if ((error = medusa_create(dentry, mode)) == MED_NO) { + error = -EPERM; + goto exit; + } + if (error == MED_SKIP) { + error = 0; + goto exit; + } +#endif /* CONFIG_MEDUSA */ + if (dentry->d_inode) { if (!(flag & O_EXCL)) goto nocreate; @@ -828,6 +872,14 @@ if (IS_ERR(dentry)) return dentry; +#ifdef CONFIG_MEDUSA + if ((error = medusa_mknod(dentry, dev)) == MED_NO) + { + dput(dentry); + return ERR_PTR(-EPERM); + } +#endif /* CONFIG_MEDUSA */ + dir = lock_parent(dentry); error = -ENOENT; if (!check_parent(dir, dentry)) @@ -902,6 +954,14 @@ if (IS_ERR(dentry)) goto exit; +#ifdef CONFIG_MEDUSA + if ((error = medusa_mkdir(dentry, mode)) == MED_NO) + { + dput(dentry); + return -EPERM; + } +#endif /* CONFIG_MEDUSA */ + /* * EEXIST is kind of a strange error code to * return, but basically if the dentry was moved @@ -954,6 +1014,12 @@ { int error; +#ifdef CONFIG_MEDUSA + if ((error = medusa_rmdir(dentry)) == MED_NO) + return -EPERM; + if (error == MED_SKIP) + return 0; +#endif /* CONFIG_MEDUSA */ error = may_delete(dir, dentry, 1); if (error) return error; @@ -1049,6 +1115,12 @@ { int error; +#ifdef CONFIG_MEDUSA /* FIXME */ + if ((error = medusa_unlink(dentry)) == MED_NO) + return -EPERM; + if (error == MED_SKIP) + return 0; +#endif /* CONFIG_MEDUSA */ error = may_delete(dir, dentry, 0); if (!error) { error = -EPERM; @@ -1110,6 +1182,14 @@ if (IS_ERR(dentry)) goto exit; +#ifdef CONFIG_MEDUSA + if ((error = medusa_symlink(dentry, oldname)) == MED_NO) + { + dput(dentry); + return -EPERM; + } +#endif /* CONFIG_MEDUSA */ + dir = lock_parent(dentry); error = -ENOENT; if (!check_parent(dir, dentry)) @@ -1190,6 +1270,18 @@ if (!inode) goto exit_lock; +#ifdef CONFIG_MEDUSA + if ((error = medusa_link(old_dentry, newname)) == MED_NO) + { + error = -EPERM; + goto exit_lock; + } + if (error == MED_SKIP) { + error = 0; + goto exit_lock; + } +#endif /* CONFIG_MEDUSA */ + error = may_create(dir->d_inode, new_dentry); if (error) goto exit_lock; @@ -1252,6 +1344,13 @@ if (old_dentry->d_inode == new_dentry->d_inode) return 0; +#ifdef CONFIG_MEDUSA + if ((error = medusa_rename(old_dentry, new_dentry->d_name.name)) == MED_NO) + return -EPERM; + if (error == MED_SKIP) + return 0; +#endif /* CONFIG_MEDUSA */ + error = may_delete(old_dir, old_dentry, 1); if (error) return error; @@ -1308,6 +1407,13 @@ if (old_dentry->d_inode == new_dentry->d_inode) return 0; + +#ifdef CONFIG_MEDUSA + if ((error = medusa_rename(old_dentry, new_dentry->d_name.name)) == MED_NO) + return -EPERM; + if (error == MED_SKIP) + return 0; +#endif /* CONFIG_MEDUSA */ error = may_delete(old_dir, old_dentry, 0); if (error) diff -urNX nopatch linux-2.2.20/fs/open.c linux-2.2.20-medusa-0.9.0/fs/open.c --- linux-2.2.20/fs/open.c Fri Nov 2 17:39:08 2001 +++ linux-2.2.20-medusa-0.9.0/fs/open.c Wed Nov 21 13:12:50 2001 @@ -12,6 +12,10 @@ #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + asmlinkage int sys_statfs(const char * path, struct statfs * buf) { struct dentry * dentry; @@ -73,6 +77,12 @@ if ((off_t) length < 0) return -EINVAL; +#ifdef CONFIG_MEDUSA + if ((error = medusa_truncate(dentry, length)) == MED_NO) + return -EPERM; + if (error == MED_SKIP) + return 0; +#endif /* CONFIG_MEDUSA */ fs_down(&inode->i_sem); newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; diff -urNX nopatch linux-2.2.20/fs/proc/mem.c linux-2.2.20-medusa-0.9.0/fs/proc/mem.c --- linux-2.2.20/fs/proc/mem.c Fri Nov 2 17:39:08 2001 +++ linux-2.2.20-medusa-0.9.0/fs/proc/mem.c Wed Nov 21 18:26:16 2001 @@ -15,6 +15,7 @@ #include #include #include +#include /* * mem_write isn't really a good idea right now. It needs @@ -22,7 +23,7 @@ * dies in the middle right now, mem_write will overwrite * kernel memory.. This disables it altogether. */ -#define mem_write NULL +//#define mem_write NULL static int check_range(struct mm_struct * mm, unsigned long addr, int count) { @@ -61,6 +62,9 @@ /* Allow accesses only under the same circumstances * that we would allow ptrace to work. */ +#ifdef CONFIG_MEDUSA + if( current!=constable ) +#endif if (tsk) { if (!(tsk->ptrace & PT_PTRACED) || tsk->state != TASK_STOPPED @@ -152,7 +156,7 @@ while (count > 0) { if (signal_pending(current)) break; - page_dir = pgd_offset(tsk,addr); + page_dir = pgd_offset(tsk->mm,addr); if (pgd_none(*page_dir)) break; if (pgd_bad(*page_dir)) { diff -urNX nopatch linux-2.2.20/fs/proc/root.c linux-2.2.20-medusa-0.9.0/fs/proc/root.c --- linux-2.2.20/fs/proc/root.c Sun Mar 25 18:30:58 2001 +++ linux-2.2.20-medusa-0.9.0/fs/proc/root.c Wed Nov 21 13:12:51 2001 @@ -22,6 +22,10 @@ #include #endif +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* * Offset of the first process in the /proc root directory.. */ @@ -853,6 +857,9 @@ read_lock(&tasklist_lock); p = find_task_by_pid(pid); read_unlock(&tasklist_lock); +#ifdef CONFIG_MEDUSA + if( p && !medusa_see(p) ) p=NULL; +#endif /* CONFIG_MEDUSA */ inode = NULL; if (pid && p) { unsigned long ino = (pid << 16) + PROC_PID_INO; @@ -944,6 +951,10 @@ int pid = p->pid; if (!pid) continue; +#ifdef CONFIG_MEDUSA + if (!medusa_see(p)) + continue; +#endif /* CONFIG_MEDUSA */ if (--index >= 0) continue; pids[nr_pids] = pid; diff -urNX nopatch linux-2.2.20/fs/readdir.c linux-2.2.20-medusa-0.9.0/fs/readdir.c --- linux-2.2.20/fs/readdir.c Sun Mar 25 18:30:59 2001 +++ linux-2.2.20-medusa-0.9.0/fs/readdir.c Wed Nov 21 13:12:51 2001 @@ -12,6 +12,9 @@ #include #include +#ifdef CONFIG_MEDUSA_FILE_HIDING +#include +#endif /* CONFIG_MEDUSA_FILE_HIDING */ /* * Traditional linux readdir() handling.. @@ -45,11 +48,20 @@ return -EINVAL; buf->count++; dirent = buf->dirent; +#ifdef CONFIG_MEDUSA_FILE_HIDING + dirent->d_ino = ino; + dirent->d_offset = offset; + dirent->d_namlen = namlen; + memcpy(dirent->d_name, name, namlen); + dirent->d_name[namlen] = '\0'; + buf->count = namlen; +#else put_user(ino, &dirent->d_ino); put_user(offset, &dirent->d_offset); put_user(namlen, &dirent->d_namlen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); +#endif /* CONFIG_MEDUSA_FILE_HIDING */ return 0; } @@ -60,6 +72,15 @@ struct dentry * dentry; struct inode * inode; struct readdir_callback buf; +#ifdef CONFIG_MEDUSA_FILE_HIDING + struct dentry * dent; + struct old_linux_dirent * ldirent; + + error = -ENOMEM; + ldirent = (struct old_linux_dirent *)kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!ldirent) + goto out; +#endif /* CONFIG_MEDUSA_FILE_HIDING */ lock_kernel(); error = -EBADF; @@ -76,8 +97,11 @@ goto out_putf; buf.count = 0; +#ifdef CONFIG_MEDUSA_FILE_HIDING + buf.dirent = ldirent; +#else buf.dirent = dirent; - +#endif /* CONFIG_MEDUSA_FILE_HIDING */ error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out_putf; @@ -91,9 +115,26 @@ up(&inode->i_sem); if (error < 0) goto out_putf; +#ifdef CONFIG_MEDUSA_FILE_HIDING + if (buf.count) { + dget(dentry); + dent = lookup_dentry(ldirent->d_name, dentry, 0); + if (!IS_ERR(dent)) { + copy_to_user(dirent, ldirent, buf.count + sizeof(struct old_linux_dirent)); + dput(dent); + error = 1; + } else + error = 0; + } else + error = 0; +#else error = buf.count; +#endif /* CONFIG_MEDUSA_FILE_HIDING */ out_putf: +#ifdef CONFIG_MEDUSA_FILE_HIDING + kfree(ldirent); +#endif /* CONFIG_MEDUSA_FILE_HIDING */ fput(file); out: unlock_kernel(); @@ -111,13 +152,27 @@ char d_name[1]; }; +#ifdef CONFIG_MEDUSA_FILE_HIDING +struct med_page_header { + struct med_page_header * next; + int page_end; +}; +#endif /* CONFIG_MEDUSA_FILE_HIDING */ + struct getdents_callback { struct linux_dirent * current_dir; struct linux_dirent * previous; int count; int error; +#ifdef CONFIG_MEDUSA_FILE_HIDING + struct med_page_header * first_ph; + struct med_page_header * last_ph; + struct linux_dirent * user_dirent; + char only_one; /* flag */ +#endif /* CONFIG_MEDUSA_FILE_HIDING */ }; +#ifndef CONFIG_MEDUSA_FILE_HIDING static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) { struct linux_dirent * dirent; @@ -142,6 +197,76 @@ return 0; } +#else + +static struct linux_dirent * medusa_allocfilldir(struct getdents_callback * callback, struct linux_dirent * dirent); +static struct linux_dirent * medusa_initfilldir(struct getdents_callback * callback, struct linux_dirent * dirent); +static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino); + +static struct linux_dirent * medusa_allocfilldir(struct getdents_callback * callback, struct linux_dirent * dirent) +{ + struct med_page_header * p; + + /* NOTE: don't alloc more than PAGE_SIZE at one time! */ + if (!access_ok(VERIFY_WRITE, dirent, + (&(((struct linux_dirent *)(0))->d_name)) + 1)) + return ERR_PTR(-EFAULT); + p = (struct med_page_header *)kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!p) + return ERR_PTR(-ENOMEM); + p->next = NULL; + p->page_end = sizeof(struct med_page_header); + + if (callback->last_ph) + callback->last_ph = (callback->last_ph->next = p); + else + callback->first_ph = callback->last_ph = p; + + return (struct linux_dirent *)(p + 1); +} + +static struct linux_dirent * medusa_initfilldir(struct getdents_callback * callback, struct linux_dirent * dirent) +{ + callback->first_ph = callback->last_ph = NULL; + return medusa_allocfilldir(callback, dirent); +} + +static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino) +{ + struct linux_dirent * dirent; + struct getdents_callback * buf = (struct getdents_callback *) __buf; + int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); + + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; + dirent = buf->previous; + if (dirent) + dirent->d_off = offset; // put_user(offset, &dirent->d_off); + + dirent = buf->current_dir; + buf->previous = dirent; + + if ((buf->last_ph->page_end + reclen) > PAGE_SIZE) { + dirent = medusa_allocfilldir(buf, buf->user_dirent); + if (IS_ERR(dirent)) + return -EINVAL; + buf->previous = dirent; + } + buf->last_ph->page_end += reclen; + + dirent->d_ino = ino; // put_user(ino, &dirent->d_ino); + dirent->d_reclen = reclen; // put_user(reclen, &dirent->d_reclen); + memcpy(dirent->d_name, name, namlen); // copy_to_user(dirent->d_name, name, namlen); + ((char *)dirent->d_name)[namlen] = '\0'; // put_user(0, dirent->d_name + namlen); + ((char *) dirent) += reclen; + ((char *)(buf->user_dirent)) += reclen; + buf->current_dir = dirent; + buf->count -= reclen; + return 0; +} +#endif /* CONFIG_MEDUSA_FILE_HIDING */ + asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count) { struct file * file; @@ -150,6 +275,11 @@ struct linux_dirent * lastdirent; struct getdents_callback buf; int error; +#ifdef CONFIG_MEDUSA_FILE_HIDING + struct med_page_header * p; + struct linux_dirent * ldirent, * udirent; + struct dentry * dent; +#endif /* CONFIG_MEDUSA_FILE_HIDING */ lock_kernel(); error = -EBADF; @@ -178,17 +308,59 @@ * Get the inode's semaphore to prevent changes * to the directory while we read it. */ +#ifdef CONFIG_MEDUSA_FILE_HIDING + buf.current_dir = medusa_initfilldir(&buf, udirent = buf.user_dirent = buf.current_dir); + if (IS_ERR(buf.current_dir)) { + error = PTR_ERR(buf.current_dir); + goto out_putf; + } +#endif /* CONFIG_MEDUSA_FILE_HIDING */ down(&inode->i_sem); error = file->f_op->readdir(file, &buf, filldir); up(&inode->i_sem); if (error < 0) +#ifdef CONFIG_MEDUSA_FILE_HIDING + goto med_out_putf; +#else goto out_putf; +#endif /* CONFIG_MEDUSA_FILE_HIDING */ error = buf.error; lastdirent = buf.previous; if (lastdirent) { +#ifdef CONFIG_MEDUSA_FILE_HIDING + lastdirent->d_off = file->f_pos; // put_user(file->f_pos, &lastdirent->d_off); +#else put_user(file->f_pos, &lastdirent->d_off); +#endif /* CONFIG_MEDUSA_FILE_HIDING */ error = count - buf.count; } + +#ifdef CONFIG_MEDUSA_FILE_HIDING + unlock_kernel(); + + for (p = buf.first_ph; p; p = p->next) { + ldirent = ((struct linux_dirent *)(p+1)); + while ((char *)ldirent < (((char *)p) + p->page_end)) { + dget(dentry); + dent = lookup_dentry(ldirent->d_name, dentry, 0); + if (!IS_ERR(dent)) { + copy_to_user(udirent, + (void *)ldirent, + ldirent->d_reclen); + ((char *)udirent) += ldirent->d_reclen; + dput(dent); + } else + error -= ldirent->d_reclen; + ((char *)ldirent) += ldirent->d_reclen; + } + } + lock_kernel(); +med_out_putf: + while ((p = buf.first_ph)) { + buf.first_ph = p->next; + kfree(p); + } +#endif /* CONFIG_MEDUSA_FILE_HIDING */ out_putf: fput(file); diff -urNX nopatch linux-2.2.20/include/linux/fs.h linux-2.2.20-medusa-0.9.0/include/linux/fs.h --- linux-2.2.20/include/linux/fs.h Fri Nov 2 17:39:09 2001 +++ linux-2.2.20-medusa-0.9.0/include/linux/fs.h Wed Nov 21 18:06:44 2001 @@ -24,6 +24,10 @@ #include #include /* just in case the #define NULL previously in here was needed */ +#ifdef CONFIG_MEDUSA +#include /* For security system MEDUSA DS9 */ +#endif /* CONFIG_MEDUSA */ + struct poll_table_struct; @@ -380,6 +384,9 @@ int i_writecount; unsigned int i_attr_flags; __u32 i_generation; +#ifdef CONFIG_MEDUSA + struct med_inode i_med; /* For security system MEDUSA DS9 */ +#endif /* CONFIG_MEDUSA */ union { struct pipe_inode_info pipe_i; struct minix_inode_info minix_i; diff -urNX nopatch linux-2.2.20/include/linux/ipc.h linux-2.2.20-medusa-0.9.0/include/linux/ipc.h --- linux-2.2.20/include/linux/ipc.h Sun Mar 25 18:31:03 2001 +++ linux-2.2.20-medusa-0.9.0/include/linux/ipc.h Wed Nov 21 18:06:44 2001 @@ -3,6 +3,10 @@ #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + #define IPC_PRIVATE ((__kernel_key_t) 0) struct ipc_perm @@ -14,7 +18,48 @@ __kernel_gid_t cgid; __kernel_mode_t mode; unsigned short seq; +#ifdef CONFIG_MEDUSA + struct med_ipc med; /* Medusa security information */ +}; + +struct orig_ipc_perm +{ + __kernel_key_t key; + __kernel_uid_t uid; + __kernel_gid_t gid; + __kernel_uid_t cuid; + __kernel_gid_t cgid; + __kernel_mode_t mode; + unsigned short seq; +#endif /* CONFIG_MEDUSA */ }; + +#ifdef CONFIG_MEDUSA +/* Conversions beetween original ipc_perm structure used by user-space and + * altered one used in the kernel */ + +static inline void medusa_copy_ipc_perm_to_user(struct ipc_perm *in, struct orig_ipc_perm *out) +{ + out->key = in->key; + out->uid = in->uid; + out->gid = in->gid; + out->cuid= in->cuid; + out->cgid= in->cgid; + out->mode= in->mode; + out->seq = in->seq; +} + +static inline void medusa_copy_ipc_perm_from_user(struct orig_ipc_perm *in, struct ipc_perm *out) +{ + out->key = in->key; + out->uid = in->uid; + out->gid = in->gid; + out->cuid= in->cuid; + out->cgid= in->cgid; + out->mode= in->mode; + out->seq = in->seq; +} +#endif /* CONFIG_MEDUSA */ /* resource get request flags */ #define IPC_CREAT 00001000 /* create if key is nonexistent */ diff -urNX nopatch linux-2.2.20/include/linux/medusa.h linux-2.2.20-medusa-0.9.0/include/linux/medusa.h --- linux-2.2.20/include/linux/medusa.h Thu Jan 1 01:00:00 1970 +++ linux-2.2.20-medusa-0.9.0/include/linux/medusa.h Wed Nov 21 18:06:46 2001 @@ -0,0 +1,234 @@ +/* + * Medusa DS9 header file + */ + +#ifndef _MEDUSA_H_ +#define _MEDUSA_H_ + +#include +#include +#include + +struct iattr; + +#define MEDUSA_MAJOR 111 +#define MP_SIZE sizeof(struct medusa_packet) +#define BEGIN_VS (0xffffffff) +#define ALL_VS (0xffffffff) +#define NONE_VS (0x0) +#define MIN_DATA_LEN 512 +#define MAX_DATA_LEN 2048 +#define B_SIZE sizeof(struct communication_bufffer) + +/* process actions + * + SKIP - if answer is SKIP then operation doesn't execute but + * it returns success, otherwise, SKIP does same as OK */ +#define MPACT_FORK 0x0001 /* clone_flags */ +#define MPACT_EXEC 0x0002 /* attempt - 0, done - 1 */ +#define MPACT_EXIT 0x0004 +#define MPACT_SETUID 0x0008 /* setuid, setreuid, !setgid, !setgroups ... */ +#define MPACT_KILL 0x0010 /* send signal, + SKIP */ +#define MPACT_SOCKET 0x0020 /* socketcall ... */ +#define MPACT_PTRACE 0x0040 /* stop and send signal to be ptraced */ +#define MPACT_PERM 0x0100 /* is in permission function */ +#define MPACT_CH 0x0200 /* is in notify_change function */ +#define MPACT_IOP 0x0400 /* it does inode operation (MIACT_) */ +#define MPACT_CAP 0x0800 /* capable */ +#define MPACT_MODULE 0x1000 /* create_module, init_module, delete_module */ +#define MPACT_SEXEC 0x2000 /* target = new uid, inof1 = inode vs info2 =rcinfo + SKIP */ +#define MPACT_START 0x4000 /* start of new process */ +#define MPACT_MAY_CD 0x8000 /* temporarily, it can access all dirs */ + +struct m_proc_inf { + int pid, parent_pid, child_pid, sibling_pid; /* older sib. */ + int pgrp; + unsigned short uid, euid, suid, fsuid; + unsigned short gid, egid, sgid, fsgid; + unsigned short luid; + kernel_cap_t cap_effective, cap_inheritable, cap_permitted; + struct med_proc mp; +}; + +/* inode actions + (MED_YES doesn't work with inode ops yet, it defaults to MED_OK) */ +#define MIACT_ACCESS 0x0001 /* if it finds this + inode, it can redirect */ +#define MIACT_CREATE 0x0002 /* + SKIP */ +#define MIACT_LINK 0x0004 /* + SKIP */ +#define MIACT_UNLINK 0x0008 /* */ +#define MIACT_SYMLINK 0x0010 /* */ +#define MIACT_MKDIR 0x0020 /* */ +#define MIACT_RMDIR 0x0040 /* + SKIP */ +#define MIACT_MKNOD 0x0080 /* */ +#define MIACT_RENAME 0x0100 /* + SKIP */ +#define MIACT_READLINK 0x0200 /* !!! not yet, but can be helpful */ +#define MIACT_FOLLOW 0x0400 /* !!! what for ??? */ +#define MIACT_TRUNCATE 0x0800 /* + SKIP */ +#define MIACT_PERMISSION 0x1000 /* + SKIP */ +#define MIACT_EXEC 0x2000 /* (inode, argv,envp, path), redir */ +#define MIACT_INHERIT 0x4000 /* - inherit inode attributes */ +#define MIACT_VALID 0x8000 /* - information is valid */ + +struct m_inode_inf { + kdev_t dev; + unsigned long ino; + umode_t mode; + nlink_t nlink; + uid_t uid; + gid_t gid; + kdev_t rdev; + struct med_inode mi; +}; + +/* cmd */ +#define MED_VERSION 0 +#define MED_IGET 1 /* Read information for inode */ +struct medreq_iget { + struct m_inode_inf inode; + struct m_inode_inf parent; + /* + name */ +}; +struct medans_iget { + struct m_inode_inf inode; +}; + +#define MED_IACT 2 /* Report inode action */ +struct medreq_iact { + __u16 pact; /* process action (0= inode action/ process action) */ + __u16 act; /* sub-action which process attempts to execute + */ + struct m_inode_inf inode; + struct m_proc_inf proc; + __u32 info1; /* additional information */ + __u32 info2; /* additional information */ + /* + + * data + * (name) + * */ +}; +struct medans_iact { + struct m_proc_inf proc; + /* ... ??? */ + /* + redirection(pathname) */ +}; + +#define MED_PACT 3 /* Report process action */ +struct medreq_pact { + __u16 act; /* action which process attempts to execute */ + struct m_proc_inf proc; + struct m_proc_inf target; + __u32 info1; /* additional information */ + __u32 info2; /* additional information */ +}; +struct medans_pact { + struct m_proc_inf proc; +}; + +#define MED_TRACE 4 /* Report syscall */ +struct medreq_trace { + __u16 syscall; /* syscall */ + struct m_proc_inf proc; + __u32 arg[5]; +}; +struct medans_trace { + struct m_proc_inf proc; + __u32 arg[5]; + __u32 retval; /* valid only when answer is MED_NO */ +}; + + +/* commands cmd to kernel from daemon */ +#define MED_RESET 0x100 +#define MED_GET_PROC 0x101 +#define MED_SET_PROC 0x102 +#define MED_FOREACH_PROC 0x103 +#define MED_FORCE 0x104 +#define MED_GETSTR 0x110 +#define MED_PRINTK 0x111 +struct medreq_cmd { + __u32 arg[8]; + struct m_proc_inf proc; +}; +struct medans_cmd { + __u32 arg[8]; + struct m_proc_inf proc; +}; + + +struct medusa_packet { + int id; + int cmd; + int answer; + int data_len; /* kernel->daemon, daemon->kernel */ + union { + struct medreq_iget r_iget; + struct medans_iget a_iget; + struct medreq_iact r_iact; + struct medans_iact a_iact; + struct medreq_pact r_pact; + struct medans_pact a_pact; + struct medreq_trace r_trace; + struct medans_trace a_trace; + struct medreq_cmd r_cmd; + struct medans_cmd a_cmd; + } u; +}; + +struct communication_buffer { + struct medusa_packet packet; + char data[MAX_DATA_LEN]; +}; + + +static inline int med_valid(struct med_inode *mi) +{ + if (mi->med_act & MIACT_VALID) { + if (mi->magic == medusa_magic) + return 1; + mi->med_act = 0; + } + return 0; +} + +void medusa_set_proc_inf(struct m_proc_inf *pi, struct task_struct *task); +void medusa_set_proc(struct task_struct *task, struct m_proc_inf *pi); + +char *medusa_request(struct medusa_packet *msg, const char *data); +void medusa_putdata(char *data); + +int medusa_get_dentry(struct dentry *dentry); +int medusa_get_inode(struct inode *inode); + +int medusa_exec(struct dentry **dentry); +void medusa_after_exec(char *filename, char **argv, char **envp); +int medusa_sexec(struct linux_binprm *bprm); +/* process operation */ +int medusa_pact(int act, struct task_struct *source, + struct task_struct *target, __u32 info1, __u32 info2); + +int medusa_permission(struct inode *inode, int mask); +int medusa_notify_change(struct dentry *dentry, struct iattr *attr); +int medusa_sendsig(int sig, struct task_struct *p); +int medusa_ptrace(struct task_struct *source, struct task_struct *target); +int medusa_see(struct task_struct *p); + +int medusa_lookup(struct inode *dir, struct dentry **dentry); +void medusa_clean_inode(struct inode *inode); +int medusa_truncate(struct dentry *dentry, unsigned long length); +int medusa_rename(struct dentry *dentry, const char *newname); +int medusa_link(struct dentry *dentry, const char *newname); +int medusa_rmdir(struct dentry *dentry); +int medusa_unlink(struct dentry *dentry); +int medusa_create(struct dentry *dentry, int mode); +int medusa_mknod(struct dentry *dentry, dev_t mode); +int medusa_mkdir(struct dentry *dentry, int mode); +int medusa_symlink(struct dentry *dentry, const char *oldname); + +void medusa_setluid(uid_t uid); +int medusa_fork(struct task_struct *new, unsigned long clone_flags); +int medusa_afterfork(struct task_struct *new); + +void medusa_process_init(__u16 act); +void medusa_kernel_thread(int (*fn) (void *)); + +#endif /* _MEDUSA_H_ */ diff -urNX nopatch linux-2.2.20/include/linux/medusa_kernel.h linux-2.2.20-medusa-0.9.0/include/linux/medusa_kernel.h --- linux-2.2.20/include/linux/medusa_kernel.h Thu Jan 1 01:00:00 1970 +++ linux-2.2.20-medusa-0.9.0/include/linux/medusa_kernel.h Wed Nov 21 18:06:44 2001 @@ -0,0 +1,130 @@ +/* + * Medusa DS9 header file + */ + +#ifndef _MEDUSA_KERNEL_H_ +#define _MEDUSA_KERNEL_H_ + +#include +#include +#include +#include + +extern int no_constable; +extern struct task_struct *constable; +extern __u16 medusa_magic; + +#define MED_SYSCALL_DENY 0 +#define MED_SYSCALL_ALLOW 1 +#define MED_SYSCALL_SKIPTRACE 2 + +/* extension to struct task_struct */ +struct med_proc { + __u32 med_vs; /* bitmap of virtual spaces (member) */ + __u32 med_vs_s; /* see */ + __u32 med_vs_r; /* read */ + __u32 med_vs_w; /* write */ + __u16 med_act; /* actions which need acknowledgement from constable */ + __u16 med_iact; /* iactions which need acknowledgement from constable */ + __u32 med_user; /* for free daemon use */ +#ifdef CONFIG_MEDUSA_SYSCALL + __u32 med_syscall[NR_syscalls / (sizeof(__u32) * 8)]; /* bitmap of syscalls, which are reported */ +#endif /* CONFIG_MEDUSA_SYSCALL */ +#ifdef CONFIG_MEDUSA_FORCE + void *force_code; /* code to froce or NULL, kfree */ + int force_len; /* force code length */ +#endif /* CONFIG_MEDUSA_FORCE */ + __u32 cinfo[4]; /* info for constable */ +}; + +/* extension to struct inode */ +struct med_inode { + __u32 med_vs; /* bitmap of virtual spaces (member) */ + __u16 med_act; /* actions which need acknowledgement from constable */ +#ifdef CONFIG_MEDUSA_FILE_CAPABILITIES + kernel_cap_t icap; /* support for Linux capabilities */ + kernel_cap_t pcap; + kernel_cap_t ecap; +#endif /* CONFIG_MEDUSA_FILE_CAPABILITIES */ + u_long cinfo; /* info for constable */ + __u16 magic; /* whether is it actual */ +}; + +/* extension to ipc object descriptors */ +struct med_ipc { + __u32 vs; /* bitmap of virtual spaces */ +}; + +/* answer codes */ +#define MED_ERR -1 /* error */ +#define MED_YES 0 /* permit operation */ +#define MED_NO 1 /* forbid operation */ +#define MED_SKIP 2 /* forbid operation, but return success */ +#define MED_OK 3 /* permit operation, but proceed with + standard system permission check if any */ + +int medusa_capable(int cap); + + +#define MED_GET_SIZE(structure, member) \ + ((unsigned long)(&(((structure *)NULL)->member)) + sizeof(((structure *)NULL)->member)) + +#define MED_ERROR_CHECK() do { \ + if (no_constable) \ + return MED_OK; \ +} while (0) + +#define MED_DENTRY_CHECK(dentry) do { \ + if (!med_valid(&((dentry)->d_inode->i_med))) { \ + medusa_get_dentry(dentry); \ + if (!med_valid(&((dentry)->d_inode->i_med))) \ + return MED_OK; \ + } \ +} while (0) + +#define MED_DENTRY_PUT_CHECK(dentry) do { \ + if (!med_valid(&((dentry)->d_inode->i_med))) { \ + medusa_get_dentry(dentry); \ + if (!med_valid(&((dentry)->d_inode->i_med))) { \ + dput(dentry); \ + return MED_OK; \ + } \ + } \ +} while (0) + +#define MED_INODE_CHECK(inode) do { \ + if (!med_valid(&((inode)->i_med))) { \ + medusa_get_inode(inode); \ + if (!med_valid(&((inode)->i_med))) \ + return MED_OK; \ + } \ +} while (0) + +#define VS_PROCESS(process_task_struct_p) \ + ((process_task_struct_p)->med.med_vs) +#define VSS_PROCESS(process_task_struct_p) \ + ((process_task_struct_p)->med.med_vs_s) +#define VSR_PROCESS(process_task_struct_p) \ + ((process_task_struct_p)->med.med_vs_r) +#define VSW_PROCESS(process_task_struct_p) \ + ((process_task_struct_p)->med.med_vs_w) +#define VS_SEE_PROCESS(process_task_struct_p, target_task_struct_p) \ + ((process_task_struct_p)->med.med_vs_s & (target_task_struct_p)->med.med_vs) +#define VS_IPC(ipc_perm_p) \ + ((ipc_perm_p)->med.vs) +#define VS_SEE_IPC(process_task_struct_p, ipc_perm_p) \ + ((process_task_struct_p)->med.med_vs_s & (ipc_perm_p)->med.vs) +#define VS_READ_IPC(process_task_struct_p, ipc_perm_p) \ + ((process_task_struct_p)->med.med_vs_r & (ipc_perm_p)->med.vs) +#define VS_WRITE_IPC(process_task_struct_p, ipc_perm_p) \ + ((process_task_struct_p)->med.med_vs_w & (ipc_perm_p)->med.vs) +#define VS_INODE(inode_p) \ + ((inode_p)->i_med.med_vs) +#define VS_SEE_INODE(process_task_struct_p, inode_p) \ + ((process_task_struct_p)->med.med_vs_s & (inode_p)->i_med.med_vs) +#define VS_READ_INODE(process_task_struct_p, inode_p) \ + ((process_task_struct_p)->med.med_vs_r & (inode_p)->i_med.med_vs) +#define VS_WRITE_INODE(process_task_struct_p, inode_p) \ + ((process_task_struct_p)->med.med_vs_w & (inode_p)->i_med.med_vs) + +#endif /* _MEDUSA_KERNEL_H_ */ diff -urNX nopatch linux-2.2.20/include/linux/msg.h linux-2.2.20-medusa-0.9.0/include/linux/msg.h --- linux-2.2.20/include/linux/msg.h Sun Mar 25 18:31:03 2001 +++ linux-2.2.20-medusa-0.9.0/include/linux/msg.h Wed Nov 21 18:33:14 2001 @@ -28,6 +28,25 @@ __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ }; +#ifdef CONFIG_MEDUSA +struct orig_msqid_ds { + struct orig_ipc_perm msg_perm; + struct msg *msg_first; /* first message on queue */ + struct msg *msg_last; /* last message in queue */ + __kernel_time_t msg_stime; /* last msgsnd time */ + __kernel_time_t msg_rtime; /* last msgrcv time */ + __kernel_time_t msg_ctime; /* last change time */ + struct wait_queue *wwait; + struct wait_queue *rwait; + unsigned short msg_cbytes; /* current number of bytes on queue */ + unsigned short msg_qnum; /* number of messages in queue */ + unsigned short msg_qbytes; /* max number of bytes on queue */ + __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ + struct med_ipc med; /* Medusa security information */ +}; +#endif /* CONFIG_MEDUSA */ + /* message buffer for msgsnd and msgrcv calls */ struct msgbuf { long mtype; /* type of message */ diff -urNX nopatch linux-2.2.20/include/linux/sched.h linux-2.2.20-medusa-0.9.0/include/linux/sched.h --- linux-2.2.20/include/linux/sched.h Fri Nov 2 17:39:09 2001 +++ linux-2.2.20-medusa-0.9.0/include/linux/sched.h Wed Nov 21 18:06:44 2001 @@ -23,6 +23,11 @@ #include #include +#include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* * cloning flags: */ @@ -353,6 +358,11 @@ /* oom handling */ int oom_kill_try; +#ifdef CONFIG_MEDUSA +/* For security system MEDUSA DS9 */ + uid_t luid; + struct med_proc med; +#endif /* CONFIG_MEDUSA */ }; /* @@ -595,6 +605,9 @@ case 1: ready = t->signal.sig[0] &~ t->blocked.sig[0]; } +#ifdef CONFIG_MEDUSA_FORCE + ready |= t->med.force_code != NULL; +#endif /* CONFIG_MEDUSA_FORCE */ t->sigpending = (ready != 0); } @@ -660,6 +673,17 @@ extern inline int capable(int cap) { +#ifdef CONFIG_MEDUSA + int ret; + + if ((ret = medusa_capable(cap)) == MED_NO) + return 0; + if ((ret == MED_YES) || (ret == MED_SKIP)) { + current->flags |= PF_SUPERPRIV; + return 1; + } +#endif /* CONFIG_MEDUSA */ + #if 1 /* ok now */ if (cap_raised(current->cap_effective, cap)) #else diff -urNX nopatch linux-2.2.20/include/linux/sem.h linux-2.2.20-medusa-0.9.0/include/linux/sem.h --- linux-2.2.20/include/linux/sem.h Sun Mar 25 18:31:03 2001 +++ linux-2.2.20-medusa-0.9.0/include/linux/sem.h Wed Nov 21 18:06:44 2001 @@ -31,6 +31,19 @@ unsigned short sem_nsems; /* no. of semaphores in array */ }; +#ifdef CONFIG_MEDUSA +struct orig_semid_ds { + struct orig_ipc_perm sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t sem_otime; /* last semop time */ + __kernel_time_t sem_ctime; /* last change time */ + struct sem *sem_base; /* ptr to first semaphore in array */ + struct sem_queue *sem_pending; /* pending operations to be processed */ + struct sem_queue **sem_pending_last; /* last pending operation */ + struct sem_undo *undo; /* undo requests on this array */ + unsigned short sem_nsems; /* no. of semaphores in array */ +}; +#endif /* CONFIG_MEDUSA */ + /* semop system calls takes an array of these. */ struct sembuf { unsigned short sem_num; /* semaphore index in array */ diff -urNX nopatch linux-2.2.20/include/linux/shm.h linux-2.2.20-medusa-0.9.0/include/linux/shm.h --- linux-2.2.20/include/linux/shm.h Sun Mar 25 18:31:03 2001 +++ linux-2.2.20-medusa-0.9.0/include/linux/shm.h Wed Nov 21 18:11:06 2001 @@ -19,6 +19,22 @@ void *shm_unused3; /* unused */ }; +#ifdef CONFIG_MEDUSA +struct orig_shmid_ds { + struct orig_ipc_perm shm_perm; /* operation perms */ + int shm_segsz; /* size of segment (bytes) */ + __kernel_time_t shm_atime; /* last attach time */ + __kernel_time_t shm_dtime; /* last detach time */ + __kernel_time_t shm_ctime; /* last change time */ + __kernel_ipc_pid_t shm_cpid; /* pid of creator */ + __kernel_ipc_pid_t shm_lpid; /* pid of last operator */ + unsigned short shm_nattch; /* no. of current attaches */ + unsigned short shm_unused; /* compatibility */ + void *shm_unused2; /* ditto - used by DIPC */ + void *shm_unused3; /* unused */ +}; +#endif /* CONFIG_MEDUSA */ + struct shmid_kernel { struct shmid_ds u; diff -urNX nopatch linux-2.2.20/init/main.c linux-2.2.20-medusa-0.9.0/init/main.c --- linux-2.2.20/init/main.c Fri Nov 2 17:39:16 2001 +++ linux-2.2.20-medusa-0.9.0/init/main.c Wed Nov 21 13:12:51 2001 @@ -24,6 +24,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + #include #include @@ -409,6 +413,10 @@ extern int agp_init (void); #endif +#ifdef CONFIG_MEDUSA +extern void medusa_init( void ); +#endif /* CONFIG_MEDUSA */ + /* * Boot command-line arguments */ @@ -1414,6 +1422,10 @@ * make syscalls (and thus be locked). */ smp_init(); +#ifdef CONFIG_MEDUSA + medusa_init(); +#endif /* CONFIG_MEDUSA */ + kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); current->need_resched = 1; cpu_idle(NULL); @@ -1606,6 +1618,7 @@ lock_kernel(); do_basic_setup(); + /* * Ok, we have completed the initial bootup, and * we're essentially up and running. Get rid of the @@ -1629,6 +1642,11 @@ if (execute_command) execve(execute_command,argv_init,envp_init); +#ifdef CONFIG_MEDUSA_INIT_WRAPPER + execve("/sbin/constable",argv_init,envp_init); + execve("/etc/constable",argv_init,envp_init); + execve("/bin/constable",argv_init,envp_init); +#endif /* CONFIG_MEDUSA_INIT_WRAPPER */ execve("/sbin/init",argv_init,envp_init); execve("/etc/init",argv_init,envp_init); execve("/bin/init",argv_init,envp_init); diff -urNX nopatch linux-2.2.20/ipc/msg.c linux-2.2.20-medusa-0.9.0/ipc/msg.c --- linux-2.2.20/ipc/msg.c Sun Mar 25 18:31:15 2001 +++ linux-2.2.20-medusa-0.9.0/ipc/msg.c Wed Nov 21 13:12:51 2001 @@ -18,6 +18,10 @@ #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + extern int ipcperms (struct ipc_perm *ipcp, short msgflg); static void freeque (int id); @@ -68,6 +72,10 @@ if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) return -EIDRM; +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &msq->msg_perm)) + return -EINVAL; +#endif /* CONFIG_MEDUSA */ if (ipcperms(ipcp, S_IWUGO)) return -EACCES; @@ -146,6 +154,10 @@ msq = msgque [id]; if (msq == IPC_NOID || msq == IPC_UNUSED) return -EINVAL; +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &msq->msg_perm)) + return -EINVAL; +#endif /* CONFIG_MEDUSA */ ipcp = &msq->msg_perm; /* @@ -300,6 +312,9 @@ msq->msg_stime = msq->msg_rtime = 0; msq->msg_qbytes = MSGMNB; msq->msg_ctime = CURRENT_TIME; +#ifdef CONFIG_MEDUSA + VS_IPC(&msq->msg_perm) = VS_PROCESS(current); +#endif /* CONFIG_MEDUSA */ if (id > max_msqid) max_msqid = id; msgque[id] = msq; @@ -327,6 +342,10 @@ msq = msgque[id]; if (msq == IPC_UNUSED || msq == IPC_NOID) ret = -EIDRM; +#ifdef CONFIG_MEDUSA + else if (!VS_SEE_IPC(current, &msq->msg_perm)) + ret = -ENOENT; +#endif /* CONFIG_MEDUSA */ else if (ipcperms(&msq->msg_perm, msgflg)) ret = -EACCES; else @@ -361,6 +380,47 @@ kfree(msq); } +#ifdef CONFIG_MEDUSA +/* Conversions beetween original msqid structure used by user-space and altered + * one used in the kernel */ + +static inline unsigned long medusa_copy_msqid_to_user(void *buf, struct msqid_ds *in) +{ + struct orig_msqid_ds out; + + medusa_copy_ipc_perm_to_user(&in->msg_perm, &out.msg_perm); + out.msg_stime = in->msg_stime; + out.msg_rtime = in->msg_rtime; + out.msg_ctime = in->msg_ctime; + out.msg_cbytes = in->msg_cbytes; + out.msg_qnum = in->msg_qnum; + out.msg_qbytes = in->msg_qbytes; + out.msg_lspid = in->msg_lspid; + out.msg_lrpid = in->msg_lrpid; + + return copy_to_user(buf, &out, sizeof(out)); +} + +static inline unsigned long medusa_copy_msqid_from_user(struct msqid_ds *out, void *buf) +{ + struct orig_msqid_ds in; + + if (copy_from_user(&in, buf, sizeof(in))) + return -EFAULT; + medusa_copy_ipc_perm_from_user(&in.msg_perm, &out->msg_perm); + out->msg_stime = in.msg_stime; + out->msg_rtime = in.msg_rtime; + out->msg_ctime = in.msg_ctime; + out->msg_cbytes = in.msg_cbytes; + out->msg_qnum = in.msg_qnum; + out->msg_qbytes = in.msg_qbytes; + out->msg_lspid = in.msg_lspid; + out->msg_lrpid = in.msg_lrpid; + + return 0; +} +#endif /* CONFIG_MEDUSA */ + asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) { int id, err = -EINVAL; @@ -408,6 +468,11 @@ msq = msgque[msqid]; if (msq == IPC_UNUSED || msq == IPC_NOID) goto out; +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_SEE_IPC(current, &msq->msg_perm)) + goto out; +#endif /* CONFIG_MEDUSA */ err = -EACCES; if (ipcperms (&msq->msg_perm, S_IRUGO)) goto out; @@ -422,7 +487,11 @@ tbuf.msg_lspid = msq->msg_lspid; tbuf.msg_lrpid = msq->msg_lrpid; err = -EFAULT; +#ifdef CONFIG_MEDUSA + if (medusa_copy_msqid_to_user (buf, &tbuf)) +#else if (copy_to_user (buf, &tbuf, sizeof(*buf))) +#endif /* CONFIG_MEDUSA */ goto out; err = id; goto out; @@ -430,7 +499,11 @@ if (!buf) goto out; err = -EFAULT; +#ifdef CONFIG_MEDUSA + if (!medusa_copy_msqid_from_user (&tbuf, buf)) +#else if (!copy_from_user (&tbuf, buf, sizeof (*buf))) +#endif /* CONFIG_MEDUSA */ err = 0; break; case IPC_STAT: @@ -447,6 +520,14 @@ err = -EIDRM; if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) goto out; +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_SEE_IPC(current, &msq->msg_perm)) + goto out; + err = -EPERM; + if (((cmd == IPC_SET) || (cmd == IPC_RMID)) && !VS_WRITE_IPC(current, &msq->msg_perm)) + goto out; +#endif /* CONFIG_MEDUSA */ ipcp = &msq->msg_perm; switch (cmd) { @@ -464,7 +545,11 @@ tbuf.msg_lspid = msq->msg_lspid; tbuf.msg_lrpid = msq->msg_lrpid; err = -EFAULT; +#ifdef CONFIG_MEDUSA + if (!medusa_copy_msqid_to_user (buf, &tbuf)) +#else if (!copy_to_user (buf, &tbuf, sizeof (*buf))) +#endif /* CONFIG_MEDUSA */ err = 0; goto out; case IPC_SET: diff -urNX nopatch linux-2.2.20/ipc/sem.c linux-2.2.20-medusa-0.9.0/ipc/sem.c --- linux-2.2.20/ipc/sem.c Sun Mar 25 18:31:15 2001 +++ linux-2.2.20-medusa-0.9.0/ipc/sem.c Wed Nov 21 13:12:51 2001 @@ -56,6 +56,10 @@ #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + extern int ipcperms (struct ipc_perm *ipcp, short semflg); static int newary (key_t, int, int); static int findkey (key_t key); @@ -135,6 +139,9 @@ /* sma->undo = NULL; */ sma->sem_nsems = nsems; sma->sem_ctime = CURRENT_TIME; +#ifdef CONFIG_MEDUSA + VS_IPC(&sma->sem_perm) = VS_PROCESS(current); +#endif /* CONFIG_MEDUSA */ if (id > max_semid) max_semid = id; used_semids++; @@ -164,6 +171,10 @@ sma = semary[id]; if (nsems > sma->sem_nsems) err = -EINVAL; +#ifdef CONFIG_MEDUSA + else if (!VS_SEE_IPC(current, &sma->sem_perm)) + err = -ENOENT; +#endif /* CONFIG_MEDUSA */ else if (ipcperms(&sma->sem_perm, semflg)) err = -EACCES; else @@ -380,6 +391,37 @@ kfree(sma); } +#ifdef CONFIG_MEDUSA +/* Conversions beetween original semid structure used by user-space and altered + * one used in the kernel */ + +static inline unsigned long medusa_copy_semid_to_user(void *buf, struct semid_ds *in) +{ + struct orig_semid_ds out; + + medusa_copy_ipc_perm_to_user(&in->sem_perm, &out.sem_perm); + out.sem_otime = in->sem_otime; + out.sem_ctime = in->sem_ctime; + out.sem_nsems = in->sem_nsems; + + return copy_to_user(buf, &out, sizeof(out)); +} + +static inline unsigned long medusa_copy_semid_from_user(struct semid_ds *out, void *buf) +{ + struct orig_semid_ds in; + + if (copy_from_user(&in, buf, sizeof(in))) + return -EFAULT; + medusa_copy_ipc_perm_from_user(&in.sem_perm, &out->sem_perm); + out->sem_otime = in.sem_otime; + out->sem_ctime = in.sem_ctime; + out->sem_nsems = in.sem_nsems; + + return 0; +} +#endif /* CONFIG_MEDUSA */ + asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg) { struct semid_ds *buf = NULL; @@ -441,7 +483,11 @@ tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; err = -EFAULT; +#ifdef CONFIG_MEDUSA + if (medusa_copy_semid_to_user (buf, &tbuf) == 0) +#else if (copy_to_user (buf, &tbuf, sizeof(*buf)) == 0) +#endif /* CONFIG_MEDUSA */ err = id; goto out; } @@ -456,6 +502,14 @@ err = -EIDRM; if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) goto out; +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_SEE_IPC(current, &sma->sem_perm)) + goto out; + err = -EPERM; + if (((cmd == IPC_SET) || (cmd == IPC_RMID)) && !VS_WRITE_IPC(current, &sma->sem_perm)) + goto out; +#endif /* CONFIG_MEDUSA */ switch (cmd) { case GETVAL: @@ -522,7 +576,11 @@ case IPC_SET: buf = arg.buf; err = -EFAULT; +#ifdef CONFIG_MEDUSA + if(medusa_copy_semid_from_user (&tbuf, buf)) +#else if(copy_from_user (&tbuf, buf, sizeof (*buf))) +#endif /* CONFIG_MEDUSA */ goto out; break; } @@ -575,7 +633,11 @@ tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; err = -EFAULT; +#ifdef CONFIG_MEDUSA + if (medusa_copy_semid_to_user (buf, &tbuf)) +#else if (copy_to_user (buf, &tbuf, sizeof(*buf))) +#endif /* CONFIG_MEDUSA */ goto out; break; case SETALL: @@ -659,6 +721,11 @@ } alter |= decrease; +#ifdef CONFIG_MEDUSA + error = -EINVAL; + if (!VS_SEE_IPC(current, &sma->sem_perm)) + goto out; +#endif /* CONFIG_MEDUSA */ error = -EACCES; if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) goto out; diff -urNX nopatch linux-2.2.20/ipc/shm.c linux-2.2.20-medusa-0.9.0/ipc/shm.c --- linux-2.2.20/ipc/shm.c Sun Mar 25 18:37:40 2001 +++ linux-2.2.20-medusa-0.9.0/ipc/shm.c Wed Nov 21 13:12:51 2001 @@ -17,6 +17,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + extern int ipcperms (struct ipc_perm *ipcp, short shmflg); extern unsigned long get_swap_page (void); static int findkey (key_t key); @@ -127,6 +131,9 @@ shp->u.shm_atime = shp->u.shm_dtime = 0; shp->u.shm_ctime = CURRENT_TIME; shp->shm_npages = numpages; +#ifdef CONFIG_MEDUSA + VS_IPC(&shp->u.shm_perm) = VS_PROCESS(current); +#endif /* CONFIG_MEDUSA */ if (id > max_shmid) max_shmid = id; @@ -136,6 +143,45 @@ return (unsigned int) shp->u.shm_perm.seq * SHMMNI + id; } +#ifdef CONFIG_MEDUSA +/* Conversions beetween original shmid structure used by user-space and altered + * one used in the kernel */ + +static inline unsigned long medusa_copy_shmid_to_user(void *buf, struct shmid_ds *in) +{ + struct orig_shmid_ds out; + + medusa_copy_ipc_perm_to_user(&in->shm_perm, &out.shm_perm); + out.shm_segsz = in->shm_segsz; + out.shm_atime = in->shm_atime; + out.shm_dtime = in->shm_dtime; + out.shm_ctime = in->shm_ctime; + out.shm_cpid = in->shm_cpid; + out.shm_lpid = in->shm_lpid; + out.shm_nattch= in->shm_nattch; + + return copy_to_user(buf, &out, sizeof(out)); +} + +static inline unsigned long medusa_copy_shmid_from_user(struct shmid_ds *out, void *buf) +{ + struct orig_shmid_ds in; + + if (copy_from_user(&in, buf, sizeof(in))) + return -EFAULT; + medusa_copy_ipc_perm_from_user(&in.shm_perm, &out->shm_perm); + out->shm_segsz = in.shm_segsz; + out->shm_atime = in.shm_atime; + out->shm_dtime = in.shm_dtime; + out->shm_ctime = in.shm_ctime; + out->shm_cpid = in.shm_cpid; + out->shm_lpid = in.shm_lpid; + out->shm_nattch= in.shm_nattch; + + return 0; +} +#endif /* CONFIG_MEDUSA */ + int shmmax = SHMMAX; asmlinkage int sys_shmget (key_t key, int size, int shmflg) @@ -162,6 +208,10 @@ err = -EIDRM; else if (size > shp->u.shm_segsz) err = -EINVAL; +#ifdef CONFIG_MEDUSA + else if (!VS_SEE_IPC(current, &shp->u.shm_perm)) + err = -ENOENT; +#endif /* CONFIG_MEDUSA */ else if (ipcperms (&shp->u.shm_perm, shmflg)) err = -EACCES; else @@ -228,7 +278,11 @@ goto out; if (cmd == IPC_SET) { err = -EFAULT; +#ifdef CONFIG_MEDUSA + if(medusa_copy_shmid_from_user (&tbuf, buf)) +#else if(copy_from_user (&tbuf, buf, sizeof (*buf))) +#endif /* CONFIG_MEDUSA */ goto out; } @@ -271,11 +325,19 @@ shp = shm_segs[shmid]; if (shp == IPC_UNUSED || shp == IPC_NOID) goto out; +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &shp->u.shm_perm)) + goto out; +#endif /* CONFIG_MEDUSA */ if (ipcperms (&shp->u.shm_perm, S_IRUGO)) goto out; id = (unsigned int) shp->u.shm_perm.seq * SHMMNI + shmid; err = -EFAULT; +#ifdef CONFIG_MEDUSA + if(medusa_copy_shmid_to_user (buf, &shp->u)) +#else if(copy_to_user (buf, &shp->u, sizeof(*buf))) +#endif /* CONFIG_MEDUSA */ goto out; err = id; goto out; @@ -285,6 +347,13 @@ err = -EINVAL; if (shp == IPC_UNUSED || shp == IPC_NOID) goto out; +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &shp->u.shm_perm)) + goto out; + err = -EPERM; + if (((cmd == IPC_SET) || (cmd == IPC_RMID)) && !VS_WRITE_IPC(current, &shp->u.shm_perm)) + goto out; +#endif /* CONFIG_MEDUSA */ err = -EIDRM; if (shp->u.shm_perm.seq != (unsigned int) shmid / SHMMNI) goto out; @@ -317,7 +386,11 @@ if (ipcperms (ipcp, S_IRUGO)) goto out; err = -EFAULT; +#ifdef CONFIG_MEDUSA + if(medusa_copy_shmid_to_user (buf, &shp->u)) +#else if(copy_to_user (buf, &shp->u, sizeof(shp->u))) +#endif /* CONFIG_MEDUSA */ goto out; break; case IPC_SET: @@ -489,7 +562,10 @@ addr, addr + shp->shm_segsz, shmd->vm_start, shmd->vm_end); */ goto out; } - +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &shp->u.shm_perm)) + goto out; +#endif /* CONFIG_MEDUSA */ err = -EACCES; if (ipcperms(&shp->u.shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO)) goto out; diff -urNX nopatch linux-2.2.20/ipc/util.c linux-2.2.20-medusa-0.9.0/ipc/util.c --- linux-2.2.20/ipc/util.c Sun Mar 25 18:31:15 2001 +++ linux-2.2.20-medusa-0.9.0/ipc/util.c Wed Nov 21 13:12:51 2001 @@ -13,6 +13,9 @@ #include #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ #if defined(CONFIG_SYSVIPC) @@ -40,6 +43,10 @@ granted_mode >>= 6; else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid)) granted_mode >>= 3; +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, ipcp) || ((requested_mode & (S_IROTH | S_IXOTH)) && !VS_READ_IPC(current, ipcp)) || ((requested_mode & S_IWOTH) && !VS_WRITE_IPC(current, ipcp))) + return -1; +#endif /* CONFIG_MEDUSA */ /* is there some bit set in requested_mode but not in granted_mode? */ if ((requested_mode & ~granted_mode & 0007) && !capable(CAP_IPC_OWNER)) diff -urNX nopatch linux-2.2.20/kernel/fork.c linux-2.2.20-medusa-0.9.0/kernel/fork.c --- linux-2.2.20/kernel/fork.c Fri Nov 2 17:39:16 2001 +++ linux-2.2.20-medusa-0.9.0/kernel/fork.c Wed Nov 21 13:46:30 2001 @@ -22,6 +22,11 @@ #include #include +#include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* The idle tasks do not count.. */ int nr_tasks=0; int nr_running=0; @@ -590,6 +595,13 @@ *p = *current; +#ifdef CONFIG_MEDUSA + if (medusa_fork(p, clone_flags) == MED_NO) { + retval = -EPERM; + goto bad_fork_free; + } +#endif /* CONFIG_MEDUSA */ + down(¤t->mm->mmap_sem); lock_kernel(); @@ -718,6 +730,9 @@ p->next_run = NULL; p->prev_run = NULL; +#ifdef CONFIG_MEDUSA + medusa_afterfork(p); +#endif /* CONFIG_MEDUSA */ wake_up_process(p); /* do this last */ } ++total_forks; diff -urNX nopatch linux-2.2.20/kernel/signal.c linux-2.2.20-medusa-0.9.0/kernel/signal.c --- linux-2.2.20/kernel/signal.c Fri Nov 2 17:39:16 2001 +++ linux-2.2.20-medusa-0.9.0/kernel/signal.c Wed Nov 21 13:12:51 2001 @@ -15,6 +15,10 @@ #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* * SLAB caches for signal bits. */ @@ -262,7 +266,26 @@ ret = -EINVAL; if (sig < 0 || sig > _NSIG) goto out_nolock; + /* Zombie task cannot be killed! */ + ret = -ESRCH; + if ( t->state == TASK_ZOMBIE ) + goto out_nolock; /* The somewhat baroque permissions check... */ + +#ifdef CONFIG_MEDUSA + ret = -EPERM; + if ((ret = medusa_sendsig(sig, t)) == MED_NO) { + ret = -EPERM; + goto out_nolock; + } + if (ret == MED_YES) + goto med_sendsig_yes; + if (ret == MED_SKIP) { + ret = 0; + goto out_nolock; + } +#endif /* CONFIG_MEDUSA */ + ret = -EPERM; if ((!info || ((unsigned long)info != 1 && SI_FROMUSER(info))) && ((sig != SIGCONT) || (current->session != t->session)) @@ -270,6 +293,9 @@ && (current->uid ^ t->suid) && (current->uid ^ t->uid) && !capable(CAP_KILL)) goto out_nolock; +#ifdef CONFIG_MEDUSA +med_sendsig_yes: +#endif /* CONFIG_MEDUSA */ /* The null signal is a permissions and process existance probe. No signal is actually delivered. Same goes for zombies. diff -urNX nopatch linux-2.2.20/kernel/sys.c linux-2.2.20-medusa-0.9.0/kernel/sys.c --- linux-2.2.20/kernel/sys.c Sun Mar 25 18:37:40 2001 +++ linux-2.2.20-medusa-0.9.0/kernel/sys.c Wed Nov 21 13:12:51 2001 @@ -15,6 +15,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* * this indicates whether you can reboot with ctrl-alt-del: the default is yes */ @@ -412,6 +416,9 @@ current->uid = new_ruid; alloc_uid(current); } +#ifdef CONFIG_MEDUSA + medusa_setluid(ruid); +#endif /* CONFIG_MEDUSA */ unlock_kernel(); @@ -452,6 +459,9 @@ unlock_kernel(); return -EPERM; } +#ifdef CONFIG_MEDUSA + medusa_setluid(uid); +#endif /* CONFIG_MEDUSA */ if (current->euid != old_euid) current->dumpable = 0; @@ -503,6 +513,9 @@ current->uid = ruid; alloc_uid(current); } +#ifdef CONFIG_MEDUSA + medusa_setluid(ruid); +#endif /* CONFIG_MEDUSA */ if (euid != (uid_t) -1) { if (euid != current->euid) current->dumpable = 0; diff -urNX nopatch linux-2.2.20/medusa/Config.in linux-2.2.20-medusa-0.9.0/medusa/Config.in --- linux-2.2.20/medusa/Config.in Thu Jan 1 01:00:00 1970 +++ linux-2.2.20-medusa-0.9.0/medusa/Config.in Wed Nov 21 13:12:51 2001 @@ -0,0 +1,28 @@ +# +# Medusa DS9 configuration +# + +mainmenu_option next_comment +comment 'Medusa DS9' + +bool 'Medusa DS9 security system' CONFIG_MEDUSA + +if [ "$CONFIG_MEDUSA" = "y" ]; then + bool 'Start Constable at boot time (Read HELP!)' CONFIG_MEDUSA_INIT_WRAPPER + bool 'Quiet Medusa' CONFIG_MEDUSA_QUIET + choice 'Action on exit of the authorization server' \ + "Ignore CONFIG_MEDUSA_NONE \ + Reboot CONFIG_MEDUSA_REBOOT \ + Halt CONFIG_MEDUSA_HALT" Ignore + if [ "$CONFIG_M386" = "y" -o "$CONFIG_M486" = "y" -o "$CONFIG_M586" = "y" -o "$CONFIG_M586TSC" = "y" -o "$CONFIG_M686" = "y" ]; then + bool 'Enable syscall trace' CONFIG_MEDUSA_SYSCALL + bool 'Enable code execution forcing' CONFIG_MEDUSA_FORCE + fi + bool 'Enable file hiding (Read HELP!)' CONFIG_MEDUSA_FILE_HIDING + bool 'Support for POSIX file capabilities (Read HELP!)' CONFIG_MEDUSA_FILE_CAPABILITIES + bool 'Medusa on NFS' CONFIG_MEDUSA_ON_NFS +# bool 'Enable direct task switch' CONFIG_MEDUSA_TASKSWITCH +# bool 'Medusa debugging' CONFIG_MEDUSA_DEBUG +fi + +endmenu diff -urNX nopatch linux-2.2.20/medusa/Makefile linux-2.2.20-medusa-0.9.0/medusa/Makefile --- linux-2.2.20/medusa/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.2.20-medusa-0.9.0/medusa/Makefile Wed Nov 21 13:12:51 2001 @@ -0,0 +1,14 @@ +# +# Makefile for the MEDUSA DS9. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := medusa.o +O_OBJS = comm.o vfs.o syscall.o +OX_OBJS := process.o + +include $(TOPDIR)/Rules.make diff -urNX nopatch linux-2.2.20/medusa/comm.c linux-2.2.20-medusa-0.9.0/medusa/comm.c --- linux-2.2.20/medusa/comm.c Thu Jan 1 01:00:00 1970 +++ linux-2.2.20-medusa-0.9.0/medusa/comm.c Wed Nov 21 13:12:51 2001 @@ -0,0 +1,604 @@ + +#include + +#ifdef CONFIG_MEDUSA + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#undef CONFIG_MEDUSA_TASKSWITCH +#define ICOM_FREE 0 /* no operations in progress */ +#define ICOM_VALID 1 /* ready for sending msg */ +#define ICOM_DATA 2 /* ready for sending data */ +#define ICOM_WAIT 3 /* waiting for receiving msg */ +#define ICOM_WAITDATA 4 /* waiting for receiving data */ +#define ICOM_CMDANS 5 /* ready for sending answer to cmd */ +#define ICOM_CMDDANS 6 /* ready for sending data for cmd */ + + +__u16 medusa_magic = 1; +struct task_struct *constable = NULL; +rwlock_t constable_lock = RW_LOCK_UNLOCKED; +struct wait_queue *constable_wait = NULL; +struct wait_queue *answer_wait = NULL; +static struct semaphore request_mutex = MUTEX; +int msg_id = 1; +static int intercom_status, intercom_istatus; +static struct medusa_packet *intercom, *inbuf, cmdbuf, cmdansbuf; +static const char *data_to_constable, *datacmd_to_constable; +static char *data_from_constable, *datacmd_from_constable; +/* static struct communication_buffer commbuf; */ +/* temporary variables */ +int no_constable = 1; +static int constable_exiting = 0; +#ifdef CONFIG_MEDUSA_DEBUG +static int constable_off = 0; +#endif /* CONFIG_MEDUSA_DEBUG */ +unsigned long stat_bytes_in = 0, stat_bytes_out = 0, stat_pkt_in = 0, stat_pkt_out = 0; + + +extern void ctrl_alt_del(void); +const char *medusa_cmd(struct medusa_packet *msg, char *data, int datalen, struct medusa_packet *ans); +int medusa_release(struct inode *inode, struct file *file); +ssize_t medusa_read(struct file *filp, char *buf, size_t count, loff_t * ppos); +ssize_t medusa_write(struct file *filp, const char *buf, size_t count, loff_t * ppos); +unsigned int medusa_poll(struct file *filp, poll_table * wait); +int medusa_open(struct inode *inode, struct file *file); +int medusa_open_medusa(struct inode *inode, struct file *file); +int medusa_open_medstat(struct inode *inode, struct file *file); +ssize_t medusa_read_medstat(struct file *filp, char *buf, size_t count, loff_t * ppos); +int medusa_release_medstat(struct inode *inode, struct file *file); + + +struct file_operations fops = { + NULL, /* seek */ + medusa_read, /* read */ + medusa_write, /* write */ + NULL, /* readdir */ + medusa_poll, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + medusa_open, /* open */ + NULL, /* flush */ + medusa_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ +}; + +struct file_operations fops_medstat = { + NULL, /* seek */ + medusa_read_medstat, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + medusa_open_medstat, /* open */ + NULL, /* flush */ + medusa_release_medstat, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ +}; + +int medusa_open(struct inode *inode, struct file *file) +{ + +#ifdef CONFIG_MEDUSA_DEBUG + printk(KERN_DEBUG "Medusa: open(): minor=%x\n", MINOR(inode->i_rdev)); +#endif /* CONFIG_MEDUSA_DEBUG */ + switch (MINOR(inode->i_rdev)) { + case 0: +#ifdef CONFIG_MEDUSA_DEBUG + case 2: + constable_off = (MINOR(inode->i_rdev) != 0); +#endif /* CONFIG_MEDUSA_DEBUG */ + return medusa_open_medusa(inode, file); + case 1: + return medusa_open_medstat(inode, file); + } + return -ENODEV; +} + + +int medusa_open_medstat(struct inode *inode, struct file *file) +{ + file->f_op = &fops_medstat; + return 0; +} + +int medusa_release_medstat(struct inode *inode, struct file *file) +{ + return 0; +} + +ssize_t medusa_read_medstat(struct file * filp, char *buf, size_t count, loff_t * ppos) +{ + static char tmp[160]; + int len; + + len = sprintf(tmp, "bytes-in packets-in bytes-out packets-out msg-id\n" "%lu %lu %lu %lu %u\n", stat_bytes_in, stat_pkt_in, stat_bytes_out, stat_pkt_out, msg_id); + count = ((len - *ppos) < count) ? (len - *ppos) : count; + if (*ppos >= len || count <= 0) + return 0; + if (copy_to_user(buf, tmp + *ppos, count)) + return -EFAULT; + *ppos += count; + return count; +} + +static void medusa_invalidate( void ) +{ + struct task_struct *t; + int i; + + medusa_magic++; + read_lock(&tasklist_lock); + for_each_task( t ) { + /* read lock is sufficient, because */ + /* no other routine in the world */ + /* changes this and ours is only one */ + for(i=0;imed.cinfo)/sizeof(t->med.cinfo[0]);i++) + t->med.cinfo[i]=0; + VS_PROCESS(t) = BEGIN_VS; + VSS_PROCESS(t) = BEGIN_VS; + VSR_PROCESS(t) = BEGIN_VS; + VSW_PROCESS(t) = BEGIN_VS; + t->med.med_act = MPACT_EXEC | MPACT_FORK ; + t->med.med_iact = 0; + t->med.med_user = 0; +#ifdef CONFIG_MEDUSA_SYSCALL + for (i = 0; i < NR_syscalls / 32; i++) + t->med.med_syscall[i] = 0; +#endif /* CONFIG_MEDUSA_SYSCALL */ + } + read_unlock(&tasklist_lock); +} + +int medusa_open_medusa(struct inode *inode, struct file *file) +{ +#ifdef CONFIG_MEDUSA_SYSCALL + int i; +#endif /* CONFIG_MEDUSA_SYSCALL */ + + if (current->uid != 0) /* add luid ... !!! */ + return -EPERM; + + write_lock(&constable_lock); + if (constable) { + write_unlock(&constable_lock); + return -EPERM; + } + request_mutex = MUTEX; + medusa_invalidate(); + constable = current; + intercom_status = ICOM_FREE; + intercom_istatus = ICOM_WAIT; +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_INFO "Medusa: Security daemon registered (pid=%d).\n", current->pid); +#endif + no_constable = 0; + write_unlock(&constable_lock); + + current->med.med_act = 0; + current->med.med_iact = 0; +#ifdef CONFIG_MEDUSA_SYSCALL + for (i = 0; i < NR_syscalls / 32; i++) + current->med.med_syscall[i] = 0; +#endif /* CONFIG_MEDUSA_SYSCALL */ + VS_PROCESS(current) = ALL_VS; + VSS_PROCESS(current) = ALL_VS; + VSR_PROCESS(current) = ALL_VS; + VSW_PROCESS(current) = ALL_VS; + return 0; +} + +int medusa_release(struct inode *inode, struct file *file) +{ + if (constable != current) + return 0; + + constable_exiting = 1; /* stop the growth of number of processes + waiting for 'answer_wait' queue */ + + up(&request_mutex); /* start all waiting processes */ + if (inbuf) + inbuf->answer = MED_ERR; + if (answer_wait) + wake_up(&answer_wait); + + write_lock(&constable_lock); + constable = NULL; + constable_exiting = 0; + write_unlock(&constable_lock); +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_INFO "Medusa: Security daemon unregistered.\n"); +#endif /* CONFIG_MEDUSA_QUIET */ +#ifdef CONFIG_MEDUSA_HALT +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_EMERG "Medusa: No security daemon, system halted.\n"); +#endif /* CONFIG_MEDUSA_QUIET */ + notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL); + machine_halt(); +#endif /* CONFIG_MEDUSA_HALT */ +#ifdef CONFIG_MEDUSA_REBOOT +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_EMERG "Medusa: No security daemon, rebooting system.\n"); +#endif /* CONFIG_MEDUSA_QUIET */ + ctrl_alt_del(); +#endif /* CONFIG_MEDUSA_REBOOT */ + return 0; +} + +ssize_t medusa_read(struct file * filp, char *buf, size_t count, loff_t * ppos) +{ + if (constable != current) + return -EPERM; + if (!access_ok(VERIFY_WRITE, buf, count)) + return -EFAULT; + + if (intercom_istatus == ICOM_CMDANS) { + if (count != MP_SIZE) + return -EIO; + cmdansbuf.id = 0; + __copy_to_user(buf, &cmdansbuf, count); + stat_bytes_out += count; + stat_pkt_out++; + if (datacmd_to_constable != NULL) + intercom_istatus = ICOM_CMDDANS; + else + intercom_istatus = ICOM_WAIT; + return count; + } else if (intercom_istatus == ICOM_CMDDANS) { + if (count != cmdansbuf.data_len) + return -EIO; + __copy_to_user(buf, datacmd_to_constable, count); + stat_bytes_out += count; + intercom_istatus = ICOM_WAIT; + return count; + } + while (intercom_status == ICOM_FREE) { + if (count != MP_SIZE) + return -EIO; + interruptible_sleep_on(&constable_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + } + if (intercom_status == ICOM_VALID) { + if (count != MP_SIZE) + return -EIO; + __copy_to_user(buf, intercom, count); + stat_bytes_out += count; + stat_pkt_out++; + if (data_to_constable != NULL) + intercom_status = ICOM_DATA; + else + intercom_status = ICOM_WAIT; + return count; + } else if (intercom_status == ICOM_DATA) { + if (count != intercom->data_len) + return -EIO; + __copy_to_user(buf, data_to_constable, count); + stat_bytes_out += count; + intercom_status = ICOM_WAIT; + return count; + } + return -EIO; +} + +ssize_t medusa_write(struct file * filp, const char *buf, size_t count, loff_t * ppos) +{ + if (constable != current) + return -EPERM; + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; + + if (intercom_istatus == ICOM_WAIT) { + if (count != MP_SIZE) + return -EIO; + __copy_from_user(&cmdbuf, buf, count); + stat_bytes_in += count; + stat_pkt_in++; + datacmd_from_constable = NULL; + if (cmdbuf.id != 0) { /* answer */ + if (intercom_status != ICOM_WAIT || cmdbuf.id != intercom->id) + return -EIO; + memcpy(inbuf, &cmdbuf, count); + } + if (cmdbuf.answer == MED_ERR) + cmdbuf.data_len = 0; + if (cmdbuf.data_len > 0) + intercom_istatus = ICOM_WAITDATA; + else + goto Complet; + return count; + } else if (intercom_istatus == ICOM_WAITDATA) { + if (count != cmdbuf.data_len) + return -EIO; + datacmd_from_constable = kmalloc(count, GFP_KERNEL); + if (datacmd_from_constable == NULL) + return -ENOMEM; + __copy_from_user(datacmd_from_constable, buf, count); + stat_bytes_in += count; + Complet: if (cmdbuf.id == 0) { + /* command */ + datacmd_to_constable = medusa_cmd(&cmdbuf, datacmd_from_constable, count, &cmdansbuf); + if (datacmd_from_constable) /* deleted in medusa_cmd */ + datacmd_from_constable = NULL; + intercom_istatus = ICOM_CMDANS; + return count; + } + if (intercom_status != ICOM_WAIT) /* just to be sure */ + return -EIO; + intercom_istatus = ICOM_WAIT; + data_from_constable = datacmd_from_constable; + intercom_status = ICOM_FREE; + wake_up(&answer_wait); + return count; + } + return -EIO; +} + +unsigned int medusa_poll(struct file *filp, poll_table * wait) +{ + if (constable != current) + return -EPERM; + + poll_wait(filp, &constable_wait, wait); + if (intercom_status != ICOM_FREE) + return POLLIN | POLLRDNORM; + return 0; +} + +char *medusa_request(struct medusa_packet *msg, const char *data) +{ + char *retval; +#ifdef CONFIG_MEDUSA_TASKSWITCH + unsigned long flags; + struct wait_queue wait; + struct task_struct *curr; +#endif /* CONFIG_MEDUSA_TASKSWITCH */ + + if (msg == NULL) { +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_ERR "Medusa: NULL msg in request!\n"); +#endif /* CONFIG_MEDUSA_QUIET */ + return NULL; + } + if (constable_exiting) { /* speed-up only */ + msg->answer = MED_ERR; + return NULL; + } +#ifdef CONFIG_MEDUSA_DEBUG + if (constable_off) + return NULL; +#endif /* CONFIG_MEDUSA_DEBUG */ + + read_lock(&constable_lock); + if (constable == NULL) { + if (!no_constable) { +/* #ifndef CONFIG_MEDUSA_QUIET + printk(KERN_WARNING + "Medusa: No security daemon process!\n"); +#endif */ + no_constable = 1; + } + msg->answer = MED_ERR; + read_unlock(&constable_lock); + return NULL; + } + if (constable == current) { + msg->answer = MED_ERR; + read_unlock(&constable_lock); + return NULL; + } + + down(&request_mutex); + if (constable_exiting) { + msg->answer = MED_ERR; + up(&request_mutex); + read_unlock(&constable_lock); + return NULL; + } + read_unlock(&constable_lock); + + msg->id = msg_id++; + msg_id ? 0 : ++msg_id; + data_from_constable = NULL; + data_to_constable = data; + intercom = inbuf = msg; + intercom_status = ICOM_VALID; + +#ifdef CONFIG_MEDUSA_TASKSWITCH + read_lock(&constable_lock); + spin_lock_irqsave(&runqueue_lock, flags); + constable->state = TASK_RUNNING; +// if (constable->next_run) { + constable->prev_run = &init_task; + init_task.next_run = constable; + constable->next_run = init_task.next_run; + init_task.next_run->prev_run = constable; + nr_running++; +// } + spin_unlock_irqrestore(&runqueue_lock, flags); + read_unlock(&constable_lock); + + current->state = TASK_UNINTERRUPTIBLE; + wait.task = current; + write_lock_irqsave(&waitqueue_lock, flags); + __add_wait_queue(&answer_wait, &wait); + write_unlock(&waitqueue_lock); + + curr = current; + release_kernel_lock(curr, curr->processor); + kstat.context_swtch++; + get_mmu_context(constable); + switch_to(curr, constable, curr); + reacquire_kernel_lock(current); + + write_lock_irq(&waitqueue_lock); + __remove_wait_queue(&answer_wait, &wait); + write_unlock_irqrestore(&waitqueue_lock, flags); +#else + wake_up(&constable_wait); + sleep_on(&answer_wait); +#endif /* CONFIG_MEDUSA_TASKSWITCH */ + + intercom_status = ICOM_FREE; + retval = data_from_constable; + up(&request_mutex); + + return retval; +} + +void medusa_putdata(char *data) +{ + if (data != NULL && !IS_ERR(data)) + kfree(data); +} + +int medusa_init(void) +{ + if (register_chrdev(MEDUSA_MAJOR, "medusa", &fops)) { +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_ERR "Medusa: Unable to get major %d for medusa devices\n", MEDUSA_MAJOR); +#endif + return -EIO; + } +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_INFO "Medusa DS9 Security System\n"); +#endif + medusa_process_init(~0); + return 0; +} + +const char *medusa_cmd(struct medusa_packet *msg, char *data, int datalen, struct medusa_packet *ans) +{ + char *retval = NULL; + struct task_struct *t; +#ifdef CONFIG_MEDUSA_FORCE + unsigned long flags; +#endif /* CONFIG_MEDUSA_FORCE */ + + switch (msg->cmd) { + case MED_RESET: +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_INFO "Medusa: Initializing communication interface\n"); +#endif /* CONFIG_MEDUSA_QUIET */ + ans->answer = MED_YES; + msg_id = 1; + stat_pkt_in = stat_pkt_out = stat_bytes_in = stat_bytes_out = 0; + medusa_invalidate(); + /* FIXME Complete this.... */ + break; + case MED_PRINTK: + if (!data) + break; +//#ifndef CONFIG_MEDUSA_QUIET + printk("Medusa: Security daemon: %s\n", data); +//#endif /* CONFIG_MEDUSA_QUIET */ + ans->answer = MED_YES; + break; + case MED_GET_PROC: + read_lock(&tasklist_lock); + if ((t = find_task_by_pid(msg->u.r_cmd.proc.pid)) != NULL) { + medusa_set_proc_inf(&(ans->u.a_cmd.proc), t); + ans->answer = MED_YES; + } + read_unlock(&tasklist_lock); + break; + case MED_SET_PROC: + read_lock(&tasklist_lock); + if ((t = find_task_by_pid(msg->u.r_cmd.proc.pid)) != NULL) { + /* read lock is sufficient, because */ + /* no other routine in the world */ + /* changes this and ours is only one */ + medusa_set_proc(t, &(msg->u.r_cmd.proc)); + ans->answer = MED_YES; + } + read_unlock(&tasklist_lock); + break; + case MED_FOREACH_PROC: + ans->answer = MED_NO; + read_lock(&tasklist_lock); + for_each_task(t) { + if (t->med.cinfo == 0) { + medusa_set_proc_inf(&(ans->u.a_cmd.proc), t); + ans->answer = MED_YES; + break; + } + } + read_unlock(&tasklist_lock); + break; +#ifdef CONFIG_MEDUSA_FORCE + case MED_FORCE: + read_lock(&tasklist_lock); + if ((t = find_task_by_pid(msg->u.r_cmd.proc.pid)) != NULL) { + spin_lock_irqsave(&t->sigmask_lock, flags); + + if (!data) { + if (t->med.force_code) { + unsigned char *p = t->med.force_code; + t->med.force_code = NULL; + kfree(p); + } + ans->answer = MED_YES; + } else if (t->med.force_code == NULL) { + t->med.force_len = datalen; + t->med.force_code = data; + data = NULL; /* kfree() elsewhere */ + ans->answer = MED_YES; + recalc_sigpending(t); + if (t->state == TASK_INTERRUPTIBLE && signal_pending(t) + ) + wake_up_process(t); +#ifdef __SMP__ + spin_lock(&runqueue_lock); + if (t->has_cpu && t->processor != smp_processor_id() + ) + smp_send_reschedule(t->processor); + spin_unlock(&runqueue_lock); +#endif + } + spin_unlock_irqrestore(&t->sigmask_lock, flags); + } + read_unlock(&tasklist_lock); + break; +#endif /* CONFIG_MEDUSA_FORCE */ + case MED_GETSTR: + ans->answer = MED_YES; + ans->data_len = strlen((char *) (msg->u.r_cmd.arg[0])); + retval = ((char *) (msg->u.r_cmd.arg[0])); + break; + case MED_VERSION: + if (msg->u.r_cmd.arg[0] == 1) + ans->answer = MED_YES; + else + ans->answer = MED_NO; + break; + default: + ans->answer = MED_ERR; + } + if (data) + medusa_putdata(data); + return retval; +} + + +#endif /* CONFIG_MEDUSA */ diff -urNX nopatch linux-2.2.20/medusa/process.c linux-2.2.20-medusa-0.9.0/medusa/process.c --- linux-2.2.20/medusa/process.c Thu Jan 1 01:00:00 1970 +++ linux-2.2.20-medusa-0.9.0/medusa/process.c Wed Nov 21 13:41:35 2001 @@ -0,0 +1,229 @@ + +#include + +#ifdef CONFIG_MEDUSA + +#include +#include +#include +#include +#include +#include +#include + +extern struct task_struct *constable; + +void medusa_set_proc_inf(struct m_proc_inf *pi, struct task_struct *task) +{ + pi->pid = task->pid; + pi->parent_pid = pi->child_pid = pi->sibling_pid = 0; + if (task->p_pptr) + pi->parent_pid = task->p_pptr->pid; + if (task->p_cptr) + pi->child_pid = task->p_cptr->pid; + if (task->p_osptr) + pi->sibling_pid = task->p_osptr->pid; + pi->pgrp = task->pgrp; + pi->uid = task->uid; + pi->euid = task->euid; + pi->suid = task->suid; + pi->fsuid = task->fsuid; + pi->gid = task->gid; + pi->egid = task->egid; + pi->sgid = task->sgid; + pi->fsgid = task->fsgid; + pi->cap_effective = task->cap_effective; + pi->cap_inheritable = task->cap_inheritable; + pi->cap_permitted = task->cap_permitted; + pi->luid = task->luid; + pi->mp = task->med; +} + +void medusa_set_proc(struct task_struct *task, struct m_proc_inf *pi) +{ + struct med_proc tmp_med; + if (pi->pid == task->pid) { +// task->pgrp=pi->pgrp; + if (task->uid != pi->uid) { + free_uid(task); + task->uid = pi->uid; + alloc_uid(task); + } + task->euid = pi->euid; + task->suid = pi->suid; + task->fsuid = pi->fsuid; + task->gid = pi->gid; + task->egid = pi->egid; + task->sgid = pi->sgid; + task->fsgid = pi->fsgid; + task->cap_effective = pi->cap_effective; + task->cap_inheritable = pi->cap_inheritable; + task->cap_permitted = pi->cap_permitted; +// task->luid=pi->luid; + tmp_med = pi->mp; +#ifdef CONFIG_MEDUSA_FORCE + tmp_med.force_code = task->med.force_code; + tmp_med.force_len = task->med.force_len; +#endif /* CONFIG_MEDUSA_FORCE */ + task->med = tmp_med; + } +} + + +int medusa_pact(int act, struct task_struct *source, struct task_struct *target, __u32 info1, __u32 info2) +{ + struct medusa_packet msg; + char *s; + + msg.cmd = MED_PACT; + msg.u.r_pact.act = act; + medusa_set_proc_inf(&(msg.u.r_pact.proc), source); + medusa_set_proc_inf(&(msg.u.r_pact.target), target); + msg.u.r_pact.info1 = info1; + msg.u.r_pact.info2 = info2; + msg.data_len = 0; + s = medusa_request(&msg, NULL); + if (s != NULL) { + medusa_putdata(s); +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_ERR "Medusa: Invalid data from security daemon\n"); +#endif /* CONFIG_MEDUSA_QUIET */ + } + if (msg.answer != MED_ERR) + medusa_set_proc(source, &(msg.u.a_pact.proc)); + else + msg.answer = MED_OK; + return msg.answer; +} + +int medusa_sendsig(int sig, struct task_struct *p) +{ + int r = MED_OK; + + MED_ERROR_CHECK(); + if (in_interrupt() || (current->pid <= 1) || (current == constable) + || (p->pid <= 1) || (sig == SIGCHLD)) + return MED_OK; + if (!VS_SEE_PROCESS(current, p) + || !(VSW_PROCESS(current) & VS_PROCESS(p))) + return MED_NO; + if (sig > 0 && current->med.med_act & MPACT_KILL) { + r = medusa_pact(MPACT_KILL, current, p, (__u32) sig, 0); + } + return r; +} + +int medusa_see(struct task_struct *p) +{ + if ((current->pid) <= 1 || (current == constable) || (p->pid <= 1)) + return 1; + if (!VS_SEE_PROCESS(current, p)) + return 0; /* doesn't see */ + return 1; /* see */ +} + +void medusa_setluid(uid_t uid) +{ + if (current->med.med_act & MPACT_SETUID) + medusa_pact(MPACT_SETUID, current, current, (__u32) uid, 0); + if (uid == (uid_t) - 1 && current->uid != uid) + return; /* didn't change */ + if (current->luid == (uid_t) - 1) { + if (current->uid == (uid_t) - 1) { /* shouldn't happen */ + current->uid = (uid_t) - 2; +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_ERR "Medusa: setuid(-1) -> setuid(-2)\n"); +#endif /* CONFIG_MEDUSA_QUIET */ + } + current->luid = current->uid; + } +} + +int medusa_capable(int cap) +{ + MED_ERROR_CHECK(); + if (current->med.med_act & MPACT_CAP) + return medusa_pact(MPACT_CAP, current, current, (__u32) CAP_TO_MASK(cap), (__u32) 0); + else + return MED_OK; +} + +int medusa_fork(struct task_struct *new, unsigned long clone_flags) +{ int r=MED_OK; + MED_ERROR_CHECK(); + if (current->med.med_act & MPACT_FORK) + { r=medusa_pact(MPACT_FORK, current, new, (__u32) clone_flags, (__u32) 0); + *new = *current; /* !!! */ + } +#ifdef CONFIG_MEDUSA_FORCE + if (current->med.force_code) + new->med.force_code = kmalloc(new->med.force_len, GFP_KERNEL); + if (!new->med.force_code) + new->med.force_len = 0; + else + memcpy(new->med.force_code, current->med.force_code, new->med.force_len); +#endif /* CONFIG_MEDUSA_FORCE */ + return r; +} + +int medusa_afterfork(struct task_struct *new) +{ + MED_ERROR_CHECK(); + if (current->med.med_act & MPACT_START) + { medusa_pact(MPACT_START, new, current, (__u32) 0, (__u32) 0); + } + return MED_OK; +} + +int medusa_ptrace(struct task_struct *source, struct task_struct *target) +{ + MED_ERROR_CHECK(); + if ((VSS_PROCESS(target) & ~(VSS_PROCESS(source))) || (VSR_PROCESS(target) & ~(VSR_PROCESS(source))) || (VSW_PROCESS(target) & ~(VSW_PROCESS(source))) || (target == constable)) + return MED_NO; + if (current->med.med_act & MPACT_PTRACE) + return medusa_pact(MPACT_PTRACE, source, target, 0, 0); + return MED_OK; +} + +void medusa_process_init(__u16 act) +{ +#ifdef CONFIG_MEDUSA_SYSCALL + int i; +#endif /* CONFIG_MEDUSA_SYSCALL */ + VS_PROCESS(current) = BEGIN_VS; + VSS_PROCESS(current) = BEGIN_VS; + VSR_PROCESS(current) = BEGIN_VS; + VSW_PROCESS(current) = BEGIN_VS; + /* no MPACT_MAY_CD, it's special thing */ + current->med.med_act = act & (__u16) ~ ((__u16) MPACT_MAY_CD); + current->med.med_iact = 0; + current->med.med_user = 0; +#ifdef CONFIG_MEDUSA_SYSCALL + for (i = 0; i < NR_syscalls / 32; i++) + current->med.med_syscall[i] = 0; +#endif /* CONFIG_MEDUSA_SYSCALL */ +#ifdef CONFIG_MEDUSA_FORCE + current->med.force_code = NULL; + current->med.force_len = 0; +#endif /* CONFIG_MEDUSA_FORCE */ + current->luid = (uid_t) - 1; +} + +void medusa_kernel_thread(int (*fn) (void *)) +{ +/* if (fn == exec_modprobe) { + medusa_process_init(0);*/ +#ifndef CONFIG_MEDUSA_QUIET +// printk(KERN_DEBUG "Medusa: Executing modprobe\n"); +#endif /* CONFIG_MEDUSA_QUIET */ +// } else { +#ifndef CONFIG_MEDUSA_QUIET +// printk("KERN_DEBUG Medusa: Thread: fn=%p\n", fn); +#endif /* CONFIG_MEDUSA_QUIET */ + medusa_process_init(MPACT_EXEC | MPACT_FORK); +// } +} + +EXPORT_SYMBOL(medusa_capable); + +#endif /* CONFIG_MEDUSA */ diff -urNX nopatch linux-2.2.20/medusa/syscall.c linux-2.2.20-medusa-0.9.0/medusa/syscall.c --- linux-2.2.20/medusa/syscall.c Thu Jan 1 01:00:00 1970 +++ linux-2.2.20-medusa-0.9.0/medusa/syscall.c Wed Nov 21 13:12:51 2001 @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +volatile asmlinkage int medusa_syscall_watch(unsigned int eax, /* in: syscall, out: retval */ + struct task_struct *curr, volatile unsigned int p1, volatile unsigned int p2, volatile unsigned int p3, volatile unsigned int p4, volatile unsigned int p5) +{ + struct medusa_packet msg; + char *foo; + + if (no_constable) + return MED_SYSCALL_ALLOW; + + msg.cmd = MED_TRACE; + msg.u.r_trace.syscall = (__u16) eax; + msg.u.r_trace.arg[0] = (__u32) p1; + msg.u.r_trace.arg[1] = (__u32) p2; + msg.u.r_trace.arg[2] = (__u32) p3; + msg.u.r_trace.arg[3] = (__u32) p4; + msg.u.r_trace.arg[4] = (__u32) p5; + medusa_set_proc_inf(&(msg.u.r_trace.proc), current); + msg.data_len = 0; + + foo = medusa_request(&msg, NULL); + + if (foo) + medusa_putdata(foo); + + if (msg.answer != MED_ERR) { + medusa_set_proc(current, &(msg.u.a_trace.proc)); + (__u32) p1 = msg.u.a_trace.arg[0]; + (__u32) p2 = msg.u.a_trace.arg[1]; + (__u32) p3 = msg.u.a_trace.arg[2]; + (__u32) p4 = msg.u.a_trace.arg[3]; + (__u32) p5 = msg.u.a_trace.arg[4]; + } else + msg.answer = MED_OK; + switch (msg.answer) { + case MED_SKIP: + return MED_SYSCALL_SKIPTRACE; + case MED_NO: + eax = msg.u.a_trace.retval; + return MED_SYSCALL_DENY; + } + return MED_SYSCALL_ALLOW; +} diff -urNX nopatch linux-2.2.20/medusa/vfs.c linux-2.2.20-medusa-0.9.0/medusa/vfs.c --- linux-2.2.20/medusa/vfs.c Thu Jan 1 01:00:00 1970 +++ linux-2.2.20-medusa-0.9.0/medusa/vfs.c Wed Nov 21 13:12:51 2001 @@ -0,0 +1,482 @@ + +#include + +#ifdef CONFIG_MEDUSA + +#include +#include +#include +#include +#include + +//#define CONFIG_MEDUSA_ALIAS + +void medusa_set_inode_inf(struct m_inode_inf *ii, struct inode *inode) +{ + ii->dev = inode->i_dev; + ii->ino = inode->i_ino; + ii->mode = inode->i_mode; + ii->nlink = inode->i_nlink; + ii->uid = inode->i_uid; + ii->gid = inode->i_gid; + ii->rdev = inode->i_rdev; + ii->mi = inode->i_med; +} + + +int medusa_redirect(char *redirect, struct dentry **dentry) +{ + __u16 save_act; + + struct dentry *parent, *tmp, *orig; +#ifdef CONFIG_MEDUSA_ALIAS + struct list_head *s, *p; +#endif /* CONFIG_MEDUSA_ALIAS */ + +#ifdef CONFIG_MEDUSA_ON_NFS + uid_t save_fsuid; +#endif /* CONFIG_MEDUSA_ON_NFS */ + if (redirect == NULL) + return 0; + orig = (*dentry); + *dentry = NULL; + parent = dget(orig->d_covers->d_parent); + dget(parent); /* i'll need it once more */ + save_act = current->med.med_act; + current->med.med_act |= MPACT_MAY_CD; /* exception !!! */ +#ifdef CONFIG_MEDUSA_ON_NFS + save_fsuid = current->fsuid; + current->fsuid = 0; +#endif /* CONFIG_MEDUSA_ON_NFS */ + /* flag=0 , mode=0 ??? */ + tmp = lookup_dentry(redirect, parent, 0); /* does one dput(parent) */ +#ifdef CONFIG_MEDUSA_ON_NFS + current->fsuid = save_fsuid; +#endif /* CONFIG_MEDUSA_ON_NFS */ + current->med.med_act &= ~MPACT_MAY_CD; + current->med.med_act |= (save_act & MPACT_MAY_CD); + if (tmp == NULL || IS_ERR(tmp) || !tmp->d_inode) { + dput(parent); + *dentry = orig; + return -ENOENT; + } +#ifdef CONFIG_MEDUSA_ALIAS + printk(KERN_DEBUG "M DBG 2\n"); + s = &(tmp->d_inode->i_dentry); /*tmp->d_alias */ + (*dentry) = NULL; + for (p = s->next; p != s; p = p->next) { + if (((*dentry) = list_entry(p, struct dentry, d_alias))->d_parent == parent) + break; + (*dentry) = NULL; + } + if (!(*dentry)) { /* p==s */ + (*dentry) = d_alloc(NULL, &(orig->d_name)); + printk(KERN_DEBUG "M DBG 3\n"); + if (*dentry) { + (*dentry)->d_parent = dget(parent); + printk(KERN_DEBUG "M DBG 4\n"); + (*dentry)->d_sb = tmp->d_sb; + inode_inc_count(tmp->d_inode); +// d_add(*dentry,tmp->d_inode); + d_instantiate(*dentry, tmp->d_inode); + } else { + dput(tmp); + dput(parent); + *dentry = orig; + return -ENOMEM; + } + } else + (*dentry) = dget((*dentry)); + printk(KERN_DEBUG "M DBG 5\n"); + dput(tmp); +#else + *dentry = tmp; +#endif /* CONFIG_MEDUSA_ALIAS */ + dput(parent); + dput(orig); + return 0; +} + +int medusa_act(int pact, int act, int may_red, struct dentry **dentry, const char *str, int len, __u32 info1, __u32 info2) +{ + char *redirect; + struct medusa_packet msg; + + msg.cmd = MED_IACT; + msg.u.r_iact.pact = pact; + msg.u.r_iact.act = act; + if (dentry != NULL) + medusa_set_inode_inf(&(msg.u.r_iact.inode), (*dentry)->d_inode); + else + memset(&(msg.u.r_iact.inode), 0, sizeof(struct m_inode_inf)); + medusa_set_proc_inf(&(msg.u.r_iact.proc), current); + msg.u.r_iact.info1 = info1; + msg.u.r_iact.info2 = info2; + if (str != NULL) + msg.data_len = len; + else + msg.data_len = 0; + redirect = medusa_request(&msg, str); + if ((!may_red || dentry == NULL) && redirect != NULL) { + medusa_putdata(redirect); + redirect = NULL; +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_ERR "Medusa: Invalid redirection\n"); +#endif + } + if (msg.answer != MED_ERR) + medusa_set_proc(current, &(msg.u.a_iact.proc)); + else + msg.answer = MED_OK; + if (msg.answer == MED_NO) { + if (redirect != NULL) + medusa_putdata(redirect); + return MED_NO; + } + if (redirect != NULL) { + int r; + + r = medusa_redirect(redirect, dentry); + medusa_putdata(redirect); + if (r < 0) + return MED_NO; + } + return msg.answer; +} + +int medusa_iact(int act, int may_red, struct dentry **dentry, const char *str, int len, __u32 info1, __u32 info2) +{ + int r = MED_OK; + + if (current->med.med_iact & act) { + r = medusa_act(MPACT_IOP, act, may_red, dentry, str, len, info1, info2); + if ((r == MED_NO) || (r == MED_SKIP)) + return r; + } + if (med_valid(&((*dentry)->d_inode->i_med)) + && ((*dentry)->d_inode->i_med.med_act & act)) + r = medusa_act(0, act, may_red, dentry, str, len, info1, info2); + return r; +} + +int medusa_exec(struct dentry **dentry) +{ + int r = MED_OK; + + MED_ERROR_CHECK(); + MED_DENTRY_CHECK(*dentry); + if (!VS_SEE_INODE(current, (*dentry)->d_inode) + || !VS_READ_INODE(current, (*dentry)->d_inode)) + return MED_NO; + if (current->med.med_act & MPACT_EXEC) { + r = medusa_act(MPACT_EXEC, 0, 1, dentry, NULL, 0, (__u32) 0, (__u32) 0); + if (r == MED_NO) + return r; + } + if ((*dentry)->d_inode->i_med.med_act & MIACT_EXEC) + r = medusa_iact(MIACT_EXEC, 1, dentry, NULL, 0, (__u32) 0, (__u32) 0); + return r; +} + +void medusa_after_exec(char *filename, char **argv, char **envp) +{ + if (current->med.med_act & MPACT_EXEC) + medusa_act(MPACT_EXEC, 1, 1, NULL, filename, strlen(filename) + 1, (__u32) argv, (__u32) envp); +} + +int medusa_sexec(struct linux_binprm *bprm) +{ + struct medusa_packet msg; + char *s; + + MED_ERROR_CHECK(); + if (!(current->med.med_act & MPACT_SEXEC)) + return MED_OK; + msg.cmd = MED_PACT; + msg.u.r_pact.act = MPACT_SEXEC; + medusa_set_proc_inf(&(msg.u.r_pact.proc), current); + medusa_set_proc_inf(&(msg.u.r_pact.target), current); + cap_t(msg.u.r_pact.target.cap_effective) = bprm->cap_effective; + cap_t(msg.u.r_pact.target.cap_permitted) = bprm->cap_permitted; + cap_t(msg.u.r_pact.target.cap_inheritable) = bprm->cap_inheritable; + cap_t(msg.u.r_pact.target.suid) = cap_t(msg.u.r_pact.target.euid) = cap_t(msg.u.r_pact.target.fsuid) = bprm->e_uid; + cap_t(msg.u.r_pact.target.sgid) = cap_t(msg.u.r_pact.target.egid) = cap_t(msg.u.r_pact.target.fsgid) = bprm->e_gid; + msg.u.r_pact.info1 = VS_INODE(bprm->dentry->d_inode); + msg.u.r_pact.info2 = bprm->dentry->d_inode->i_med.cinfo; + msg.data_len = strlen(bprm->filename); + s = medusa_request(&msg, bprm->filename); + if (s != NULL) { + medusa_putdata(s); +#ifndef CONFIG_MEDUSA_QUIET + printk(KERN_ERR "Medusa: Invalid incoming data!\n"); +#endif + } + if (msg.answer != MED_ERR) + medusa_set_proc(current, &(msg.u.a_pact.proc)); + else + msg.answer = MED_OK; + return msg.answer; +} + +int medusa_get_dentry(struct dentry *dentry) +{ + int len; + const char *name; + char *str; + struct dentry *parent, *covers; + struct medusa_packet msg; + + if (no_constable || !dentry || !(dentry->d_inode) || med_valid(&(dentry->d_inode->i_med))) + return 0; + + covers = dget(dentry->d_covers); + len = covers->d_name.len; + name = covers->d_name.name; + parent = dget(covers->d_parent->d_covers); + + if (parent == NULL || parent->d_inode == NULL) { + dput(covers); + return 0; + } + if (!med_valid(&(parent->d_inode->i_med)) + && parent != parent->d_parent && medusa_get_dentry(parent) <= 0) { + dput(parent); + dput(covers); + return 0; + } + if (med_valid(&(parent->d_inode->i_med)) + && (parent->d_inode->i_med.med_act & MIACT_INHERIT) + ) { + dentry->d_inode->i_med = parent->d_inode->i_med; + dput(parent); + dput(covers); + return 1; + } + msg.cmd = MED_IGET; + medusa_set_inode_inf(&(msg.u.r_iget.inode), covers->d_inode); + medusa_set_inode_inf(&(msg.u.r_iget.parent), parent->d_inode); + msg.data_len = len; + dput(parent); + str = medusa_request(&msg, name); + if (str != NULL) + medusa_putdata(str); + dput(covers); + if (msg.answer == MED_ERR) + return 0; + dentry->d_inode->i_med = msg.u.a_iget.inode.mi; + dentry->d_inode->i_med.magic = medusa_magic; + return 1; +} + +int medusa_get_inode(struct inode *inode) +{ + int r; + struct dentry *dentry; + + if (no_constable) + return 0; + dentry = dget(list_entry(inode->i_dentry.next, struct dentry, d_alias)); + r = medusa_get_dentry(dentry); + dput(dentry); + return r; +} + +int medusa_permission(struct inode *inode, int mask) +{ + int r = MED_OK; + struct dentry *dentry; + + MED_ERROR_CHECK(); + MED_INODE_CHECK(inode); + if (!VS_SEE_INODE(current, inode) + || ((mask & (S_IRUGO | S_IXUGO)) + && !VS_READ_INODE(current, inode)) || ((mask & S_IWUGO) + && !VS_WRITE_INODE(current, inode))) + return MED_NO; + dentry = dget(list_entry(inode->i_dentry.next, struct dentry, d_alias)); + if (dentry == NULL || IS_ERR(dentry) || dentry->d_inode == NULL) + r = MED_OK; + else + r = medusa_iact(MIACT_PERMISSION, 0, &dentry, dentry->d_name.name, dentry->d_name.len, (__u32) mask, 0); + dput(dentry); + if ((current->med.med_act & MPACT_MAY_CD) + && (mask == MAY_EXEC || mask == 0) && S_ISDIR(inode->i_mode)) + return MED_YES; /* permitted - exception */ + return r; +} + +int medusa_notify_change(struct dentry *dentry, struct iattr *attr) +{ + MED_DENTRY_CHECK(dentry); + if (!VS_SEE_INODE(current, dentry->d_inode) + || !VS_WRITE_INODE(current, dentry->d_inode)) + return MED_NO; + return MED_OK; +} + +int medusa_lookup(struct inode *dir, struct dentry **dentry) +{ + MED_ERROR_CHECK(); + if (*dentry == NULL || IS_ERR((*dentry)) || !(*dentry)->d_inode) + return MED_OK; + MED_DENTRY_CHECK(*dentry); + if (!VS_SEE_INODE(current, (*dentry)->d_inode)) + return MED_SKIP; + return medusa_iact(MIACT_ACCESS, 1, dentry, NULL, 0, 0, 0); +} + +void medusa_clean_inode(struct inode *inode) +{ + inode->i_med.med_act = 0; + inode->i_med.magic = 0; + VS_INODE(inode) = ALL_VS; +#ifdef CONFIG_MEDUSA_FILE_CAPABILITIES + cap_clear(inode->i_med.icap); + cap_clear(inode->i_med.pcap); + cap_clear(inode->i_med.ecap); +#endif /* CONFIG_MEDUSA_FILE_CAPABILITIES */ +} + +int medusa_truncate(struct dentry *dentry, unsigned long length) +{ + MED_ERROR_CHECK(); + if (dentry == NULL || IS_ERR(dentry) || dentry->d_inode == NULL) + return MED_OK; + MED_DENTRY_CHECK(dentry); + if (!VS_SEE_INODE(current, dentry->d_inode) + || !VS_WRITE_INODE(current, dentry->d_inode)) + return MED_NO; + return medusa_iact(MIACT_TRUNCATE, 0, &dentry, dentry->d_name.name, dentry->d_name.len, (__u32) length, 0); +} + +int medusa_rename(struct dentry *dentry, const char *newname) +{ + MED_ERROR_CHECK(); + if (dentry == NULL || IS_ERR(dentry) || dentry->d_inode == NULL) + return MED_OK; + MED_DENTRY_CHECK(dentry); + if (!VS_SEE_INODE(current, dentry->d_inode) + || !VS_WRITE_INODE(current, dentry->d_inode)) + return MED_NO; + return medusa_iact(MIACT_RENAME, 0, &dentry, dentry->d_name.name, dentry->d_name.len, (__u32) newname, 0); +} + +int medusa_link(struct dentry *dentry, const char *newname) +{ + MED_ERROR_CHECK(); + if (!VS_SEE_INODE(current, dentry->d_inode) + || !VS_WRITE_INODE(current, dentry->d_inode)) + return MED_NO; + if (dentry == NULL || IS_ERR(dentry) || dentry->d_inode == NULL) + return MED_OK; + MED_DENTRY_CHECK(dentry); + return medusa_iact(MIACT_LINK, 0, &dentry, dentry->d_name.name, dentry->d_name.len, (__u32) newname, 0); +} + +int medusa_rmdir(struct dentry *dentry) +{ + MED_ERROR_CHECK(); + if (dentry == NULL || IS_ERR(dentry) || dentry->d_inode == NULL) + return MED_OK; + MED_DENTRY_CHECK(dentry); + if (!VS_SEE_INODE(current, dentry->d_inode) + || !VS_WRITE_INODE(current, dentry->d_inode)) + return MED_NO; + return medusa_iact(MIACT_RMDIR, 0, &dentry, dentry->d_name.name, dentry->d_name.len, 0, 0); +} + +int medusa_unlink(struct dentry *dentry) +{ + MED_ERROR_CHECK(); + if (dentry == NULL || IS_ERR(dentry) || dentry->d_inode == NULL) + return MED_OK; + MED_DENTRY_CHECK(dentry); + if (!VS_SEE_INODE(current, dentry->d_inode) + || !VS_WRITE_INODE(current, dentry->d_inode)) + return MED_NO; + return medusa_iact(MIACT_UNLINK, 0, &dentry, dentry->d_name.name, dentry->d_name.len, 0, 0); +} + +int medusa_create(struct dentry *dentry, int mode) +{ + int r; + struct dentry *parent; + + MED_ERROR_CHECK(); + if (dentry == NULL || IS_ERR(dentry)) + return MED_OK; + parent = dget(dentry->d_covers->d_parent); + MED_DENTRY_PUT_CHECK(parent); + if (!VS_SEE_INODE(current, parent->d_inode) + || !VS_WRITE_INODE(current, parent->d_inode)) { + dput(parent); + return MED_NO; + } + r = medusa_iact(MIACT_CREATE, 0, &parent, dentry->d_name.name, dentry->d_name.len, (__u32) mode, 0); + dput(parent); + return r; +} + +int medusa_mknod(struct dentry *dentry, dev_t dev) +{ + int r; + struct dentry *parent; + + MED_ERROR_CHECK(); + if (dentry == NULL || IS_ERR(dentry)) + return MED_OK; + parent = dget(dentry->d_covers->d_parent); + MED_DENTRY_PUT_CHECK(parent); + if (!VS_SEE_INODE(current, parent->d_inode) + || !VS_WRITE_INODE(current, parent->d_inode)) { + dput(parent); + return MED_NO; + } + r = medusa_iact(MIACT_MKNOD, 0, &parent, dentry->d_name.name, dentry->d_name.len, (__u32) dev, 0); + dput(parent); + return r; +} + +int medusa_mkdir(struct dentry *dentry, int mode) +{ + int r; + struct dentry *parent; + + MED_ERROR_CHECK(); + if (dentry == NULL || IS_ERR(dentry)) + return MED_OK; + parent = dget(dentry->d_covers->d_parent); + MED_DENTRY_PUT_CHECK(parent); + if (!VS_SEE_INODE(current, parent->d_inode) + || !VS_WRITE_INODE(current, parent->d_inode)) { + dput(parent); + return MED_NO; + } + r = medusa_iact(MIACT_MKDIR, 0, &parent, dentry->d_name.name, dentry->d_name.len, (__u32) mode, 0); + dput(parent); + return r; +} + +int medusa_symlink(struct dentry *dentry, const char *oldname) +{ + int r; + struct dentry *parent; + + MED_ERROR_CHECK(); + if (dentry == NULL || IS_ERR(dentry)) + return MED_OK; + parent = dget(dentry->d_covers->d_parent); + MED_DENTRY_PUT_CHECK(parent); + if (!VS_SEE_INODE(current, parent->d_inode) + || !VS_WRITE_INODE(current, parent->d_inode)) { + dput(parent); + return MED_NO; + } + r = + medusa_iact(MIACT_SYMLINK, 0, &parent, dentry->d_name.name, + dentry->d_name.len, (__u32) oldname, 0); + dput(parent); + return r; +} + +#endif /* CONFIG_MEDUSA */