diff -ruN linux-2.4.23-clean/Documentation/Configure.help linux-2.4.23-medusa/Documentation/Configure.help --- linux-2.4.23-clean/Documentation/Configure.help 2003-12-08 19:15:19.000000000 +0100 +++ linux-2.4.23-medusa/Documentation/Configure.help 2003-12-08 19:31:37.000000000 +0100 @@ -22985,6 +22985,101 @@ This option allows you to run the kernel with data cache disabled. Say Y if you experience CPM lock-ups. +CONFIG_MEDUSA + This option provides a facility to improve overall security of + Linux by extending its standard security architecture, while + remaining fully transparent to the applications. Technically, + it's a kernel support of the VS security model (capable of + emulating vast majority of current security models), and + authorization server, which works with this model. Medusa comes + with userspace authorization server named Constable, and few + example configurations. + + For more info see README in the source package, and + . + +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. On the + other side, it is a very useful feature and is used in many + configuration files. + + If in doubt, say Y. + +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_CONSTABLE + Say Y, if you will be using the user-space authorization + daemon, which communicates with kernel via character device + named /dev/medusa. This is how our official authorization + daemon Constable does it, so it is recommended to answer Y. + + Don't answer M, unless you really want the support for Constable + to be built as a module (that way you will be unable to start + Constable at the boot time). + + If in doubt, say Y. + +CONFIG_MEDUSA_INIT_WRAPPER + Say Y here, if you want the kernel to execute the Constable + immediately after bootup. If you say Y here, the Constable will + initialize, THEN launch the usual init application. + Note that Constable have to be installed at /sbin, /etc or /bin. + + This is preferred, when you have a working configuration file. + If you are just preparing to make one, say N. + +CONFIG_MEDUSA_ON_NFS + Enabling this allows you to use Medusa file redirections to NFS + filesystem. Being a small hack, we created a separate config option + for it. + + Say Y only if you need to use file redirections to NFS filesystem. + Otherwise say N. + +CONFIG_MEDUSA_NONE + If you say "Ignore", the system will remain fully functional + after the authorization server has died. Note that this may introduce + a security risk, and is recommended only for the configuration time, + to enable testing of multiple configurations. + + If you say "Reboot" or "Halt", the system will reboot or halt, + when the authorization server dies. + + If you require minumum downtime, choose "Reboot". + If you have the acess to your server, or don't mind your downtime, + choose "Halt" instead. + If you are just about to play with your configuration, choose "Ignore". + +CONFIG_MEDUSA_QUIET + This option prevents Medusa from displaying any kernel messages. + + If you want to hide Medusa on your machine, answer Y. + If in doubt, say N. + +CONFIG_MEDUSA_MEMKOBJECT + This enables the authorization server to access a memory of any + desired user-space process. This is not a security improvement itself, + it is just needed by some of the security models you might want to use. + Note that if you will compile this as a module, it will not be loaded + automatically on demand - you still have to insmod it manually. + + If in doubt, say 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 -ruN linux-2.4.23-clean/MAINTAINERS linux-2.4.23-medusa/MAINTAINERS --- linux-2.4.23-clean/MAINTAINERS 2003-12-08 19:15:19.000000000 +0100 +++ linux-2.4.23-medusa/MAINTAINERS 2003-12-08 19:31:37.000000000 +0100 @@ -1155,6 +1155,16 @@ L: linux-fbdev-devel@lists.sourceforge.net S: Maintained +MEDUSA DS9 SECURITY SYSTEM +P: Milan Pikula +M: www@terminus.sk +P: Marek Zelem +P: Martin Ockajak +M: medusa-devel@terminus.sk +L: medusa@medusa.terminus.sk +W: http://medusa.terminus.sk/ +S: Maintained + MEMORY TECHNOLOGY DEVICES P: David Woodhouse M: dwmw2@redhat.com diff -ruN linux-2.4.23-clean/Makefile linux-2.4.23-medusa/Makefile --- linux-2.4.23-clean/Makefile 2003-12-08 19:15:19.000000000 +0100 +++ linux-2.4.23-medusa/Makefile 2003-12-08 19:31:37.000000000 +0100 @@ -130,6 +130,11 @@ LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib crypto +ifdef CONFIG_MEDUSA +CORE_FILES += medusa/medusa.o +SUBDIRS += medusa +endif + DRIVERS-n := DRIVERS-y := DRIVERS-m := @@ -371,7 +376,7 @@ init/do_mounts.o: init/do_mounts.c include/config/MARKER $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $@ $< -fs lib mm ipc kernel drivers net: dummy +fs lib mm ipc kernel drivers net medusa: dummy $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) TAGS: dummy diff -ruN linux-2.4.23-clean/arch/i386/Makefile linux-2.4.23-medusa/arch/i386/Makefile --- linux-2.4.23-clean/arch/i386/Makefile 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-medusa/arch/i386/Makefile 2003-12-08 19:31:37.000000000 +0100 @@ -96,7 +96,7 @@ HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o -SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib +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 @@ -148,6 +148,7 @@ archclean: @$(MAKEBOOT) clean + @$(MAKE) -C arch/$(ARCH)/tools clean archmrproper: diff -ruN linux-2.4.23-clean/arch/i386/config.in linux-2.4.23-medusa/arch/i386/config.in --- linux-2.4.23-clean/arch/i386/config.in 2003-12-08 19:15:19.000000000 +0100 +++ linux-2.4.23-medusa/arch/i386/config.in 2003-12-08 19:31:37.000000000 +0100 @@ -14,6 +14,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 -ruN linux-2.4.23-clean/arch/i386/kernel/Makefile linux-2.4.23-medusa/arch/i386/kernel/Makefile --- linux-2.4.23-clean/arch/i386/kernel/Makefile 2003-12-08 19:15:19.000000000 +0100 +++ linux-2.4.23-medusa/arch/i386/kernel/Makefile 2003-12-08 19:31:37.000000000 +0100 @@ -44,4 +44,11 @@ obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o obj-$(CONFIG_EDD) += edd.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 -ruN linux-2.4.23-clean/arch/i386/kernel/entry.S linux-2.4.23-medusa/arch/i386/kernel/entry.S --- linux-2.4.23-clean/arch/i386/kernel/entry.S 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-medusa/arch/i386/kernel/entry.S 2003-12-08 19:31:37.000000000 +0100 @@ -72,14 +72,8 @@ /* * these are offsets into the task-struct. */ -state = 0 -flags = 4 -sigpending = 8 -addr_limit = 12 -exec_domain = 16 -need_resched = 20 -tsk_ptrace = 24 -processor = 52 + +#include ENOSYS = 38 @@ -207,7 +201,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_i386) + 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 @@ -243,7 +259,26 @@ movl ORIG_EAX(%esp),%eax cmpl $(NR_syscalls),%eax jae tracesys_exit + +#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_i386) + 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 tracesys_exit: call SYMBOL_NAME(syscall_trace) diff -ruN linux-2.4.23-clean/arch/i386/kernel/process.c linux-2.4.23-medusa/arch/i386/kernel/process.c --- linux-2.4.23-clean/arch/i386/kernel/process.c 2003-12-08 19:15:19.000000000 +0100 +++ linux-2.4.23-medusa/arch/i386/kernel/process.c 2003-12-08 19:31:37.000000000 +0100 @@ -52,6 +52,10 @@ #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); int hlt_counter; @@ -507,6 +511,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 -ruN linux-2.4.23-clean/arch/i386/kernel/ptrace.c linux-2.4.23-medusa/arch/i386/kernel/ptrace.c --- linux-2.4.23-clean/arch/i386/kernel/ptrace.c 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-medusa/arch/i386/kernel/ptrace.c 2003-12-08 19:31:37.000000000 +0100 @@ -14,6 +14,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + #include #include #include @@ -153,6 +157,24 @@ struct user * dummy = NULL; int i, ret; +#ifdef CONFIG_MEDUSA + /* we need to get called BEFORE the kernel lock */ + if (request != PTRACE_TRACEME) { + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + return -ESRCH; + if (medusa_ptrace(current, child) == MED_NO) { + free_task_struct(child); + return -EPERM; + } + } +#define out out_tsk +#endif /* CONFIG_MEDUSA */ + lock_kernel(); ret = -EPERM; if (request == PTRACE_TRACEME) { @@ -164,6 +186,9 @@ ret = 0; goto out; } +#ifdef CONFIG_MEDUSA +#undef out +#else ret = -ESRCH; read_lock(&tasklist_lock); child = find_task_by_pid(pid); @@ -172,6 +197,7 @@ read_unlock(&tasklist_lock); if (!child) goto out; +#endif ret = -EPERM; if (pid == 1) /* you may not mess with init */ @@ -435,6 +461,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 -ruN linux-2.4.23-clean/arch/i386/kernel/signal.c linux-2.4.23-medusa/arch/i386/kernel/signal.c --- linux-2.4.23-clean/arch/i386/kernel/signal.c 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-medusa/arch/i386/kernel/signal.c 2003-12-08 19:31:37.000000000 +0100 @@ -20,6 +20,10 @@ #include #include #include +#ifdef CONFIG_MEDUSA +#include +#include +#endif #include #include #include @@ -391,11 +395,30 @@ struct sigframe *frame; int err = 0; +#ifdef CONFIG_MEDUSA_FORCE + if (sig < 0) { + frame = get_sigframe(ka, regs, sizeof(*frame)-sig); + printk("get_sigframe %x %x %d\n", + ((unsigned char *)ka)[0], + ((unsigned char *)ka)[1], + -sig); + } + 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 +441,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 +454,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 +635,47 @@ if (!oldset) oldset = ¤t->blocked; +#ifdef CONFIG_MEDUSA_FORCE + if (current->med.force_code) { + void * force_code; + int force_len; + + printk("LAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAAAAAAAAAA\n"); + +/****** 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 -ruN linux-2.4.23-clean/arch/i386/tools/Makefile linux-2.4.23-medusa/arch/i386/tools/Makefile --- linux-2.4.23-clean/arch/i386/tools/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/arch/i386/tools/Makefile 2003-12-08 19:31:37.000000000 +0100 @@ -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 -ruN linux-2.4.23-clean/arch/i386/tools/printoffsets.c linux-2.4.23-medusa/arch/i386/tools/printoffsets.c --- linux-2.4.23-clean/arch/i386/tools/printoffsets.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/arch/i386/tools/printoffsets.c 2003-12-08 19:31:37.000000000 +0100 @@ -0,0 +1,40 @@ +#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), }, + { "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 *, ...); + +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 -ruN linux-2.4.23-clean/fs/attr.c linux-2.4.23-medusa/fs/attr.c --- linux-2.4.23-clean/fs/attr.c 2002-02-25 20:38:07.000000000 +0100 +++ linux-2.4.23-medusa/fs/attr.c 2003-12-08 19:31:37.000000000 +0100 @@ -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 -ruN linux-2.4.23-clean/fs/exec.c linux-2.4.23-medusa/fs/exec.c --- linux-2.4.23-clean/fs/exec.c 2003-12-08 19:15:44.000000000 +0100 +++ linux-2.4.23-medusa/fs/exec.c 2003-12-08 19:31:37.000000000 +0100 @@ -20,6 +20,10 @@ * table to check for several different types of binary formats. We keep * trying until we recognize the file or we run out of supported binary * formats. + * + * Modified formula for evolving capabilities to allow nice SUID emulation + * which work together with (future) VFS capabilities implementation. + * Feb 2002 by Marek Zelem */ #include @@ -53,6 +57,12 @@ int core_setuid_ok = 0; /* The maximal length of core_pattern is also specified in sysctl.c */ +#include +#ifdef CONFIG_MEDUSA +#include +#include +#endif /* CONFIG_MEDUSA */ + static struct linux_binfmt *formats; static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED; @@ -382,7 +392,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); @@ -668,11 +690,23 @@ bprm->e_uid = current->euid; bprm->e_gid = current->egid; + /* We don't have VFS support for capabilities yet */ + cap_clear(bprm->cap_permitted); + cap_set_full(bprm->cap_inheritable); + cap_set_full(bprm->cap_effective); + if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) { /* Set-uid? */ - if (mode & S_ISUID) + if (mode & S_ISUID) { bprm->e_uid = inode->i_uid; - + if (bprm->e_uid == 0) { + if (!issecure(SECURE_NOROOT)) + cap_set_full(bprm->cap_permitted); + } + else { + cap_clear(bprm->cap_effective); + } + } /* Set-gid? */ /* * If setgid is set but no group execute bit then this @@ -683,27 +717,47 @@ bprm->e_gid = inode->i_gid; } - /* We don't have VFS support for capabilities yet */ - cap_clear(bprm->cap_inheritable); - cap_clear(bprm->cap_permitted); - cap_clear(bprm->cap_effective); +#ifdef CONFIG_MEDUSA_FILE_CAPABILITIES + if (MED_MAGIC_VALID(&inode->med) || + file_kobj_validate_dentry(bprm->file->f_dentry,NULL) > 0) { + /* If the security daemon sets the file capabilities, use them */ + cap_t(bprm->cap_inheritable) = cap_t(inode->med.icap); + cap_t(bprm->cap_permitted) = cap_t(inode->med.pcap); + cap_t(bprm->cap_effective) = cap_t(inode->med.ecap); + } +#endif /* CONFIG_MEDUSA_FILE_CAPABILITIES */ - /* To support inheritance of root-permissions and suid-root - * executables under compatibility mode, we raise all three - * capability sets for the file. - * - * If only the real uid is 0, we only raise the inheritable - * and permitted sets of the executable file. - */ - - if (!issecure(SECURE_NOROOT)) { - if (bprm->e_uid == 0 || current->uid == 0) { - cap_set_full(bprm->cap_inheritable); - cap_set_full(bprm->cap_permitted); +#ifdef CONFIG_MEDUSA + { + int retval; +#ifndef CONFIG_MEDUSA_FILE_CAPABILITIES + kernel_cap_t new_permitted, working; + +/* 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); +#endif + if (bprm->e_uid != current->uid || bprm->e_gid != current->gid +#ifndef CONFIG_MEDUSA_FILE_CAPABILITIES + || !cap_issubset(new_permitted, current->cap_permitted) +#endif + ) { + if ((retval = medusa_sexec(bprm)) == MED_NO) + return -EPERM; + if (retval == MED_SKIP) { + bprm->e_uid = current->euid; + bprm->e_gid = current->egid; +#ifndef CONFIG_MEDUSA_FILE_CAPABILITIES + cap_clear(bprm->cap_inheritable); + bprm->cap_permitted = current->cap_permitted; + bprm->cap_effective = current->cap_effective; +#endif + } } - if (bprm->e_uid == 0) - cap_set_full(bprm->cap_effective); } +#endif /* CONFIG_MEDUSA */ memset(bprm->buf,0,BINPRM_BUF_SIZE); return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); @@ -715,6 +769,11 @@ * * The formula used for evolving capabilities is: * + * (***) pP' = (fP & X) | (fI & pI) + * pI' = pP' + * pE' = ((pP' & pE) | fP) & X & fE + * + * original was: * pI' = pI * (***) pP' = (fP & X) | (fI & pI) * pE' = pP' & fE [NB. fE is 0 or ~0] @@ -761,6 +820,14 @@ * capability rules */ if (current->pid != 1) { current->cap_permitted = new_permitted; +/* This is to allow good SUID emulation (Marek Zelem ) */ + current->cap_inheritable = new_permitted; + working = + cap_intersect(new_permitted,current->cap_effective); + new_permitted = + cap_combine(working,bprm->cap_permitted); + new_permitted = cap_intersect(new_permitted, cap_bset); +/* END of good SUID emulation (Marek Zelem ) */ current->cap_effective = cap_intersect(new_permitted, bprm->cap_effective); } @@ -947,7 +1014,25 @@ if (retval < 0) goto out; +#ifdef CONFIG_MEDUSA + { int flagp, flaga; + flagp = medusa_monitored_pexec(); + medusa_monitor_pexec(0); + flaga = medusa_monitored_afterexec(); + medusa_monitor_afterexec(0); +#endif /* CONFIG_MEDUSA */ retval = search_binary_handler(&bprm,regs); +#ifdef CONFIG_MEDUSA + medusa_monitor_afterexec(flaga); + medusa_monitor_pexec(flagp); + } +#endif /* CONFIG_MEDUSA */ + +#ifdef CONFIG_MEDUSA + if (retval >= 0) + medusa_afterexec(filename, argv, envp); +#endif /* CONFIG_MEDUSA */ + if (retval >= 0) /* execve success */ return retval; diff -ruN linux-2.4.23-clean/fs/inode.c linux-2.4.23-medusa/fs/inode.c --- linux-2.4.23-clean/fs/inode.c 2003-12-08 19:15:44.000000000 +0100 +++ linux-2.4.23-medusa/fs/inode.c 2003-12-08 19:31:37.000000000 +0100 @@ -5,6 +5,9 @@ */ #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ #include #include #include @@ -117,6 +120,9 @@ mapping->host = inode; mapping->gfp_mask = GFP_HIGHUSER; inode->i_mapping = mapping; +#ifdef CONFIG_MEDUSA + medusa_clean_inode(inode); +#endif /* CONFIG_MEDUSA */ } return inode; } diff -ruN linux-2.4.23-clean/fs/namei.c linux-2.4.23-medusa/fs/namei.c --- linux-2.4.23-clean/fs/namei.c 2003-08-25 13:44:43.000000000 +0200 +++ linux-2.4.23-medusa/fs/namei.c 2003-12-08 19:31:37.000000000 +0100 @@ -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,11 @@ { struct dentry * dentry = d_lookup(parent, name); +#ifdef CONFIG_MEDUSA + if (dentry/*speedup*/ && parent->d_inode && + !MED_MAGIC_VALID(&parent->d_inode->med)) + file_kobj_validate_dentry(parent, NULL); +#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); @@ -530,6 +547,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; @@ -592,6 +622,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) { @@ -964,6 +1007,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) @@ -1076,6 +1125,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; @@ -1238,6 +1300,10 @@ { int error = -EPERM; +#ifdef CONFIG_MEDUSA + if(medusa_mknod(dentry, dev, mode) == MED_NO) + return error; +#endif /* CONFIG_MEDUSA */ down(&dir->i_zombie); if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) goto exit_lock; @@ -1309,6 +1375,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) @@ -1397,6 +1468,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; @@ -1472,6 +1549,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) { @@ -1541,6 +1624,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) @@ -1667,6 +1754,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); } @@ -1716,6 +1811,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; @@ -1794,6 +1896,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) return error; diff -ruN linux-2.4.23-clean/fs/open.c linux-2.4.23-medusa/fs/open.c --- linux-2.4.23-clean/fs/open.c 2003-08-25 13:44:43.000000000 +0200 +++ linux-2.4.23-medusa/fs/open.c 2003-12-08 19:31:37.000000000 +0100 @@ -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; @@ -105,6 +109,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_write(&inode->i_alloc_sem); down(&inode->i_sem); newattrs.ia_size = length; diff -ruN linux-2.4.23-clean/fs/proc/base.c linux-2.4.23-medusa/fs/proc/base.c --- linux-2.4.23-clean/fs/proc/base.c 2003-12-08 19:15:44.000000000 +0100 +++ linux-2.4.23-medusa/fs/proc/base.c 2003-12-08 19:31:37.000000000 +0100 @@ -26,6 +26,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 @@ -432,7 +436,7 @@ return copied; } -#define mem_write NULL +//#define mem_write NULL #ifndef mem_write /* This is a security hazard */ @@ -1072,6 +1076,11 @@ read_lock(&tasklist_lock); task = find_task_by_pid(pid); +#ifdef CONFIG_MEDUSA + if (task && !VS_INTERSECT(VSS(¤t->med),VS(&task->med)) && + current->pid > 1 && task->pid > 1) + task = NULL; +#endif /* CONFIG_MEDUSA */ if (task) get_task_struct(task); read_unlock(&tasklist_lock); @@ -1124,6 +1133,11 @@ int pid = p->pid; if (!pid) continue; +#ifdef CONFIG_MEDUSA + if (!VS_INTERSECT(VSS(¤t->med),VS(&p->med)) && + p->pid > 1 && current->pid > 1) + continue; +#endif /* CONFIG_MEDUSA */ if (--index >= 0) continue; pids[nr_pids] = pid; diff -ruN linux-2.4.23-clean/fs/read_write.c linux-2.4.23-medusa/fs/read_write.c --- linux-2.4.23-clean/fs/read_write.c 2003-08-25 13:44:43.000000000 +0200 +++ linux-2.4.23-medusa/fs/read_write.c 2003-12-08 19:31:37.000000000 +0100 @@ -27,6 +27,11 @@ #include #include +#include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + #include struct file_operations generic_ro_fops = { @@ -167,6 +172,17 @@ ret = -EBADF; file = fget(fd); if (file) { +#ifdef CONFIG_MEDUSA + int r; + if ((r = medusa_read(file)) == MED_NO) { + fput(file); + return -EACCES; + } + if (r == MED_SKIP) { + fput(file); + return count; + } +#endif /* CONFIG_MEDUSA */ if (file->f_mode & FMODE_READ) { ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode, file, file->f_pos, count); @@ -192,6 +208,17 @@ ret = -EBADF; file = fget(fd); if (file) { +#ifdef CONFIG_MEDUSA + int r; + if ((r = medusa_write(file)) == MED_NO) { + fput(file); + return -EACCES; + } + if (r == MED_SKIP) { + fput(file); + return count; + } +#endif /* CONFIG_MEDUSA */ if (file->f_mode & FMODE_WRITE) { struct inode *inode = file->f_dentry->d_inode; ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, @@ -337,6 +364,19 @@ file = fget(fd); if (!file) goto bad_file; +#ifdef CONFIG_MEDUSA + { + int r; + if ((r = medusa_read(file)) == MED_NO) { + fput(file); + return -EACCES; + } + if (r == MED_SKIP) { + fput(file); + return count; + } + } +#endif /* CONFIG_MEDUSA */ if (file->f_op && (file->f_mode & FMODE_READ) && (file->f_op->readv || file->f_op->read)) ret = do_readv_writev(VERIFY_WRITE, file, vector, count); @@ -357,6 +397,19 @@ file = fget(fd); if (!file) goto bad_file; +#ifdef CONFIG_MEDUSA + { + int r; + if ((r = medusa_write(file)) == MED_NO) { + fput(file); + return -EACCES; + } + if (r == MED_SKIP) { + fput(file); + return count; + } + } +#endif /* CONFIG_MEDUSA */ if (file->f_op && (file->f_mode & FMODE_WRITE) && (file->f_op->writev || file->f_op->write)) ret = do_readv_writev(VERIFY_READ, file, vector, count); @@ -383,6 +436,19 @@ goto bad_file; if (!(file->f_mode & FMODE_READ)) goto out; +#ifdef CONFIG_MEDUSA + { + int r; + if ((r = medusa_read(file)) == MED_NO) { + fput(file); + return -EACCES; + } + if (r == MED_SKIP) { + fput(file); + return count; + } + } +#endif /* CONFIG_MEDUSA */ ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode, file, pos, count); if (ret) @@ -412,6 +478,19 @@ file = fget(fd); if (!file) goto bad_file; +#ifdef CONFIG_MEDUSA + { + int r; + if ((r = medusa_write(file)) == MED_NO) { + fput(file); + return -EACCES; + } + if (r == MED_SKIP) { + fput(file); + return count; + } + } +#endif /* CONFIG_MEDUSA */ if (!(file->f_mode & FMODE_WRITE)) goto out; ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode, diff -ruN linux-2.4.23-clean/include/linux/capability.h linux-2.4.23-medusa/include/linux/capability.h --- linux-2.4.23-clean/include/linux/capability.h 2001-11-22 20:46:19.000000000 +0100 +++ linux-2.4.23-medusa/include/linux/capability.h 2003-12-08 19:31:37.000000000 +0100 @@ -14,7 +14,7 @@ #define _LINUX_CAPABILITY_H #include -#include +//#include /* User-level do most of the mapping between kernel and user capabilities based on the version tag given by the kernel. The @@ -303,8 +303,9 @@ #define CAP_EMPTY_SET to_cap_t(0) #define CAP_FULL_SET to_cap_t(~0) -#define CAP_INIT_EFF_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP)) -#define CAP_INIT_INH_SET to_cap_t(0) +//#define CAP_INIT_EFF_SET to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP)) +#define CAP_INIT_EFF_SET to_cap_t(~0) +#define CAP_INIT_INH_SET to_cap_t(~0) #define CAP_TO_MASK(x) (1 << (x)) #define cap_raise(c, flag) (cap_t(c) |= CAP_TO_MASK(flag)) diff -ruN linux-2.4.23-clean/include/linux/fs.h linux-2.4.23-medusa/include/linux/fs.h --- linux-2.4.23-clean/include/linux/fs.h 2003-12-08 19:15:46.000000000 +0100 +++ linux-2.4.23-medusa/include/linux/fs.h 2003-12-08 19:31:37.000000000 +0100 @@ -25,6 +25,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include /* For security system MEDUSA DS9 */ +#endif /* CONFIG_MEDUSA */ + struct poll_table_struct; @@ -488,6 +492,9 @@ atomic_t i_writecount; unsigned int i_attr_flags; __u32 i_generation; +#ifdef CONFIG_MEDUSA + struct medusa_l1_inode_s med; /* For security system MEDUSA DS9 */ +#endif /* CONFIG_MEDUSA */ union { struct minix_inode_info minix_i; struct ext2_inode_info ext2_i; diff -ruN linux-2.4.23-clean/include/linux/ipc.h linux-2.4.23-medusa/include/linux/ipc.h --- linux-2.4.23-clean/include/linux/ipc.h 2001-11-22 20:46:18.000000000 +0100 +++ linux-2.4.23-medusa/include/linux/ipc.h 2003-12-08 19:31:37.000000000 +0100 @@ -2,6 +2,10 @@ #define _LINUX_IPC_H #include +#ifdef CONFIG_MEDUSA +#include +#include +#endif /* CONFIG_MEDUSA */ #define IPC_PRIVATE ((__kernel_key_t) 0) @@ -63,6 +67,9 @@ gid_t cgid; mode_t mode; unsigned long seq; +#ifdef CONFIG_MEDUSA + struct medusa_l1_ipc_s med; +#endif /* CONFIG_MEDUSA */ }; #endif /* __KERNEL__ */ diff -ruN linux-2.4.23-clean/include/linux/sched.h linux-2.4.23-medusa/include/linux/sched.h --- linux-2.4.23-clean/include/linux/sched.h 2003-12-08 19:15:46.000000000 +0100 +++ linux-2.4.23-medusa/include/linux/sched.h 2003-12-08 19:31:37.000000000 +0100 @@ -29,6 +29,12 @@ struct exec_domain; +#ifdef CONFIG_MEDUSA +#include +#include +#include +#endif /* CONFIG_MEDUSA */ + /* * cloning flags: */ @@ -415,6 +421,10 @@ /* journalling filesystem info */ void *journal_info; + +#ifdef CONFIG_MEDUSA + struct medusa_l1_task_s med; +#endif /* CONFIG_MEDUSA */ }; /* @@ -680,6 +690,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. */ @@ -740,6 +753,18 @@ static inline int capable(int cap) { +#ifdef CONFIG_MEDUSA + int ret; + + ret = medusa_capable(cap); + if (ret == MED_NO || ret == MED_SKIP) + return 0; + if (ret == MED_YES) { + current->flags |= PF_SUPERPRIV; + return 1; + } +#endif /* CONFIG_MEDUSA */ + #if 1 /* ok now */ if (cap_raised(current->cap_effective, cap)) #else diff -ruN linux-2.4.23-clean/include/linux/timex.h linux-2.4.23-medusa/include/linux/timex.h --- linux-2.4.23-clean/include/linux/timex.h 2001-11-22 20:46:18.000000000 +0100 +++ linux-2.4.23-medusa/include/linux/timex.h 2003-12-08 19:31:37.000000000 +0100 @@ -52,6 +52,7 @@ #define _LINUX_TIMEX_H #include +#include /* * The following defines establish the engineering parameters of the PLL diff -ruN linux-2.4.23-clean/include/medusa/l1/file_handlers.h linux-2.4.23-medusa/include/medusa/l1/file_handlers.h --- linux-2.4.23-clean/include/medusa/l1/file_handlers.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l1/file_handlers.h 2003-12-08 19:31:37.000000000 +0100 @@ -0,0 +1,46 @@ +/* + * medusa/l1/file_handlers.h + * + * prototypes of L2 file related handlers called from L1 hooks + * + */ + +#ifndef _MEDUSA_L1_FILE_HANDLERS_H +#define _MEDUSA_L1_FILE_HANDLERS_H + +#include +#include +#include +#include + +extern medusa_answer_t medusa_exec(struct dentry ** dentryp); +extern medusa_answer_t medusa_create(struct dentry * dentry, int mode); +extern medusa_answer_t medusa_lookup(struct inode *dir, struct dentry **dentry); +extern medusa_answer_t medusa_truncate(struct dentry *dentry, unsigned long length); +extern medusa_answer_t medusa_mkdir(struct dentry *dentry, int mode); +extern medusa_answer_t medusa_mknod(struct dentry *dentry, dev_t dev, int mode); +extern medusa_answer_t medusa_permission(struct inode * inode, int mask); +extern medusa_answer_t medusa_rmdir(struct dentry *dentry); +extern medusa_answer_t medusa_symlink(struct dentry *dentry, + const char * oldname); +extern medusa_answer_t medusa_unlink(struct dentry *dentry); +extern medusa_answer_t medusa_link(struct dentry *dentry, const char * newname); +extern medusa_answer_t medusa_rename(struct dentry *dentry, const char * newname); + +/* the following routines are a support for many of access types, + * and they're used both in L1 and L2 code. They're defined in + * l2/evtype_getfile.c. Look there before using any of these routines. + */ +extern int file_kobj_validate_dentry(struct dentry * dentry, struct vfsmount * mnt); +extern void medusa_get_upper_and_parent(struct nameidata * ndsource, + struct nameidata * ndupperp, struct nameidata * ndparentp); +extern void medusa_put_upper_and_parent(struct nameidata * ndupper, struct nameidata * ndparent); +extern struct vfsmount * medusa_evocate_mnt(struct dentry *dentry); +extern void medusa_clean_inode(struct inode * inode); +extern medusa_answer_t medusa_notify_change(struct dentry *dentry, struct iattr * attr); + +extern medusa_answer_t medusa_read(struct file * file); +extern medusa_answer_t medusa_write(struct file * file); + +#endif /* _MEDUSA_L1_FILE_HANDLERS_H */ + diff -ruN linux-2.4.23-clean/include/medusa/l1/inode.h linux-2.4.23-medusa/include/medusa/l1/inode.h --- linux-2.4.23-clean/include/medusa/l1/inode.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l1/inode.h 2003-12-08 19:31:37.000000000 +0100 @@ -0,0 +1,30 @@ +/* medusa/l1/inode.h, (C) 2002 Milan Pikula + * + * struct inode extension: this structure is appended to in-kernel data, + * and we define it separately just to make l1 code shorter. + * + * for another data structure - kobject, describing inode for upper layers - + * see l2/kobject_file.[ch]. + */ + +#ifndef _MEDUSA_L1_INODE_H +#define _MEDUSA_L1_INODE_H + +#include +#include +#include +#include + +struct medusa_l1_inode_s { + MEDUSA_OBJECT_VARS; + __u32 user; +#ifdef CONFIG_MEDUSA_FILE_CAPABILITIES + kernel_cap_t icap, pcap, ecap; /* support for POSIX file capabilities */ +#endif /* CONFIG_MEDUSA_FILE_CAPABILITIES */ + + /* for kobject_file.c - don't touch! */ + struct inode * next_live; + int use_count; +}; + +#endif diff -ruN linux-2.4.23-clean/include/medusa/l1/ipc.h linux-2.4.23-medusa/include/medusa/l1/ipc.h --- linux-2.4.23-clean/include/medusa/l1/ipc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l1/ipc.h 2003-12-08 19:31:37.000000000 +0100 @@ -0,0 +1,21 @@ +/* medusa/l1/ipc.h, (C) 2002 Milan Pikula + * + * IPC struct extension: this structure is appended to in-kernel data, + * and we define it separately just to make l1 code shorter. + * + * for another data structure - kobject, describing ipc for upper layers - + * see l2/ipc_kobject.[ch]. + */ + +#ifndef _MEDUSA_L1_IPC_H +#define _MEDUSA_L1_IPC_H + +#include +#include + +struct medusa_l1_ipc_s { + MEDUSA_OBJECT_VARS; +}; + +#endif + diff -ruN linux-2.4.23-clean/include/medusa/l1/process_handlers.h linux-2.4.23-medusa/include/medusa/l1/process_handlers.h --- linux-2.4.23-clean/include/medusa/l1/process_handlers.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l1/process_handlers.h 2003-12-08 19:31:37.000000000 +0100 @@ -0,0 +1,37 @@ +/* + * medusa/l1/process_handlers.h + * + * prototypes of L2 process related handlers called from L1 hooks + * + */ + +#ifndef _MEDUSA_L1_PROCESS_HANDLERS_H +#define _MEDUSA_L1_PROCESS_HANDLERS_H + +#include +#include +#include +#include + +extern medusa_answer_t medusa_setresuid(uid_t ruid, uid_t euid, uid_t suid); +extern medusa_answer_t medusa_capable(int cap); +extern medusa_answer_t medusa_fork(struct task_struct *new, + unsigned long clone_flags); +extern medusa_answer_t medusa_init_process(struct task_struct *new); +extern medusa_answer_t medusa_sendsig(int sig, struct siginfo *info, + struct task_struct *p); +extern medusa_answer_t medusa_afterexec(char *filename, char **argv, + char **envp); +extern int medusa_monitored_pexec(void); +extern void medusa_monitor_pexec(int flag); +extern int medusa_monitored_afterexec(void); +extern void medusa_monitor_afterexec(int flag); +extern medusa_answer_t medusa_sexec(struct linux_binprm * bprm); +extern medusa_answer_t medusa_ptrace(struct task_struct * tracer, + struct task_struct * tracee); +extern void medusa_kernel_thread(int (*fn) (void *)); + +extern int process_kobj_validate_task(struct task_struct * ts); + +#endif /* _MEDUSA_L1_PROCESS_HANDLERS_H */ + diff -ruN linux-2.4.23-clean/include/medusa/l1/task.h linux-2.4.23-medusa/include/medusa/l1/task.h --- linux-2.4.23-clean/include/medusa/l1/task.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l1/task.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,38 @@ +/* medusa/l1/inode.h, (C) 2002 Milan Pikula + * + * task-struct extension: this structure is appended to in-kernel data, + * and we define it separately just to make l1 code shorter. + * + * for another data structure - kobject, describing task for upper layers - + * see l2/kobject_process.[ch]. + */ + +#ifndef _MEDUSA_L1_TASK_H +#define _MEDUSA_L1_TASK_H + +#include +#include +#include +#include + +struct medusa_l1_task_s { + uid_t luid; + MEDUSA_SUBJECT_VARS; + MEDUSA_OBJECT_VARS; + __u32 user; +#ifdef CONFIG_MEDUSA_FORCE + void *force_code; /* code to force or NULL, kfree */ + int force_len; /* force code length */ +#endif /* CONFIG_MEDUSA_FORCE */ +#ifdef CONFIG_MEDUSA_SYSCALL + /* FIXME: we only watch linux syscalls. Not only that's not good, + * but I am not sure whether NR_syscalls is enough on non-i386 archs. + * If you know how to write this correctly, mail to www@terminus.sk, + * thanks :). + */ + /* bitmap of syscalls, which are reported */ + unsigned char med_syscall[NR_syscalls / (sizeof(unsigned char) * 8)]; +#endif +}; + +#endif diff -ruN linux-2.4.23-clean/include/medusa/l2/kobject_file.h linux-2.4.23-medusa/include/medusa/l2/kobject_file.h --- linux-2.4.23-clean/include/medusa/l2/kobject_file.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l2/kobject_file.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,69 @@ +/* inode_kobject.h, (C) 2002 Milan Pikula + * + * FILE kobject: this file defines the kobject structure for inode, e.g. + * the data, which we want to pass to the authorization server. + * + * The structure contains some data from ordinary struct inode, + * and some data from medusa_l1_inode_s, which is defined in + * medusa/l1/inode.h. + * + * This file (as well as many others) is based on Medusa DS9, version + * 0.9.2, which is (C) Marek Zelem, Martin Ockajak and myself. + */ + +#ifndef _INODE_KOBJECT_H +#define _INODE_KOBJECT_H + +//#include +#include /* contains all includes we need ;) */ +#include + +struct file_kobject { /* was: m_inode_inf */ + MEDUSA_KOBJECT_HEADER; +/* + * 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. + * + * ... for more folklore read the comment in kdev_t.h ;) + */ + unsigned long dev; + unsigned long ino; + + umode_t mode; + nlink_t nlink; + uid_t uid; + gid_t gid; + unsigned long rdev; + + MEDUSA_OBJECT_VARS; + + __u32 user; +#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 */ +}; +extern MED_DECLARE_KCLASSOF(file_kobject); + +struct file_sub_kobject { /* the 'subject' view... */ + struct file_kobject f; + MEDUSA_SUBJECT_VARS; +}; +extern MED_DECLARE_KCLASSOF(file_sub_kobject); + +/* the conversion routines */ +int file_kobj2kern(struct file_kobject * fk, struct inode * inode); +int file_kern2kobj(struct file_kobject * fk, struct inode * inode); + +/* we want to keep a cache of "live" inodes - the ones which participate + * on some access right now + */ +void file_kobj_live_add(struct inode * ino); +void file_kobj_live_remove(struct inode * ino); + +/* conversion beteween filename (stored in dentry) and static buffer */ +void file_kobj_dentry2string(struct dentry * dentry, char * buf); + +#endif diff -ruN linux-2.4.23-clean/include/medusa/l2/kobject_process.h linux-2.4.23-medusa/include/medusa/l2/kobject_process.h --- linux-2.4.23-clean/include/medusa/l2/kobject_process.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l2/kobject_process.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,43 @@ +/* process_kobject.h, (C) 2002 Milan Pikula */ + +#ifndef _TASK_KOBJECT_H +#define _TASK_KOBJECT_H + +/* TASK kobject: this file defines the kobject structure for task, e.g. + * the data, which we want to pass to the authorization server. + * + * The structure contains some data from ordinary task_struct + * (such as pid etc.), and some data from medusa_l1_task_s, which is + * defined in medusa/l1/task.h. + */ + +// #include +#include /* contains all includes we need ;) */ +#include + +struct process_kobject { /* was: m_proc_inf */ + MEDUSA_KOBJECT_HEADER; + + pid_t pid, parent_pid, child_pid, sibling_pid; + pid_t pgrp; + uid_t uid, euid, suid, fsuid; + gid_t gid, egid, sgid, fsgid; + + uid_t luid; + kernel_cap_t ecap, icap, pcap; + MEDUSA_SUBJECT_VARS; + MEDUSA_OBJECT_VARS; + __u32 user; +#ifdef CONFIG_MEDUSA_SYSCALL + /* FIXME: this is wrong on non-i386 architectures */ + + /* bitmap of syscalls, which are reported */ + unsigned char med_syscall[NR_syscalls / (sizeof(unsigned char) * 8)]; +#endif +}; +extern MED_DECLARE_KCLASSOF(process_kobject); + +int process_kobj2kern(struct process_kobject * tk, struct task_struct * ts); +int process_kern2kobj(struct process_kobject * tk, struct task_struct * ts); + +#endif diff -ruN linux-2.4.23-clean/include/medusa/l3/arch.h linux-2.4.23-medusa/include/medusa/l3/arch.h --- linux-2.4.23-clean/include/medusa/l3/arch.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l3/arch.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,45 @@ +#ifndef _MEDUSA_ARCH_H +#define _MEDUSA_ARCH_H +#include +#include + +/* data locks */ +#define MED_DECLARE_LOCK_DATA(name) extern rwlock_t name +#define MED_LOCK_DATA(name) rwlock_t name = RW_LOCK_UNLOCKED +#define MED_LOCK_R(name) read_lock(&name) +#define MED_LOCK_W(name) write_lock(&name) +#define MED_UNLOCK_R(name) read_unlock(&name) +#define MED_UNLOCK_W(name) write_unlock(&name) + +/* debug output */ +#ifdef CONFIG_MEDUSA_QUIET +#define MED_PRINTF(fmt...) do { } while (0) +#else +#define MED_PRINTF(fmt...) printk("medusa: " fmt) +#endif + +/* u_intX_t */ +#include + +/* memcpy */ + +/* non-atomic bit set/test operations */ +#include +#define MED_SET_BIT(bit,ptr) __set_bit((bit),(void *)(ptr)) +#define MED_CLR_BIT(bit,ptr) clear_bit((bit),(void *)(ptr)) +#define MED_TST_BIT(bit,ptr) test_bit((bit),(void *)(ptr)) + +/* sanity checks for decision */ +#include +#include +#define ARCH_CANNOT_DECIDE(x) (in_interrupt() || current->pid == 0) + +/* linkage */ /* FIXME: is this needed? */ +#include + +#define MEDUSA_EXPORT_SYMBOL(symname) EXPORT_SYMBOL(x) +#define MEDUSA_INIT_FUNC(symname) module_init(symname) +#define MEDUSA_EXIT_FUNC(symname) module_exit(symname) +#define MEDUSA_KETCHUP MODULE_LICENSE("GPL"); + +#endif diff -ruN linux-2.4.23-clean/include/medusa/l3/arch_types.h linux-2.4.23-medusa/include/medusa/l3/arch_types.h --- linux-2.4.23-clean/include/medusa/l3/arch_types.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l3/arch_types.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,7 @@ +#ifndef _MEDUSA_ARCH_TYPES_H +#define _MEDUSA_ARCH_TYPES_H + +/* u_intX_t */ +#include + +#endif diff -ruN linux-2.4.23-clean/include/medusa/l3/config.h linux-2.4.23-medusa/include/medusa/l3/config.h --- linux-2.4.23-clean/include/medusa/l3/config.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l3/config.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,11 @@ +#ifndef _MEDUSA_CONFIG_H +#define _MEDUSA_CONFIG_H +#include + +/* configuration options */ +#include + +/* operating system */ +#define OS_LINUX 1 + +#endif diff -ruN linux-2.4.23-clean/include/medusa/l3/constants.h linux-2.4.23-medusa/include/medusa/l3/constants.h --- linux-2.4.23-clean/include/medusa/l3/constants.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l3/constants.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,42 @@ +#ifndef _MEDUSA_CONSTANTS_H +#define _MEDUSA_CONSTANTS_H + +#include + +/* these constants may be used by both internal kernel data structures, + * and a communication protocol. if you alter them, you'll break the + * comm protocol, and build of some l4 servers might fail. + * + * moreover, if you change the medusa_answer_t, the world will die in pain. + */ + +/* elementary data types for attributes */ +#define MED_END MED_COMM_TYPE_END /* end of attribute list */ +#define MED_UNSIGNED MED_COMM_TYPE_UNSIGNED /* unsigned integer attr */ +#define MED_SIGNED MED_COMM_TYPE_SIGNED /* signed integer attr */ +#define MED_STRING MED_COMM_TYPE_STRING /* string attr */ +#define MED_BITMAP MED_COMM_TYPE_BITMAP /* bitmap attr */ + +#define MED_KEY MED_COMM_TYPE_PRIMARY_KEY /* attribute is used to lookup kobject */ +#define MED_RO MED_COMM_TYPE_READ_ONLY /* attribute is read-only */ + +/* string lengths in various structures */ +#define MEDUSA_ATTRNAME_MAX MEDUSA_COMM_ATTRNAME_MAX +#define MEDUSA_KCLASSNAME_MAX MEDUSA_COMM_KCLASSNAME_MAX +#define MEDUSA_EVNAME_MAX MEDUSA_COMM_EVNAME_MAX +#define MEDUSA_ACCNAME_MAX MEDUSA_EVNAME_MAX +#define MEDUSA_SERVERNAME_MAX 128 + +/* answer codes */ + +typedef enum { + MED_ERR = -1, /* error */ + MED_YES = 0, /* permit the operation */ + MED_NO = 1, /* forbid the operation */ + MED_SKIP = 2, /* forbid the operation, but return success */ + MED_OK = 3 /* permit the operation, but proceed with + standard system permission check if any */ +} medusa_answer_t; + +#endif + diff -ruN linux-2.4.23-clean/include/medusa/l3/kobject.h linux-2.4.23-medusa/include/medusa/l3/kobject.h --- linux-2.4.23-clean/include/medusa/l3/kobject.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l3/kobject.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,238 @@ +#ifndef _MEDUSA_KOBJECT_H +#define _MEDUSA_KOBJECT_H + +/* + * Used by l2, l3, l4 + * + * This file defines + * ATTRIBUTE TYPE (defined in l2, used by l4) medusa_attribute_s + * + * KCLASS (defined in l2, used by l3, l4) medusa_kclass_s + * KOBJECT (defined in l2, used by l3, l4) medusa_kobject_s + * + * EVENT TYPE (defined in l2, used by l4) medusa_evtype_s + * (and ACCESS TYPE) + * EVENT (defined in l2, used by l3, l4) medusa_event_s + * (and ACCESS) + */ + +/* + * While you are not looking, this source is in Pascal. + */ + +#include +#include +#include + +struct medusa_attribute_s; +struct medusa_kclass_s; +struct medusa_kobject_s; +struct medusa_evtype_s; + +/**/ +/**/ + +/* describes one attribute in kclass (defined in l2 code, used by l4) */ +struct medusa_attribute_s { + char name[MEDUSA_ATTRNAME_MAX]; /* string: attribute name */ + unsigned int type; /* data type (MED_xxx) */ + unsigned long offset; /* offset of attribute in kobject */ + unsigned long length; /* bytes consumed by data */ +}; + +#define MED_ATTRSOF(structname) (structname##_attrs) + +/* macros for l2 to simplify attribute definitions */ +#define MED_ATTRS(structname) struct medusa_attribute_s (MED_ATTRSOF(structname))[] = + +#define MED_ATTR(structname,structmember,attrname,type) { \ + (attrname), \ + (type), \ + (int)(&(((struct structname *)0)->structmember)), \ + sizeof (((struct structname *)0)->structmember) \ + } +#define MED_ATTR_END {"", MED_END, 0, 0} + +#define MED_ATTR_RO(sn,sm,an,ty) MED_ATTR(sn,sm,an,(ty)|MED_RO) +#define MED_ATTR_KEY(sn,sm,an,ty) MED_ATTR(sn,sm,an,(ty)|MED_KEY) +#define MED_ATTR_KEY_RO(sn,sm,an,ty) MED_ATTR(sn,sm,an,(ty)|MED_KEY|MED_RO) +#define __MED_ATTR_SUBJ(sn,mn) /* internal macro copying medusa/l3/model.h */ \ + MED_ATTR(sn,mn.vsr, "vsr", MED_BITMAP), \ + MED_ATTR(sn,mn.vsw, "vsw", MED_BITMAP), \ + MED_ATTR(sn,mn.vss, "vss", MED_BITMAP), \ + MED_ATTR(sn,mn.act, "med_sact", MED_BITMAP), \ + MED_ATTR(sn,mn.cinfo, "s_cinfo", MED_BITMAP) +#define MED_ATTR_SUBJECT(sn) __MED_ATTR_SUBJ(sn,med_subject) +#define MED_SUBATTR_SUBJECT(sn,mn) __MED_ATTR_SUBJ(sn,mn.med_subject) +#define __MED_ATTR_OBJ(sn,mn) /* internal macro copying medusa/l3/model.h */ \ + MED_ATTR(sn,mn.vs, "vs", MED_BITMAP), \ + MED_ATTR(sn,mn.act, "med_oact", MED_BITMAP), \ + MED_ATTR(sn,mn.cinfo, "o_cinfo", MED_BITMAP) +#define MED_ATTR_OBJECT(sn) __MED_ATTR_OBJ(sn,med_object) +#define MED_SUBATTR_OBJECT(sn,mn) __MED_ATTR_OBJ(sn,mn.med_object) + +/**/ +/**/ + +/* description of kclass (defined in l2 code, used by l3, l4) */ +#define MED_KCLASSOF(structname) (structname##_kclass) +#define MED_DECLARE_KCLASSOF(structname) struct medusa_kclass_s (structname##_kclass) +struct medusa_kclass_s { + /* l3-defined data, filled by register_kobject */ + struct medusa_kclass_s * next; /* through all kclasses */ + int use_count; + cinfo_t cinfo; /* l4 hint */ +#ifdef CONFIG_MEDUSA_PROFILING + unsigned long long l2_to_l4; + unsigned long long l4_to_l2; +#endif + + /* l2-defined data */ + unsigned int kobject_size; /* sizeof(kobject) */ + struct medusa_attribute_s * attr; /* attributes */ + char name[MEDUSA_KCLASSNAME_MAX]; /* string: kclass name */ + void * reg; + void * unreg; + struct medusa_kobject_s * (* fetch)(struct medusa_kobject_s * key_obj); /* fetch the kobj. by key */ + medusa_answer_t (* update)(struct medusa_kobject_s * kobj); /* update the kobj. */ + void (* unmonitor)(struct medusa_kobject_s * kobj); /* disable all monitoring on kobj. optional; cannot sleep. */ +}; + +#ifdef CONFIG_MEDUSA_PROFILING +#define MEDUSA_DEFAULT_KCLASS_HEADER \ + NULL, 0, /* register_kclass */ \ + 0, /* cinfo */ \ + 0, 0 /* stats */ +#else +#define MEDUSA_DEFAULT_KCLASS_HEADER \ + NULL, 0, /* register_kclass */ \ + 0 /* cinfo */ +#endif + +/* macros for l2 to simplify kclass definition */ +#define MED_KCLASS(structname) struct medusa_kclass_s (MED_KCLASSOF(structname)) = +#define MEDUSA_KCLASS_HEADER(structname) \ + MEDUSA_DEFAULT_KCLASS_HEADER, \ + sizeof(struct structname), \ + MED_ATTRSOF(structname) + +/**/ +/**/ + +/* this is the kobject header - use it at the beginning of l2 structures */ +#define MEDUSA_KOBJECT_HEADER \ + struct medusa_kclass_s * kclass_id /* kclass - type of kobject */ + +/* used by l3 and l4 to easily access the header of l2 structures */ +struct medusa_kobject_s { + MEDUSA_KOBJECT_HEADER; + unsigned char data[0]; +}; + +#define MED_EVTYPEOF(structname) (structname##_evtype) +struct medusa_evtype_s { + /* l3-defined data */ + struct medusa_evtype_s * next; + unsigned short bitnr; /* which bit at subject or object triggers + * monitoring of this evtype. The value is + * OR'd with these flags: */ + /* if you change/swap them, check the usage anywhere (l3/registry.c) */ +#define MEDUSA_EVTYPE_NOTTRIGGERED 0xffff +#define MEDUSA_EVTYPE_TRIGGEREDATSUBJECT 0x0000 /* for the beauty of L2 */ +#define MEDUSA_EVTYPE_TRIGGEREDATOBJECT 0x8000 + +#define MEDUSA_EVTYPE_TRIGGEREDBYSUBJECTBIT 0x0000 /* for the beauty of L2 */ +#define MEDUSA_EVTYPE_TRIGGEREDBYOBJECTTBIT 0x4000 + +#define MEDUSA_ACCTYPE_NOTTRIGGERED MEDUSA_EVTYPE_NOTTRIGGERED +#define MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT (MEDUSA_EVTYPE_TRIGGEREDATSUBJECT | \ + MEDUSA_EVTYPE_TRIGGEREDBYSUBJECTBIT) +#define MEDUSA_ACCTYPE_TRIGGEREDATOBJECT (MEDUSA_EVTYPE_TRIGGEREDATOBJECT | \ + MEDUSA_EVTYPE_TRIGGEREDBYOBJECTTBIT) + +/* internal macro */ +#define ___MEDUSA_EVENTOP(evname,kobjptr,OP,WHAT,WHERE) \ + OP(MED_EVTYPEOF(evname).WHAT, &((kobjptr)->med_ ## WHERE.act)) + +/* is the event monitored (at object) ? */ +#define MEDUSA_MONITORED_EVENT_O(evname,kobjptr) \ + ___MEDUSA_EVENTOP(evname,kobjptr,MED_TST_BIT,bitnr & 0x3fff, object) +/* is the event monitored (at subject) ? */ +#define MEDUSA_MONITORED_EVENT_S(evname,kobjptr) \ + ___MEDUSA_EVENTOP(evname,kobjptr,MED_TST_BIT,bitnr, subject) +/* set the event monitoring at object */ +#define MEDUSA_MONITOR_EVENT_O(evname,kobjptr) \ + ___MEDUSA_EVENTOP(evname,kobjptr,MED_SET_BIT,bitnr & 0x3fff, object) +/* set the event monitoring at subject */ +#define MEDUSA_MONITOR_EVENT_S(evname,kobjptr) \ + ___MEDUSA_EVENTOP(evname,kobjptr,MED_SET_BIT,bitnr, subject) +/* unset the event monitoring at object */ +#define MEDUSA_UNMONITOR_EVENT_O(evname,kobjptr) \ + ___MEDUSA_EVENTOP(evname,kobjptr,MED_CLR_BIT,bitnr & 0x3fff, object) +/* unset the event monitoring at subject */ +#define MEDUSA_UNMONITOR_EVENT_S(evname,kobjptr) \ + ___MEDUSA_EVENTOP(evname,kobjptr,MED_CLR_BIT,bitnr, subject) + +#define MEDUSA_MONITORED_ACCESS_O(evname,kobjptr) \ + MEDUSA_MONITORED_EVENT_O(evname,kobjptr) +#define MEDUSA_MONITORED_ACCESS_S(evname,kobjptr) \ + MEDUSA_MONITORED_EVENT_S(evname,kobjptr) +#define MEDUSA_MONITOR_ACCESS_O(evname,kobjptr) \ + MEDUSA_MONITOR_EVENT_O(evname,kobjptr) +#define MEDUSA_MONITOR_ACCESS_S(evname,kobjptr) \ + MEDUSA_MONITOR_EVENT_S(evname,kobjptr) +#define MEDUSA_UNMONITOR_ACCESS_O(evname,kobjptr) \ + MEDUSA_UNMONITOR_EVENT_O(evname,kobjptr) +#define MEDUSA_UNMONITOR_ACCESS_S(evname,kobjptr) \ + MEDUSA_UNMONITOR_EVENT_S(evname,kobjptr) + + cinfo_t cinfo; /* l4 hint */ +#ifdef CONFIG_MEDUSA_PROFILING + unsigned long long l2_to_l4; + unsigned long long l4_to_l2; +#endif + + /* l2-defined data */ + char name[MEDUSA_EVNAME_MAX]; /* string: event name */ + struct medusa_kclass_s * arg_kclass[2]; /* kclasses of arguments */ + char arg_name[2][MEDUSA_ATTRNAME_MAX]; /* names of arguments */ + unsigned int event_size; /* sizeof(event) */ + struct medusa_attribute_s * attr; /* attributes */ +}; + +#ifdef CONFIG_MEDUSA_PROFILING +#define MEDUSA_DEFAULT_EVTYPE_HEADER \ + NULL, /* register_evtype */ \ + 0 /* bitnr */, \ + 0 /* cinfo */, \ + 0, 0 +#else +#define MEDUSA_DEFAULT_EVTYPE_HEADER \ + NULL, /* register_evtype */ \ + 0 /* bitnr */, \ + 0 /* cinfo */ +#endif +#define MEDUSA_DEFAULT_ACCTYPE_HEADER MEDUSA_DEFAULT_EVTYPE_HEADER + +#define MED_EVTYPE(structname,evtypename,s1name,arg1name,s2name,arg2name) \ + struct medusa_evtype_s (MED_EVTYPEOF(structname)) = { \ + MEDUSA_DEFAULT_ACCTYPE_HEADER, \ + (evtypename), \ + { &MED_KCLASSOF(s1name), &MED_KCLASSOF(s2name) }, \ + { (arg1name), (arg2name) }, \ + sizeof(struct structname), \ + MED_ATTRSOF(structname) \ + } +#define MED_ACCTYPE(structname,acctypename,s1name,arg1name,s2name,arg2name) \ + MED_EVTYPE(structname,acctypename,s1name,arg1name,s2name,arg2name) + +/* this is the access header - use it at the beginning of l2 structures */ +#define MEDUSA_ACCESS_HEADER \ + struct medusa_evtype_s * evtype_id +/* used by l3 and l4 to easily access the header of l2 structures */ +struct medusa_event_s { + MEDUSA_ACCESS_HEADER; + unsigned char data[0]; +}; + +#endif diff -ruN linux-2.4.23-clean/include/medusa/l3/model.h linux-2.4.23-medusa/include/medusa/l3/model.h --- linux-2.4.23-clean/include/medusa/l3/model.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l3/model.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,192 @@ +#ifndef _MEDUSA_MODEL_H +#define _MEDUSA_MODEL_H + +#include + +/* this header file defines the VS model */ + +/* objects and subjects are two different kinds of kobjects: + * `subject' is the initiator of some operation, `object' is + * the target of operation. + */ + +#if CONFIG_MEDUSA_VS <= 32 +typedef u_int32_t vs_t; +#else +typedef struct { u_int32_t vspack[((CONFIG_MEDUSA_VS+31)/32)]; } vs_t; +#endif +typedef u_int32_t act_t; +typedef struct { /* this is at each subject */ + u_int32_t data[4]; +} s_cinfo_t; +typedef struct { /* this is at each object */ + u_int32_t data[1]; +} o_cinfo_t; +typedef u_int32_t cinfo_t; /* this is at kclass; must be able to hold pointer */ + +struct medusa_object_s { + vs_t vs; /* virt. spaces of this object */ + act_t act; /* actions on this object, which are reported to L4 */ + /* this may slightly correspond with defined access + types ;> */ + o_cinfo_t cinfo;/* l4 hint */ + int magic; /* whether this piece of crap is valid */ +}; + +struct medusa_subject_s { + vs_t vsr; /* which vs I can read from */ + vs_t vsw; /* which vs I can write to */ + vs_t vss; /* which vs I can see */ + act_t act; /* which actions of me are monitored. this may slig.. */ + s_cinfo_t cinfo;/* l4 hint */ + /* subject does not have a magic. As it executes operations on its + * own right, it surely gets the vs* spaces set by auth. server some + * time. + */ +}; + +#define _VS(X) ((X)->vs) +#define _VSR(X) ((X)->vsr) +#define _VSW(X) ((X)->vsw) +#define _VSS(X) ((X)->vss) + +#if CONFIG_MEDUSA_VS <= 32 +#define VS_ISSUBSET(X,Y) ((X) & ~((Y)) == 0) +#define VS_ISSUPERSET(X,Y) VS_ISSUBSET((Y),(X)) +#define VS_INTERSECT(X,Y) (((X) & (Y)) != 0) +#else +static inline int VS_ISSUBSET(vs_t X, vs_t Y) +{ + int i; + for (i=0; i<(CONFIG_MEDUSA_VS+31)/32; i++) + if (X.vspack[i] & ~Y.vspack[i]) + return 0; + return 1; +} +#define VS_ISSUPERSET(X,Y) VS_ISSUBSET((Y),(X)) +static inline int VS_INTERSECT(vs_t X, vs_t Y) +{ + int i; + for (i=0; i<(CONFIG_MEDUSA_VS+31)/32; i++) + if (X.vspack[i] & Y.vspack[i]) + return 1; + return 0; +} +#endif + +/* infrastructure for l1, l2 */ + +#define VS(X) _VS(&((X)->med_object)) +#define VSR(X) _VSR(&((X)->med_subject)) +#define VSW(X) _VSW(&((X)->med_subject)) +#define VSS(X) _VSS(&((X)->med_subject)) + +/* this is an object data - add to system structures and kobjects, which act as + objects of some operation */ +#define MEDUSA_OBJECT_VARS \ + struct medusa_object_s med_object +#define COPY_MEDUSA_OBJECT_VARS(to,from) \ + do { \ + (to)->med_object = (from)->med_object; \ + } while (0) +#if CONFIG_MEDUSA_VS <= 32 +#define INIT_MEDUSA_OBJECT_VARS(ptr) \ + do { /* don't touch, unless you REALLY know what you are doing. */ \ + (ptr)->med_object.vs = 0xffffffff; \ + (ptr)->med_object.act = 0xffffffff; \ + (ptr)->med_object.cinfo.data[0] = 0; \ + (ptr)->med_object.magic = 0; \ + } while (0) +#define UNMONITOR_MEDUSA_OBJECT_VARS(ptr) \ + do { /* don't touch, unless you REALLY know what you are doing. */ \ + (ptr)->med_object.vs = 0xffffffff; \ + (ptr)->med_object.act = 0; \ + } while (0) +#else +#define INIT_MEDUSA_OBJECT_VARS(ptr) \ + do { /* don't touch, unless you REALLY know what you are doing. */ \ + int i; \ + for (i=0; i<(CONFIG_MEDUSA_VS+31)/32; i++) \ + (ptr)->med_object.vs.vspack[i] = 0xffffffff; \ + (ptr)->med_object.act = 0xffffffff; \ + (ptr)->med_object.cinfo.data[0] = 0; \ + (ptr)->med_object.magic = 0; \ + } while (0) +#define UNMONITOR_MEDUSA_OBJECT_VARS(ptr) \ + do { /* don't touch, unless you REALLY know what you are doing. */ \ + int i; \ + for (i=0; i<(CONFIG_MEDUSA_VS+31)/32; i++) \ + (ptr)->med_object.vs.vspack[i] = 0xffffffff; \ + (ptr)->med_object.act = 0; \ + } while (0) +#endif + +/* this is an subject data - add to system structures and kobjects, which act as + subjects of some operation */ +#define MEDUSA_SUBJECT_VARS \ + struct medusa_subject_s med_subject +#define COPY_MEDUSA_SUBJECT_VARS(to,from) \ + do { \ + (to)->med_subject = (from)->med_subject; \ + } while (0) +#if CONFIG_MEDUSA_VS <= 32 +#define INIT_MEDUSA_SUBJECT_VARS(ptr) \ + do { /* don't touch, unless you REALLY know what you are doing. */ \ + (ptr)->med_subject.vss = 0xffffffff; \ + (ptr)->med_subject.vsr = 0xffffffff; \ + (ptr)->med_subject.vsw = 0xffffffff; \ + (ptr)->med_subject.act = 0xffffffff; \ + (ptr)->med_subject.cinfo.data[0] = 0; \ + (ptr)->med_subject.cinfo.data[1] = 0; \ + (ptr)->med_subject.cinfo.data[2] = 0; \ + (ptr)->med_subject.cinfo.data[3] = 0; \ + } while (0) +#define UNMONITOR_MEDUSA_SUBJECT_VARS(ptr) \ + do { /* don't touch, unless you REALLY know what you are doing. */ \ + (ptr)->med_subject.vss = 0xffffffff; \ + (ptr)->med_subject.vsr = 0xffffffff; \ + (ptr)->med_subject.vsw = 0xffffffff; \ + (ptr)->med_subject.act = 0; \ + } while (0) +#else +#define INIT_MEDUSA_SUBJECT_VARS(ptr) \ + do { /* don't touch, unless you REALLY know what you are doing. */ \ + int i; \ + for (i=0; i<(CONFIG_MEDUSA_VS+31)/32; i++) \ + (ptr)->med_subject.vss.vspack[i] = \ + (ptr)->med_subject.vsr.vspack[i] = \ + (ptr)->med_subject.vsw.vspack[i] = \ + 0xffffffff; \ + (ptr)->med_subject.act = 0xffffffff; \ + (ptr)->med_subject.cinfo.data[0] = 0; \ + (ptr)->med_subject.cinfo.data[1] = 0; \ + (ptr)->med_subject.cinfo.data[2] = 0; \ + (ptr)->med_subject.cinfo.data[3] = 0; \ + } while (0) +#define UNMONITOR_MEDUSA_SUBJECT_VARS(ptr) \ + do { /* don't touch, unless you REALLY know what you are doing. */ \ + int i; \ + for (i=0; i<(CONFIG_MEDUSA_VS+31)/32; i++) \ + (ptr)->med_subject.vss.vspack[i] = \ + (ptr)->med_subject.vsr.vspack[i] = \ + (ptr)->med_subject.vsw.vspack[i] = \ + 0xffffffff; \ + (ptr)->med_subject.act = 0; \ + } while (0) +#endif + +/* read the comment in l3/registry.c on this magic number */ +extern int medusa_authserver_magic; +#define MED_MAGIC_VALID(pointer) \ + ((pointer)->med_object.magic == medusa_authserver_magic) +#define MED_MAGIC_VALIDATE(pointer) \ + do { \ + (pointer)->med_object.magic = medusa_authserver_magic; \ + } while (0) +#define MED_MAGIC_INVALIDATE(pointer) \ + do { \ + (pointer)->med_object.magic = 0; \ + } while (0) + +#endif /* _MEDUSA_MODEL_H */ + diff -ruN linux-2.4.23-clean/include/medusa/l3/registry.h linux-2.4.23-medusa/include/medusa/l3/registry.h --- linux-2.4.23-clean/include/medusa/l3/registry.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l3/registry.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,68 @@ +/* medusa/l3/registry.h, (C) 2002 Milan Pikula + * + * This header file defines the routines and data structures + * for L2 and L4 code to interact with L3. This means access + * to both registry functions, and decision process. + * + * The name or contents of this file should probably change. + */ + +#ifndef _MEDUSA_REGISTRY_H +#define _MEDUSA_REGISTRY_H + +#include +#include +#include + +extern int authserver_magic; /* to be checked against magic in objects */ + +/* interface to L2 */ +extern int med_register_kclass(struct medusa_kclass_s * ptr); +medusa_answer_t med_unlink_kclass(struct medusa_kclass_s * ptr); +extern void med_unregister_kclass(struct medusa_kclass_s * ptr); +#define MED_REGISTER_KCLASS(structname) \ + med_register_kclass(&MED_KCLASSOF(structname)) +#define MED_UNLINK_KCLASS(structname) \ + med_unlink_kclass(&MED_KCLASSOF(structname)) +#define MED_UNREGISTER_KCLASS(structname) \ + med_unregister_kclass(&MED_KCLASSOF(structname)) + +extern int med_register_evtype(struct medusa_evtype_s * ptr, int flags); +extern void med_unregister_evtype(struct medusa_evtype_s * ptr); +#define MED_REGISTER_EVTYPE(structname,flags) \ + med_register_evtype(&MED_EVTYPEOF(structname),flags) +#define MED_UNREGISTER_EVTYPE(structname) \ + med_unregister_evtype(&MED_EVTYPEOF(structname)) + +#define MED_REGISTER_ACCTYPE(structname,flags) \ + MED_REGISTER_EVTYPE(structname, flags) +#define MED_UNREGISTER_ACCTYPE(structname) \ + MED_UNREGISTER_EVTYPE(structname) +/* here, the 'flags' field is one of + * MEDUSA_ACCTYPE_NOTTRIGGERED (monitoring of this event can't be turned off), + * MEDUSA_ACCTYPE_TRIGGEREDATOBJECT (the event is triggered by changing the object) + * MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT (the ... subject) + */ + +extern medusa_answer_t med_decide(struct medusa_evtype_s * acctype, void * access, void * o1, void * o2); +#define MED_DECIDE(structname,arg1,arg2,arg3) \ + med_decide(&MED_EVTYPEOF(structname), arg1, arg2, arg3) + +/* interface to L2 and L4 */ +extern medusa_answer_t med_get_kclass(struct medusa_kclass_s * ptr); +extern void med_put_kclass(struct medusa_kclass_s * ptr); +extern struct medusa_kclass_s * med_get_kclass_by_name(char * name); +extern struct medusa_kclass_s * med_get_kclass_by_cinfo(cinfo_t cinfo); +struct medusa_kclass_s * med_get_kclass_by_pointer(struct medusa_kclass_s * ptr); +extern struct medusa_authserver_s * med_get_authserver(void); +extern void med_put_authserver(struct medusa_authserver_s * ptr); + +/* interface to L4 */ +extern int med_register_authserver(struct medusa_authserver_s * ptr); +extern void med_unregister_authserver(struct medusa_authserver_s * ptr); +#define MED_REGISTER_AUTHSERVER(structname) \ + med_register_authserver(&structname) +#define MED_UNREGISTER_AUTHSERVER(structname) \ + med_unregister_authserver(&structname) + +#endif diff -ruN linux-2.4.23-clean/include/medusa/l3/server.h linux-2.4.23-medusa/include/medusa/l3/server.h --- linux-2.4.23-clean/include/medusa/l3/server.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l3/server.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,57 @@ +#ifndef _MEDUSA_SERVER_H +#define _MEDUSA_SERVER_H + +/* + * Used by l3, l4 + * + * This file defines the authorization server structure + * and constants, and API for the auth. server. + */ + +#include +#include + +struct medusa_authserver_s { + char name[MEDUSA_SERVERNAME_MAX]; + int use_count; /* don't modify this directly from L2/L4 code */ + + /* + * callbacks of authorization server. + * any callback, except from decide(), + * can be NULL. + */ + + void (*close)(void); /* this gets called after the use-count + * has dropped to zero, and the + * server can safely exit. + */ + + /* + * the following callbacks must return MED_YES + * for the forward compatibility. del_* are unconditional; + * after return, no use of kclasses or evtypes is permitted. + * + * they're guaranteed to be run one at time by l3; cannot sleep. + */ + + int (*add_kclass)(struct medusa_kclass_s * cl); + /* called when new kclass arrives */ + void (*del_kclass)(struct medusa_kclass_s * cl); + /* and this when it dies */ + int (*add_evtype)(struct medusa_evtype_s * at); + /* called when new event type arrives */ + void (*del_evtype)(struct medusa_evtype_s * at); + /* and this when it dies */ + + /* + * this is the main callback routine of any auth server. + * - and the only which must NOT be NULL. + * May sleep. I hope. + */ + + medusa_answer_t (*decide)(struct medusa_event_s * req, + struct medusa_kobject_s * o1, + struct medusa_kobject_s * o2); +}; + +#endif diff -ruN linux-2.4.23-clean/include/medusa/l4/comm.h linux-2.4.23-medusa/include/medusa/l4/comm.h --- linux-2.4.23-clean/include/medusa/l4/comm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/include/medusa/l4/comm.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,76 @@ +#ifndef _MEDUSA_COMM_H +#define _MEDUSA_COMM_H + +#include + +/* + * the following constants and structures cover the standard + * communication protocol. + * + * this means: DON'T TOUCH! Not only you will break the comm + * protocol, but also the code which relies on particular + * facts about them. + */ + +/* version of this communication protocol */ +#define MEDUSA_COMM_VERSION 1 + +#define MEDUSA_COMM_GREETING 0x66007e5a + +#define MEDUSA_COMM_ATTRNAME_MAX (32-5) +#define MEDUSA_COMM_KCLASSNAME_MAX (32-6) +#define MEDUSA_COMM_EVNAME_MAX (32-6) + +/* comm protocol commands. 'k' stands for kernel, 'c' for constable. */ + +#define MEDUSA_COMM_AUTHREQUEST 0x01 /* k->c */ +#define MEDUSA_COMM_AUTHANSWER 0x81 /* c->k */ + +#define MEDUSA_COMM_KCLASSDEF 0x02 /* k->c */ +#define MEDUSA_COMM_KCLASSUNDEF 0x03 /* k->c */ +#define MEDUSA_COMM_EVTYPEDEF 0x04 /* k->c */ +#define MEDUSA_COMM_EVTYPEUNDEF 0x05 /* k->c */ + +#define MEDUSA_COMM_FETCH_REQUEST 0x88 /* c->k */ +#define MEDUSA_COMM_FETCH_ANSWER 0x08 /* k->c */ +#define MEDUSA_COMM_FETCH_ERROR 0x09 /* k->c */ + +#define MEDUSA_COMM_UPDATE_REQUEST 0x8a /* c->k */ +#define MEDUSA_COMM_UPDATE_ANSWER 0x0a /* k->c */ + +struct medusa_comm_attribute_s { + u_int16_t offset; /* offset of attribute in object */ + u_int16_t length; /* bytes consumed by data */ + u_int8_t type; /* data type (MED_COMM_TYPE_xxx) */ + char name[MEDUSA_COMM_ATTRNAME_MAX]; /* string: attribute name */ +}; + +#define MED_COMM_TYPE_END 0x00 /* end of attribute list */ +#define MED_COMM_TYPE_UNSIGNED 0x01 /* unsigned integer attr */ +#define MED_COMM_TYPE_SIGNED 0x02 /* signed integer attr */ +#define MED_COMM_TYPE_STRING 0x03 /* string attr */ +#define MED_COMM_TYPE_BITMAP 0x04 /* bitmap attr */ + +#define MED_COMM_TYPE_READ_ONLY 0x80 /* this attribute is read-only */ +#define MED_COMM_TYPE_PRIMARY_KEY 0x40 /* this attribute is used to lookup object */ + +struct medusa_comm_kclass_s { + u_int32_t kclassid; /* unique identifier of this kclass */ + u_int16_t size; /* size of object */ + char name[MEDUSA_COMM_KCLASSNAME_MAX]; +}; + +struct medusa_comm_evtype_s { + u_int32_t evid; + u_int16_t size; + u_int16_t actbit; /* which bit of 'act' controls this evtype: + * 0x8000 + bitnr: bitnr at subject, + * 0x0000 + bitnr: bitnr at object, + * 0xffff: there is no way to trigger this ev. + */ + u_int32_t ev_kclass[2]; + char name[MEDUSA_COMM_EVNAME_MAX]; + char ev_name[2][MEDUSA_COMM_ATTRNAME_MAX]; +}; + +#endif diff -ruN linux-2.4.23-clean/init/main.c linux-2.4.23-medusa/init/main.c --- linux-2.4.23-clean/init/main.c 2003-12-08 19:15:46.000000000 +0100 +++ linux-2.4.23-medusa/init/main.c 2003-12-08 19:35:37.000000000 +0100 @@ -29,6 +29,10 @@ #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + #include #include @@ -112,6 +116,10 @@ extern void ipc_init(void); #endif +#ifdef CONFIG_MEDUSA +extern void medusa_init(void); +#endif /* CONFIG_MEDUSA */ + /* * Boot command-line arguments */ @@ -437,6 +445,9 @@ #if defined(CONFIG_SYSVIPC) ipc_init(); #endif +#ifdef CONFIG_MEDUSA + medusa_init(); +#endif /* CONFIG_MEDUSA */ rest_init(); } @@ -595,6 +606,11 @@ if (execute_command) run_init_process(execute_command); +#ifdef CONFIG_MEDUSA_INIT_WRAPPER + run_init_process("/sbin/constable"); + run_init_process("/etc/constable"); + run_init_process("/bin/constable"); +#endif /* CONFIG_MEDUSA_INIT_WRAPPER */ run_init_process("/sbin/init"); run_init_process("/etc/init"); run_init_process("/bin/init"); diff -ruN linux-2.4.23-clean/ipc/msg.c linux-2.4.23-medusa/ipc/msg.c --- linux-2.4.23-clean/ipc/msg.c 2003-06-13 16:51:39.000000000 +0200 +++ linux-2.4.23-medusa/ipc/msg.c 2003-12-08 19:31:38.000000000 +0100 @@ -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 + COPY_MEDUSA_OBJECT_VARS(&msq->q_perm.med, ¤t->med); +#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_INTERSECT(VSS(¤t->med), VS(&msq->q_perm.med))) { + 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_INTERSECT(VSS(¤t->med), VS(&msq->q_perm.med))) + 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_INTERSECT(VSS(¤t->med), VS(&msq->q_perm.med))) + 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_INTERSECT(VSS(¤t->med), VS(&msq->q_perm.med))) + 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_INTERSECT(VSS(¤t->med), VS(&msq->q_perm.med))) + goto out_unlock; +#endif /* CONFIG_MEDUSA */ err=-EACCES; if (ipcperms (&msq->q_perm, S_IRUGO)) goto out_unlock; diff -ruN linux-2.4.23-clean/ipc/sem.c linux-2.4.23-medusa/ipc/sem.c --- linux-2.4.23-clean/ipc/sem.c 2003-08-25 13:44:44.000000000 +0200 +++ linux-2.4.23-medusa/ipc/sem.c 2003-12-08 19:31:38.000000000 +0100 @@ -66,6 +66,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) @@ -145,6 +149,9 @@ /* sma->undo = NULL; */ sma->sem_nsems = nsems; sma->sem_ctime = CURRENT_TIME; +#ifdef CONFIG_MEDUSA + COPY_MEDUSA_OBJECT_VARS(&sma->sem_perm.med, ¤t->med); +#endif /* CONFIG_MEDUSA */ sem_unlock(id); return sem_buildid(id, sma->sem_perm.seq); @@ -174,6 +181,13 @@ BUG(); if (nsems > sma->sem_nsems) err = -EINVAL; +#ifdef CONFIG_MEDUSA + if (!VS_INTERSECT(VSS(¤t->med), VS(&sma->sem_perm.med))) { + sem_unlock(id); + up(&sem_ids.sem); + return -ENOENT; + } +#endif /* CONFIG_MEDUSA */ else if (ipcperms(&sma->sem_perm, semflg)) err = -EACCES; else @@ -198,6 +212,10 @@ return -EIDRM; } +#ifdef CONFIG_MEDUSA + if (!VS_INTERSECT(VSS(¤t->med), VS(&sma->sem_perm.med))) + return -ENOENT; +#endif /* CONFIG_MEDUSA */ if (ipcperms(&sma->sem_perm, flg)) { sem_unlock(semid); return -EACCES; @@ -485,6 +503,11 @@ if(sma == NULL) return -EINVAL; +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_INTERSECT(VSS(¤t->med), VS(&sma->sem_perm.med))) + goto out_unlock; +#endif /* CONFIG_MEDUSA */ err = -EACCES; if (ipcperms (&sma->sem_perm, S_IRUGO)) goto out_unlock; @@ -527,6 +550,11 @@ if (sem_checkid(sma,semid)) goto out_unlock; +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_INTERSECT(VSS(¤t->med), VS(&sma->sem_perm.med))) + goto out_unlock; +#endif /* CONFIG_MEDUSA */ err = -EACCES; if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO)) goto out_unlock; @@ -714,6 +742,14 @@ err=-EIDRM; goto out_unlock; } +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_INTERSECT(VSS(¤t->med), VS(&sma->sem_perm.med))) + goto out_unlock; + err = -EPERM; + if (!VS_INTERSECT(VSW(¤t->med), VS(&sma->sem_perm.med))) + goto out_unlock; +#endif /* CONFIG_MEDUSA */ ipcp = &sma->sem_perm; if (current->euid != ipcp->cuid && @@ -896,6 +932,11 @@ } alter |= decrease; +#ifdef CONFIG_MEDUSA + error = -EINVAL; + if (!VS_INTERSECT(VSS(¤t->med), VS(&sma->sem_perm.med))) + goto out_unlock_free; +#endif /* CONFIG_MEDUSA */ error = -EACCES; if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) goto out_unlock_free; diff -ruN linux-2.4.23-clean/ipc/shm.c linux-2.4.23-medusa/ipc/shm.c --- linux-2.4.23-clean/ipc/shm.c 2002-08-03 02:39:46.000000000 +0200 +++ linux-2.4.23-medusa/ipc/shm.c 2003-12-08 19:31:38.000000000 +0100 @@ -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; @@ -211,6 +216,9 @@ shp->shm_ctim = CURRENT_TIME; shp->shm_segsz = size; shp->shm_nattch = 0; +#ifdef CONFIG_MEDUSA + COPY_MEDUSA_OBJECT_VARS(&shp->shm_perm.med, ¤t->med); +#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; @@ -247,6 +255,13 @@ BUG(); if (shp->shm_segsz < size) err = -EINVAL; +#ifdef CONFIG_MEDUSA + if (!VS_INTERSECT(VSS(¤t->med), VS(&shp->shm_perm.med))) { + shm_unlock(id); + up(&shm_ids.sem); + return -ENOENT; + } +#endif /* CONFIG_MEDUSA */ else if (ipcperms(&shp->shm_perm, shmflg)) err = -EACCES; else @@ -442,6 +457,11 @@ goto out_unlock; result = 0; } +#ifdef CONFIG_MEDUSA + err = -EINVAL; + if (!VS_INTERSECT(VSS(¤t->med), VS(&shp->shm_perm.med))) + goto out_unlock; +#endif /* CONFIG_MEDUSA */ err=-EACCES; if (ipcperms (&shp->shm_perm, S_IRUGO)) goto out_unlock; @@ -471,6 +491,10 @@ if(shp==NULL) return -EINVAL; err = shm_checkid(shp,shmid); +#ifdef CONFIG_MEDUSA + if (!VS_INTERSECT(VSS(¤t->med), VS(&shp->shm_perm.med))) + err = -EINVAL; +#endif /* CONFIG_MEDUSA */ if(err) goto out_unlock; if(cmd==SHM_LOCK) { @@ -501,6 +525,12 @@ if (shp == NULL) goto out_up; err = shm_checkid(shp, shmid); +#ifdef CONFIG_MEDUSA + if (!VS_INTERSECT(VSS(¤t->med), VS(&shp->shm_perm.med))) + err = -EINVAL; + else if (!VS_INTERSECT(VSW(¤t->med), VS(&shp->shm_perm.med))) + 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_INTERSECT(VSS(¤t->med), VS(&shp->shm_perm.med))) + err = -EINVAL; + else if (!VS_INTERSECT(VSW(¤t->med), VS(&shp->shm_perm.med))) + 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_INTERSECT(VSS(¤t->med), VS(&shp->shm_perm.med))) { + shm_unlock(shmid); + return -EINVAL; + } +#endif /* CONFIG_MEDUSA */ if (ipcperms(&shp->shm_perm, acc_mode)) { shm_unlock(shmid); return -EACCES; diff -ruN linux-2.4.23-clean/ipc/util.c linux-2.4.23-medusa/ipc/util.c --- linux-2.4.23-clean/ipc/util.c 2003-08-25 13:44:44.000000000 +0200 +++ linux-2.4.23-medusa/ipc/util.c 2003-12-08 19:31:38.000000000 +0100 @@ -19,6 +19,9 @@ #include #include #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ #if defined(CONFIG_SYSVIPC) @@ -258,6 +261,16 @@ granted_mode >>= 6; else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid)) granted_mode >>= 3; +#ifdef CONFIG_MEDUSA + if ( + !VS_INTERSECT(VSS(¤t->med), VS(&ipcp->med)) || + ((requested_mode & (S_IROTH | S_IXOTH)) && + !VS_INTERSECT(VSR(¤t->med), VS(&ipcp->med))) || + ((requested_mode & S_IWOTH) && + !VS_INTERSECT(VSW(¤t->med), VS(&ipcp->med))) + ) + 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 -ruN linux-2.4.23-clean/kernel/fork.c linux-2.4.23-medusa/kernel/fork.c --- linux-2.4.23-clean/kernel/fork.c 2003-12-08 19:15:46.000000000 +0100 +++ linux-2.4.23-medusa/kernel/fork.c 2003-12-08 19:31:38.000000000 +0100 @@ -29,6 +29,11 @@ #include #include +#include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* The idle threads do not count.. */ int nr_threads; int nr_running; @@ -661,6 +666,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 @@ -811,6 +823,10 @@ if (p->ptrace & PT_PTRACED) send_sig(SIGSTOP, p, 1); +#ifdef CONFIG_MEDUSA + medusa_init_process(p); +#endif /* CONFIG_MEDUSA */ + wake_up_process(p); /* do this last */ ++total_forks; if (clone_flags & CLONE_VFORK) diff -ruN linux-2.4.23-clean/kernel/kmod.c linux-2.4.23-medusa/kernel/kmod.c --- linux-2.4.23-clean/kernel/kmod.c 2003-12-08 19:15:46.000000000 +0100 +++ linux-2.4.23-medusa/kernel/kmod.c 2003-12-08 19:31:38.000000000 +0100 @@ -128,6 +128,8 @@ curtask->ngroups = 0; cap_set_full(curtask->cap_effective); + cap_set_full(curtask->cap_inheritable); + cap_set_full(curtask->cap_permitted); /* Allow execve args to be in kernel space. */ set_fs(KERNEL_DS); diff -ruN linux-2.4.23-clean/kernel/signal.c linux-2.4.23-medusa/kernel/signal.c --- linux-2.4.23-clean/kernel/signal.c 2003-06-13 16:51:39.000000000 +0200 +++ linux-2.4.23-medusa/kernel/signal.c 2003-12-08 19:31:38.000000000 +0100 @@ -16,6 +16,10 @@ #include +#ifdef CONFIG_MEDUSA +#include +#endif /* CONFIG_MEDUSA */ + /* * SLAB caches for signal bits. */ @@ -543,7 +547,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, 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; @@ -553,6 +576,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 -ruN linux-2.4.23-clean/kernel/sys.c linux-2.4.23-medusa/kernel/sys.c --- linux-2.4.23-clean/kernel/sys.c 2003-12-08 19:15:46.000000000 +0100 +++ linux-2.4.23-medusa/kernel/sys.c 2003-12-08 19:31:38.000000000 +0100 @@ -37,6 +37,10 @@ # define GET_FPEXC_CTL(a,b) (-EINVAL) #endif +#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 @@ -500,6 +504,8 @@ !current->keep_capabilities) { cap_clear(current->cap_permitted); cap_clear(current->cap_effective); +/* This is to allow good SETUID emulation (Marek Zelem ) */ + cap_clear(current->cap_inheritable); } if (old_euid == 0 && current->euid != 0) { cap_clear(current->cap_effective); @@ -523,6 +529,10 @@ current->mm->dumpable = 0; wmb(); } +#ifdef CONFIG_MEDUSA + if (current->med.luid == (uid_t)-1) + current->med.luid = (new_ruid == (uid_t)-1 ? -2 : new_ruid); +#endif current->uid = new_ruid; return 0; } @@ -567,6 +577,24 @@ return -EPERM; } +#ifdef CONFIG_MEDUSA +{ + /* TODO: do this a bit sooner to enable MED_YES */ + int med_retval; + + med_retval = medusa_setresuid(new_ruid, new_euid, + /* this is modeled after the 'if' statment + at the end of this routine */ + (ruid != (uid_t) -1 || + (euid != (uid_t) -1 && euid != old_ruid)) ? + new_euid : -1 + ); + if (med_retval == MED_SKIP) + return 0; + if (med_retval != MED_YES && med_retval != MED_OK) + return -EPERM; +} +#endif /* CONFIG_MEDUSA */ if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) return -EAGAIN; @@ -606,16 +634,37 @@ int old_euid = current->euid; int old_ruid, old_suid, new_ruid, new_suid; +#ifdef CONFIG_MEDUSA + int med_retval; +#endif /* CONFIG_MEDUSA */ + old_ruid = new_ruid = current->uid; old_suid = current->suid; new_suid = old_suid; if (capable(CAP_SETUID)) { +#ifdef CONFIG_MEDUSA + med_retval = medusa_setresuid(uid, uid, uid); + if (med_retval == MED_SKIP) + return 0; + if (med_retval != MED_YES && med_retval != MED_OK) + return -EPERM; +#endif /* CONFIG_MEDUSA */ if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) return -EAGAIN; new_suid = uid; - } else if ((uid != current->uid) && (uid != new_suid)) + } else { +#ifdef CONFIG_MEDUSA + med_retval = medusa_setresuid(-1, uid, -1); + if (med_retval == MED_SKIP) + return 0; + if (med_retval != MED_YES && med_retval != MED_OK) + return -EPERM; + if (med_retval == MED_OK) +#endif /* CONFIG_MEDUSA */ + if ((uid != current->uid) && (uid != new_suid)) return -EPERM; + } if (old_euid != uid) { @@ -643,6 +692,17 @@ int old_euid = current->euid; int old_suid = current->suid; +#ifdef CONFIG_MEDUSA + int med_retval; + + med_retval = medusa_setresuid(ruid, euid, suid); + if (med_retval == MED_SKIP) + return 0; + if (med_retval != MED_YES && med_retval != MED_OK) + return -EPERM; + + if (med_retval != MED_YES) +#endif /* CONFIG_MEDUSA */ if (!capable(CAP_SETUID)) { if ((ruid != (uid_t) -1) && (ruid != current->uid) && (ruid != current->euid) && (ruid != current->suid)) diff -ruN linux-2.4.23-clean/medusa/Config.in linux-2.4.23-medusa/medusa/Config.in --- linux-2.4.23-clean/medusa/Config.in 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/Config.in 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,41 @@ +# +# Medusa DS9 configuration +# + +mainmenu_option next_comment +comment 'Medusa DS9' + +bool 'Medusa DS9 security system support' CONFIG_MEDUSA + +if [ "$CONFIG_MEDUSA" = "y" ]; then + comment 'L1, L2 (i.e. core) options' + int 'Number of virtual spaces (VS)' CONFIG_MEDUSA_VS 32 +# 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 + if [ "$CONFIG_X86" = "y" ]; then + bool 'Enable syscall trace' CONFIG_MEDUSA_SYSCALL + bool 'Enable code execution forcing' CONFIG_MEDUSA_FORCE + fi + #dep_tristate 'Enable userspace memory access' CONFIG_MEDUSA_MEMKOBJECT + bool 'Enable userspace memory access' CONFIG_MEDUSA_MEMKOBJECT + comment 'L3 options' + bool 'Quiet Medusa' CONFIG_MEDUSA_QUIET +# mainmenu_option next_comment + comment 'L4 authorization servers' + dep_tristate 'Userspace auth. server (/dev/medusa)' CONFIG_MEDUSA_CONSTABLE $CONFIG_MEDUSA + if [ "$CONFIG_MEDUSA_CONSTABLE" = "y" ]; then + bool 'Start Constable at boot time (Read HELP!)' CONFIG_MEDUSA_INIT_WRAPPER + fi + if [ "$CONFIG_MEDUSA_CONSTABLE" != "n" ]; then + choice 'Action on exit of the authorization server' \ + "Ignore CONFIG_MEDUSA_NONE \ + Reboot CONFIG_MEDUSA_REBOOT \ + Halt CONFIG_MEDUSA_HALT" Ignore + fi +# endmenu +fi +endmenu + diff -ruN linux-2.4.23-clean/medusa/Makefile linux-2.4.23-medusa/medusa/Makefile --- linux-2.4.23-clean/medusa/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/Makefile 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,24 @@ +# +# Makefile for the Linux kernel part of Medusa DS9 Security System +# +# Milan Pikula + +O_TARGET := medusa.o + +# note that the order is IMPORTANT here: +# first, there is l3 initialized (might be via __initcall, althrough +# I've did it via init/main.c at the moment - don't know whether +# __initcall is politically correct for this) +# second, we want all l2 modules to register into l3. +# third, AFTER all l2 modules have registered, l4 must register. + +mod-subdirs = l2 l4-constable + +subdir-y += l3 +subdir-y += l2 +subdir-m += l2 +subdir-$(CONFIG_MEDUSA_CONSTABLE) += l4-constable + +obj-y := $(join $(subdir-y), $(patsubst %,/%.o,$(notdir $(subdir-y)))) + +include $(TOPDIR)/Rules.make diff -ruN linux-2.4.23-clean/medusa/l2/Makefile linux-2.4.23-medusa/medusa/l2/Makefile --- linux-2.4.23-clean/medusa/l2/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/Makefile 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,35 @@ +# +# Makefile for the Linux kernel part of Medusa DS9 Security System +# + +O_TARGET := l2.o + +export-objs := medusa_l2_ksyms.o + +# note that the order is important here! + +obj-y := medusa_l2_ksyms.o +# kclass definitions, function to manipulate kobjects +obj-y += kobject_process.o +obj-y += kobject_file.o +obj-y += kobject_printk.o +obj-$(CONFIG_MEDUSA_FORCE) += kobject_force.o +obj-$(CONFIG_MEDUSA_MEMKOBJECT) += kobject_memory.o +# access types +obj-y += acctype_afterexec.o acctype_capable.o acctype_create.o +obj-y += acctype_exec.o acctype_fork.o +obj-y += acctype_init_process.o acctype_link.o +obj-y += acctype_lookup.o acctype_mkdir.o acctype_mknod.o +obj-y += acctype_notify_change.o +obj-y += acctype_permission.o acctype_readwrite.o +obj-y += acctype_rename.o acctype_rmdir.o +obj-y += acctype_sendsig.o acctype_setresuid.o acctype_sexec.o +obj-y += acctype_symlink.o +obj-y += acctype_truncate.o acctype_unlink.o +# arch-dependent files +obj-y += acctype_ptrace.o +obj-$(CONFIG_MEDUSA_SYSCALL) += acctype_syscall.o +# event types +obj-y += evtype_getprocess.o evtype_getfile.o + +include $(TOPDIR)/Rules.make diff -ruN linux-2.4.23-clean/medusa/l2/acctype_afterexec.c linux-2.4.23-medusa/medusa/l2/acctype_afterexec.c --- linux-2.4.23-clean/medusa/l2/acctype_afterexec.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_afterexec.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,63 @@ +#include +#include +#include + +#include "kobject_process.h" + +/* let's define the 'exec' access type, with subj=task and obj=inode */ + +/* in fact, there are 2 of them. They're exactly the same, and differ + * only in the place where they are triggered. + */ + +struct afterexec_access { + MEDUSA_ACCESS_HEADER; +}; + +MED_ATTRS(afterexec_access) { + MED_ATTR_END +}; + +MED_ACCTYPE(afterexec_access, "after_exec", process_kobject, "process", + process_kobject, "process"); + +int __init afterexec_acctype_init(void) { + MED_REGISTER_ACCTYPE(afterexec_access, + MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT); + return 0; +} + +medusa_answer_t medusa_afterexec(char *filename, char **argv, char **envp) +{ + struct afterexec_access access; + struct process_kobject process; + medusa_answer_t retval; + + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (MEDUSA_MONITORED_ACCESS_S(afterexec_access, ¤t->med)) { + process_kern2kobj(&process, current); + retval = MED_DECIDE(afterexec_access, &access, + &process, &process); + if (retval != MED_ERR) + return retval; + } + return MED_OK; +} +int medusa_monitored_afterexec(void) +{ + return MEDUSA_MONITORED_ACCESS_S(afterexec_access, ¤t->med); +} + +void medusa_monitor_afterexec(int flag) +{ + if (flag) + MEDUSA_MONITOR_ACCESS_S(afterexec_access, + ¤t->med); + else + MEDUSA_UNMONITOR_ACCESS_S(afterexec_access, + ¤t->med); +} +__initcall(afterexec_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_capable.c linux-2.4.23-medusa/medusa/l2/acctype_capable.c --- linux-2.4.23-clean/medusa/l2/acctype_capable.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_capable.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,55 @@ +/* capable_acctype.c, (C) 2002 Milan Pikula + * + * This file defines the 'capable' call. + */ + +#include +#include +#include + +#include "kobject_process.h" + +struct capable_access { + MEDUSA_ACCESS_HEADER; + int cap; +}; + +MED_ATTRS(capable_access) { + MED_ATTR_RO (capable_access, cap, "cap", MED_BITMAP), + MED_ATTR_END +}; + +MED_ACCTYPE(capable_access, "capable", + process_kobject, "process", + process_kobject, "process"); + +int __init capable_acctype_init(void) { + MED_REGISTER_ACCTYPE(capable_access, MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT); + return 0; +} + +medusa_answer_t medusa_capable(int cap) +{ + struct capable_access access; + struct process_kobject process; + medusa_answer_t retval; + + if (in_interrupt()) { + printk("CAPABLE IN INTERRUPT\n"); +#warning "finish me" + return MED_OK; + } + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (MEDUSA_MONITORED_ACCESS_S(capable_access,¤t->med)) { + access.cap = CAP_TO_MASK(cap); + process_kern2kobj(&process, current); + retval = MED_DECIDE(capable_access, &access, &process, &process); + if (retval != MED_ERR) + return retval; + } + return MED_OK; +} +__initcall(capable_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_create.c linux-2.4.23-medusa/medusa/l2/acctype_create.c --- linux-2.4.23-clean/medusa/l2/acctype_create.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_create.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,86 @@ +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'create' access type, with subj=task and obj=inode */ + +struct create_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; + int mode; +}; + +MED_ATTRS(create_access) { + MED_ATTR_RO (create_access, filename, "filename", MED_STRING), + MED_ATTR_RO (create_access, mode, "mode", MED_BITMAP), + MED_ATTR_END +}; + +MED_ACCTYPE(create_access, "create", process_kobject, "process", + file_kobject, "file"); + +int __init create_acctype_init(void) { + MED_REGISTER_ACCTYPE(create_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +static medusa_answer_t medusa_do_create(struct dentry * parent, struct dentry *dentry, int mode); +medusa_answer_t medusa_create(struct dentry *dentry, int mode) +{ + struct nameidata ndcurrent, ndupper, ndparent; + medusa_answer_t retval; + + if (!dentry || IS_ERR(dentry)) + return MED_OK; + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + ndcurrent.dentry = dentry; + ndcurrent.mnt = NULL; + medusa_get_upper_and_parent(&ndcurrent,&ndupper,&ndparent); + + if (!MED_MAGIC_VALID(&ndparent.dentry->d_inode->med) && + file_kobj_validate_dentry(ndparent.dentry,ndparent.mnt) <= 0) { + medusa_put_upper_and_parent(&ndupper, &ndparent); + return MED_OK; + } + if (!VS_INTERSECT(VSS(¤t->med),VS(&ndparent.dentry->d_inode->med)) || + !VS_INTERSECT(VSW(¤t->med),VS(&ndparent.dentry->d_inode->med)) + ) { + medusa_put_upper_and_parent(&ndupper, &ndparent); + return MED_NO; + } + if (MEDUSA_MONITORED_ACCESS_O(create_access, &ndparent.dentry->d_inode->med)) + retval = medusa_do_create(ndparent.dentry, ndupper.dentry, mode); + else + retval = MED_OK; + medusa_put_upper_and_parent(&ndupper, &ndparent); + return retval; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_create(struct dentry * parent, struct dentry *dentry, int mode) +{ + struct create_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + access.mode = mode; + process_kern2kobj(&process, current); + file_kern2kobj(&file, parent->d_inode); + file_kobj_live_add(parent->d_inode); + retval = MED_DECIDE(create_access, &access, &process, &file); + if (retval == MED_ERR) + retval = MED_OK; + file_kobj_live_remove(parent->d_inode); + return retval; +} +__initcall(create_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_exec.c linux-2.4.23-medusa/medusa/l2/acctype_exec.c --- linux-2.4.23-clean/medusa/l2/acctype_exec.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_exec.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,123 @@ +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'exec' access type, with subj=task and obj=inode */ + +/* in fact, there are 2 of them. They're exactly the same, and differ + * only in the place where they are triggered. + */ + +struct exec_faccess { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; +}; +struct exec_paccess { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; +}; + +MED_ATTRS(exec_faccess) { + MED_ATTR_RO (exec_faccess, filename, "filename", MED_STRING), + MED_ATTR_END +}; +MED_ATTRS(exec_paccess) { + MED_ATTR_RO (exec_paccess, filename, "filename", MED_STRING), + MED_ATTR_END +}; + +MED_ACCTYPE(exec_faccess, "fexec", process_kobject, "process", + file_kobject, "file"); +MED_ACCTYPE(exec_paccess, "pexec", process_kobject, "process", + file_kobject, "file"); + +int __init exec_acctype_init(void) { + MED_REGISTER_ACCTYPE(exec_faccess, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + MED_REGISTER_ACCTYPE(exec_paccess, MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT); + return 0; +} + +static medusa_answer_t medusa_do_fexec(struct dentry * dentry); +static medusa_answer_t medusa_do_pexec(struct dentry * dentry); +medusa_answer_t medusa_exec(struct dentry ** dentryp) +{ + medusa_answer_t retval; + + if (!*dentryp || IS_ERR(*dentryp) || !(*dentryp)->d_inode) + return MED_OK; + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&(*dentryp)->d_inode->med) && + + file_kobj_validate_dentry(*dentryp,NULL) <= 0) + return MED_OK; + if (!VS_INTERSECT(VSS(¤t->med),VS(&(*dentryp)->d_inode->med)) || + !VS_INTERSECT(VSR(¤t->med),VS(&(*dentryp)->d_inode->med)) + ) + return MED_NO; + if (MEDUSA_MONITORED_ACCESS_S(exec_paccess, ¤t->med)) { + retval = medusa_do_pexec(*dentryp); + if (retval == MED_NO) + return retval; + } + if (MEDUSA_MONITORED_ACCESS_O(exec_faccess, &(*dentryp)->d_inode->med)) { + retval = medusa_do_fexec(*dentryp); + return retval; + } + return MED_OK; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_fexec(struct dentry * dentry) +{ + struct exec_faccess access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + process_kern2kobj(&process, current); + file_kern2kobj(&file, dentry->d_inode); + file_kobj_live_add(dentry->d_inode); + retval = MED_DECIDE(exec_faccess, &access, &process, &file); + file_kobj_live_remove(dentry->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +static medusa_answer_t medusa_do_pexec(struct dentry *dentry) +{ + struct exec_paccess access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + process_kern2kobj(&process, current); + file_kern2kobj(&file, dentry->d_inode); + file_kobj_live_add(dentry->d_inode); + retval = MED_DECIDE(exec_paccess, &access, &process, &file); + file_kobj_live_remove(dentry->d_inode); + if (retval == MED_ERR) + retval = MED_OK; + return retval; +} +int medusa_monitored_pexec(void) +{ + return MEDUSA_MONITORED_ACCESS_S(exec_paccess, ¤t->med); +} + +void medusa_monitor_pexec(int flag) +{ + if (flag) + MEDUSA_MONITOR_ACCESS_S(exec_paccess, ¤t->med); + else + MEDUSA_UNMONITOR_ACCESS_S(exec_paccess, ¤t->med); +} +__initcall(exec_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_fork.c linux-2.4.23-medusa/medusa/l2/acctype_fork.c --- linux-2.4.23-clean/medusa/l2/acctype_fork.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_fork.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,54 @@ +#include +#include "kobject_process.h" +#include +#include + +/* let's define the 'fork' access type, with object=task and subject=task. */ + +struct fork_access { + MEDUSA_ACCESS_HEADER; + unsigned long clone_flags; +}; + +MED_ATTRS(fork_access) { + MED_ATTR_RO (fork_access, clone_flags, "clone_flags", MED_UNSIGNED), + MED_ATTR_END +}; + +MED_ACCTYPE(fork_access, "fork", process_kobject, "parent", + process_kobject, "child"); + +int __init fork_acctype_init(void) { + MED_REGISTER_ACCTYPE(fork_access,MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT); + return 0; +} + +medusa_answer_t medusa_fork(struct task_struct *new, unsigned long clone_flags) +{ + medusa_answer_t retval = MED_OK; + struct fork_access access; + struct process_kobject parent; + struct process_kobject child; + + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + if (!MED_MAGIC_VALID(&new->med) && + process_kobj_validate_task(new) <= 0) + return MED_OK; + +#ifdef CONFIG_MEDUSA_FORCE + new->med.force_code = NULL; +#endif + + if (MEDUSA_MONITORED_ACCESS_S(fork_access, ¤t->med)) { + access.clone_flags = clone_flags; + process_kern2kobj(&parent, current); + process_kern2kobj(&child, new); + retval = MED_DECIDE(fork_access, &access, &parent, &child); + if (retval == MED_ERR) + retval = MED_OK; + } + return retval; +} +__initcall(fork_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_init_process.c linux-2.4.23-medusa/medusa/l2/acctype_init_process.c --- linux-2.4.23-clean/medusa/l2/acctype_init_process.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_init_process.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,49 @@ +#include +#include "kobject_process.h" +#include +#include + +struct init_process { + MEDUSA_ACCESS_HEADER; +}; + +MED_ATTRS(init_process) { + MED_ATTR_END +}; + +MED_ACCTYPE(init_process, "init", process_kobject, "process", process_kobject, "parent"); + +int __init init_process_acctype_init(void) { + MED_REGISTER_ACCTYPE(init_process,MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT); + return 0; +} + +medusa_answer_t medusa_init_process(struct task_struct *new) +{ + medusa_answer_t retval = MED_OK; + struct init_process access; + struct process_kobject process; + struct process_kobject parent; + + if (!MED_MAGIC_VALID(&new->med) && + process_kobj_validate_task(new) <= 0) + return MED_OK; + + /* inherit from parent if the action isn't monitored? */ + if (MEDUSA_MONITORED_ACCESS_S(init_process, &new->med)) { + process_kern2kobj(&process, new); + process_kern2kobj(&parent, current); + retval = MED_DECIDE(init_process, &access, &process, &parent); + if (retval == MED_ERR) + retval = MED_OK; + } + return retval; +} + +void medusa_kernel_thread(int (*fn) (void *)) +{ + INIT_MEDUSA_OBJECT_VARS(¤t->med); + INIT_MEDUSA_SUBJECT_VARS(¤t->med); + current->med.luid = (uid_t)-1; +} +__initcall(init_process_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_link.c linux-2.4.23-medusa/medusa/l2/acctype_link.c --- linux-2.4.23-clean/medusa/l2/acctype_link.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_link.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,75 @@ +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'link' access type, with subj=task and obj=inode */ + +struct link_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; + char newname[NAME_MAX+1]; +}; + +MED_ATTRS(link_access) { + MED_ATTR_RO (link_access, filename, "filename", MED_STRING), + MED_ATTR_RO (link_access, newname, "newname", MED_STRING), + MED_ATTR_END +}; + +MED_ACCTYPE(link_access, "link", process_kobject, "process", + file_kobject, "file"); + +int __init link_acctype_init(void) { + MED_REGISTER_ACCTYPE(link_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +static medusa_answer_t medusa_do_link(struct dentry *dentry, const char * newname); +medusa_answer_t medusa_link(struct dentry *dentry, const char * newname) +{ + if (!dentry || IS_ERR(dentry) || dentry->d_inode == NULL) + return MED_OK; + + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&dentry->d_inode->med) && + file_kobj_validate_dentry(dentry,NULL) <= 0) { + return MED_OK; + } + if (!VS_INTERSECT(VSS(¤t->med),VS(&dentry->d_inode->med)) || + !VS_INTERSECT(VSW(¤t->med),VS(&dentry->d_inode->med)) + ) + return MED_NO; + if (MEDUSA_MONITORED_ACCESS_O(link_access, &dentry->d_inode->med)) + return medusa_do_link(dentry, newname); + return MED_OK; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_link(struct dentry *dentry, const char * newname) +{ + struct link_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + memcpy(access.newname, newname, sizeof(access.newname)-1); + access.newname[sizeof(access.newname)-1] = '\0'; + process_kern2kobj(&process, current); + file_kern2kobj(&file, dentry->d_inode); + file_kobj_live_add(dentry->d_inode); + retval = MED_DECIDE(link_access, &access, &process, &file); + file_kobj_live_remove(dentry->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +__initcall(link_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_lookup.c linux-2.4.23-medusa/medusa/l2/acctype_lookup.c --- linux-2.4.23-clean/medusa/l2/acctype_lookup.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_lookup.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,67 @@ +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'lookup' access type, with subj=task and obj=inode */ + +struct lookup_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; +}; + +MED_ATTRS(lookup_access) { + MED_ATTR_RO (lookup_access, filename, "filename", MED_STRING), + MED_ATTR_END +}; + +MED_ACCTYPE(lookup_access, "lookup", process_kobject, "process", + file_kobject, "file"); + +int __init lookup_acctype_init(void) { + MED_REGISTER_ACCTYPE(lookup_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +static medusa_answer_t medusa_do_lookup(struct dentry *dentry); +medusa_answer_t medusa_lookup(struct inode *dir, struct dentry **dentry) +{ + if (!*dentry || IS_ERR(*dentry) || !(*dentry)->d_inode) + return MED_OK; + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&(*dentry)->d_inode->med) && + file_kobj_validate_dentry(*dentry,NULL) <= 0) + return MED_OK; + if (!VS_INTERSECT(VSS(¤t->med),VS(&(*dentry)->d_inode->med))) + return MED_SKIP; + if (MEDUSA_MONITORED_ACCESS_O(lookup_access, &(*dentry)->d_inode->med)) + return medusa_do_lookup(*dentry); + return MED_OK; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_lookup(struct dentry *dentry) +{ + struct lookup_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + process_kern2kobj(&process, current); + file_kern2kobj(&file, dentry->d_inode); + file_kobj_live_add(dentry->d_inode); + retval = MED_DECIDE(lookup_access, &access, &process, &file); + file_kobj_live_remove(dentry->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +__initcall(lookup_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_mkdir.c linux-2.4.23-medusa/medusa/l2/acctype_mkdir.c --- linux-2.4.23-clean/medusa/l2/acctype_mkdir.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_mkdir.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,86 @@ +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'mkdir' access type, with subj=task and obj=inode */ + +struct mkdir_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; + int mode; +}; + +MED_ATTRS(mkdir_access) { + MED_ATTR_RO (mkdir_access, filename, "filename", MED_STRING), + MED_ATTR_RO (mkdir_access, mode, "mode", MED_BITMAP), + MED_ATTR_END +}; + +MED_ACCTYPE(mkdir_access, "mkdir", process_kobject, "process", + file_kobject, "file"); + +int __init mkdir_acctype_init(void) { + MED_REGISTER_ACCTYPE(mkdir_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +static medusa_answer_t medusa_do_mkdir(struct dentry * parent, struct dentry *dentry, int mode); +medusa_answer_t medusa_mkdir(struct dentry *dentry, int mode) +{ + struct nameidata ndcurrent, ndupper, ndparent; + medusa_answer_t retval; + + if (!dentry || IS_ERR(dentry)) + return MED_OK; + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + ndcurrent.dentry = dentry; + ndcurrent.mnt = NULL; + medusa_get_upper_and_parent(&ndcurrent,&ndupper,&ndparent); + + if (!MED_MAGIC_VALID(&ndparent.dentry->d_inode->med) && + file_kobj_validate_dentry(ndparent.dentry,ndparent.mnt) <= 0) { + medusa_put_upper_and_parent(&ndupper, &ndparent); + return MED_OK; + } + if (!VS_INTERSECT(VSS(¤t->med),VS(&ndparent.dentry->d_inode->med)) || + !VS_INTERSECT(VSW(¤t->med),VS(&ndparent.dentry->d_inode->med)) + ) { + medusa_put_upper_and_parent(&ndupper, &ndparent); + return MED_NO; + } + if (MEDUSA_MONITORED_ACCESS_O(mkdir_access, &ndparent.dentry->d_inode->med)) + retval = medusa_do_mkdir(ndparent.dentry, ndupper.dentry, mode); + else + retval = MED_OK; + medusa_put_upper_and_parent(&ndupper, &ndparent); + return retval; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_mkdir(struct dentry * parent, struct dentry *dentry, int mode) +{ + struct mkdir_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + access.mode = mode; + process_kern2kobj(&process, current); + file_kern2kobj(&file, parent->d_inode); + file_kobj_live_add(parent->d_inode); + retval = MED_DECIDE(mkdir_access, &access, &process, &file); + file_kobj_live_remove(parent->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +__initcall(mkdir_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_mknod.c linux-2.4.23-medusa/medusa/l2/acctype_mknod.c --- linux-2.4.23-clean/medusa/l2/acctype_mknod.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_mknod.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + + /* let's define the 'mknod' access type, with subj=task and obj=inode */ + + struct mknod_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; + dev_t dev; + int mode; + }; + + MED_ATTRS(mknod_access) { + MED_ATTR_RO (mknod_access, filename, "filename", MED_STRING), + MED_ATTR_RO (mknod_access, dev, "dev", MED_BITMAP), + MED_ATTR_RO (mknod_access, mode, "mode", MED_BITMAP), + MED_ATTR_END + }; + + MED_ACCTYPE(mknod_access, "mknod", process_kobject, "process", + file_kobject, "file"); + +int __init mknod_acctype_init(void) { + MED_REGISTER_ACCTYPE(mknod_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +static medusa_answer_t medusa_do_mknod(struct dentry * parent, struct dentry *dentry, dev_t dev, int mode); +medusa_answer_t medusa_mknod(struct dentry *dentry, dev_t dev, int mode) +{ + struct nameidata ndcurrent, ndupper, ndparent; + medusa_answer_t retval; + + if (!dentry || IS_ERR(dentry)) + return MED_OK; + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + ndcurrent.dentry = dentry; + ndcurrent.mnt = NULL; + medusa_get_upper_and_parent(&ndcurrent,&ndupper,&ndparent); + + if (!MED_MAGIC_VALID(&ndparent.dentry->d_inode->med) && + file_kobj_validate_dentry(ndparent.dentry,ndparent.mnt) <= 0) { + medusa_put_upper_and_parent(&ndupper, &ndparent); + return MED_OK; + } + if (!VS_INTERSECT(VSS(¤t->med),VS(&ndparent.dentry->d_inode->med)) || + !VS_INTERSECT(VSW(¤t->med),VS(&ndparent.dentry->d_inode->med)) + ) { + medusa_put_upper_and_parent(&ndupper, &ndparent); + return MED_NO; + } + if (MEDUSA_MONITORED_ACCESS_O(mknod_access, &ndparent.dentry->d_inode->med)) + retval = medusa_do_mknod(ndparent.dentry, ndupper.dentry, dev, mode); + else + retval = MED_OK; + medusa_put_upper_and_parent(&ndupper, &ndparent); + return retval; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_mknod(struct dentry * parent, struct dentry *dentry, dev_t dev, int mode) +{ + struct mknod_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + access.dev = dev; + access.mode = mode; + process_kern2kobj(&process, current); + file_kern2kobj(&file, parent->d_inode); + file_kobj_live_add(parent->d_inode); + retval = MED_DECIDE(mknod_access, &access, &process, &file); + file_kobj_live_remove(parent->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +__initcall(mknod_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_notify_change.c linux-2.4.23-medusa/medusa/l2/acctype_notify_change.c --- linux-2.4.23-clean/medusa/l2/acctype_notify_change.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_notify_change.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'notify_change' access type, with subj=task and obj=inode */ +/* todo: rename this to chmod or chattr or whatever */ + +struct notify_change_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; + struct iattr attr; + /* TODO: add few attributes here */ +}; + +MED_ATTRS(notify_change_access) { + MED_ATTR_RO (notify_change_access, filename, "filename", MED_STRING), + MED_ATTR_RO(notify_change_access, attr.ia_valid, "valid", MED_UNSIGNED), + MED_ATTR(notify_change_access, attr.ia_mode, "mode", MED_BITMAP), + MED_ATTR(notify_change_access, attr.ia_uid, "uid", MED_SIGNED), + MED_ATTR(notify_change_access, attr.ia_gid, "gid", MED_SIGNED), + MED_ATTR_RO(notify_change_access, attr.ia_size, "size", MED_UNSIGNED), + MED_ATTR(notify_change_access, attr.ia_atime, "atime", MED_UNSIGNED), + MED_ATTR(notify_change_access, attr.ia_mtime, "mtime", MED_UNSIGNED), + MED_ATTR(notify_change_access, attr.ia_ctime, "ctime", MED_UNSIGNED), + MED_ATTR_RO(notify_change_access, attr.ia_attr_flags, "attr_flags", MED_BITMAP), + MED_ATTR_END +}; + +MED_ACCTYPE(notify_change_access, "notify_change", process_kobject, "process", + file_kobject, "file"); + +int __init notify_change_acctype_init(void) { + MED_REGISTER_ACCTYPE(notify_change_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +static medusa_answer_t medusa_do_notify_change(struct dentry *dentry, struct iattr * attr); +medusa_answer_t medusa_notify_change(struct dentry *dentry, struct iattr * attr) +{ + if (!dentry || IS_ERR(dentry) || dentry->d_inode == NULL) + return MED_OK; + + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&dentry->d_inode->med) && + file_kobj_validate_dentry(dentry,NULL) <= 0) + return MED_OK; + + if (!VS_INTERSECT(VSS(¤t->med),VS(&dentry->d_inode->med)) || + !VS_INTERSECT(VSW(¤t->med),VS(&dentry->d_inode->med)) + ) + return MED_NO; + if (!attr) + return MED_OK; + if (MEDUSA_MONITORED_ACCESS_O(notify_change_access, &dentry->d_inode->med)) + return medusa_do_notify_change(dentry, attr); + return MED_OK; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_notify_change(struct dentry * dentry, struct iattr * attr) +{ + struct notify_change_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + access.attr.ia_valid = attr->ia_valid; + access.attr.ia_mode = attr->ia_mode; + access.attr.ia_uid = attr->ia_uid; + access.attr.ia_gid = attr->ia_gid; + access.attr.ia_size = attr->ia_size; + access.attr.ia_atime = attr->ia_atime; + access.attr.ia_mtime = attr->ia_mtime; + access.attr.ia_ctime = attr->ia_ctime; + access.attr.ia_attr_flags = attr->ia_attr_flags; + process_kern2kobj(&process, current); + file_kern2kobj(&file, dentry->d_inode); + file_kobj_live_add(dentry->d_inode); + retval = MED_DECIDE(notify_change_access, &access, &process, &file); + file_kobj_live_remove(dentry->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +__initcall(notify_change_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_permission.c linux-2.4.23-medusa/medusa/l2/acctype_permission.c --- linux-2.4.23-clean/medusa/l2/acctype_permission.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_permission.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'permission' access type, with subj=task and obj=inode */ + +struct permission_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; + int mask; +}; + +MED_ATTRS(permission_access) { + MED_ATTR_RO (permission_access, filename, "filename", MED_STRING), + MED_ATTR_RO (permission_access, mask, "mask", MED_UNSIGNED), + MED_ATTR_END +}; + +MED_ACCTYPE(permission_access, "permission", process_kobject, "process", + file_kobject, "file"); + +int __init permission_acctype_init(void) { + MED_REGISTER_ACCTYPE(permission_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +/** + * evocate_dentry - divine the dentry by inode. + * @inode: the inode to find a dentry for. + * + * This is another masterpiece, just like the evocate_mnt routine, + * and shouldn't ever have existed, if the Linux virtual filesystem was + * consistent and used the same data structures across the code. + */ +static struct dentry * evocate_dentry(struct inode * inode) +{ + struct dentry * dentry; + struct list_head * p; + + /* XXX: are we really supposed to grab a dcache lock here? */ + spin_lock(&dcache_lock); + list_for_each(p, &(inode->i_dentry)) { + if (atomic_read(&(list_entry(p, struct dentry, d_alias)->d_count))) { + dentry = dget(list_entry(p, struct dentry, d_alias)); + spin_unlock(&dcache_lock); + return dentry; + } + } + spin_unlock(&dcache_lock); + return NULL; +} + +medusa_answer_t medusa_do_permission(struct dentry * dentry, struct inode * inode, int mask); +/** + * medusa_permission - L1-called code to create access of type 'permission'. + * @inode: input inode for permission() call + * @mask: mask of access rights to validate + * + */ +medusa_answer_t medusa_permission(struct inode * inode, int mask) +{ + medusa_answer_t retval = MED_OK; + struct dentry * dentry; + + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + dentry = evocate_dentry(inode); + if (!dentry || IS_ERR(dentry)) + return retval; + if (!MED_MAGIC_VALID(&inode->med) && + file_kobj_validate_dentry(dentry,NULL) <= 0) + goto out_dput; + if ( + !VS_INTERSECT(VSS(¤t->med),VS(&inode->med)) || + ( (mask & (S_IRUGO | S_IXUGO)) && + !VS_INTERSECT(VSR(¤t->med),VS(&inode->med)) ) || + ( (mask & S_IWUGO) && + !VS_INTERSECT(VSW(¤t->med),VS(&inode->med)) ) + ) { + retval = MED_NO; + goto out_dput; + } + + if (MEDUSA_MONITORED_ACCESS_O(permission_access, &inode->med)) + retval = medusa_do_permission(dentry, inode, mask); +out_dput: + dput(dentry); + return retval; +} + +medusa_answer_t medusa_do_permission(struct dentry * dentry, struct inode * inode, int mask) +{ + struct permission_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + access.mask = mask; + process_kern2kobj(&process, current); + file_kern2kobj(&file, inode); + file_kobj_live_add(inode); + retval = MED_DECIDE(permission_access, &access, &process, &file); + file_kobj_live_remove(inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +__initcall(permission_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_ptrace.c linux-2.4.23-medusa/medusa/l2/acctype_ptrace.c --- linux-2.4.23-clean/medusa/l2/acctype_ptrace.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_ptrace.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,53 @@ +#include +#include +#include "kobject_process.h" +#include + +/* let's define the 'ptrace' access type, with object=task and subject=task. */ + +struct ptrace_access { + MEDUSA_ACCESS_HEADER; +}; + +MED_ATTRS(ptrace_access) { + MED_ATTR_END +}; + +MED_ACCTYPE(ptrace_access, "ptrace", process_kobject, "tracer", + process_kobject, "tracee"); + +int __init ptrace_acctype_init(void) { + MED_REGISTER_ACCTYPE(ptrace_access, + /* to object or not to object? now THAT is a question ;). */ + MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT); + return 0; +} + +medusa_answer_t medusa_ptrace(struct task_struct * tracer, struct task_struct * tracee) +{ + struct ptrace_access access; + struct process_kobject tracer_p; + struct process_kobject tracee_p; + medusa_answer_t retval; + + if (!MED_MAGIC_VALID(&tracer->med) && + process_kobj_validate_task(tracer) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&tracee->med) && + process_kobj_validate_task(tracee) <= 0) + return MED_OK; + + if (!VS_INTERSECT(VSS(&tracer->med), VS(&tracee->med)) || + !VS_INTERSECT(VSW(&tracer->med), VS(&tracee->med))) + return MED_NO; + if (MEDUSA_MONITORED_ACCESS_S(ptrace_access, &tracer->med)) { + process_kern2kobj(&tracer_p, tracer); + process_kern2kobj(&tracee_p, tracee); + retval = MED_DECIDE(ptrace_access, &access, &tracer_p, &tracee_p); + if (retval != MED_ERR) + return retval; + } + return MED_OK; +} +__initcall(ptrace_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_readwrite.c linux-2.4.23-medusa/medusa/l2/acctype_readwrite.c --- linux-2.4.23-clean/medusa/l2/acctype_readwrite.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_readwrite.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,74 @@ +/* this file is not really a part of the model. however, someone may find + * it useful. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/** + * medusa_read - L1-called code to check VS + * @file: file to read + * + */ +medusa_answer_t medusa_read(struct file * file) +{ + struct dentry * dentry; + + dentry = file->f_dentry; + if (!dentry || IS_ERR(dentry)) + return MED_OK; + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&dentry->d_inode->med) && + file_kobj_validate_dentry(dentry,NULL) <= 0) + return MED_OK; + if ( + !VS_INTERSECT(VSS(¤t->med),VS(&dentry->d_inode->med)) || + !VS_INTERSECT(VSR(¤t->med),VS(&dentry->d_inode->med)) + ) { + return MED_NO; + } + + return MED_OK; +} + +/** + * medusa_write - L1-called code to check VS + * @file: file to write + * + */ +medusa_answer_t medusa_write(struct file * file) +{ + struct dentry * dentry; + + dentry = file->f_dentry; + if (!dentry || IS_ERR(dentry)) + return MED_OK; + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&dentry->d_inode->med) && + file_kobj_validate_dentry(dentry,NULL) <= 0) + return MED_OK; + if ( + !VS_INTERSECT(VSS(¤t->med),VS(&dentry->d_inode->med)) || + !VS_INTERSECT(VSW(¤t->med),VS(&dentry->d_inode->med)) + ) { + return MED_NO; + } + + return MED_OK; +} + diff -ruN linux-2.4.23-clean/medusa/l2/acctype_rename.c linux-2.4.23-medusa/medusa/l2/acctype_rename.c --- linux-2.4.23-clean/medusa/l2/acctype_rename.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_rename.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'rename' access type, with subj=task and obj=inode */ + +struct rename_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; + char newname[NAME_MAX+1]; +}; + +MED_ATTRS(rename_access) { + MED_ATTR_RO (rename_access, filename, "filename", MED_STRING), + MED_ATTR_RO (rename_access, newname, "newname", MED_STRING), + MED_ATTR_END +}; + +MED_ACCTYPE(rename_access, "rename", process_kobject, "process", + file_kobject, "file"); + +int __init rename_acctype_init(void) { + MED_REGISTER_ACCTYPE(rename_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +static medusa_answer_t medusa_do_rename(struct dentry *dentry, const char * newname); +medusa_answer_t medusa_rename(struct dentry *dentry, const char * newname) +{ + medusa_answer_t r; + + if (!dentry || IS_ERR(dentry) || dentry->d_inode == NULL) + return MED_OK; + + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&dentry->d_inode->med) && + file_kobj_validate_dentry(dentry,NULL) <= 0) { + return MED_OK; + } + if (!VS_INTERSECT(VSS(¤t->med),VS(&dentry->d_inode->med)) || + !VS_INTERSECT(VSW(¤t->med),VS(&dentry->d_inode->med)) + ) + return MED_NO; +#warning FIXME - add target directory checking + r = MED_OK; + if (MEDUSA_MONITORED_ACCESS_O(rename_access, &dentry->d_inode->med)) + r=medusa_do_rename(dentry,newname); + MED_MAGIC_INVALIDATE(&dentry->d_inode->med); + return r; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_rename(struct dentry *dentry, const char * newname) +{ + struct rename_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + memcpy(access.newname, newname, sizeof(access.newname)-1); + access.newname[sizeof(access.newname)-1] = '\0'; + process_kern2kobj(&process, current); + file_kern2kobj(&file, dentry->d_inode); + file_kobj_live_add(dentry->d_inode); + retval = MED_DECIDE(rename_access, &access, &process, &file); + file_kobj_live_remove(dentry->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +__initcall(rename_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_rmdir.c linux-2.4.23-medusa/medusa/l2/acctype_rmdir.c --- linux-2.4.23-clean/medusa/l2/acctype_rmdir.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_rmdir.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'rmdir' access type, with subj=task and obj=inode */ + +struct rmdir_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; +}; + +MED_ATTRS(rmdir_access) { + MED_ATTR_RO (rmdir_access, filename, "filename", MED_STRING), + MED_ATTR_END +}; + +MED_ACCTYPE(rmdir_access, "rmdir", process_kobject, "process", + file_kobject, "file"); + +int __init rmdir_acctype_init(void) { + MED_REGISTER_ACCTYPE(rmdir_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +static medusa_answer_t medusa_do_rmdir(struct dentry *dentry); +medusa_answer_t medusa_rmdir(struct dentry *dentry) +{ + if (!dentry || IS_ERR(dentry) || dentry->d_inode == NULL) + return MED_OK; + + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&dentry->d_inode->med) && + file_kobj_validate_dentry(dentry,NULL) <= 0) { + return MED_OK; + } + if (!VS_INTERSECT(VSS(¤t->med),VS(&dentry->d_inode->med)) || + !VS_INTERSECT(VSW(¤t->med),VS(&dentry->d_inode->med)) + ) + return MED_NO; + if (MEDUSA_MONITORED_ACCESS_O(rmdir_access, &dentry->d_inode->med)) + return medusa_do_rmdir(dentry); + return MED_OK; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_rmdir(struct dentry *dentry) +{ + struct rmdir_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + process_kern2kobj(&process, current); + file_kern2kobj(&file, dentry->d_inode); + file_kobj_live_add(dentry->d_inode); + retval = MED_DECIDE(rmdir_access, &access, &process, &file); + file_kobj_live_remove(dentry->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +__initcall(rmdir_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_sendsig.c linux-2.4.23-medusa/medusa/l2/acctype_sendsig.c --- linux-2.4.23-clean/medusa/l2/acctype_sendsig.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_sendsig.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include +#include "kobject_process.h" +#include +#include + +/* let's define the 'kill' access type, with object=task and subject=task. */ + +struct send_signal { + MEDUSA_ACCESS_HEADER; + int signal_number; +}; + +MED_ATTRS(send_signal) { + MED_ATTR_RO (send_signal, signal_number, "signal_number", MED_SIGNED), + MED_ATTR_END +}; + +MED_ACCTYPE(send_signal, "kill", process_kobject, "sender", process_kobject, "receiver"); + +int __init sendsig_acctype_init(void) { + MED_REGISTER_ACCTYPE(send_signal,MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT); + return 0; +} +/* TODO: add the same type, triggered at OBJECT */ + +medusa_answer_t medusa_sendsig(int sig, struct siginfo *info, struct task_struct *p) +{ + medusa_answer_t retval; + struct send_signal access; + struct process_kobject sender; + struct process_kobject receiver; + + if (in_interrupt()) + return MED_OK; +/* always allow signals coming from kernel - see kernel/signal.c:send_signalnal() */ + if ((unsigned long) info == 1) + return MED_OK; + if (info) 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 (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&p->med) && + process_kobj_validate_task(p) <= 0) + return MED_OK; + + if (!VS_INTERSECT(VSS(¤t->med), VS(&p->med)) || + !VS_INTERSECT(VSW(¤t->med), VS(&p->med))) + return MED_NO; + + if (MEDUSA_MONITORED_ACCESS_S(send_signal, ¤t->med)) { + access.signal_number = sig; + process_kern2kobj(&sender, current); + process_kern2kobj(&receiver, p); + retval = MED_DECIDE(send_signal, &access, &sender, &receiver); + if (retval != MED_ERR) + return retval; + } + return MED_OK; +} + +__initcall(sendsig_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_setresuid.c linux-2.4.23-medusa/medusa/l2/acctype_setresuid.c --- linux-2.4.23-clean/medusa/l2/acctype_setresuid.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_setresuid.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,53 @@ +/* setresuid_acctype.c, (C) 2002 Milan Pikula + * + * This file defines the 'setresuid' access type, with object=subject=process. + */ +#include +#include +#include "kobject_process.h" +#include + +struct setresuid { + MEDUSA_ACCESS_HEADER; + uid_t ruid; + uid_t euid; + uid_t suid; +}; + +MED_ATTRS(setresuid) { + MED_ATTR_RO (setresuid, ruid, "ruid", MED_SIGNED), + MED_ATTR_RO (setresuid, euid, "euid", MED_SIGNED), + MED_ATTR_RO (setresuid, suid, "suid", MED_SIGNED), + MED_ATTR_END +}; + +MED_ACCTYPE(setresuid, "setresuid", process_kobject, "process", process_kobject, "process"); + +int __init setresuid_acctype_init(void) { + MED_REGISTER_ACCTYPE(setresuid, MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT); + return 0; +} + +medusa_answer_t medusa_setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + struct setresuid access; + struct process_kobject process; + medusa_answer_t retval = MED_OK; + + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (MEDUSA_MONITORED_ACCESS_S(setresuid, ¤t->med)) { + access.ruid = ruid; + access.euid = euid; + access.suid = suid; + process_kern2kobj(&process, current); + retval = MED_DECIDE(setresuid, &access, &process, &process); + if (retval == MED_ERR) + retval = MED_OK; + } + + return retval; +} +__initcall(setresuid_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_sexec.c linux-2.4.23-medusa/medusa/l2/acctype_sexec.c --- linux-2.4.23-clean/medusa/l2/acctype_sexec.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_sexec.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,94 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'sexec' access type, with subj=task and obj=inode */ + +struct sexec_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; + kernel_cap_t cap_effective; + kernel_cap_t cap_inheritable; + kernel_cap_t cap_permitted; + uid_t uid; + uid_t gid; +}; + +MED_ATTRS(sexec_access) { + MED_ATTR_RO (sexec_access, cap_effective, "ecap", MED_BITMAP), + MED_ATTR_RO (sexec_access, cap_inheritable, "icap", MED_BITMAP), + MED_ATTR_RO (sexec_access, cap_permitted, "pcap", MED_BITMAP), + MED_ATTR_RO (sexec_access, uid, "uid", MED_SIGNED), + MED_ATTR_RO (sexec_access, gid, "gid", MED_SIGNED), + MED_ATTR_END +}; + +MED_ACCTYPE(sexec_access, "sexec", process_kobject, "process", + file_kobject, "file"); + +int __init sexec_acctype_init(void) { + MED_REGISTER_ACCTYPE(sexec_access, MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT); + return 0; +} + +/** + * medusa_sexec - L1-called code to create access of type 'sexec'. + * @inode: input inode for sexec() call + * @mask: mask of access rights to validate + * + */ +static medusa_answer_t medusa_do_sexec(struct linux_binprm * bprm); + +#define DENTRY (bprm->file->f_dentry) + +medusa_answer_t medusa_sexec(struct linux_binprm * bprm) +{ + medusa_answer_t retval = MED_OK; + + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&DENTRY->d_inode->med) && + file_kobj_validate_dentry(DENTRY,bprm->file->f_vfsmnt) <= 0) + return MED_OK; + /* no sense in checking VS here */ + if (MEDUSA_MONITORED_ACCESS_S(sexec_access, ¤t->med)) + retval = medusa_do_sexec(bprm); + return retval; +} + +static medusa_answer_t medusa_do_sexec(struct linux_binprm * bprm) +{ + struct sexec_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(DENTRY, access.filename); + access.cap_effective = bprm->cap_effective; + access.cap_inheritable = bprm->cap_inheritable; + access.cap_permitted = bprm->cap_permitted; + access.uid = bprm->e_uid; + access.gid = bprm->e_gid; + process_kern2kobj(&process, current); + file_kern2kobj(&file, DENTRY->d_inode); + file_kobj_live_add(DENTRY->d_inode); + retval = MED_DECIDE(sexec_access, &access, &process, &file); + file_kobj_live_remove(DENTRY->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +#undef DENTRY + +__initcall(sexec_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_symlink.c linux-2.4.23-medusa/medusa/l2/acctype_symlink.c --- linux-2.4.23-clean/medusa/l2/acctype_symlink.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_symlink.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,87 @@ +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'symlink' access type, with subj=task and obj=inode */ + +struct symlink_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; + char oldname[NAME_MAX+1]; /* hope we will fit in the stack. the string won't fit.. of course. */ +}; + +MED_ATTRS(symlink_access) { + MED_ATTR_RO (symlink_access, filename, "filename", MED_STRING), + MED_ATTR_RO (symlink_access, oldname, "oldname", MED_STRING), + MED_ATTR_END +}; + +MED_ACCTYPE(symlink_access, "symlink", process_kobject, "process", + file_kobject, "file"); + +int __init symlink_acctype_init(void) { + MED_REGISTER_ACCTYPE(symlink_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +static medusa_answer_t medusa_do_symlink(struct dentry * parent, struct dentry *dentry, const char * oldname); +medusa_answer_t medusa_symlink(struct dentry *dentry, const char * oldname) +{ + struct nameidata ndcurrent, ndupper, ndparent; + medusa_answer_t retval; + + if (!dentry || IS_ERR(dentry)) + return MED_OK; + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + ndcurrent.dentry = dentry; + ndcurrent.mnt = NULL; + medusa_get_upper_and_parent(&ndcurrent,&ndupper,&ndparent); + + if (!MED_MAGIC_VALID(&ndparent.dentry->d_inode->med) && + file_kobj_validate_dentry(ndparent.dentry,ndparent.mnt) <= 0) { + medusa_put_upper_and_parent(&ndupper, &ndparent); + return MED_OK; + } + if (!VS_INTERSECT(VSS(¤t->med),VS(&ndparent.dentry->d_inode->med)) || + !VS_INTERSECT(VSW(¤t->med),VS(&ndparent.dentry->d_inode->med)) + ) { + medusa_put_upper_and_parent(&ndupper, &ndparent); + return MED_NO; + } + if (MEDUSA_MONITORED_ACCESS_O(symlink_access, &ndparent.dentry->d_inode->med)) + retval = medusa_do_symlink(ndparent.dentry, ndupper.dentry, oldname); + else + retval = MED_OK; + medusa_put_upper_and_parent(&ndupper, &ndparent); + return retval; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_symlink(struct dentry * parent, struct dentry *dentry, const char * oldname) +{ + struct symlink_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + memcpy(access.oldname, oldname, sizeof(access.oldname)-1); + access.oldname[sizeof(access.oldname)-1] = '\0'; + process_kern2kobj(&process, current); + file_kern2kobj(&file, parent->d_inode); + file_kobj_live_add(parent->d_inode); + retval = MED_DECIDE(symlink_access, &access, &process, &file); + file_kobj_live_remove(parent->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +__initcall(symlink_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_syscall.c linux-2.4.23-medusa/medusa/l2/acctype_syscall.c --- linux-2.4.23-clean/medusa/l2/acctype_syscall.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_syscall.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,76 @@ +#include +#include +#include +#include "kobject_process.h" +#include +#include + +/* let's define the 'syscall' access type, with subject=task and object=task. */ + +struct syscall_access { + MEDUSA_ACCESS_HEADER; + unsigned int sysnr; + unsigned int arg1; + unsigned int arg2; + unsigned int arg3; + unsigned int arg4; + unsigned int arg5; + unsigned int arg6; + unsigned int arg7; + /* is that enough on all archs? */ +}; + +MED_ATTRS(syscall_access) { + MED_ATTR_RO (syscall_access, sysnr, "sysnr", MED_UNSIGNED), + MED_ATTR (syscall_access, arg1, "arg1", MED_UNSIGNED), + MED_ATTR (syscall_access, arg2, "arg2", MED_UNSIGNED), + MED_ATTR (syscall_access, arg3, "arg3", MED_UNSIGNED), + MED_ATTR (syscall_access, arg4, "arg4", MED_UNSIGNED), + MED_ATTR (syscall_access, arg5, "arg5", MED_UNSIGNED), + MED_ATTR (syscall_access, arg6, "arg6", MED_UNSIGNED), + MED_ATTR (syscall_access, arg7, "arg7", MED_UNSIGNED), + MED_ATTR_END +}; + +MED_ACCTYPE(syscall_access, "syscall", process_kobject, "process", process_kobject, "process"); + +int __init syscall_acctype_init(void) { + MED_REGISTER_ACCTYPE(syscall_access,MEDUSA_ACCTYPE_TRIGGEREDATSUBJECT); + return 0; +} + +medusa_answer_t asmlinkage medusa_syscall_i386( + 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) +{ + medusa_answer_t retval = MED_OK; + struct syscall_access access; + struct process_kobject proc; + + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (MEDUSA_MONITORED_ACCESS_S(syscall_access, ¤t->med)) { + access.sysnr = eax; + access.arg1 = p1; access.arg2 = p2; + access.arg3 = p3; access.arg4 = p4; + access.arg5 = p5; + access.arg6 = access.arg7 = 0; + process_kern2kobj(&proc, current); + retval = MED_DECIDE(syscall_access, &access, &proc, &proc); + } + /* this needs more optimization some day */ + if (retval == MED_NO) + return 0; /* deny */ + if (retval != MED_SKIP) + return 1; /* allow */ + return 2; /* skip trace code */ +} + +__initcall(syscall_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_truncate.c linux-2.4.23-medusa/medusa/l2/acctype_truncate.c --- linux-2.4.23-clean/medusa/l2/acctype_truncate.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_truncate.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'truncate' access type, with subj=task and obj=inode */ + +struct truncate_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; + loff_t length; +}; + +MED_ATTRS(truncate_access) { + MED_ATTR_RO (truncate_access, filename, "filename", MED_STRING), + MED_ATTR_RO (truncate_access, length, "length", MED_UNSIGNED), + MED_ATTR_END +}; + +MED_ACCTYPE(truncate_access, "truncate", process_kobject, "process", + file_kobject, "file"); + +int __init truncate_acctype_init(void) { + MED_REGISTER_ACCTYPE(truncate_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +static medusa_answer_t medusa_do_truncate(struct dentry *dentry, unsigned long length); +medusa_answer_t medusa_truncate(struct dentry *dentry, unsigned long length) +{ + if (!dentry || IS_ERR(dentry) || !dentry->d_inode) + return MED_OK; + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&dentry->d_inode->med) && + file_kobj_validate_dentry(dentry,NULL) <= 0) + return MED_OK; + if (!VS_INTERSECT(VSS(¤t->med),VS(&dentry->d_inode->med)) || + !VS_INTERSECT(VSW(¤t->med),VS(&dentry->d_inode->med)) + ) + return MED_NO; + if (MEDUSA_MONITORED_ACCESS_O(truncate_access, &dentry->d_inode->med)) + return medusa_do_truncate(dentry, length); + return MED_OK; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_truncate(struct dentry *dentry, unsigned long length) +{ + struct truncate_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + access.length = length; + process_kern2kobj(&process, current); + file_kern2kobj(&file, dentry->d_inode); + file_kobj_live_add(dentry->d_inode); + retval = MED_DECIDE(truncate_access, &access, &process, &file); + file_kobj_live_remove(dentry->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +__initcall(truncate_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/acctype_unlink.c linux-2.4.23-medusa/medusa/l2/acctype_unlink.c --- linux-2.4.23-clean/medusa/l2/acctype_unlink.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/acctype_unlink.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* let's define the 'unlink' access type, with subj=task and obj=inode */ + +struct unlink_access { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; +}; + +MED_ATTRS(unlink_access) { + MED_ATTR_RO (unlink_access, filename, "filename", MED_STRING), + MED_ATTR_END +}; + +MED_ACCTYPE(unlink_access, "unlink", process_kobject, "process", + file_kobject, "file"); + +int __init unlink_acctype_init(void) { + MED_REGISTER_ACCTYPE(unlink_access, MEDUSA_ACCTYPE_TRIGGEREDATOBJECT); + return 0; +} + +static medusa_answer_t medusa_do_unlink(struct dentry *dentry); +medusa_answer_t medusa_unlink(struct dentry *dentry) +{ + if (!dentry || IS_ERR(dentry) || dentry->d_inode == NULL) + return MED_OK; + + if (!MED_MAGIC_VALID(¤t->med) && + process_kobj_validate_task(current) <= 0) + return MED_OK; + + if (!MED_MAGIC_VALID(&dentry->d_inode->med) && + file_kobj_validate_dentry(dentry,NULL) <= 0) { + return MED_OK; + } + if (!VS_INTERSECT(VSS(¤t->med),VS(&dentry->d_inode->med)) || + !VS_INTERSECT(VSW(¤t->med),VS(&dentry->d_inode->med)) + ) + return MED_NO; + if (MEDUSA_MONITORED_ACCESS_O(unlink_access, &dentry->d_inode->med)) + return medusa_do_unlink(dentry); + return MED_OK; +} + +/* XXX Don't try to inline this. GCC tries to be too smart about stack. */ +static medusa_answer_t medusa_do_unlink(struct dentry *dentry) +{ + struct unlink_access access; + struct process_kobject process; + struct file_kobject file; + medusa_answer_t retval; + + file_kobj_dentry2string(dentry, access.filename); + process_kern2kobj(&process, current); + file_kern2kobj(&file, dentry->d_inode); + file_kobj_live_add(dentry->d_inode); + retval = MED_DECIDE(unlink_access, &access, &process, &file); + file_kobj_live_remove(dentry->d_inode); + if (retval != MED_ERR) + return retval; + return MED_OK; +} +__initcall(unlink_acctype_init); diff -ruN linux-2.4.23-clean/medusa/l2/evtype_getfile.c linux-2.4.23-medusa/medusa/l2/evtype_getfile.c --- linux-2.4.23-clean/medusa/l2/evtype_getfile.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/evtype_getfile.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,255 @@ +/* (C) 2002 Milan Pikula */ + +#include +#include +#include + +#include "kobject_process.h" +#include "kobject_file.h" +#include + +/* the getfile event types (yes, there are more of them) are a bit special: + * 1) they are called from the beginning of various access types to get the + * initial VS set, + * 2) they gain some additional information, which enables L4 code to keep + * the file hierarchy, if it wants. + * 3) due to creepy VFS design in Linux we sometimes do some magic. + */ + +struct getfile_event { + MEDUSA_ACCESS_HEADER; + char filename[NAME_MAX+1]; +}; + +MED_ATTRS(getfile_event) { + MED_ATTR_RO (getfile_event, filename, "filename", MED_STRING), + MED_ATTR_END +}; +MED_EVTYPE(getfile_event, "getfile", file_kobject, "file", + file_kobject, "parent"); + +/** + * medusa_evocate_mnt - find the uppermost struct vfsmount for given dentry/inode. + * @dentry: dentry to perform lookup on. + * + * This is a helper routine for file_kobj_validate_dentry. It does the black + * magic to get the needed information, and owes for its existence to + * the dirty design of VFS, where some parts of information are just missing. + * From all possible vfsmounts, we must return the uppermost one to get + * it right; and we try to avoid recursion 'cause we value the stack. + */ + +struct vfsmount * medusa_evocate_mnt(struct dentry *dentry) +{ + int depth, last_depth, maxdepth, can_nest; + struct vfsmount * p; + int count = 0; + + /* get the local root */ + 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; + + /* hope that init isn't chrooted; get "global" root */ + read_lock(&init_task.fs->lock); + p = init_task.fs->rootmnt; + while (p->mnt_parent != p->mnt_parent->mnt_parent) + p = p->mnt_parent; + mntget(p); + read_unlock(&init_task.fs->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)); + last_depth = depth; + continue; + + } + + mntput(p); + p = mntget(p->mnt_parent); + last_depth = depth--; + + } while (depth >= 0); + spin_unlock(&dcache_lock); + mntput(p); + maxdepth++; + } while (can_nest); + + dput(dentry); + printk("Fatal error: too drunk to evocate mnt. Returning init's mnt instead.\n"); + return mntget(init_task.fs->rootmnt); +} + +static medusa_answer_t do_file_kobj_validate_dentry(struct nameidata * ndcurrent, + struct nameidata * ndupper, struct nameidata * ndparent); + +void medusa_clean_inode(struct inode * inode) +{ + INIT_MEDUSA_OBJECT_VARS(&inode->med); +} +void medusa_get_upper_and_parent(struct nameidata * ndsource, + struct nameidata * ndupperp, struct nameidata * ndparentp) +{ + *ndupperp = *ndsource; + dget(ndupperp->dentry); + if (ndupperp->mnt) + mntget(ndupperp->mnt); + else if (IS_ROOT(ndupperp->dentry)) + ndupperp->mnt = medusa_evocate_mnt(ndupperp->dentry); /* FIXME: may fail [?] */ + + while (IS_ROOT(ndupperp->dentry)) { + struct vfsmount * tmp; + if (ndupperp->mnt->mnt_parent == ndupperp->mnt->mnt_parent->mnt_parent) + break; + dput(ndupperp->dentry); + ndupperp->dentry = dget(ndupperp->mnt->mnt_mountpoint); + tmp = mntget(ndupperp->mnt->mnt_parent); + mntput(ndupperp->mnt); + ndupperp->mnt = tmp; + } + if (ndparentp) { + if (IS_ROOT(ndupperp->dentry)) + *ndparentp = *ndsource; + else { + ndparentp->dentry = ndupperp->dentry->d_parent; + ndparentp->mnt = ndupperp->mnt; + } + dget(ndparentp->dentry); + if (ndparentp->mnt) + mntget(ndparentp->mnt); + } + + /* Now we have dentry and mnt. If IS_ROOT(dentry) then the dentry is global filesystem root */ + return; +} + +void medusa_put_upper_and_parent(struct nameidata * ndupper, struct nameidata * ndparent) +{ + if (ndupper) { + dput(ndupper->dentry); + if (ndupper->mnt) + mntput(ndupper->mnt); + } + if (ndparent) { + dput(ndparent->dentry); + if (ndparent->mnt) + mntput(ndparent->mnt); + } +} + +/** + * file_kobj_validate_dentry - get dentry security information from auth. server + * @dentry: dentry to get the information for. + * @mnt: optional vfsmount structure for that dentry + * + * This routine expects the existing, but !MED_MAGIC_VALID dentry. + */ +int file_kobj_validate_dentry(struct dentry * dentry, struct vfsmount * mnt) +{ + struct nameidata ndcurrent; + struct nameidata ndupper; + struct nameidata ndparent; + + INIT_MEDUSA_OBJECT_VARS(&dentry->d_inode->med); +#ifdef CONFIG_MEDUSA_FILE_CAPABILITIES + cap_clear(dentry->d_inode->med.pcap); + cap_set_full(dentry->d_inode->med.icap); + cap_set_full(dentry->d_inode->med.ecap); +#endif + ndcurrent.dentry = dentry; + ndcurrent.mnt = mnt; /* may be NULL */ + medusa_get_upper_and_parent(&ndcurrent, &ndupper, &ndparent); + + if (ndparent.dentry->d_inode == NULL) { + medusa_put_upper_and_parent(&ndupper, &ndparent); + return 0; + } + + if (ndcurrent.dentry != ndparent.dentry) { + if (!MED_MAGIC_VALID(&ndparent.dentry->d_inode->med) && + file_kobj_validate_dentry(ndparent.dentry, ndparent.mnt) <= 0) { + medusa_put_upper_and_parent(&ndupper, &ndparent); + return 0; + } + + if (!MEDUSA_MONITORED_ACCESS_O(getfile_event, + &ndparent.dentry->d_inode->med)) { + + COPY_MEDUSA_OBJECT_VARS(&ndcurrent.dentry->d_inode->med, + &ndparent.dentry->d_inode->med); + ndcurrent.dentry->d_inode->med.user = ndparent.dentry->d_inode->med.user; +#ifdef CONFIG_MEDUSA_FILE_CAPABILITIES + ndcurrent.dentry->d_inode->med.icap = ndparent.dentry->d_inode->med.icap; + ndcurrent.dentry->d_inode->med.pcap = ndparent.dentry->d_inode->med.pcap; + ndcurrent.dentry->d_inode->med.ecap = ndparent.dentry->d_inode->med.ecap; +#endif + medusa_put_upper_and_parent(&ndupper, &ndparent); + return 1; + } + } + + /* we're global root, or cannot inherit from our parent */ + + if (do_file_kobj_validate_dentry(&ndcurrent, &ndupper, &ndparent) + != MED_ERR) { + medusa_put_upper_and_parent(&ndupper, &ndparent); + return MED_MAGIC_VALID(&ndcurrent.dentry->d_inode->med); + } + medusa_put_upper_and_parent(&ndupper, &ndparent); + return -1; +} + +static medusa_answer_t do_file_kobj_validate_dentry(struct nameidata * ndcurrent, + struct nameidata * ndupper, struct nameidata * ndparent) +{ + struct getfile_event event; + struct file_kobject file; + struct file_kobject directory; + medusa_answer_t retval; + + file_kern2kobj(&file, ndcurrent->dentry->d_inode); + file_kobj_dentry2string(ndupper->dentry, event.filename); + file_kern2kobj(&directory, ndparent->dentry->d_inode); + file_kobj_live_add(ndcurrent->dentry->d_inode); + file_kobj_live_add(ndparent->dentry->d_inode); + retval = MED_DECIDE(getfile_event, &event, &file, &directory); + file_kobj_live_remove(ndparent->dentry->d_inode); + file_kobj_live_remove(ndcurrent->dentry->d_inode); + return retval; +} + +int __init getfile_evtype_init(void) { + MED_REGISTER_EVTYPE(getfile_event, + MEDUSA_EVTYPE_TRIGGEREDATSUBJECT | + MEDUSA_EVTYPE_TRIGGEREDBYOBJECTTBIT); + return 0; +} +__initcall(getfile_evtype_init); diff -ruN linux-2.4.23-clean/medusa/l2/evtype_getprocess.c linux-2.4.23-medusa/medusa/l2/evtype_getprocess.c --- linux-2.4.23-clean/medusa/l2/evtype_getprocess.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/evtype_getprocess.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,52 @@ +/* (C) 2002 Milan Pikula */ + +#include +#include + +#include "kobject_process.h" +#include + +/* + * + * This routine has to validate the process. Because we don't have + * the (useful) information to build the process hierarchy, it is + * useless to call L3 here. We do it anyway: otherwise the first + * access after restart of auth. server will go with full VS set, + * and thus will succeed. + * + */ + +struct getprocess_event { + MEDUSA_ACCESS_HEADER; +}; + +MED_ATTRS(getprocess_event) { + MED_ATTR_END +}; +MED_EVTYPE(getprocess_event, "getprocess", process_kobject, "process", + process_kobject, "process"); + +int process_kobj_validate_task(struct task_struct * ts) +{ + medusa_answer_t retval; + struct getprocess_event event; + struct process_kobject proc; + + INIT_MEDUSA_OBJECT_VARS(&ts->med); + INIT_MEDUSA_SUBJECT_VARS(&ts->med); +#ifdef CONFIG_MEDUSA_FORCE + ts->med.force_code = NULL; +#endif + process_kern2kobj(&proc, ts); + retval = MED_DECIDE(getprocess_event, &event, &proc, &proc); + if (retval != MED_ERR) + return 1; + return -1; +} + +int __init getprocess_evtype_init(void) { + MED_REGISTER_EVTYPE(getprocess_event, + MEDUSA_EVTYPE_NOTTRIGGERED); + return 0; +} +__initcall(getprocess_evtype_init); diff -ruN linux-2.4.23-clean/medusa/l2/kobject_file.c linux-2.4.23-medusa/medusa/l2/kobject_file.c --- linux-2.4.23-clean/medusa/l2/kobject_file.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/kobject_file.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,228 @@ +/* file_kobject.c, (C) 2002 Milan Pikula */ + +#include +#include +#include +#include +#include +#include + +#include "kobject_file.h" + +int file_kobj2kern(struct file_kobject * fk, struct inode * inode) +{ + /* TODO: either update the i-node on disk, or don't allow this at all */ + inode->i_mode = fk->mode; + inode->i_uid = fk->uid; + inode->i_gid = fk->gid; + COPY_MEDUSA_OBJECT_VARS(&inode->med, fk); + inode->med.user = fk->user; +#ifdef CONFIG_MEDUSA_FILE_CAPABILITIES + inode->med.ecap = fk->ecap; + inode->med.icap = fk->icap; + inode->med.pcap = fk->pcap; +#endif /* CONFIG_MEDUSA_FILE_CAPABILITIES */ + MED_MAGIC_VALIDATE(&inode->med); + return 0; +} + +int file_kern2kobj(struct file_kobject * fk, struct inode * inode) +{ + fk->dev = kdev_t_to_nr(inode->i_dev); + fk->ino = inode->i_ino; + fk->mode = inode->i_mode; + fk->nlink = inode->i_nlink; + fk->uid = inode->i_uid; + fk->gid = inode->i_gid; + fk->rdev = kdev_t_to_nr(inode->i_rdev); + COPY_MEDUSA_OBJECT_VARS(fk, &inode->med); + fk->user = inode->med.user; +#ifdef CONFIG_MEDUSA_FILE_CAPABILITIES + fk->ecap = inode->med.ecap; + fk->icap = inode->med.icap; + fk->pcap = inode->med.pcap; +#endif /* CONFIG_MEDUSA_FILE_CAPABILITIES */ + return 0; +} + +/* second, we will describe its attributes, and provide fetch and update + * routines */ +/* (that's for l4, they will be working with those descriptions) */ + +MED_ATTRS(file_kobject) { + MED_ATTR_KEY_RO (file_kobject, dev, "dev", MED_UNSIGNED), + MED_ATTR_KEY_RO (file_kobject, ino, "ino", MED_UNSIGNED), + MED_ATTR (file_kobject, mode, "mode", MED_BITMAP), + MED_ATTR_RO (file_kobject, nlink, "nlink", MED_UNSIGNED), + MED_ATTR (file_kobject, uid, "uid", MED_UNSIGNED), + MED_ATTR (file_kobject, gid, "gid", MED_UNSIGNED), + MED_ATTR_RO (file_kobject, rdev, "rdev", MED_UNSIGNED), + MED_ATTR_OBJECT (file_kobject), + MED_ATTR (file_kobject, user, "user", MED_UNSIGNED), +#ifdef CONFIG_MEDUSA_FILE_CAPABILITIES + MED_ATTR (file_kobject, ecap, "ecap", MED_BITMAP), + MED_ATTR (file_kobject, icap, "icap", MED_BITMAP), + MED_ATTR (file_kobject, pcap, "pcap", MED_BITMAP), +#endif + MED_ATTR_END +}; + +/* here are the inodes, which are currently being examined by the L4 + * code. This simplifies a lookup, and at the moment it is also the only + * way for L4 to fetch or update a i-node. + */ +static rwlock_t live_lock = RW_LOCK_UNLOCKED; + static struct inode * live_inodes = NULL; + +/* TODO: if it shows there are many concurrent inodes in the list, + * rewrite this to use in-kernel hashes; if there will be a FAST global + * lookup routine, maybe we can delete this at all. + * + * Note that we don't modify inode ref_count: call this only with + * locked i-node. + */ +void file_kobj_live_add(struct inode * ino) +{ + struct inode * tmp; + + write_lock(&live_lock); + for (tmp = live_inodes; tmp; tmp = tmp->med.next_live) + if (tmp == ino) { + tmp->med.use_count++; + write_unlock(&live_lock); + return; + } + ino->med.next_live = live_inodes; + ino->med.use_count = 1; + live_inodes = ino; + write_unlock(&live_lock); +} +void file_kobj_live_remove(struct inode * ino) +{ + struct inode * tmp; + + write_lock(&live_lock); + if (--ino->med.use_count) + goto out; + if (ino == live_inodes) { + live_inodes = ino->med.next_live; + write_unlock(&live_lock); + return; + } + for (tmp = live_inodes; tmp->med.next_live; tmp = tmp->med.next_live) + if (tmp->med.next_live == ino) { + tmp->med.next_live = ino->med.next_live; + break; + } +out: + write_unlock(&live_lock); +} +void file_kobj_dentry2string(struct dentry * dentry, char * buf) +{ + int len; + + if( IS_ROOT(dentry) ) + { + struct nameidata ndcurrent, ndupper; + + ndcurrent.dentry = dentry; + ndcurrent.mnt = NULL; + medusa_get_upper_and_parent(&ndcurrent,&ndupper,NULL); + dentry=dget(ndupper.dentry); + medusa_put_upper_and_parent(&ndupper, NULL); + } + else + dget(dentry); + + if (!dentry || IS_ERR(dentry) || !dentry->d_name.name) { + buf[0] = '\0'; + dput(dentry); + return; + } + len = dentry->d_name.len < NAME_MAX ? + dentry->d_name.len : NAME_MAX; + memcpy(buf, dentry->d_name.name, len); + buf[len] = '\0'; + dput(dentry); +} + +static struct file_kobject storage; + +static inline struct inode * __lookup_inode_by_key(struct file_kobject * key_obj) +{ + struct inode * p; + + read_lock(&live_lock); + for (p = live_inodes; p; p = p->med.next_live) + if (p->i_ino == key_obj->ino) + if (p->i_dev == key_obj->dev) + break; + + return p; +} + +static inline void __unlookup(void) +{ + read_unlock(&live_lock); +} + +static struct medusa_kobject_s * file_fetch(struct medusa_kobject_s * key_obj) +{ + struct inode * p; + + p = __lookup_inode_by_key((struct file_kobject *)key_obj); + if (p) { + file_kern2kobj(&storage, p); + __unlookup(); + return (struct medusa_kobject_s *)&storage; + } + __unlookup(); + return NULL; +} + +static void file_unmonitor(struct medusa_kobject_s * kobj) +{ + struct inode * p; + + p = __lookup_inode_by_key((struct file_kobject *)kobj); + if (p) { + UNMONITOR_MEDUSA_OBJECT_VARS(&p->med); + MED_MAGIC_VALIDATE(&p->med); + } + __unlookup(); +} + +static medusa_answer_t file_update(struct medusa_kobject_s * kobj) +{ + struct inode * p; + medusa_answer_t retval = MED_ERR; + + p = __lookup_inode_by_key((struct file_kobject *)kobj); + if (p) { + file_kobj2kern((struct file_kobject *)kobj, p); + retval = MED_OK; + } + __unlookup(); + return retval; +} + +/* third, we will define the kclass, describing such objects */ +/* that's for L3, to make it happy */ + +MED_KCLASS(file_kobject) { + MEDUSA_KCLASS_HEADER(file_kobject), + "file", + + NULL, /* init kclass */ + NULL, /* destroy kclass */ + file_fetch, /* fetch kobject */ + file_update, /* update kobject */ + file_unmonitor, /* disable all monitoring on kobj. */ +}; + +int __init file_kobject_init(void) { + MED_REGISTER_KCLASS(file_kobject); + return 0; +} + +__initcall(file_kobject_init); diff -ruN linux-2.4.23-clean/medusa/l2/kobject_file.h linux-2.4.23-medusa/medusa/l2/kobject_file.h --- linux-2.4.23-clean/medusa/l2/kobject_file.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/kobject_file.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,69 @@ +/* inode_kobject.h, (C) 2002 Milan Pikula + * + * FILE kobject: this file defines the kobject structure for inode, e.g. + * the data, which we want to pass to the authorization server. + * + * The structure contains some data from ordinary struct inode, + * and some data from medusa_l1_inode_s, which is defined in + * medusa/l1/inode.h. + * + * This file (as well as many others) is based on Medusa DS9, version + * 0.9.2, which is (C) Marek Zelem, Martin Ockajak and myself. + */ + +#ifndef _INODE_KOBJECT_H +#define _INODE_KOBJECT_H + +//#include +#include /* contains all includes we need ;) */ +#include + +struct file_kobject { /* was: m_inode_inf */ + MEDUSA_KOBJECT_HEADER; +/* + * 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. + * + * ... for more folklore read the comment in kdev_t.h ;) + */ + unsigned long dev; + unsigned long ino; + + umode_t mode; + nlink_t nlink; + uid_t uid; + gid_t gid; + unsigned long rdev; + + MEDUSA_OBJECT_VARS; + + __u32 user; +#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 */ +}; +extern MED_DECLARE_KCLASSOF(file_kobject); + +struct file_sub_kobject { /* the 'subject' view... */ + struct file_kobject f; + MEDUSA_SUBJECT_VARS; +}; +extern MED_DECLARE_KCLASSOF(file_sub_kobject); + +/* the conversion routines */ +int file_kobj2kern(struct file_kobject * fk, struct inode * inode); +int file_kern2kobj(struct file_kobject * fk, struct inode * inode); + +/* we want to keep a cache of "live" inodes - the ones which participate + * on some access right now + */ +void file_kobj_live_add(struct inode * ino); +void file_kobj_live_remove(struct inode * ino); + +/* conversion beteween filename (stored in dentry) and static buffer */ +void file_kobj_dentry2string(struct dentry * dentry, char * buf); + +#endif diff -ruN linux-2.4.23-clean/medusa/l2/kobject_force.c linux-2.4.23-medusa/medusa/l2/kobject_force.c --- linux-2.4.23-clean/medusa/l2/kobject_force.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/kobject_force.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,78 @@ +/* kobject_force.c, (C) 2002 Milan Pikula */ + +#include +#include +#include +#include +#include + +#include + +#include /* in fact, linux/sched includes that ;) */ + +#define MAX_FORCE_SIZE 16384 /* TODO: configurable size */ + +struct force_kobject { + MEDUSA_KOBJECT_HEADER; + + pid_t pid; + unsigned char code[MAX_FORCE_SIZE]; +}; + +MED_ATTRS(force_kobject) { + MED_ATTR_KEY_RO (force_kobject, pid, "pid", MED_SIGNED), + MED_ATTR (force_kobject, code, "code", MED_BITMAP), + + MED_ATTR_END +}; + +static medusa_answer_t force_update(struct medusa_kobject_s * kobj) +{ + struct task_struct * p; + medusa_answer_t retval; + char * buf; + + printk("force: 1\n"); + retval = MED_ERR; + read_lock_irq(&tasklist_lock); + p = find_task_by_pid(((struct force_kobject *)kobj)->pid); + if (!p) + goto out_unlock; + printk("force: 2\n"); + if (p->med.force_code) + goto out_unlock; + printk("force: 3\n"); + buf = kmalloc(MAX_FORCE_SIZE, GFP_KERNEL); + if (!buf) + goto out_unlock; + memcpy(buf, ((struct force_kobject *)kobj)->code, MAX_FORCE_SIZE); + printk("force: 4 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", + ((struct force_kobject *)kobj)->code[0], + ((struct force_kobject *)kobj)->code[1], + ((struct force_kobject *)kobj)->code[2], + ((struct force_kobject *)kobj)->code[3] + ); + p->med.force_code = buf; + retval = MED_OK; +out_unlock: + read_unlock_irq(&tasklist_lock); + return retval; +} + +MED_KCLASS(force_kobject) { + MEDUSA_KCLASS_HEADER(force_kobject), + "force", + NULL, /* init kclass */ + NULL, /* destroy kclass */ + NULL, /* fetch */ + force_update, + NULL, /* unmonitor */ +}; + +int __init force_kobject_init(void) { + MED_REGISTER_KCLASS(force_kobject); + return 0; +} + +__initcall(force_kobject_init); + diff -ruN linux-2.4.23-clean/medusa/l2/kobject_memory.c linux-2.4.23-medusa/medusa/l2/kobject_memory.c --- linux-2.4.23-clean/medusa/l2/kobject_memory.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/kobject_memory.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,140 @@ +/* kobject_memory.c, (C) 2002 Martin Ockajak, Milan Pikula */ + +/* This kclass allows a user to read from a given process's memory, or + * write there, using `fetch' and `update'. Kobjects of this type are + * never used as a subject or object of any `access' (and thus they don't + * need to contain object or subject vars). + */ + +/* And as it isn't really necessary, it's a perfect example of loadable L2 + * module. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +struct memory_kobject { + MEDUSA_KOBJECT_HEADER; + pid_t pid; /* pid of process to read/write */ + void * address; /* address for read/write */ + size_t size; /* size of the data, must be <= 512 */ + ssize_t retval; /* either the size of data, or errno */ + char data[512]; /* data to be written, or data read */ +}; + +MED_ATTRS(memory_kobject) { + MED_ATTR_KEY_RO (memory_kobject, pid, "pid", MED_UNSIGNED), + MED_ATTR_KEY_RO (memory_kobject, address, "address", MED_UNSIGNED), + MED_ATTR_KEY_RO (memory_kobject, size, "size", MED_UNSIGNED), + MED_ATTR_RO (memory_kobject, retval, "retval", MED_SIGNED), + MED_ATTR (memory_kobject, data, "data", MED_STRING), + MED_ATTR_END +}; + +static struct medusa_kobject_s * memory_fetch(struct medusa_kobject_s *); +static medusa_answer_t memory_update(struct medusa_kobject_s *); + +MED_KCLASS(memory_kobject) { + MEDUSA_KCLASS_HEADER(memory_kobject), + "memory", + NULL, /* init kclass */ + NULL, /* destroy kclass */ + memory_fetch, /* fetch kobject */ + memory_update, /* update kobject */ + NULL, /* unmonitor */ +}; + +/* module stuff */ + +#ifdef MODULE +static int memory_kobject_unload_check(void) __exit; +#endif + +int __init memory_kobject_init(void) +{ +#ifdef MODULE + THIS_MODULE->can_unload = memory_kobject_unload_check; +#endif + MED_REGISTER_KCLASS(memory_kobject); + return 1; +} + +/* After this is called, and returns 0, memory_kobject_rmmod should be. */ +static int __exit memory_kobject_unload_check(void) +{ + if (med_unlink_kclass(&MED_KCLASSOF(memory_kobject)) != MED_OK) + return -EBUSY; + return 0; +} + +void __exit memory_kobject_rmmod(void) +{ + med_unregister_kclass(&MED_KCLASSOF(memory_kobject)); +} + +module_init(memory_kobject_init); +module_exit(memory_kobject_rmmod); +/* quoting the comment in module.h: + * + * There are dual licensed components, but when running with Linux it is the + * GPL that is relevant so this is a non issue. + */ +MODULE_LICENSE("GPL"); + +/* implementation */ + +static struct memory_kobject storage; + +static struct medusa_kobject_s * memory_fetch(struct medusa_kobject_s * key_obj) +{ + int ret; + struct task_struct * p; + + storage.pid = ((struct memory_kobject *) key_obj)->pid; + storage.address = ((struct memory_kobject *) key_obj)->address; + storage.size = ((struct memory_kobject *) key_obj)->size; + read_lock_irq(&tasklist_lock); + p = find_task_by_pid(storage.pid); + if (p) { + get_task_struct(p); + read_unlock_irq(&tasklist_lock); + ret = access_process_vm(p, (unsigned long)storage.address, storage.data, storage.size, 0); + free_task_struct(p); + storage.retval = ret; + return (struct medusa_kobject_s *)&storage; + } + read_unlock_irq(&tasklist_lock); + /* subject to change */ + storage.retval = -ESRCH; + return (struct medusa_kobject_s *)&storage; +} + +static medusa_answer_t memory_update(struct medusa_kobject_s * kobj) +{ + int ret; + struct task_struct * p; + + read_lock_irq(&tasklist_lock); + p = find_task_by_pid(((struct memory_kobject *) kobj)->pid); + if (p) { + get_task_struct(p); + read_unlock_irq(&tasklist_lock); + ret = access_process_vm(p, + (unsigned long) + ((struct memory_kobject *) kobj)->address, + ((struct memory_kobject *) kobj)->data, + ((struct memory_kobject *) kobj)->size, + 1); + free_task_struct(p); + return (ret == ((struct memory_kobject *) kobj)->size) ? + MED_OK : MED_ERR; + } + read_unlock_irq(&tasklist_lock); + return MED_ERR; +} + diff -ruN linux-2.4.23-clean/medusa/l2/kobject_printk.c linux-2.4.23-medusa/medusa/l2/kobject_printk.c --- linux-2.4.23-clean/medusa/l2/kobject_printk.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/kobject_printk.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,70 @@ +/* kobject_printk.c, (C) 2002 Milan Pikula */ + +#include +#include +#include +#include +#include +#include + +struct printk_kobject { + /* int loglevel; */ /* TODO: add loglevels some day */ + char message[512]; +}; + +MED_ATTRS(printk_kobject) { + MED_ATTR_KEY (printk_kobject, message, "message", MED_STRING), + MED_ATTR_END +}; + +static struct medusa_kobject_s * printk_fetch(struct medusa_kobject_s * key_obj) +{ + return NULL; +} +static medusa_answer_t printk_update(struct medusa_kobject_s * kobj) +{ + ((struct printk_kobject *) kobj)->message[sizeof(((struct printk_kobject *) kobj)->message)-1] = '\0'; + MED_PRINTF("%s",((struct printk_kobject *) kobj)->message); + return MED_OK; +} + +MED_KCLASS(printk_kobject) { + MEDUSA_KCLASS_HEADER(printk_kobject), + "printk", + NULL, /* init kclass */ + NULL, /* destroy kclass */ + printk_fetch, + printk_update, + NULL, /* unmonitor */ +}; + +#ifdef MODULE +static int printk_kobject_unload_check(void) __exit; +#endif + +void printk_kobject_rmmod(void); + +int __init printk_kobject_init(void) { +#ifdef MODULE + THIS_MODULE->can_unload = printk_kobject_unload_check; +#endif + MED_REGISTER_KCLASS(printk_kobject); + return 0; +} + +/* After this is called, and returns 0, printk_kobject_rmmod should be. */ +static int __exit printk_kobject_unload_check(void) +{ + if (med_unlink_kclass(&MED_KCLASSOF(printk_kobject)) != MED_OK) + return -EBUSY; + return 0; +} + +void __exit printk_kobject_rmmod(void) +{ + med_unregister_kclass(&MED_KCLASSOF(printk_kobject)); +} + +module_init(printk_kobject_init); +module_exit(printk_kobject_rmmod); +MODULE_LICENSE("GPL"); diff -ruN linux-2.4.23-clean/medusa/l2/kobject_process.c linux-2.4.23-medusa/medusa/l2/kobject_process.c --- linux-2.4.23-clean/medusa/l2/kobject_process.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/kobject_process.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,188 @@ +/* process_kobject.c, (C) 2002 Milan Pikula */ + +#include +#include +#include +#include + +#include + +#include /* in fact, linux/sched includes that ;) */ + +/* first, we will create the data storage structure, also known as 'kobject', + * and provide simple conversion routines */ + +/* (that's for L2, e.g. for us:) */ + +#include "kobject_process.h" + +medusa_answer_t process_kobj2kern(struct process_kobject * tk, struct task_struct * ts) +{ + // ts->pgrp = tk->pgrp; + + if (ts->uid != tk->uid) { /* copied from sys.c:set_user() */ + struct user_struct * old_user, * new_user; + + new_user = alloc_uid(tk->uid); + if (!new_user) + return MED_SKIP; + old_user = ts->user; + atomic_dec(&old_user->processes); + atomic_inc(&new_user->processes); + if (ts->med.luid == (uid_t)-1) + ts->med.luid = (tk->uid == (uid_t)-1 ? -2 : tk->uid); + ts->uid = tk->uid; + ts->user = new_user; + free_uid(old_user); + } + + ts->euid = tk->euid; + ts->suid = tk->suid; ts->fsuid = tk->fsuid; + + ts->gid = tk->gid; ts->egid = tk->egid; ts->sgid = tk->sgid; + ts->fsgid = tk->fsgid; + ts->cap_effective = tk->ecap; + ts->cap_inheritable = tk->icap; + ts->cap_permitted = tk->pcap; + + if( ts->med.luid==(uid_t)-1 ) + ts->med.luid = tk->luid; + COPY_MEDUSA_SUBJECT_VARS(&ts->med,tk); + COPY_MEDUSA_OBJECT_VARS(&ts->med,tk); + ts->med.user = tk->user; +#ifdef CONFIG_MEDUSA_SYSCALL + memcpy(ts->med.med_syscall, tk->med_syscall, sizeof(ts->med.med_syscall)); +#endif + MED_MAGIC_VALIDATE(&ts->med); + return MED_OK; +} +int process_kern2kobj(struct process_kobject * tk, struct task_struct * ts) +{ + tk->parent_pid = tk->child_pid = tk->sibling_pid = 0; + + tk->pid = ts->pid; + if (ts->p_pptr) tk->parent_pid = ts->p_pptr->pid; + if (ts->p_cptr) tk->child_pid = ts->p_cptr->pid; + if (ts->p_ysptr) tk->sibling_pid = ts->p_ysptr->pid; + tk->pgrp = ts->pgrp; tk->uid = ts->uid; tk->euid = ts->euid; + tk->suid = ts->suid; tk->fsuid = ts->fsuid; + tk->gid = ts->gid; tk->egid = ts->egid; tk->sgid = ts->sgid; + tk->fsgid = ts->fsgid; + tk->ecap = ts->cap_effective; + tk->icap = ts->cap_inheritable; + tk->pcap = ts->cap_permitted; + + tk->luid = ts->med.luid; + COPY_MEDUSA_SUBJECT_VARS(tk,&ts->med); + COPY_MEDUSA_OBJECT_VARS(tk,&ts->med); + tk->user = ts->med.user; +#ifdef CONFIG_MEDUSA_SYSCALL + memcpy(tk->med_syscall, ts->med.med_syscall, sizeof(tk->med_syscall)); +#endif + return 0; +} + +/* second, we will describe its attributes, and provide fetch and update + * routines */ +/* (that's for l4, they will be working with those descriptions) */ + + +MED_ATTRS(process_kobject) { + MED_ATTR_KEY_RO (process_kobject, pid, "pid", MED_SIGNED), + MED_ATTR_RO (process_kobject, parent_pid, "parent_pid", MED_SIGNED), + MED_ATTR_RO (process_kobject, child_pid, "child_pid", MED_SIGNED), + MED_ATTR_RO (process_kobject, sibling_pid, "sibling_pid", MED_SIGNED), + MED_ATTR_RO (process_kobject, pgrp, "pgrp", MED_SIGNED), + MED_ATTR (process_kobject, uid, "uid", MED_UNSIGNED), + MED_ATTR (process_kobject, uid, "ruid", MED_UNSIGNED), + MED_ATTR (process_kobject, euid, "euid", MED_UNSIGNED), + MED_ATTR (process_kobject, suid, "suid", MED_UNSIGNED), + MED_ATTR (process_kobject, fsuid, "fsuid", MED_UNSIGNED), + MED_ATTR (process_kobject, gid, "rgid", MED_UNSIGNED), + MED_ATTR (process_kobject, gid, "gid", MED_UNSIGNED), + MED_ATTR (process_kobject, egid, "egid", MED_UNSIGNED), + MED_ATTR (process_kobject, sgid, "sgid", MED_UNSIGNED), + MED_ATTR (process_kobject, fsgid, "fsgid", MED_UNSIGNED), + MED_ATTR (process_kobject, ecap, "ecap", MED_BITMAP), + MED_ATTR (process_kobject, icap, "icap", MED_BITMAP), + MED_ATTR (process_kobject, pcap, "pcap", MED_BITMAP), + + MED_ATTR (process_kobject, luid, "luid", MED_UNSIGNED), + MED_ATTR_SUBJECT(process_kobject), + MED_ATTR_OBJECT (process_kobject), + MED_ATTR (process_kobject, user, "user", MED_UNSIGNED), +#ifdef CONFIG_MEDUSA_SYSCALL + MED_ATTR (process_kobject, med_syscall, "syscall", MED_BITMAP), +#endif + + MED_ATTR_END +}; + +static struct process_kobject storage; + +static struct medusa_kobject_s * process_fetch(struct medusa_kobject_s * key_obj) +{ + struct task_struct * p; + + read_lock_irq(&tasklist_lock); + p = find_task_by_pid(((struct process_kobject *)key_obj)->pid); + if (!p) + goto out_err; + process_kern2kobj(&storage, p); + read_unlock_irq(&tasklist_lock); + return (struct medusa_kobject_s *)&storage; +out_err: + read_unlock_irq(&tasklist_lock); + return NULL; +} +static medusa_answer_t process_update(struct medusa_kobject_s * kobj) +{ + struct task_struct * p; + medusa_answer_t retval; + + read_lock_irq(&tasklist_lock); + p = find_task_by_pid(((struct process_kobject *)kobj)->pid); + if (p) { + retval = process_kobj2kern((struct process_kobject *)kobj, p); + read_unlock_irq(&tasklist_lock); + return retval; + } + read_unlock_irq(&tasklist_lock); + return MED_ERR; +} + +static void process_unmonitor(struct medusa_kobject_s * kobj) +{ + struct task_struct * p; + + read_lock_irq(&tasklist_lock); + p = find_task_by_pid(((struct process_kobject *)kobj)->pid); + if (p) { + UNMONITOR_MEDUSA_OBJECT_VARS(&p->med); + UNMONITOR_MEDUSA_SUBJECT_VARS(&p->med); + MED_MAGIC_VALIDATE(&p->med); + } + read_unlock_irq(&tasklist_lock); + return; +} + +/* third, we will define the kclass, describing such objects */ +/* that's for L3, to make it happy */ + +MED_KCLASS(process_kobject) { + MEDUSA_KCLASS_HEADER(process_kobject), + "process", + NULL, + NULL, + process_fetch, + process_update, + process_unmonitor, +}; + +int __init process_kobject_init(void) { + MED_REGISTER_KCLASS(process_kobject); + return 0; +} + +/* voila, we're done. */ +__initcall(process_kobject_init); diff -ruN linux-2.4.23-clean/medusa/l2/kobject_process.h linux-2.4.23-medusa/medusa/l2/kobject_process.h --- linux-2.4.23-clean/medusa/l2/kobject_process.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/kobject_process.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,43 @@ +/* process_kobject.h, (C) 2002 Milan Pikula */ + +#ifndef _TASK_KOBJECT_H +#define _TASK_KOBJECT_H + +/* TASK kobject: this file defines the kobject structure for task, e.g. + * the data, which we want to pass to the authorization server. + * + * The structure contains some data from ordinary task_struct + * (such as pid etc.), and some data from medusa_l1_task_s, which is + * defined in medusa/l1/task.h. + */ + +// #include +#include /* contains all includes we need ;) */ +#include + +struct process_kobject { /* was: m_proc_inf */ + MEDUSA_KOBJECT_HEADER; + + pid_t pid, parent_pid, child_pid, sibling_pid; + pid_t pgrp; + uid_t uid, euid, suid, fsuid; + gid_t gid, egid, sgid, fsgid; + + uid_t luid; + kernel_cap_t ecap, icap, pcap; + MEDUSA_SUBJECT_VARS; + MEDUSA_OBJECT_VARS; + __u32 user; +#ifdef CONFIG_MEDUSA_SYSCALL + /* FIXME: this is wrong on non-i386 architectures */ + + /* bitmap of syscalls, which are reported */ + unsigned char med_syscall[NR_syscalls / (sizeof(unsigned char) * 8)]; +#endif +}; +extern MED_DECLARE_KCLASSOF(process_kobject); + +int process_kobj2kern(struct process_kobject * tk, struct task_struct * ts); +int process_kern2kobj(struct process_kobject * tk, struct task_struct * ts); + +#endif diff -ruN linux-2.4.23-clean/medusa/l2/medusa_l2_ksyms.c linux-2.4.23-medusa/medusa/l2/medusa_l2_ksyms.c --- linux-2.4.23-clean/medusa/l2/medusa_l2_ksyms.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l2/medusa_l2_ksyms.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,28 @@ +/* + * L2 layer of Medusa DS9 for Linux + * Copyright (C) 2002 Milan Pikula + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * This is the main file of L2. It used to call the initialization routines, + * but now it just exports some symbols. + */ + +#include +#include + +EXPORT_SYMBOL(medusa_capable); + diff -ruN linux-2.4.23-clean/medusa/l3/Makefile linux-2.4.23-medusa/medusa/l3/Makefile --- linux-2.4.23-clean/medusa/l3/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l3/Makefile 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,12 @@ +# +# Makefile for the Linux kernel part of Medusa DS9 Security System, L3 +# + +O_TARGET := l3.o + +export-objs := med_l3_init.o + +obj-y := comm.o registry.o med_l3_init.o + +include $(TOPDIR)/Rules.make + diff -ruN linux-2.4.23-clean/medusa/l3/comm.c linux-2.4.23-medusa/medusa/l3/comm.c --- linux-2.4.23-clean/medusa/l3/comm.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l3/comm.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,47 @@ +/* comm.c, (C) 2002 Milan Pikula + * + */ +#include +#include +#include +#include "l3_internals.h" + +medusa_answer_t med_decide(struct medusa_evtype_s * evtype, void * event, void * o1, void * o2) +{ + int retval; + struct medusa_authserver_s * authserver; + + if (ARCH_CANNOT_DECIDE(evtype)) + return MED_OK; + + MED_LOCK_W(registry_lock); +#ifdef CONFIG_MEDUSA_PROFILING + evtype->arg_kclass[0]->l2_to_l4++; + evtype->arg_kclass[1]->l2_to_l4++; + evtype->l2_to_l4++; +#endif + authserver = med_get_authserver(); + if (!authserver) { + if (evtype->arg_kclass[0]->unmonitor) + evtype->arg_kclass[0]->unmonitor((struct medusa_kobject_s *) o1); + if (evtype->arg_kclass[1]->unmonitor) + evtype->arg_kclass[1]->unmonitor((struct medusa_kobject_s *) o2); + MED_UNLOCK_W(registry_lock); + return MED_OK; + } + MED_UNLOCK_W(registry_lock); + + ((struct medusa_event_s *)event)->evtype_id = evtype; + ((struct medusa_kobject_s *)o1)->kclass_id = evtype->arg_kclass[0]; + ((struct medusa_kobject_s *)o2)->kclass_id = evtype->arg_kclass[1]; + retval = authserver->decide(event, o1, o2); +#ifdef CONFIG_MEDUSA_PROFILING + if (retval != MED_ERR) { + MED_LOCK_W(registry_lock); + evtype->l4_to_l2++; + MED_UNLOCK_W(registry_lock); + } +#endif + med_put_authserver(authserver); + return retval; +} diff -ruN linux-2.4.23-clean/medusa/l3/l3_internals.h linux-2.4.23-medusa/medusa/l3/l3_internals.h --- linux-2.4.23-clean/medusa/l3/l3_internals.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l3/l3_internals.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,10 @@ +#ifndef L3_INTERNALS_H +#define L3_INTERNALS_H + +/* data structures, internal l3 use only. */ +MED_DECLARE_LOCK_DATA(registry_lock); +extern struct medusa_kclass_s * kclasses; +extern struct medusa_acctype_s * acctypes; +extern struct medusa_authserver_s * authserver; + +#endif diff -ruN linux-2.4.23-clean/medusa/l3/med_l3_init.c linux-2.4.23-medusa/medusa/l3/med_l3_init.c --- linux-2.4.23-clean/medusa/l3/med_l3_init.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l3/med_l3_init.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,55 @@ +/* + * L3 layer of Medusa DS9 for Linux + * Copyright (C) 2002 Milan Pikula + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * This is the main file of L3. It calls initialization routines of + * l3 related code, and it also exports some symbols. What a surprise, + * it gets registered before anything else and cannot be built as a + * module. + */ + +#include +#include + +// EXPORT_SYMBOL(kclasses); +// EXPORT_SYMBOL(evtypes); +// EXPORT_SYMBOL(authserver); + +EXPORT_SYMBOL(med_register_kclass); +EXPORT_SYMBOL(med_unregister_kclass); +EXPORT_SYMBOL(med_get_kclass); +EXPORT_SYMBOL(med_get_kclass_by_name); +EXPORT_SYMBOL(med_get_kclass_by_cinfo); +EXPORT_SYMBOL(med_get_kclass_by_pointer); +EXPORT_SYMBOL(med_put_kclass); +EXPORT_SYMBOL(med_unlink_kclass); +EXPORT_SYMBOL(med_register_evtype); +EXPORT_SYMBOL(med_unregister_evtype); +EXPORT_SYMBOL(med_register_authserver); +EXPORT_SYMBOL(med_get_authserver); +EXPORT_SYMBOL(med_unregister_authserver); +EXPORT_SYMBOL(med_put_authserver); +EXPORT_SYMBOL(med_decide); + +void __init medusa_l3_init(void) { +} + +void __init medusa_init(void) { + medusa_l3_init(); +} + diff -ruN linux-2.4.23-clean/medusa/l3/registry.c linux-2.4.23-medusa/medusa/l3/registry.c --- linux-2.4.23-clean/medusa/l3/registry.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l3/registry.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,418 @@ +#include +#include +#include "l3_internals.h" + +/* nesting as follows: registry_lock is outer, usecount_lock is inner. */ + +MED_LOCK_DATA(registry_lock); /* the linked list lock */ + static MED_LOCK_DATA(usecount_lock); /* the lock for modifying use-count */ + struct medusa_kclass_s * kclasses = NULL; + struct medusa_evtype_s * evtypes = NULL; + struct medusa_authserver_s * authserver = NULL; + int medusa_authserver_magic = 1; /* the 'version' of authserver */ +/* WARNING! medusa_authserver_magic is not locked, nor atomic type, + * because we want to have as much portable (and easy and fast) code + * as possible. thus we must change its value BEFORE modifying authserver, + * and place some memory barrier between, or get lock there - the lock + * hopefully contains some kind of such barrier ;). + */ + +static int mystrcmp(char * p1, char * p2) +{ + while (*p1) { + if (*p2 != *p1) + return *p1 - *p2; + p1++; p2++; + } + return -*p2; +} + +/** + * med_get_kclass - lock the kclass by incrementing its use-count. + * @ptr: pointer to the kclass to lock + * + * This increments the use-count; works great even if you want to sleep. + * when calling this function, the use-count must already be non-zero. + */ +medusa_answer_t med_get_kclass(struct medusa_kclass_s * ptr) +{ + MED_LOCK_W(usecount_lock); + ptr->use_count++; + MED_UNLOCK_W(usecount_lock); + return MED_OK; +} + +/** + * med_put_kclass - unlock the kclass by decrementing its use-count. + * @ptr: pointer to the kclass to unlock + * + * This decrements the use-count. Note that it does nothing special when + * the use-count goes to zero. Someone still may find the kclass in the + * linked list and claim it by using med_get_kclass. + */ +void med_put_kclass(struct medusa_kclass_s * ptr) +{ + MED_LOCK_W(usecount_lock); + if (ptr->use_count) /* sanity check only */ + ptr->use_count--; + MED_UNLOCK_W(usecount_lock); +} + +/** + * med_get_kclass_by_name - find a kclass and return get-kclassed refference. + * @name: name of the kclass to find + * + * It may return NULL on failure; caller must verify this each time. + */ +struct medusa_kclass_s * med_get_kclass_by_name(char * name) +{ + struct medusa_kclass_s * tmp; + + MED_LOCK_R(registry_lock); + for (tmp = kclasses; tmp; tmp = tmp->next) + if (!mystrcmp(name, tmp->name)) { + MED_LOCK_W(usecount_lock); + tmp->use_count++; + MED_UNLOCK_W(usecount_lock); + break; + } + MED_UNLOCK_R(registry_lock); + return tmp; +} + +/** + * med_get_kclass_by_cinfo - find a kclass and return get-kclassed refference. + * @cinfo: cinfo of the kclass to find + * + * It may return NULL on failure; caller must verify this each time. + */ +struct medusa_kclass_s * med_get_kclass_by_cinfo(cinfo_t cinfo) +{ + struct medusa_kclass_s * tmp; + + MED_LOCK_R(registry_lock); + for (tmp = kclasses; tmp; tmp = tmp->next) + if (cinfo == tmp->cinfo) { + MED_LOCK_W(usecount_lock); + tmp->use_count++; + MED_UNLOCK_W(usecount_lock); + break; + } + MED_UNLOCK_R(registry_lock); + return tmp; +} + +/** + * med_get_kclass_by_pointer - find a kclass and return get-kclassed refference. + * @ptr: unsafe pointer to the kclass to find + * + * It may return NULL on failure; caller must verify this each time. + */ +struct medusa_kclass_s * med_get_kclass_by_pointer(struct medusa_kclass_s * ptr) +{ + struct medusa_kclass_s * tmp; + + MED_LOCK_R(registry_lock); + for (tmp = kclasses; tmp; tmp = tmp->next) + if (ptr == tmp) { + MED_LOCK_W(usecount_lock); + tmp->use_count++; + MED_UNLOCK_W(usecount_lock); + break; + } + MED_UNLOCK_R(registry_lock); + return tmp; +} + +/** + * med_unlink_kclass - unlink the kclass from all L3 lists + * @ptr: kclass to unlink + * + * This is called with use-count=0 to remove the kclass from L3 + * lists. It may be called with all kinds of locks held, and thus + * it does not notify the authserver. + * + * That is: if the authserver really relies on the kclass, it should use + * med_get_kclass() at the very beginning. + * + * If the use-count is nonzero, it fails gracefully. This allows use of + * med_unlink_kclass as an atomic uninstallation check & unlink. Always + * check the return value of this call. + * + * After returning from this function, some servers might still use + * the kclass, but they must be able to give it up on del_kclass callback. + * No new servers and/or event types will be able to attach to the kclass, + * and it waits for its final deletion by med_unregister_kclass(). + * + * callers, who call med_unlink_kclass and get MED_OK, should really call + * med_unregister_kclass soon. + */ + +medusa_answer_t med_unlink_kclass(struct medusa_kclass_s * ptr) +{ + int retval = MED_OK; + struct medusa_kclass_s * tmp; + + MED_LOCK_W(registry_lock); + MED_LOCK_R(usecount_lock); + if (!ptr->use_count) { + if (ptr == kclasses) + kclasses = ptr->next; + else + for (tmp = kclasses; tmp; tmp = tmp->next) + if (tmp->next == ptr) { + tmp->next = tmp->next->next; + break; + } + /* TODO: verify whether we found it! */ + ptr->next = NULL; + } else + retval = MED_ERR; + MED_UNLOCK_R(usecount_lock); + MED_UNLOCK_W(registry_lock); + return retval; +} + +/** + * med_unregister_kclass - unregister the kclass. + * + * This is called after the usage-count has dropped to 0, and also + * after someone has called med_unlink_kclass. Its whole purpose is to + * notify few routines about disappearance of kclass. They must accept + * it and stop using the kclass, because after returning from this + * function, the k-kclass does not exist. + * + * The callbacks called from here may sleep. + */ +void med_unregister_kclass(struct medusa_kclass_s * ptr) +{ + MED_PRINTF("Unregistering kclass %s\n", ptr->name); + MED_LOCK_R(registry_lock); + MED_LOCK_R(usecount_lock); + if (ptr->use_count || ptr->next) { /* useless sanity check */ + MED_PRINTF("l3/med_unregister_kclass: A fatal ERROR has occured; expect system crash.\n"); + MED_PRINTF("If you're removing a file-related kclass, press reset. Otherwise save now.\n"); + MED_UNLOCK_R(usecount_lock); + MED_UNLOCK_R(registry_lock); + return; + } + MED_UNLOCK_R(usecount_lock); + MED_UNLOCK_R(registry_lock); + if (authserver && authserver->del_kclass) + authserver->del_kclass(ptr); + /* FIXME: this isn't safe. add use-count to authserver too... */ +} + +/** + * med_register_kclass - register a kclass of k-objects and notify the authserver + * @ptr: pointer to the kclass to register + * + * The authserver call must be in lock or a semaphore - we promised + * that in authserver.h. :) + */ +int med_register_kclass(struct medusa_kclass_s * ptr) +{ + struct medusa_kclass_s * p; + + ptr->name[MEDUSA_KCLASSNAME_MAX-1] = '\0'; + MED_PRINTF("Registering kclass %s\n", ptr->name); + MED_LOCK_W(registry_lock); + for (p=kclasses; p; p=p->next) + if (ptr==p || !mystrcmp(p->name, ptr->name)) { + MED_PRINTF("Error: such kclass already exists.\n"); + MED_UNLOCK_W(registry_lock); + return -1; + } + /* we don't write-lock usecount_lock. That's OK, because noone is + * able to find the entry before it's in the linked list. + * we set use-count to 1, and decrement it soon hereafter. + */ + ptr->use_count = 1; + ptr->next = kclasses; + kclasses = ptr; + MED_UNLOCK_W(registry_lock); + if (authserver && authserver->add_kclass) + authserver->add_kclass(ptr); /* TODO: some day, check the return value */ + med_put_kclass(ptr); + return 0; +} + +/** + * med_register_evtype - register an event type and notify the authserver. + * @ptr: pointer to the event type to register + * + * The event type must be prepared by l2 routines to contain pointers to + * all related kclasses of k-objects. + */ +int med_register_evtype(struct medusa_evtype_s * ptr, int flags) +{ + struct medusa_evtype_s * p; + + ptr->name[MEDUSA_EVNAME_MAX-1] = '\0'; + ptr->arg_name[0][MEDUSA_ATTRNAME_MAX-1] = '\0'; + ptr->arg_name[1][MEDUSA_ATTRNAME_MAX-1] = '\0'; + /* TODO: check whether kclasses are registered, maybe register automagically */ + MED_PRINTF("Registering event type %s(%s:%s->%s:%s)\n", ptr->name, + ptr->arg_name[0],ptr->arg_kclass[0]->name, + ptr->arg_name[1],ptr->arg_kclass[1]->name + ); + MED_LOCK_W(registry_lock); + for (p=evtypes; p; p=p->next) + if (!mystrcmp(p->name, ptr->name)) { + MED_UNLOCK_W(registry_lock); + MED_PRINTF("Error: such event type already exists.\n"); + return -1; + } + ptr->next = evtypes; + ptr->bitnr = flags; + +#define MASK (~(MEDUSA_EVTYPE_TRIGGEREDATOBJECT | MEDUSA_EVTYPE_TRIGGEREDATSUBJECT)) + if (flags != MEDUSA_EVTYPE_NOTTRIGGERED) + for (p=evtypes; p; p ? (p=p->next) : (p=evtypes)) + if (p->bitnr != MEDUSA_EVTYPE_NOTTRIGGERED && + (p->bitnr & MASK) == (ptr->bitnr & MASK)) { + + ptr->bitnr++; /* TODO: check for the upper limit! */ + p = NULL; + continue; + } +#undef MASK + evtypes = ptr; + if (authserver && authserver->add_evtype) + authserver->add_evtype(ptr); /* TODO: some day, check for response */ + MED_UNLOCK_W(registry_lock); + return 0; +} + +/** + * med_unregister_evtype - unregister an event type and notify the authserver. + * @ptr: pointer to the event type to unregister + * + */ +void med_unregister_evtype(struct medusa_evtype_s * ptr) +{ + struct medusa_evtype_s * tmp; + MED_PRINTF("Unregistering event type %s\n", ptr->name); + MED_LOCK_W(registry_lock); + if (ptr == evtypes) + evtypes = ptr->next; + else + for (tmp = evtypes; tmp; tmp = tmp->next) + if (tmp->next == ptr) { + tmp->next = tmp->next->next; + if (authserver && authserver->del_evtype) + authserver->del_evtype(ptr); + break; + } + /* TODO: verify whether we found it */ + MED_UNLOCK_W(registry_lock); +} + +/** + * med_register_authserver - register the authorization server + * @ptr: pointer to the filled medusa_authserver_s structure + * + * This routine inserts the authorization server in the internal data + * structures, sets the use-count to 1 (i.e. returns get-servered entry), + * and announces all known classes to the server. + */ +int med_register_authserver(struct medusa_authserver_s * ptr) +{ + struct medusa_kclass_s * cp; + struct medusa_evtype_s * ap; + + MED_PRINTF("Registering authentication server %s\n", ptr->name); + MED_LOCK_W(registry_lock); + if (authserver) { + MED_PRINTF("Registration of auth. server '%s' failed: '%s' already present!\n", ptr->name, authserver->name); + MED_UNLOCK_W(registry_lock); + return -1; + } + /* we don't write-lock usecount_lock. That's OK, because noone is + * able to find the entry before it's in the linked list. + * we set use-count to 1, and somebody has to decrement it some day. + */ + ptr->use_count = 1; + medusa_authserver_magic++; + authserver = ptr; + + /* we must remain in write-lock here, to synchronize add_* + * events across our code. + */ + if (ptr->add_kclass) + for (cp = kclasses; cp; cp = cp->next) + ptr->add_kclass(cp); /* TODO: some day we might want to check the return value, to support specialized servers */ + if (ptr->add_evtype) + for (ap = evtypes; ap; ap = ap->next) + ptr->add_evtype(ap); /* TODO: the same for this */ + + MED_UNLOCK_W(registry_lock); + return 0; +} + +/** + * med_unregister_authserver - unlink the auth. server from L3. + * @ptr: pointer to the server to unlink. + * + * This function is called by L4 code to unregister the auth. server. + * After it has returned, no new questions will be placed to the server. + * Note that some old questions might be pending, and after calling this, + * it is wise to wait for close() callback to proceed with uninstallation. + */ +void med_unregister_authserver(struct medusa_authserver_s * ptr) +{ + MED_PRINTF("Unregistering authserver %s\n", ptr->name); + MED_LOCK_W(registry_lock); + /* the following code is a little bit useless, but we keep it here + * to allow multiple different authentication servers some day + */ + if (ptr != authserver) { + MED_UNLOCK_W(registry_lock); + return; + } + medusa_authserver_magic++; + authserver = NULL; + MED_UNLOCK_W(registry_lock); + med_put_authserver(ptr); +} + +/** + * med_get_authserver - lock the authserver by increasing its use-count. + * + * This function gets one more refference to the authserver. Use it, + * when you want to be sure the authserver won't vanish. + */ +struct medusa_authserver_s * med_get_authserver(void) +{ + MED_LOCK_W(usecount_lock); + if (authserver) { + authserver->use_count++; + MED_UNLOCK_W(usecount_lock); + return authserver; + } + MED_UNLOCK_W(usecount_lock); + return NULL; +} + +/** + * med_put_authserver - release the authserver by decrementing its use-count + * @ptr: a pointer to the authserver + * + * This is an opposite function to med_get_authserver. Please, try to call + * this without any locks; the close() callback of L4 server, which may + * eventually get called from here, may block. This might change, if + * reasonable. + */ +void med_put_authserver(struct medusa_authserver_s * ptr) +{ + MED_LOCK_W(usecount_lock); + if (ptr->use_count) /* sanity check only */ + ptr->use_count--; + if (ptr->use_count) { /* fast path */ + MED_UNLOCK_W(usecount_lock); + return; + } + MED_UNLOCK_W(usecount_lock); + if (ptr->close) + ptr->close(); +} diff -ruN linux-2.4.23-clean/medusa/l4-constable/Makefile linux-2.4.23-medusa/medusa/l4-constable/Makefile --- linux-2.4.23-clean/medusa/l4-constable/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l4-constable/Makefile 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,14 @@ +# +# Makefile for the Linux kernel part of Medusa DS9 Security System, +# L4/constable +# + +O_TARGET := l4-constable.o + +export-objs := + +obj-$(CONFIG_MEDUSA_CONSTABLE) := teleport.o chardev.o + +include $(TOPDIR)/Rules.make + + diff -ruN linux-2.4.23-clean/medusa/l4-constable/chardev.c linux-2.4.23-medusa/medusa/l4-constable/chardev.c --- linux-2.4.23-clean/medusa/l4-constable/chardev.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l4-constable/chardev.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,869 @@ +/* + * L4 authorization server for Medusa DS9 + * Copyright (C) 2002 Milan Pikula , all rights reserved. + * + * This program comes with both BSD and GNU GPL v2 licenses. Check the + * documentation for more information. + * + * + * This server communicates with an user-space + * authorization daemon, using a character device + * + * /dev/medusa c 111 0 on Linux + * /dev/medusa c 90 0 on NetBSD + */ + +/* define this if you want fatal protocol errors to cause segfault of + * auth. daemon. Note that issuing strange read(), write(), or trying + * to access the character device multiple times at once is not considered + * a protocol error. This triggers only if we REALLY get some junk from the + * user-space. + */ +#define ERRORS_CAUSE_SEGFAULT + +/* define this to support workaround of decisions for named process. This + * is especially usefull when using GDB on constable. + */ +#define GDB_HACK + +/* TODO: Check the calls to l3; they can't be called from a lock. */ + + +#include + +#ifndef OS_LINUX +# ifndef OS_NETBSD +# error "Your system is not supported." +# endif +#endif + +#ifdef OS_NETBSD +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define MEDUSA_MAJOR 90 +#define MODULENAME "chardev/netbsd" +#define MOD_INC_USE_COUNT do { } while (0) +#define MOD_DEC_USE_COUNT do { } while (0) +typedef int atomic_t; +#define atomic_read(p) (*(p)) +#define atomic_set(p, val) do { *(p) = val; } while (0) +#define ATOMIC_INIT(x) (x) +#define DECLARE_WAIT_QUEUE_HEAD(x) struct selinfo x +#define wakeup(p) wakeup_one(p) + +#define DECLARE_MUTEX(x) struct lock x +#define down(ptr) lockmgr(ptr, LK_EXCLUSIVE, 0) +#define up(ptr) lockmgr(ptr, LK_RELEASE, 0) +#define pid p_pid +#define CURRENTPTR curproc +#endif + +#ifdef OS_LINUX +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define MEDUSA_MAJOR 111 +#define MODULENAME "chardev/linux" +#define selwakeup(x) do { } while (0) +#define wakeup(p) wake_up(p) +#define CURRENTPTR current +#endif + +#include +#include +#include + +#include "teleport.h" + + +static teleport_t teleport = { + cycle: tpc_HALT, +}; +static teleport_insn_t tele_mem[6]; + +/* constable, our brave userspace daemon */ +static atomic_t constable_present = ATOMIC_INIT(0); +#ifdef OS_NETBSD + static struct proc * constable = NULL; +#endif +#ifdef OS_LINUX + static struct task_struct * constable = NULL; +#endif + static MED_LOCK_DATA(constable_openclose); + + +/* fetch or update answer */ +static int send_fetch_or_update_answer = 0; + static struct medusa_kclass_s * answ_kclass; + static struct medusa_kobject_s * answ_kobj; + static u_int32_t answ_kclassid; + static u_int32_t answ_seq; + static medusa_answer_t answ_result; + +/* to-register queue for constable */ +static MED_LOCK_DATA(registration_lock); + static struct medusa_kclass_s * kclasses_to_register = NULL; + static struct medusa_evtype_s * evtypes_to_register = NULL; + /* the following two are circular lists */ + static struct medusa_kclass_s * kclasses_registered = NULL; + static struct medusa_evtype_s * evtypes_registered = NULL; + static int announce_ready = 0; + +/* a question from kernel to constable */ +static DECLARE_MUTEX(constable_mutex); + static int question_ready = 0; + static struct medusa_event_s * decision_event; + static struct medusa_kobject_s * decision_o1, * decision_o2; + /* and the answer */ + static medusa_answer_t user_answer; + static DECLARE_WAIT_QUEUE_HEAD(userspace); +#ifdef OS_LINUX + static DECLARE_COMPLETION(userspace_answer); +#endif +#ifdef OS_NETBSD + static struct simplelock userspace_answer_rw; + static int userspace_answer_flag = 0; +#endif + +/* is the user-space currently sending us something? */ +static atomic_t currently_receiving = ATOMIC_INIT(0); + static char recv_buf[32768]; /* hopefully enough */ + static u_int32_t recv_type; + static int recv_phase; + +static DECLARE_WAIT_QUEUE_HEAD(close_wait); + +#ifdef GDB_HACK +static pid_t gdb_pid = -1; +#ifdef OS_LINUX +MODULE_PARM(gdb_pid, "i"); +MODULE_PARM_DESC(gdb_pid, "PID to exclude from monitoring"); +#endif +#endif + +/*********************************************************************** + * kernel-space interface + */ + +static medusa_answer_t l4_decide( struct medusa_event_s * event, + struct medusa_kobject_s * o1, + struct medusa_kobject_s * o2); +static int l4_add_kclass(struct medusa_kclass_s * cl); +static int l4_add_evtype(struct medusa_evtype_s * at); +static void l4_close_wake(void); + +static struct medusa_authserver_s chardev_medusa = { + MODULENAME, + 0, /* use-count */ + l4_close_wake, /* close */ + l4_add_kclass, /* add_kclass */ + NULL, /* del_kclass */ + l4_add_evtype, /* add_evtype */ + NULL, /* del_evtype */ + l4_decide /* decide */ +}; + +static void l4_close_wake(void) +{ +#ifdef OS_NETBSD + MED_LOCK_W(constable_openclose); +#endif + wakeup(&close_wait); +#ifdef OS_NETBSD + MED_UNLOCK_W(constable_openclose); +#endif +} + +static int l4_add_kclass(struct medusa_kclass_s * cl) +{ + med_get_kclass(cl); + MED_LOCK_W(registration_lock); + cl->cinfo = (cinfo_t)kclasses_to_register; + kclasses_to_register=cl; + announce_ready = 1; + wakeup(&userspace); + selwakeup(&userspace); + MED_UNLOCK_W(registration_lock); + return MED_YES; +} + +static int l4_add_evtype(struct medusa_evtype_s * at) +{ + MED_LOCK_W(registration_lock); + at->cinfo = (cinfo_t)evtypes_to_register; + evtypes_to_register=at; + announce_ready = 1; + wakeup(&userspace); + selwakeup(&userspace); + MED_UNLOCK_W(registration_lock); + return MED_YES; +} + +/* the sad fact about this routine is that it sleeps... + * + * guess what? we can FULLY solve that silly problem on SMP, + * eating one processor by a constable... ;) One can imagine + * the performance improvement, and buy one more CPU in advance :) + */ +static medusa_answer_t l4_decide(struct medusa_event_s * event, + struct medusa_kobject_s * o1, struct medusa_kobject_s * o2) +{ + int retval; +#ifdef OS_NETBSD + struct proc * current = curproc; + + if (current == NULL) { +#endif +#ifdef OS_LINUX + if (in_interrupt()) { +#endif + /* houston, we have a problem! */ + MED_PRINTF("decide called from interrupt context :(\n"); + return MED_ERR; + } + if (current == constable || current->pid < 1) + return MED_ERR; +#ifdef GDB_HACK + if (gdb_pid == current->pid) + return MED_OK; +#endif + + down(&constable_mutex); + + /* end before sleeping, if possible */ + if (!atomic_read(&constable_present)) { + /* because of Linux implementation of semaphores, + * this path is pretty fast and won't affect SMP + * much, when constable is off. + */ + up(&constable_mutex); + return MED_ERR; + } + + /* place the question and ask. */ + decision_event = event; + decision_o1 = o1; + decision_o2 = o2; + /* wmb() */ + question_ready = 1; /* doesn't matter whether this is atomic or not */ + wakeup(&userspace); + selwakeup(&userspace); +#ifdef OS_NETBSD + simple_lock(&userspace_answer_rw); + while (!userspace_answer_flag) + ltsleep(&userspace_answer_flag, PRIBIO, 0, 0, + &userspace_answer_rw); + userspace_answer_flag = 0; + simple_unlock(&userspace_answer_rw); +#endif +#ifdef OS_LINUX + wait_for_completion(&userspace_answer); +#endif + + if (atomic_read(&constable_present)) + retval = user_answer; + else + retval = MED_ERR; + up(&constable_mutex); + return retval; +} + +/*********************************************************************** + * user-space interface + */ + +#ifdef OS_NETBSD +struct uio * userspace_buf; + +static ssize_t to_user(void * from, size_t len) +{ + size_t orig = userspace_buf->uio_resid; + int i; + + i = uiomove(from, len, userspace_buf); + if (i) + return -i; + return (orig - userspace_buf->uio_resid); +} +#endif /* OS_NETBSD */ +#ifdef OS_LINUX +static ssize_t user_read(struct file *filp, char *buf, size_t count, loff_t * ppos); +static ssize_t user_write(struct file *filp, const char *buf, size_t count, loff_t * ppos); +static unsigned int user_poll(struct file *filp, poll_table * wait); +static int user_open(struct inode *inode, struct file *file); +static int user_release(struct inode *inode, struct file *file); + +static struct file_operations fops = { + read: user_read, + write: user_write, + llseek: no_llseek, /* -ESPIPE */ + poll: user_poll, + open: user_open, + release: user_release +/* we don't support async IO. I have no idea, when to call kill_fasync + * to be correct. Only on decisions? Or also on answers to user-space + * questions? Not a big problem, though... noone seems to be supporting + * it anyway :). If you need it, let me know. + */ + /* also, we don't like the ioctl() - we hope the character device can + * be used over the network. + */ +}; +static char * userspace_buf; + +static ssize_t to_user(void * from, size_t len) +{ /* we verify the access rights elsewhere */ + __copy_to_user(userspace_buf, from, len); + userspace_buf += len; + return len; +} +#endif /* OS_LINUX */ + +/* + * READ() + */ +#ifdef OS_NETBSD +#define XFER_COUNT buf->uio_resid +int medusads9userspaceread(dev_t dev, struct uio * buf, int ioflag) +{ + int retval; + if (constable != curproc) + return EPERM; +#endif /* OS_NETBSD */ +#ifdef OS_LINUX +#define XFER_COUNT count +static ssize_t user_read(struct file * filp, char * buf, + size_t count, loff_t * ppos) +{ + ssize_t retval; + if (constable != current) + return -EPERM; + if (*ppos != filp->f_pos) + return -ESPIPE; + if (!access_ok(VERIFY_WRITE, buf, count)) + return -EFAULT; +#endif /* OS_LINUX */ + + /* do we have an unfinished write? (e.g. dumb user-space) */ + if (atomic_read(¤tly_receiving)) +#ifdef OS_LINUX + return -EIO; +#else + return EIO; +#endif + userspace_buf = buf; +feed_lions: + retval = teleport_cycle(&teleport, XFER_COUNT); +#ifdef OS_LINUX + if (retval < 0) /* unexpected error; data lost */ + return retval; + if (retval > 0 || teleport.cycle != tpc_HALT) + return retval; +#else + if (retval < 0) /* unexpected error; data lost */ + return -retval; + if (retval > 0 || teleport.cycle != tpc_HALT) + return 0; +#endif + + + // l4->constable: Fetch object - answer + // locked by the fact we're in the context of Constable + if (send_fetch_or_update_answer) + goto do_fetch_update; /* the common case goes faster */ + +#ifdef OS_NETBSD + while (!announce_ready && !question_ready) { + retval = tsleep(&userspace, PRIBIO|PCATCH, "medusaread", 0); + if (retval != 0) /* ERESTART/EINTR */ + return retval; + } +#endif /* OS_NETBSD */ +#ifdef OS_LINUX + retval = wait_event_interruptible(userspace, + announce_ready||question_ready); + if (retval != 0) /* -ERESTARTSYS */ + return retval; +#endif /* OS_LINUX */ + + if (announce_ready) + goto do_announce; /* the common case goes faster */ + + + /* question_ready */ +#define decision_evtype (decision_event->evtype_id) + tele_mem[0].opcode = tp_PUT32; + tele_mem[0].args.put32.what = (u_int32_t)decision_evtype; + tele_mem[1].opcode = tp_PUT32; + tele_mem[1].args.put32.what = 0; + tele_mem[2].opcode = tp_CUTNPASTE; + tele_mem[2].args.cutnpaste.from = (unsigned char *)decision_event; + tele_mem[2].args.cutnpaste.count = decision_evtype->event_size; + tele_mem[3].opcode = tp_CUTNPASTE; + tele_mem[3].args.cutnpaste.from = (unsigned char *)decision_o1; + tele_mem[3].args.cutnpaste.count = + decision_evtype->arg_kclass[0]->kobject_size; + if (decision_o1 == decision_o2) { + tele_mem[4].opcode = tp_HALT; + } else { + tele_mem[4].opcode = tp_CUTNPASTE; + tele_mem[4].args.cutnpaste.from = + (unsigned char *)decision_o2; + tele_mem[4].args.cutnpaste.count = + decision_evtype->arg_kclass[1]->kobject_size; + tele_mem[5].opcode = tp_HALT; + } +#undef decision_evtype + teleport_reset(&teleport, &(tele_mem[0]), to_user); + question_ready = 0; + goto feed_lions; + +do_fetch_update: + tele_mem[0].opcode = tp_PUT32; + tele_mem[0].args.put32.what = 0; + tele_mem[1].opcode = tp_PUT32; + if (send_fetch_or_update_answer == MEDUSA_COMM_FETCH_REQUEST) { /* fetch */ + tele_mem[1].args.put32.what = answ_kobj ? + MEDUSA_COMM_FETCH_ANSWER : MEDUSA_COMM_FETCH_ERROR; + } else { /* update */ + tele_mem[1].args.put32.what = MEDUSA_COMM_UPDATE_ANSWER; + } + tele_mem[2].opcode = tp_PUT32; + tele_mem[2].args.put32.what = answ_kclassid; + tele_mem[3].opcode = tp_PUT32; + tele_mem[3].args.put32.what = answ_seq; + if (send_fetch_or_update_answer == MEDUSA_COMM_UPDATE_REQUEST) { + tele_mem[4].opcode = tp_PUT32; + tele_mem[4].args.put32.what = answ_result; + tele_mem[5].opcode = tp_HALT; + } else if (answ_kobj) { + tele_mem[4].opcode = tp_CUTNPASTE; + tele_mem[4].args.cutnpaste.from = (void *)answ_kobj; + tele_mem[4].args.cutnpaste.count = answ_kclass->kobject_size; + tele_mem[5].opcode = tp_HALT; + } else + tele_mem[4].opcode = tp_HALT; + med_put_kclass(answ_kclass); /* slightly too soon */ + teleport_reset(&teleport, &(tele_mem[0]), to_user); + send_fetch_or_update_answer = 0; + goto feed_lions; + +do_announce: + /* announce_ready */ + MED_LOCK_W(registration_lock); + if (kclasses_to_register) { + struct medusa_kclass_s * p; + + p = kclasses_to_register; + kclasses_to_register = (struct medusa_kclass_s *)p->cinfo; + + p->cinfo = (cinfo_t)kclasses_registered; + kclasses_registered = p; + + tele_mem[0].opcode = tp_PUT32; + tele_mem[0].args.put32.what = 0; + tele_mem[1].opcode = tp_PUT32; + tele_mem[1].args.put32.what = + MEDUSA_COMM_KCLASSDEF; + tele_mem[2].opcode = tp_PUTKCLASS; + tele_mem[2].args.putkclass.kclassdef = p; + tele_mem[3].opcode = tp_PUTATTRS; + tele_mem[3].args.putattrs.attrlist = p->attr; + tele_mem[4].opcode = tp_HALT; + } else if (evtypes_to_register) { + struct medusa_evtype_s * p; + + p = evtypes_to_register; + evtypes_to_register = (struct medusa_evtype_s *)p->cinfo; + + p->cinfo = (cinfo_t)evtypes_registered; + evtypes_registered = p; + + tele_mem[0].opcode = tp_PUT32; + tele_mem[0].args.put32.what = 0; + tele_mem[1].opcode = tp_PUT32; + tele_mem[1].args.put32.what = + MEDUSA_COMM_EVTYPEDEF; + tele_mem[2].opcode = tp_PUTEVTYPE; + tele_mem[2].args.putevtype.evtypedef = p; + tele_mem[3].opcode = tp_PUTATTRS; + tele_mem[3].args.putattrs.attrlist = p->attr; + tele_mem[4].opcode = tp_HALT; + } + teleport_reset(&teleport, &(tele_mem[0]), to_user); + announce_ready = (kclasses_to_register || evtypes_to_register); + MED_UNLOCK_W(registration_lock); + goto feed_lions; +} + +/* + * WRITE() + */ +#ifdef OS_NETBSD +# define GET_UPTO(to_read) do { \ + int howmuch = (to_read)-recv_phase; \ + if (howmuch > (signed int)buf->uio_resid) \ + howmuch = buf->uio_resid; \ + if (howmuch <= 0) \ + break; \ + uiomove(recv_buf+recv_phase-4, howmuch, buf); \ + recv_phase += howmuch; \ +} while (0) +int medusads9userspacewrite(dev_t dev, struct uio * buf, int ioflag) +{ + struct medusa_kclass_s * cl; + if (constable != curproc) + return EPERM; +#endif /* OS_NETBSD */ +#ifdef OS_LINUX +# define GET_UPTO(to_read) do { \ + int howmuch = (to_read)-recv_phase; \ + if (howmuch > (signed int)count) \ + howmuch = count; \ + if (howmuch <= 0) \ + break; \ + __copy_from_user(recv_buf+recv_phase-4, buf, howmuch); \ + buf += howmuch; count -= howmuch; recv_phase += howmuch; \ +} while (0) +static ssize_t user_write(struct file *filp, const char *buf, size_t count, loff_t * ppos) +{ + size_t orig_count = count; + struct medusa_kclass_s * cl; + + if (constable != current) + return -EPERM; + if (*ppos != filp->f_pos) + return -ESPIPE; + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; +#endif /* OS_LINUX */ + + while (XFER_COUNT) { + if (!atomic_read(¤tly_receiving)) { + recv_phase = 0; + atomic_set(¤tly_receiving, 1); + } + if (recv_phase < 4) { + int to_read = 4 - recv_phase; + if (to_read > XFER_COUNT) + to_read = XFER_COUNT; +#ifdef OS_LINUX + __copy_from_user(((char *)&recv_type)+recv_phase, buf, + to_read); + buf += to_read; count -= to_read; +#endif +#ifdef OS_NETBSD + uiomove(((char *)&recv_type)+recv_phase, to_read, buf); +#endif + recv_phase += to_read; + if (recv_phase < 4) + continue; + } + if (recv_type == MEDUSA_COMM_AUTHANSWER) { + GET_UPTO(10); + if (recv_phase < 10) + continue; + user_answer = *(int16_t *)(recv_buf+4); +#ifdef OS_LINUX + complete(&userspace_answer); +#endif +#ifdef OS_NETBSD + simple_lock(&userspace_answer_rw); + userspace_answer_flag = 1; + wakeup(&userspace_answer_flag); + simple_unlock(&userspace_answer_rw); +#endif + atomic_set(¤tly_receiving, 0); + } else if (recv_type == MEDUSA_COMM_FETCH_REQUEST || + recv_type == MEDUSA_COMM_UPDATE_REQUEST) { + GET_UPTO(12); + if (recv_phase < 12) + continue; + + cl = med_get_kclass_by_pointer( + (struct medusa_kclass_s *) + (*(u_int32_t *)(recv_buf)) + ); + if (!cl) { + MED_PRINTF(MODULENAME ": protocol error at write(): unknown kclass 0x%.4x!\n", (cinfo_t)(*(u_int32_t *)(recv_buf))); + atomic_set(¤tly_receiving, 0); +#ifdef ERRORS_CAUSE_SEGFAULT +# ifdef OS_LINUX + return -EFAULT; +# else + return EFAULT; +# endif +#else + break; +#endif + } + GET_UPTO(12+cl->kobject_size); + if (recv_phase < 12+cl->kobject_size) { + med_put_kclass(cl); + continue; + } + if (send_fetch_or_update_answer) { + /* not so much to do... */ + med_put_kclass(answ_kclass); + } + answ_kclass = cl; + if (recv_type == MEDUSA_COMM_FETCH_REQUEST) { + if (cl->fetch) + answ_kobj = cl->fetch((struct medusa_kobject_s *) + (recv_buf+8)); + else + answ_kobj = NULL; + } else { + if (cl->update) + answ_result = cl->update( + (struct medusa_kobject_s *)(recv_buf+8)); + else + answ_result = MED_ERR; + } + answ_kclassid = (*(u_int32_t *)(recv_buf)); + answ_seq = (*((u_int32_t *)(recv_buf)+1)); + send_fetch_or_update_answer = recv_type; + + atomic_set(¤tly_receiving, 0); + } else { + MED_PRINTF(MODULENAME ": protocol error at write(): unknown command 0x%.4x!\n", recv_type); + atomic_set(¤tly_receiving, 0); +#ifdef ERRORS_CAUSE_SEGFAULT +# ifdef OS_LINUX + return -EFAULT; +# else + return EFAULT; +# endif +#endif + } + } +#ifdef OS_LINUX + return orig_count; +#else + return 0; +#endif +} + +/* + * POLL() + */ +#ifdef OS_NETBSD +int medusads9userspacepoll __P((dev_t dev, int events, struct proc * p)) +{ + if (atomic_read(¤tly_receiving) && + (events & (POLLOUT | POLLWRNORM)) ) + return events & (POLLOUT | POLLWRNORM); + + if (events & (POLLIN | POLLRDNORM)) { + selrecord(p, &userspace); + if (teleport.cycle != tpc_HALT || + send_fetch_or_update_answer || + announce_ready || + question_ready + ) + return events & (POLLIN | POLLRDNORM); + } + return 0; +} +#endif /* OS_NETBSD */ +#ifdef OS_LINUX +static unsigned int user_poll(struct file *filp, poll_table * wait) +{ + if (constable != current) + return -EPERM; + poll_wait(filp, &userspace, wait); + if (atomic_read(¤tly_receiving)) + return POLLOUT | POLLWRNORM; + if (teleport.cycle != tpc_HALT) + return POLLIN | POLLRDNORM; + if (send_fetch_or_update_answer || announce_ready || question_ready) + return POLLIN | POLLRDNORM; + return POLLOUT | POLLWRNORM; +} +#endif /* OS_LINUX */ + +/* + * OPEN() + */ +#ifdef OS_NETBSD +int medusads9userspaceopen (dev_t dev, int flags, int ifmt, struct proc * p) +{ + int retval = EPERM; + + if (p != curproc) { + MED_PRINTF(MODULENAME ": the ufo has been encountered.\n"); + return ENXIO; + } +#endif /* OS_NETBSD */ +#ifdef OS_LINUX +static int user_open(struct inode *inode, struct file *file) +{ + int retval = -EPERM; + +#endif /* OS_LINUX */ + + MOD_INC_USE_COUNT; + + MED_LOCK_W(constable_openclose); + if (atomic_read(&constable_present)) + goto out; + + constable = CURRENTPTR; + + atomic_set(¤tly_receiving, 0); + tele_mem[0].opcode = tp_PUT32; + tele_mem[0].args.put32.what = MEDUSA_COMM_GREETING; + tele_mem[1].opcode = tp_HALT; + teleport_reset(&teleport, &(tele_mem[0]), to_user); + + /* this must be the last thing done */ + atomic_set(&constable_present, 1); + MED_UNLOCK_W(constable_openclose); + + evtypes_to_register = NULL; + kclasses_to_register = NULL; + MED_REGISTER_AUTHSERVER(chardev_medusa); + return 0; /* success */ +out: + MED_UNLOCK_W(constable_openclose); + return retval; +} + +/* + * CLOSE() + */ +#ifdef OS_NETBSD +int medusads9userspaceclose(dev_t dev, int flags, int fmt, struct proc * p) +{ + if (constable != p) + return 0; /* ;) */ +#endif +#ifdef OS_LINUX +static int user_release(struct inode *inode, struct file *file) +{ + DECLARE_WAITQUEUE(wait,current); +#endif + + if (constable != CURRENTPTR) + return 0; /* ;) */ + MED_LOCK_W(registration_lock); + if (evtypes_registered) { + struct medusa_evtype_s * p1, * p2; + p1 = evtypes_registered; + do { + p2 = p1; + p1 = (struct medusa_evtype_s *)p1->cinfo; + // med_put_evtype(p2); + } while (p1); + } + evtypes_registered = NULL; + if (kclasses_registered) { + struct medusa_kclass_s * p1, * p2; + p1 = kclasses_registered; + do { + p2 = p1; + p1 = (struct medusa_kclass_s *)p1->cinfo; + med_put_kclass(p2); + } while (p1); + } + kclasses_registered = NULL; + MED_UNLOCK_W(registration_lock); + if (send_fetch_or_update_answer) { + med_put_kclass(answ_kclass); + send_fetch_or_update_answer = 0; + } + + MED_PRINTF("Security daemon unregistered.\n"); +#if defined(CONFIG_MEDUSA_HALT) + MED_PRINTF("No security daemon, system halted.\n"); + notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL); + machine_halt(); +#elif defined(CONFIG_MEDUSA_REBOOT) + MED_PRINTF("No security daemon, rebooting system.\n"); + ctrl_alt_del(); +#endif +#ifdef OS_LINUX + add_wait_queue(&close_wait, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); +#endif + MED_UNREGISTER_AUTHSERVER(chardev_medusa); + MED_LOCK_W(constable_openclose); + atomic_set(&constable_present, 0); + constable = NULL; +#ifdef OS_LINUX + complete(&userspace_answer); /* the one which already might be in */ +#endif +#ifdef OS_NETBSD + simple_lock(&userspace_answer_rw); + userspace_answer_flag = 1; + wakeup(&userspace_answer_flag); + simple_unlock(&userspace_answer_rw); +#endif + +#ifdef OS_NETBSD + while (chardev_medusa.use_count) + ltsleep(&close_wait, PRIBIO, 0, 0, &constable_openclose); + userspace_answer_flag = 0; +#endif + question_ready = announce_ready = 0; + MED_UNLOCK_W(constable_openclose); +#ifdef OS_LINUX + schedule(); + remove_wait_queue(&close_wait, &wait); +#endif + MOD_DEC_USE_COUNT; + return 0; +} + +#ifdef OS_NETBSD +void medusads9userspaceattach (struct device * dev1, struct device * dev2, void * p) +{ + MED_PRINTF(MODULENAME ": registering L4 character device\n", MEDUSA_MAJOR); + lockinit(&constable_mutex, PZERO, "constablewait", 0, 0); +} +#endif +#ifdef OS_LINUX +static int chardev_constable_init(void) +{ + MED_PRINTF(MODULENAME ": registering L4 character device with major %d\n", MEDUSA_MAJOR); + if (register_chrdev(MEDUSA_MAJOR, MODULENAME, &fops)) { + MED_PRINTF(MODULENAME ": cannot register character device with major %d\n", MEDUSA_MAJOR); + return -1; + } + devfs_register(NULL, "medusa", DEVFS_FL_DEFAULT, + MEDUSA_MAJOR, 0, + S_IFCHR | S_IRUSR | S_IWUSR , + &fops, NULL); + + return 0; +} +#endif + +#ifdef OS_LINUX +static void chardev_constable_exit(void) +{ + devfs_unregister(devfs_find_handle + (NULL, "medusa", MEDUSA_MAJOR, 0, + DEVFS_SPECIAL_CHR, 0)); + unregister_chrdev(MEDUSA_MAJOR, MODULENAME); +} + +module_init(chardev_constable_init); +module_exit(chardev_constable_exit); +MODULE_LICENSE("GPL"); +#endif diff -ruN linux-2.4.23-clean/medusa/l4-constable/teleport.c linux-2.4.23-medusa/medusa/l4-constable/teleport.c --- linux-2.4.23-clean/medusa/l4-constable/teleport.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l4-constable/teleport.c 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,202 @@ +/* + * L4 authentication server for Medusa DS9 + * Copyright (C) 2002 Milan Pikula + * + * data to userspace go through this programmable teleport ;) + */ + +#include +#include +#include +#include + +#if MED_RO != MED_COMM_TYPE_READ_ONLY +#error "L3 and L4 constants don't match. We don't convert them. Go well, go hell." +#endif + +#define DEBUG /* define this to get extra debugging output */ + +#include "teleport.h" + +#undef PARANOIA_CHECKS /* define this to enable extra checking */ + +/* much of this code is platform independent */ +/* assumption: we're completely serialized (!!!) */ + +static ssize_t (*_to_user)(void *, size_t) = NULL; +static inline ssize_t place_to_user(teleport_t * teleport, + size_t * userlimit); + +/****/ + +void teleport_reset(teleport_t * teleport, teleport_insn_t * addr, + ssize_t (*to_user)(void *, size_t)) +{ + _to_user = to_user; + teleport->ip = addr-1; + teleport->cycle = tpc_FETCH; +} + +ssize_t teleport_cycle(teleport_t * teleport, size_t userlimit) +{ + ssize_t retval = 0; + ssize_t tmp; + + while (userlimit || teleport->cycle == tpc_FETCH) { + tmp = 0; + switch(teleport->cycle) { + case tpc_HALT: + return retval; + case tpc_FETCH: + teleport->cycle = tpc_EXECUTE; + switch ((++teleport->ip)->opcode) { + case tp_PUT16: + teleport->data_to_user = + (unsigned char *)&teleport->ip->args.put16.what; + teleport->remaining = 2; + break; + case tp_PUT32: + teleport->data_to_user = + (unsigned char *)&teleport->ip->args.put32.what; + teleport->remaining = 4; + break; + case tp_CUTNPASTE: + teleport->data_to_user = + teleport->ip->args.cutnpaste.from; + teleport->remaining = + teleport->ip->args.cutnpaste.count; + break; + case tp_PUTATTRS: + teleport->u.putattrs.current_attr = -1; + teleport->remaining = 0; + break; + case tp_PUTKCLASS: + teleport->u.putkclass.cl.kclassid = + (u_int32_t)teleport->ip->args.putkclass.kclassdef; + teleport->u.putkclass.cl.size = + teleport->ip->args.putkclass.kclassdef->kobject_size; + memcpy(teleport->u.putkclass.cl.name, + teleport->ip->args.putkclass.kclassdef->name, + MEDUSA_COMM_KCLASSNAME_MAX < MEDUSA_KCLASSNAME_MAX ? MEDUSA_COMM_KCLASSNAME_MAX : MEDUSA_KCLASSNAME_MAX); + teleport->data_to_user = + (unsigned char *)&teleport->u.putkclass.cl; + teleport->remaining = + sizeof(struct medusa_comm_kclass_s); +#ifdef DEBUG + MED_PRINTF("-> class %s [%x]\n", teleport->u.putkclass.cl.name, + teleport->u.putkclass.cl.kclassid); +#endif + break; + case tp_PUTEVTYPE: + teleport->u.putevtype.ev.evid = + (u_int32_t)teleport->ip->args.putevtype.evtypedef; + teleport->u.putevtype.ev.size = + teleport->ip->args.putevtype.evtypedef->event_size; + teleport->u.putevtype.ev.actbit = + teleport->ip->args.putevtype.evtypedef->bitnr; + memcpy(teleport->u.putevtype.ev.name, + teleport->ip->args.putevtype.evtypedef->name, + MEDUSA_COMM_EVNAME_MAX < MEDUSA_EVNAME_MAX ? MEDUSA_COMM_EVNAME_MAX : MEDUSA_EVNAME_MAX); + teleport->u.putevtype.ev.ev_kclass[0] = + (u_int32_t)teleport->ip->args.putevtype.evtypedef->arg_kclass[0]; + teleport->u.putevtype.ev.ev_kclass[1] = + (u_int32_t)teleport->ip->args.putevtype.evtypedef->arg_kclass[1]; + +#ifdef DEBUG + MED_PRINTF("-> evtype %s [%x] with [%x] and [%x]\n", teleport->u.putevtype.ev.name, + teleport->u.putevtype.ev.evid, + teleport->u.putevtype.ev.ev_kclass[0], + teleport->u.putevtype.ev.ev_kclass[1] + ); +#endif + + memcpy(teleport->u.putevtype.ev.ev_name[0], + teleport->ip->args.putevtype.evtypedef->arg_name[0], + MEDUSA_COMM_ATTRNAME_MAX < MEDUSA_ATTRNAME_MAX ? MEDUSA_COMM_ATTRNAME_MAX : MEDUSA_ATTRNAME_MAX); + memcpy(teleport->u.putevtype.ev.ev_name[1], + teleport->ip->args.putevtype.evtypedef->arg_name[1], + MEDUSA_COMM_ATTRNAME_MAX < MEDUSA_ATTRNAME_MAX ? MEDUSA_COMM_ATTRNAME_MAX : MEDUSA_ATTRNAME_MAX); + teleport->data_to_user = + (unsigned char *)&teleport->u.putevtype.ev; + teleport->remaining = + sizeof(struct medusa_comm_evtype_s); + break; + case tp_HALT: + teleport->cycle = tpc_HALT; + break; + } + if (teleport->cycle == tpc_HALT) + break; + /* fallthrough */ + case tpc_EXECUTE: + switch (teleport->ip->opcode) { + case tp_PUT16: + case tp_PUT32: + case tp_CUTNPASTE: + case tp_PUTKCLASS: + case tp_PUTEVTYPE: + tmp = place_to_user(teleport, &userlimit); + if (!teleport->remaining) + teleport->cycle = tpc_FETCH; + break; + case tp_PUTATTRS: + if (teleport->remaining) { + tmp = place_to_user(teleport, &userlimit); + if (teleport->remaining) + break; + } + if (teleport->u.putattrs.current_attr >= 0 && + teleport->ip->args.putattrs.attrlist[ + teleport->u.putattrs.current_attr + ].type == MED_END) { + teleport->cycle = tpc_FETCH; + break; + } + teleport->u.putattrs.current_attr++; + teleport->u.putattrs.attr.offset = teleport->ip->args.putattrs.attrlist[teleport->u.putattrs.current_attr].offset; + teleport->u.putattrs.attr.length = teleport->ip->args.putattrs.attrlist[teleport->u.putattrs.current_attr].length; + teleport->u.putattrs.attr.type = teleport->ip->args.putattrs.attrlist[teleport->u.putattrs.current_attr].type; + memcpy(teleport->u.putattrs.attr.name, teleport->ip->args.putattrs.attrlist[teleport->u.putattrs.current_attr].name, MEDUSA_COMM_ATTRNAME_MAX < MEDUSA_ATTRNAME_MAX ? MEDUSA_COMM_ATTRNAME_MAX : MEDUSA_ATTRNAME_MAX); + teleport->data_to_user = + (unsigned char *)&teleport->u.putattrs.attr; + teleport->remaining = + sizeof(struct medusa_comm_attribute_s); + break; + case tp_HALT: + teleport->cycle = tpc_HALT; + break; + default: + MED_PRINTF("l4/teleport: unknown instruction (0x%2x) at %p\n", teleport->ip->opcode, teleport->ip); + teleport->cycle = tpc_HALT; + } + } + if (tmp > 0) + retval += tmp; + else if (tmp < 0) + return tmp; /* abnormal condition, data lost */ + } + return retval; +} + +static inline ssize_t place_to_user(teleport_t * teleport, + size_t * userlimit) +{ + ssize_t len = *userlimit < teleport->remaining ? + *userlimit : teleport->remaining; + + if (!len) + return 0; +#ifdef PARANOIA_CHECKS + if (!_to_user) { + MED_PRINTF("teleport wrongly initialized!\n"); + return 0; + } +#endif + len = _to_user(teleport->data_to_user, len); + if (len < 0) + return len; + teleport->data_to_user += len; teleport->remaining -= len; + *userlimit -= len; + return len; +} + diff -ruN linux-2.4.23-clean/medusa/l4-constable/teleport.h linux-2.4.23-medusa/medusa/l4-constable/teleport.h --- linux-2.4.23-clean/medusa/l4-constable/teleport.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-medusa/medusa/l4-constable/teleport.h 2003-12-08 19:31:38.000000000 +0100 @@ -0,0 +1,78 @@ +#ifndef _MEDUSA_TELEPORT_H +#define _MEDUSA_TELEPORT_H + +#include + +typedef enum { + tp_NOP, /* do nothing */ + tp_PUT16, /* put 16-bit constant */ + tp_PUT32, /* put 32-bit constant */ + tp_CUTNPASTE, /* put the memory region */ + tp_PUTATTRS, /* put attributes */ + tp_PUTKCLASS, /* put kclass (without attrs) and assign it a number */ + tp_PUTEVTYPE, /* put evtype (...) ... */ + + tp_HALT, /* end of the routine */ +} teleport_opcode_t; + +typedef enum { + tpc_FETCH, /* instruction fetch (and decode as well) */ + tpc_EXECUTE, /* instruction execution */ + tpc_HALT, /* does nothing */ +} teleport_cycle_t; + +typedef struct { + int opcode; + union { + struct { + void * data[2]; + } nop; + struct { + u_int16_t what; + } put16; + struct { + u_int32_t what; + } put32; + struct { + unsigned char * from; + unsigned int count; + } cutnpaste; + struct { + struct medusa_attribute_s * attrlist; + } putattrs; + struct { + struct medusa_kclass_s * kclassdef; + } putkclass; + struct { + struct medusa_evtype_s * evtypedef; + } putevtype; + } args; +} teleport_insn_t; + +typedef struct { + /* instruction to execute */ + teleport_insn_t * ip; + teleport_cycle_t cycle; + + /* registers of the processor */ + unsigned char * data_to_user; + size_t remaining; + union { + struct { + int current_attr; + struct medusa_comm_attribute_s attr; + } putattrs; + struct { + struct medusa_comm_kclass_s cl; + } putkclass; + struct { + struct medusa_comm_evtype_s ev; + } putevtype; + } u; +} teleport_t; + +extern void teleport_reset(teleport_t * teleport, teleport_insn_t * addr, + ssize_t (*to_user)(void * from, size_t len)); +extern ssize_t teleport_cycle(teleport_t * teleport, + size_t userlimit); +#endif