diff -urNX nopatch linux-2.4.18.orig/Documentation/Configure.help linux-2.4.18/Documentation/Configure.help --- linux-2.4.18.orig/Documentation/Configure.help Mon Feb 25 20:37:51 2002 +++ linux-2.4.18/Documentation/Configure.help Fri Apr 12 16:44:00 2002 @@ -19947,6 +19947,50 @@ "Area6" will work for most boards. For ADX, select "Area5". +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. + + # # m68k-specific kernel options # Documented by Chris Lawrence et al. diff -urNX nopatch linux-2.4.18.orig/Makefile linux-2.4.18/Makefile --- linux-2.4.18.orig/Makefile Mon Feb 25 20:37:52 2002 +++ linux-2.4.18/Makefile Fri Apr 12 16:44:00 2002 @@ -124,6 +124,11 @@ LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib +ifdef CONFIG_MEDUSA +CORE_FILES += medusa/medusa.o +SUBDIRS += medusa +endif + DRIVERS-n := DRIVERS-y := DRIVERS-m := diff -urNX nopatch linux-2.4.18.orig/arch/i386/config.in linux-2.4.18/arch/i386/config.in --- linux-2.4.18.orig/arch/i386/config.in Mon Feb 25 20:37:52 2002 +++ linux-2.4.18/arch/i386/config.in Fri Apr 12 16:44:00 2002 @@ -15,6 +15,8 @@ bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL 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.4.18.orig/arch/i386/kernel/entry.S linux-2.4.18/arch/i386/kernel/entry.S --- linux-2.4.18.orig/arch/i386/kernel/entry.S Fri Apr 12 17:16:37 2002 +++ linux-2.4.18/arch/i386/kernel/entry.S Fri Apr 12 16:44:00 2002 @@ -193,7 +193,29 @@ jne tracesys cmpl $(NR_syscalls),%eax jae badsys + +#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: /* here used to be the ptrace-skip code. this is no longer */ +2: /* possible with new trace semantics */ +#endif + call *SYMBOL_NAME(sys_call_table)(,%eax,4) + +#ifdef CONFIG_MEDUSA_SYSCALL +3: +#endif + movl %eax,EAX(%esp) # save the return value ENTRY(ret_from_sys_call) cli # need_resched and signals atomic test diff -urNX nopatch linux-2.4.18.orig/arch/i386/kernel/process.c linux-2.4.18/arch/i386/kernel/process.c --- linux-2.4.18.orig/arch/i386/kernel/process.c Mon Feb 25 20:37:53 2002 +++ linux-2.4.18/arch/i386/kernel/process.c Fri Apr 12 16:44:01 2002 @@ -50,6 +50,10 @@ #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); int hlt_counter; @@ -497,6 +501,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.4.18.orig/arch/i386/kernel/ptrace.c linux-2.4.18/arch/i386/kernel/ptrace.c --- linux-2.4.18.orig/arch/i386/kernel/ptrace.c Wed Nov 21 19:42:41 2001 +++ linux-2.4.18/arch/i386/kernel/ptrace.c Fri Apr 12 16:44:01 2002 @@ -14,6 +14,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + #include #include #include @@ -153,6 +157,12 @@ struct user * dummy = NULL; 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) { @@ -444,6 +454,11 @@ 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 */ + /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) diff -urNX nopatch linux-2.4.18.orig/arch/i386/kernel/signal.c linux-2.4.18/arch/i386/kernel/signal.c --- linux-2.4.18.orig/arch/i386/kernel/signal.c Mon Feb 25 20:37:53 2002 +++ linux-2.4.18/arch/i386/kernel/signal.c Fri Apr 12 16:44:01 2002 @@ -20,6 +20,10 @@ #include #include #include +#ifdef CONFIG_MEDUSA +#include +#include +#endif #include #include #include @@ -391,11 +395,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 @@ -418,7 +436,11 @@ /* Set up to return from userspace. If provided, use a stub already in userspace. */ +#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 { err |= __put_user(frame->retcode, &frame->pretcode); @@ -427,12 +449,22 @@ 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); @@ -598,6 +630,45 @@ 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.4.18.orig/arch/i386/tools/printoffsets.c linux-2.4.18/arch/i386/tools/printoffsets.c --- linux-2.4.18.orig/arch/i386/tools/printoffsets.c Fri Apr 12 17:16:37 2002 +++ linux-2.4.18/arch/i386/tools/printoffsets.c Fri Apr 12 16:44:01 2002 @@ -16,6 +16,9 @@ { "need_resched", OFFSET(struct task_struct, need_resched), }, { "tsk_ptrace", OFFSET(struct task_struct, ptrace), }, { "processor", OFFSET(struct task_struct, processor), }, +#ifdef CONFIG_MEDUSA_SYSCALL + { "med_syscall", OFFSET(struct task_struct, med.med_syscall) } +#endif }; extern int printf (const char *, ...); diff -urNX nopatch linux-2.4.18.orig/fs/attr.c linux-2.4.18/fs/attr.c --- linux-2.4.18.orig/fs/attr.c Mon Feb 25 20:38:07 2002 +++ linux-2.4.18/fs/attr.c Fri Apr 12 16:44:01 2002 @@ -13,6 +13,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* Taken over from the old code... */ /* POSIX UID/GID verification for setting inode attributes. */ @@ -127,6 +131,10 @@ if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; +#ifdef CONFIG_MEDUSA + if ((error = medusa_notify_change(dentry,attr)) == MED_NO) + return -EPERM; +#endif /* CONFIG_MEDUSA */ lock_kernel(); if (inode->i_op && inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); diff -urNX nopatch linux-2.4.18.orig/fs/exec.c linux-2.4.18/fs/exec.c --- linux-2.4.18.orig/fs/exec.c Fri Apr 12 17:16:37 2002 +++ linux-2.4.18/fs/exec.c Fri Apr 12 16:44:01 2002 @@ -52,6 +52,11 @@ int core_uses_pid; +#include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + static struct linux_binfmt *formats; static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED; @@ -355,7 +360,19 @@ file = ERR_PTR(-EACCES); if (!(nd.mnt->mnt_flags & MNT_NOEXEC) && S_ISREG(inode->i_mode)) { +#ifdef CONFIG_MEDUSA + int err; + if ((err = medusa_exec(&(nd.dentry))) == MED_NO) { + path_release(&nd); + return ERR_PTR(-EPERM); + } + if (err == MED_YES) + err = 0; + else + err = permission(inode, MAY_EXEC); +#else int err = permission(inode, MAY_EXEC); +#endif /* CONFIG_MEDUSA */ if (!err && !(inode->i_mode & 0111)) err = -EACCES; file = ERR_PTR(err); @@ -655,6 +672,39 @@ bprm->e_gid = inode->i_gid; } +#ifdef CONFIG_MEDUSA_FILE_CAPABILITIES + /* 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 */ + +#ifdef CONFIG_MEDUSA + { + kernel_cap_t new_permitted, working; + int retval; + +/* Privilege elevation check copied from compute_creds() */ + new_permitted = cap_intersect(bprm->cap_permitted, cap_bset); + working = cap_intersect(bprm->cap_inheritable, + current->cap_inheritable); + new_permitted = cap_combine(new_permitted, working); + + if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || + !cap_issubset(new_permitted, current->cap_permitted)) { + if ((retval = medusa_sexec(bprm)) == MED_NO) + return -EPERM; + if (retval == MED_SKIP) { + bprm->e_uid = current->euid; + bprm->e_gid = current->egid; + cap_clear(bprm->cap_inheritable); + bprm->cap_permitted = current->cap_permitted; + bprm->cap_effective = current->cap_effective; + } + } + } +#endif /* CONFIG_MEDUSA */ + memset(bprm->buf,0,BINPRM_BUF_SIZE); return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); } @@ -910,7 +960,22 @@ if (retval < 0) goto out; +#ifdef CONFIG_MEDUSA + { __u16 x; + x = current->med.med_act; + current->med.med_act &= ~MPACT_EXEC; +#endif /* CONFIG_MEDUSA */ retval = search_binary_handler(&bprm,regs); +#ifdef CONFIG_MEDUSA + current->med.med_act |= x & MPACT_EXEC; + } +#endif /* CONFIG_MEDUSA */ + +#ifdef CONFIG_MEDUSA + if (retval >= 0) + medusa_after_exec(filename, argv, envp); +#endif /* CONFIG_MEDUSA */ + if (retval >= 0) /* execve success */ return retval; diff -urNX nopatch linux-2.4.18.orig/fs/inode.c linux-2.4.18/fs/inode.c --- linux-2.4.18.orig/fs/inode.c Fri Dec 21 18:41:55 2001 +++ linux-2.4.18/fs/inode.c Fri Apr 12 16:44:01 2002 @@ -5,6 +5,9 @@ */ #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ #include #include #include @@ -787,6 +790,9 @@ inode->i_data.host = inode; inode->i_data.gfp_mask = GFP_HIGHUSER; inode->i_mapping = &inode->i_data; +#ifdef CONFIG_MEDUSA + medusa_clean_inode(inode); +#endif /* CONFIG_MEDUSA */ } /** diff -urNX nopatch linux-2.4.18.orig/fs/namei.c linux-2.4.18/fs/namei.c --- linux-2.4.18.orig/fs/namei.c Mon Feb 25 20:38:09 2002 +++ linux-2.4.18/fs/namei.c Fri Apr 12 16:44:01 2002 @@ -26,6 +26,11 @@ #include #include +#include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) /* [Feb-1997 T. Schoebel-Theuer] @@ -198,6 +203,13 @@ 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) { int retval; lock_kernel(); @@ -264,6 +276,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); @@ -528,6 +543,19 @@ /* Check mountpoints.. */ while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry)) ; +#ifdef CONFIG_MEDUSA + { + int ret; + if ((ret = medusa_lookup(nd->dentry->d_inode, &dentry)) == MED_NO) { + err = -EPERM; + goto out_dput; + } + if (ret == MED_SKIP) { + err = -ENOENT; + goto out_dput; + } + } +#endif /* CONFIG_MEDUSA */ err = -ENOENT; inode = dentry->d_inode; @@ -590,6 +618,19 @@ } while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry)) ; +#ifdef CONFIG_MEDUSA + { + int ret; + if ((ret = medusa_lookup(nd->dentry->d_inode, &dentry)) == MED_NO) { + err = -EPERM; + goto out_dput; + } + if (ret == MED_SKIP) { + err = -ENOENT; + goto out_dput; + } + } +#endif /* CONFIG_MEDUSA */ inode = dentry->d_inode; if ((lookup_flags & LOOKUP_FOLLOW) && inode && inode->i_op && inode->i_op->follow_link) { @@ -936,6 +977,12 @@ mode &= S_IALLUGO; mode |= S_IFREG; +#ifdef CONFIG_MEDUSA + if ((error = medusa_create(dentry, mode)) == MED_NO) + return -EACCES; + if (error == MED_SKIP) + return 0; +#endif /* CONFIG_MEDUSA */ down(&dir->i_zombie); error = may_create(dir, dentry); if (error) @@ -1050,6 +1097,19 @@ goto exit_dput; while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry)); } +#ifdef CONFIG_MEDUSA + { + int ret; + if ((ret = medusa_lookup(nd->dentry->d_inode, &dentry)) == MED_NO) { + error = -EPERM; + goto exit_dput; + } + if (ret == MED_SKIP) { + error = -ENOENT; + goto exit_dput; + } + } +#endif /* CONFIG_MEDUSA */ error = -ENOENT; if (!dentry->d_inode) goto exit_dput; @@ -1212,6 +1272,10 @@ { int error = -EPERM; +#ifdef CONFIG_MEDUSA + if(medusa_mknod(dentry, dev) == MED_NO) + return error; +#endif /* CONFIG_MEDUSA */ down(&dir->i_zombie); if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) goto exit_lock; @@ -1284,6 +1348,11 @@ { int error; +#ifdef CONFIG_MEDUSA + error = medusa_mkdir(dentry, mode); + if(error == MED_NO) + return -EPERM; +#endif /* CONFIG_MEDUSA */ down(&dir->i_zombie); error = may_create(dir, dentry); if (error) @@ -1369,6 +1438,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; @@ -1447,6 +1522,12 @@ { int error; +#ifdef CONFIG_MEDUSA + if ((error = medusa_unlink(dentry)) == MED_NO) + return -EPERM; + if (error == MED_SKIP) + return 0; +#endif /* CONFIG_MEDUSA */ down(&dir->i_zombie); error = may_delete(dir, dentry, 0); if (!error) { @@ -1517,6 +1598,10 @@ { int error; +#ifdef CONFIG_MEDUSA + if ((error = medusa_symlink(dentry, oldname)) == MED_NO) + return -EPERM; +#endif /* CONFIG_MEDUSA */ down(&dir->i_zombie); error = may_create(dir, dentry); if (error) @@ -1651,6 +1736,14 @@ new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { +#ifdef CONFIG_MEDUSA /* FIXME - move me to the VFS layer */ + error = medusa_link(old_nd.dentry, newname); + if (error == MED_NO) + error = -EPERM; + else if (error == MED_SKIP) + error = 0; + else +#endif /* CONFIG_MEDUSA */ error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); dput(new_dentry); } @@ -1702,6 +1795,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; @@ -1781,6 +1881,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.4.18.orig/fs/open.c linux-2.4.18/fs/open.c --- linux-2.4.18.orig/fs/open.c Fri Oct 12 22:48:42 2001 +++ linux-2.4.18/fs/open.c Fri Apr 12 16:44:01 2002 @@ -20,6 +20,10 @@ #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + int vfs_statfs(struct super_block *sb, struct statfs *buf) { int retval = -ENODEV; @@ -81,6 +85,12 @@ if (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 */ down(&inode->i_sem); newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; diff -urNX nopatch linux-2.4.18.orig/fs/proc/base.c linux-2.4.18/fs/proc/base.c --- linux-2.4.18.orig/fs/proc/base.c Mon Feb 25 20:38:09 2002 +++ linux-2.4.18/fs/proc/base.c Fri Apr 12 16:44:01 2002 @@ -24,6 +24,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* * For hysterical raisins we keep the same inumbers as in the old procfs. * Feel free to change the macro below - just keep the range distinct from @@ -286,8 +290,13 @@ read: proc_info_read, }; +#ifdef CONFIG_MEDUSA +#define MAY_PTRACE(p) \ +(current==constable||p==current||(p->p_pptr==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED)) +#else #define MAY_PTRACE(p) \ (p==current||(p->p_pptr==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED)) +#endif static int mem_open(struct inode* inode, struct file* file) @@ -352,7 +361,7 @@ return copied; } -#define mem_write NULL +//#define mem_write NULL #ifndef mem_write /* This is a security hazard */ @@ -966,6 +975,10 @@ read_lock(&tasklist_lock); task = find_task_by_pid(pid); +#ifdef CONFIG_MEDUSA + if (task && !medusa_see(task)) + task = NULL; +#endif /* CONFIG_MEDUSA */ if (task) get_task_struct(task); read_unlock(&tasklist_lock); @@ -1018,6 +1031,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.4.18.orig/fs/readdir.c linux-2.4.18/fs/readdir.c --- linux-2.4.18.orig/fs/readdir.c Sun Aug 12 23:59:08 2001 +++ linux-2.4.18/fs/readdir.c Fri Apr 12 16:44:01 2002 @@ -145,6 +145,7 @@ int error; struct file * file; struct readdir_callback buf; + error = -EBADF; file = fget(fd); diff -urNX nopatch linux-2.4.18.orig/include/linux/fs.h linux-2.4.18/include/linux/fs.h --- linux-2.4.18.orig/include/linux/fs.h Mon Feb 25 20:38:13 2002 +++ linux-2.4.18/include/linux/fs.h Fri Apr 12 16:44:01 2002 @@ -25,6 +25,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include /* For security system MEDUSA DS9 */ +#endif /* CONFIG_MEDUSA */ + struct poll_table_struct; @@ -477,6 +481,9 @@ atomic_t 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 minix_inode_info minix_i; struct ext2_inode_info ext2_i; diff -urNX nopatch linux-2.4.18.orig/include/linux/ipc.h linux-2.4.18/include/linux/ipc.h --- linux-2.4.18.orig/include/linux/ipc.h Thu Nov 22 20:46:18 2001 +++ linux-2.4.18/include/linux/ipc.h Fri Apr 12 16:44:01 2002 @@ -2,6 +2,9 @@ #define _LINUX_IPC_H #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ #define IPC_PRIVATE ((__kernel_key_t) 0) @@ -63,6 +66,9 @@ gid_t cgid; mode_t mode; unsigned long seq; +#ifdef CONFIG_MEDUSA + struct med_ipc med; +#endif /* CONFIG_MEDUSA */ }; #endif /* __KERNEL__ */ diff -urNX nopatch linux-2.4.18.orig/include/linux/medusa.h linux-2.4.18/include/linux/medusa.h --- linux-2.4.18.orig/include/linux/medusa.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.18/include/linux/medusa.h Fri Apr 12 16:44:01 2002 @@ -0,0 +1,244 @@ +/* + * Medusa DS9 header file + */ + +#ifndef _MEDUSA_H_ +#define _MEDUSA_H_ + +#include +#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 { + +/* +As a preparation for the total deletion of device numbers, +we introduce a type unsigned long to hold them. No information about +this type is known outside of this include file. + +... pre viac folkloru citaj poznamku v kdev_t.h ;) +*/ + unsigned long dev; + + unsigned long ino; + umode_t mode; + nlink_t nlink; + uid_t uid; + gid_t gid; + unsigned long 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 siginfo *info, 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.4.18.orig/include/linux/medusa_kernel.h linux-2.4.18/include/linux/medusa_kernel.h --- linux-2.4.18.orig/include/linux/medusa_kernel.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.18/include/linux/medusa_kernel.h Fri Apr 12 16:44:01 2002 @@ -0,0 +1,131 @@ +/* + * 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 */ + u_long 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.4.18.orig/include/linux/sched.h linux-2.4.18/include/linux/sched.h --- linux-2.4.18.orig/include/linux/sched.h Fri Dec 21 18:42:03 2001 +++ linux-2.4.18/include/linux/sched.h Fri Apr 12 16:44:01 2002 @@ -29,6 +29,10 @@ struct exec_domain; +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* * cloning flags: */ @@ -410,6 +414,12 @@ /* journalling filesystem info */ void *journal_info; + +#ifdef CONFIG_MEDUSA +/* For security system MEDUSA DS9 */ + uid_t luid; + struct med_proc med; +#endif /* CONFIG_MEDUSA */ }; /* @@ -671,6 +681,9 @@ static inline void recalc_sigpending(struct task_struct *t) { t->sigpending = has_pending_signals(&t->pending.signal, &t->blocked); +#ifdef CONFIG_MEDUSA_FORCE + t->sigpending |= (t->med.force_code != NULL); +#endif /* CONFIG_MEDUSA_FORCE */ } /* True if we are on the alternate signal stack. */ @@ -731,6 +744,17 @@ static 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.4.18.orig/init/main.c linux-2.4.18/init/main.c --- linux-2.4.18.orig/init/main.c Mon Feb 25 20:38:13 2002 +++ linux-2.4.18/init/main.c Fri Apr 12 16:44:01 2002 @@ -28,6 +28,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + #include #include @@ -110,6 +114,10 @@ extern void perfmon_init(void); #endif +#ifdef CONFIG_MEDUSA +extern void medusa_init( void ); +#endif /* CONFIG_MEDUSA */ + /* * Boot command-line arguments */ @@ -625,6 +633,9 @@ * make syscalls (and thus be locked). */ smp_init(); +#ifdef CONFIG_MEDUSA + medusa_init(); +#endif /* CONFIG_MEDUSA */ rest_init(); } @@ -832,6 +843,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.4.18.orig/ipc/msg.c linux-2.4.18/ipc/msg.c --- linux-2.4.18.orig/ipc/msg.c Fri Sep 14 23:17:00 2001 +++ linux-2.4.18/ipc/msg.c Fri Apr 12 16:44:01 2002 @@ -25,6 +25,10 @@ #include #include "util.h" +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* sysctl: */ int msg_ctlmax = MSGMAX; int msg_ctlmnb = MSGMNB; @@ -135,6 +139,9 @@ msq->q_cbytes = msq->q_qnum = 0; msq->q_qbytes = msg_ctlmnb; msq->q_lspid = msq->q_lrpid = 0; +#ifdef CONFIG_MEDUSA + VS_IPC(&msq->q_perm) = VS_PROCESS(current); +#endif /* CONFIG_MEDUSA */ INIT_LIST_HEAD(&msq->q_messages); INIT_LIST_HEAD(&msq->q_receivers); INIT_LIST_HEAD(&msq->q_senders); @@ -319,6 +326,13 @@ msq = msg_lock(id); if(msq==NULL) BUG(); +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &msq->q_perm)) { + msg_unlock(id); + up(&msg_ids.sem); + return -ENOENT; + } +#endif /* CONFIG_MEDUSA */ if (ipcperms(&msq->q_perm, msgflg)) ret = -EACCES; else @@ -490,6 +504,11 @@ goto out_unlock; success_return = 0; } +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_SEE_IPC(current, &msq->q_perm)) + goto out_unlock; +#endif /* CONFIG_MEDUSA */ err = -EACCES; if (ipcperms (&msq->q_perm, S_IRUGO)) goto out_unlock; @@ -529,6 +548,11 @@ err = -EIDRM; if (msg_checkid(msq,msqid)) goto out_unlock_up; +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_SEE_IPC(current, &msq->q_perm)) + goto out_unlock_up; +#endif /* CONFIG_MEDUSA */ ipcp = &msq->q_perm; err = -EPERM; if (current->euid != ipcp->cuid && @@ -653,6 +677,11 @@ if (msg_checkid(msq,msqid)) goto out_unlock_free; +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_SEE_IPC(current, &msq->q_perm)) + goto out_unlock_free; +#endif /* CONFIG_MEDUSA */ err=-EACCES; if (ipcperms(&msq->q_perm, S_IWUGO)) goto out_unlock_free; @@ -747,6 +776,11 @@ if (msg_checkid(msq,msqid)) goto out_unlock; +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_SEE_IPC(current, &msq->q_perm)) + goto out_unlock; +#endif /* CONFIG_MEDUSA */ err=-EACCES; if (ipcperms (&msq->q_perm, S_IRUGO)) goto out_unlock; diff -urNX nopatch linux-2.4.18.orig/ipc/sem.c linux-2.4.18/ipc/sem.c --- linux-2.4.18.orig/ipc/sem.c Sun Sep 30 21:26:42 2001 +++ linux-2.4.18/ipc/sem.c Fri Apr 12 16:44:01 2002 @@ -65,6 +65,10 @@ #include #include "util.h" +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + #define sem_lock(id) ((struct sem_array*)ipc_lock(&sem_ids,id)) #define sem_unlock(id) ipc_unlock(&sem_ids,id) @@ -144,6 +148,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 */ sem_unlock(id); return sem_buildid(id, sma->sem_perm.seq); @@ -173,6 +180,13 @@ BUG(); if (nsems > sma->sem_nsems) err = -EINVAL; +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &sma->sem_perm)) { + sem_unlock(id); + up(&sem_ids.sem); + return -ENOENT; + } +#endif /* CONFIG_MEDUSA */ else if (ipcperms(&sma->sem_perm, semflg)) err = -EACCES; else @@ -197,6 +211,10 @@ return -EIDRM; } +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &sma->sem_perm)) + return -ENOENT; +#endif /* CONFIG_MEDUSA */ if (ipcperms(&sma->sem_perm, flg)) { sem_unlock(semid); return -EACCES; @@ -489,6 +507,11 @@ if(sma == NULL) return -EINVAL; +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_SEE_IPC(current, &sma->sem_perm)) + goto out_unlock; +#endif /* CONFIG_MEDUSA */ err = -EACCES; if (ipcperms (&sma->sem_perm, S_IRUGO)) goto out_unlock; @@ -531,6 +554,11 @@ if (sem_checkid(sma,semid)) goto out_unlock; +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_SEE_IPC(current, &sma->sem_perm)) + goto out_unlock; +#endif /* CONFIG_MEDUSA */ err = -EACCES; if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO)) goto out_unlock; @@ -717,6 +745,14 @@ err=-EIDRM; goto out_unlock; } +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_SEE_IPC(current, &sma->sem_perm)) + goto out_unlock; + err = -EPERM; + if (!VS_WRITE_IPC(current, &sma->sem_perm)) + goto out_unlock; +#endif /* CONFIG_MEDUSA */ ipcp = &sma->sem_perm; if (current->euid != ipcp->cuid && @@ -879,6 +915,11 @@ } alter |= decrease; +#ifdef CONFIG_MEDUSA + error = -EINVAL; + if (!VS_SEE_IPC(current, &sma->sem_perm)) + goto out_unlock_free; +#endif /* CONFIG_MEDUSA */ error = -EACCES; if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) goto out_unlock_free; diff -urNX nopatch linux-2.4.18.orig/ipc/shm.c linux-2.4.18/ipc/shm.c --- linux-2.4.18.orig/ipc/shm.c Fri Dec 21 18:42:04 2001 +++ linux-2.4.18/ipc/shm.c Fri Apr 12 16:44:01 2002 @@ -26,6 +26,11 @@ #include "util.h" +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + + struct shmid_kernel /* private to the kernel */ { struct kern_ipc_perm shm_perm; @@ -209,6 +214,9 @@ shp->shm_ctim = CURRENT_TIME; shp->shm_segsz = size; shp->shm_nattch = 0; +#ifdef CONFIG_MEDUSA + VS_IPC(&shp->shm_perm) = VS_PROCESS(current); +#endif /* CONFIG_MEDUSA */ shp->id = shm_buildid(id,shp->shm_perm.seq); shp->shm_file = file; file->f_dentry->d_inode->i_ino = shp->id; @@ -245,6 +253,13 @@ BUG(); if (shp->shm_segsz < size) err = -EINVAL; +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &shp->shm_perm)) { + shm_unlock(id); + up(&shm_ids.sem); + return -ENOENT; + } +#endif /* CONFIG_MEDUSA */ else if (ipcperms(&shp->shm_perm, shmflg)) err = -EACCES; else @@ -440,6 +455,11 @@ goto out_unlock; result = 0; } +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_SEE_IPC(current, &shp->shm_perm)) + goto out_unlock; +#endif /* CONFIG_MEDUSA */ err=-EACCES; if (ipcperms (&shp->shm_perm, S_IRUGO)) goto out_unlock; @@ -469,6 +489,10 @@ if(shp==NULL) return -EINVAL; err = shm_checkid(shp,shmid); +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &shp->shm_perm)) + err = -EINVAL; +#endif /* CONFIG_MEDUSA */ if(err) goto out_unlock; if(cmd==SHM_LOCK) { @@ -499,6 +523,12 @@ if (shp == NULL) goto out_up; err = shm_checkid(shp, shmid); +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &shp->shm_perm)) + err = -EINVAL; + else if (!VS_WRITE_IPC(current, &shp->shm_perm)) + err = -EPERM; +#endif /* CONFIG_MEDUSA */ if(err) goto out_unlock_up; if (current->euid != shp->shm_perm.uid && @@ -530,6 +560,12 @@ if(shp==NULL) goto out_up; err = shm_checkid(shp,shmid); +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &shp->shm_perm)) + err = -EINVAL; + else if (!VS_WRITE_IPC(current, &shp->shm_perm)) + err = -EPERM; +#endif /* CONFIG_MEDUSA */ if(err) goto out_unlock_up; err=-EPERM; @@ -618,6 +654,12 @@ shm_unlock(shmid); return err; } +#ifdef CONFIG_MEDUSA + if (!VS_SEE_IPC(current, &shp->shm_perm)) { + shm_unlock(shmid); + return -EINVAL; + } +#endif /* CONFIG_MEDUSA */ if (ipcperms(&shp->shm_perm, acc_mode)) { shm_unlock(shmid); return -EACCES; diff -urNX nopatch linux-2.4.18.orig/ipc/util.c linux-2.4.18/ipc/util.c --- linux-2.4.18.orig/ipc/util.c Mon Aug 13 02:37:53 2001 +++ linux-2.4.18/ipc/util.c Fri Apr 12 16:44:01 2002 @@ -19,6 +19,9 @@ #include #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ #if defined(CONFIG_SYSVIPC) @@ -258,6 +261,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.4.18.orig/kernel/fork.c linux-2.4.18/kernel/fork.c --- linux-2.4.18.orig/kernel/fork.c Mon Feb 25 20:38:13 2002 +++ linux-2.4.18/kernel/fork.c Fri Apr 12 16:44:01 2002 @@ -26,6 +26,11 @@ #include #include +#include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* The idle threads do not count.. */ int nr_threads; int nr_running; @@ -587,6 +592,13 @@ *p = *current; +#ifdef CONFIG_MEDUSA + if (medusa_fork(p, clone_flags) == MED_NO) { + retval = -EPERM; + goto bad_fork_free; + } +#endif /* CONFIG_MEDUSA */ + retval = -EAGAIN; /* * Check if we are over our maximum process limit, but be sure to @@ -731,6 +743,10 @@ if (p->ptrace & PT_PTRACED) send_sig(SIGSTOP, p, 1); + +#ifdef CONFIG_MEDUSA + medusa_afterfork(p); +#endif /* CONFIG_MEDUSA */ wake_up_process(p); /* do this last */ ++total_forks; diff -urNX nopatch linux-2.4.18.orig/kernel/signal.c linux-2.4.18/kernel/signal.c --- linux-2.4.18.orig/kernel/signal.c Fri Apr 12 17:16:37 2002 +++ linux-2.4.18/kernel/signal.c Fri Apr 12 16:44:01 2002 @@ -16,6 +16,10 @@ #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* * SLAB caches for signal bits. */ @@ -519,6 +523,21 @@ if ( t->state == TASK_ZOMBIE ) goto out_nolock; /* The somewhat baroque permissions check... */ + +#ifdef CONFIG_MEDUSA + ret = -EPERM; + if ((ret = medusa_sendsig(sig, info, 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 (bad_signal(sig, info, t)) goto out_nolock; @@ -528,6 +547,9 @@ ret = 0; if (!sig || !t->sig) goto out_nolock; +#ifdef CONFIG_MEDUSA +med_sendsig_yes: +#endif /* CONFIG_MEDUSA */ spin_lock_irqsave(&t->sigmask_lock, flags); handle_stop_signal(sig, t); diff -urNX nopatch linux-2.4.18.orig/kernel/sys.c linux-2.4.18/kernel/sys.c --- linux-2.4.18.orig/kernel/sys.c Fri Apr 12 17:16:37 2002 +++ linux-2.4.18/kernel/sys.c Fri Apr 12 16:44:01 2002 @@ -18,6 +18,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* * this is where the system-wide overflow UID and GID are defined, for * architectures that now have 32-bit UID/GID but didn't in the past @@ -561,6 +565,9 @@ if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) return -EAGAIN; +#ifdef CONFIG_MEDUSA + medusa_setluid(ruid); +#endif /* CONFIG_MEDUSA */ if (new_euid != old_euid) { @@ -620,6 +627,9 @@ if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); } +#ifdef CONFIG_MEDUSA + medusa_setluid(uid); +#endif /* CONFIG_MEDUSA */ return 0; } @@ -650,6 +660,9 @@ if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0) return -EAGAIN; } +#ifdef CONFIG_MEDUSA + medusa_setluid(ruid); +#endif /* CONFIG_MEDUSA */ if (euid != (uid_t) -1) { if (euid != current->euid) { diff -urNX nopatch linux-2.4.18.orig/medusa/Config.in linux-2.4.18/medusa/Config.in --- linux-2.4.18.orig/medusa/Config.in Thu Jan 1 01:00:00 1970 +++ linux-2.4.18/medusa/Config.in Fri Apr 12 16:44:01 2002 @@ -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_X86" = "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.4.18.orig/medusa/Makefile linux-2.4.18/medusa/Makefile --- linux-2.4.18.orig/medusa/Makefile Thu Jan 1 01:00:00 1970 +++ linux-2.4.18/medusa/Makefile Fri Apr 12 16:44:01 2002 @@ -0,0 +1,17 @@ +# +# Makefile for the linux kernel. +# +# 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 definitions are now in the main makefile... + +O_TARGET := medusa.o + +export-objs = process.o + +obj-y = vfs.o comm.o process.o +obj-$(CONFIG_MEDUSA_SYSCALL) += syscall.o + +include $(TOPDIR)/Rules.make diff -urNX nopatch linux-2.4.18.orig/medusa/comm.c linux-2.4.18/medusa/comm.c --- linux-2.4.18.orig/medusa/comm.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.18/medusa/comm.c Fri Apr 12 16:44:01 2002 @@ -0,0 +1,545 @@ + +#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; +DECLARE_WAIT_QUEUE_HEAD(constable_wait); +DECLARE_WAIT_QUEUE_HEAD(answer_wait); +static DECLARE_MUTEX(request_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 = { + read: medusa_read, + write: medusa_write, + poll: medusa_poll, + open: medusa_open, + release: medusa_release, +}; + +struct file_operations fops_medstat = { + read: medusa_read_medstat, + open: medusa_open_medstat, + release: medusa_release_medstat, +}; + +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 | MPACT_START ; + 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; + } + init_MUTEX(&request_mutex); + medusa_invalidate(); + constable = current; + intercom_status = ICOM_FREE; + intercom_istatus = ICOM_WAIT; +#ifndef CONFIG_MEDUSA_QUIET +#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; + 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; + DECLARE_WAIT_QUEUE(wait, current); + 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; + + wake_up(&constable_wait); + sleep_on(&answer_wait); + + 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] == 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.4.18.orig/medusa/process.c linux-2.4.18/medusa/process.c --- linux-2.4.18.orig/medusa/process.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.18/medusa/process.c Fri Apr 12 16:44:01 2002 @@ -0,0 +1,246 @@ + +#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->user); + task->uid = pi->uid; + task->user = alloc_uid(task->uid); + } + 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 siginfo *info, struct task_struct *p) +{ + int r = MED_OK; + + MED_ERROR_CHECK(); + if (in_interrupt() || (current->pid <= 1) || (current == constable) + || info==(struct siginfo *)1 + || (p->pid <= 1) +// || (sig == SIGCHLD) + ) + return MED_OK; + if (p == constable && (sig==SIGSTOP || sig==SIGTSTP)) + return MED_NO; + if( info!=(struct siginfo *)0 ) + { switch( info->si_code ) + { + case CLD_TRAPPED: + case CLD_STOPPED: + case CLD_DUMPED: + case CLD_KILLED: + case CLD_EXITED: + case SI_KERNEL: + 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.4.18.orig/medusa/syscall.c linux-2.4.18/medusa/syscall.c --- linux-2.4.18.orig/medusa/syscall.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.18/medusa/syscall.c Fri Apr 12 16:44:01 2002 @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +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.4.18.orig/medusa/vfs.c linux-2.4.18/medusa/vfs.c --- linux-2.4.18.orig/medusa/vfs.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.18/medusa/vfs.c Wed Feb 27 18:01:46 2002 @@ -0,0 +1,596 @@ + +#include + +#ifdef CONFIG_MEDUSA + +#include +#include +#include +#include +#include + +extern rwlock_t constable_lock; + +//#define CONFIG_MEDUSA_ALIAS + +/* Get vfsmount structure for dentry */ +struct vfsmount *evocate_mnt(struct dentry *dentry) +{ + int depth, last_depth, maxdepth, can_nest; + struct vfsmount * p; + int count = 0; + + spin_lock(&dcache_lock); + while (!IS_ROOT(dentry)) + dentry = dentry->d_parent; + dget(dentry); + spin_unlock(&dcache_lock); + + maxdepth = 0; + do { + can_nest = 0; + last_depth = -1; depth = 0; + + read_lock(&constable_lock); + if (!constable) { // what else to do, when constable quits??? + read_lock(¤t->fs->lock); + p = mntget(current->fs->rootmnt); + read_unlock(¤t->fs->lock); + } else { + read_lock(&constable->fs->lock); + p = mntget(constable->fs->rootmnt); + read_unlock(&constable->fs->lock); + } + read_unlock(&constable_lock); + + spin_lock(&dcache_lock); + do { + count++; + if (depth == maxdepth) { + if (p->mnt_root == dentry) { + spin_unlock(&dcache_lock); + dput(dentry); + return p; + } + can_nest = can_nest || !list_empty(&(p->mnt_mounts)); + } + if ((depth < maxdepth) && (last_depth <= depth) && !list_empty(&(p->mnt_mounts))) { + + mntput(p); + p = mntget(list_entry((p->mnt_mounts.next), struct vfsmount, mnt_child)); + last_depth = depth++; + continue; + + } + if (!list_empty(&(p->mnt_child)) && list_entry((p->mnt_child.next), struct vfsmount, mnt_mounts) != p->mnt_parent) { + + mntput(p); + p = mntget(list_entry((p->mnt_child.next), struct vfsmount, mnt_child)); + continue; + + } + + mntput(p); + p = mntget(p->mnt_parent); + last_depth = depth--; + + } while (depth >= 0); + spin_unlock(&dcache_lock); + maxdepth++; + } while (can_nest); + + dput(dentry); + return NULL; +} + +/* Safely get parent dentry */ +/* FIXME: check locking in all places that call this one */ +struct dentry * medusa_get_parent_dentry(struct dentry *base) +{ + struct vfsmount * mnt; + struct dentry *p; + + if (IS_ROOT(base)) { + mnt = evocate_mnt(base); + if (!mnt) + return NULL; + if( mnt!=constable->fs->rootmnt ) + { p = dget(mnt->mnt_mountpoint); + base = dget(p->d_parent); + dput(p); + } + mntput(mnt); + } else + base = dget(base->d_parent); + return base; +} + +void medusa_set_inode_inf(struct m_inode_inf *ii, struct inode *inode) +{ + ii->dev = kdev_t_to_nr(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 = kdev_t_to_nr(inode->i_rdev); + ii->mi = inode->i_med; +} + +int medusa_redirect(char *redirect, struct dentry **dentry) +{ + __u16 save_act; + struct nameidata nd; + int retval; + +#ifdef CONFIG_MEDUSA_ON_NFS + uid_t save_fsuid; +#endif + + if (redirect == NULL) + return 0; + + 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 + + nd.last_type = LAST_ROOT; + nd.flags = 0; + if (*redirect == '/') { + read_lock(&constable->fs->lock); + nd.dentry = dget(constable->fs->root); + nd.mnt = mntget(constable->fs->rootmnt); + read_unlock(&constable->fs->lock); + } else { + nd.dentry = medusa_get_parent_dentry(*dentry); + nd.mnt = evocate_mnt(nd.dentry); /* does a global dcache lock */ + } + + retval = path_walk(redirect, &nd); + +#ifdef CONFIG_MEDUSA_ON_NFS + current->fsuid = save_fsuid; +#endif + current->med.med_act &= ~MPACT_MAY_CD; + current->med.med_act |= (save_act & MPACT_MAY_CD); + + if (retval) + return -ENOENT; + + mntput(nd.mnt); + + dput(*dentry); + *dentry = nd.dentry; + + 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->file->f_dentry->d_inode); + msg.u.r_pact.info2 = bprm->file->f_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; + struct vfsmount * mnt; + struct dentry *p=NULL; + struct medusa_packet msg; + + if (!dentry || !(dentry->d_inode) || med_valid(&(dentry->d_inode->i_med))) + return 0; + if (no_constable) { +setcap: +#ifdef CONFIG_MEDUSA_FILE_CAPABILITIES + cap_clear(dentry->d_inode->i_med.pcap); + cap_set_full(dentry->d_inode->i_med.icap); + cap_set_full(dentry->d_inode->i_med.ecap); +#if 0 + if( dentry->d_inode->i_mode & S_ISUID ) { + if( dentry->d_inode->i_uid == 0 ) { + if (!issecure(SECURE_NOROOT)) + cap_set_full(dentry->d_inode->i_med.pcap); + } + else { + cap_clear(dentry->d_inode->i_med->ecap); + } + } +#endif +#endif /* CONFIG_MEDUSA_FILE_CAPABILITIES */ + return 0; + } + + if (IS_ROOT(dentry)) { + mnt = evocate_mnt(dentry); + if (!mnt) + return 0; + p = dget(mnt->mnt_mountpoint); + mntput(mnt); + len = p->d_name.len; + name = p->d_name.name; + } else { + len = dentry->d_name.len; + name = dentry->d_name.name; + } + parent = medusa_get_parent_dentry(dentry); + + if (parent == NULL || parent->d_inode == NULL) { + if( p!=NULL ) dput(p); + goto setcap; + } + if (!med_valid(&(parent->d_inode->i_med)) + && parent != parent->d_parent && medusa_get_dentry(parent) <= 0) { + if( p!=NULL ) dput(p); + dput(parent); + goto setcap; + } + 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; + if( p!=NULL ) dput(p); + dput(parent); + return 1; + } + msg.cmd = MED_IGET; + medusa_set_inode_inf(&(msg.u.r_iget.inode), dentry->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( p!=NULL ) dput(p); + if (str != NULL) + medusa_putdata(str); + if (msg.answer == MED_ERR) + goto setcap; + dentry->d_inode->i_med = msg.u.a_iget.inode.mi; + dentry->d_inode->i_med.magic = medusa_magic; + return 1; +} + +/* helper function for medusa_permission */ +int medusa_get_inode(struct inode *inode) +{ + int r; + struct list_head * tmp; + struct dentry *dentry; + + if (no_constable) + return 0; + list_for_each(tmp, &(inode->i_dentry)) { + if (atomic_read(&(list_entry(tmp, struct dentry, d_alias)->d_count))) + break; + } + dentry = dget(list_entry(tmp, struct dentry, d_alias)); + // 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 list_head * tmp; + 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; + list_for_each(tmp, &(inode->i_dentry)) { + if (atomic_read(&(list_entry(tmp, struct dentry, d_alias)->d_count))) + break; + } + dentry = dget(list_entry(tmp, struct dentry, d_alias)); + // dentry = dget(list_entry(inode->i_dentry.next, struct dentry, d_alias)); /* sad but true */ + 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 = medusa_get_parent_dentry(dentry); + 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 = medusa_get_parent_dentry(dentry); + 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 = medusa_get_parent_dentry(dentry); + 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 = medusa_get_parent_dentry(dentry); + 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 */