I've been academically examining (== ripping off) LSM and GrSecurity for the past few days, and managed to implement an LSM infrastructure that does full transparent stacking and allows about 5-10 hooks (I'm not counting) to implement part of GrSecurity (very little). This patch has been tested with 3 dummy modules to do transparent stacking. The dummy modules produce unique output with printk(KERN_INFO) when you cat /proc/self/maps. There's also a kernsec module to implement GrSecurity linking restrictions and partial /proc restrictions, which I wrote to learn how those work. Here's the patch. I'm not on the list so CC me replies. Any comments? It's just an academic toy, not a patch to LSM or anything; but I'd like to know how I did. I designed the stacking myself in 5 minutes, implemented in 10, then spent all day fixing an obscure bug (I treated the doubly linked list as singly linked when registering, and doubly when unregistering). It's nothing major. -- All content of all messages exchanged herein are left in the Public Domain, unless otherwise explicitly stated. diff -urNp linux-2.6.10/arch/alpha/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/alpha/kernel/vmlinux.lds.S --- linux-2.6.10/arch/alpha/kernel/vmlinux.lds.S 2004-12-24 16:34:57.000000000 -0500 +++ linux-2.6.10-grs/arch/alpha/kernel/vmlinux.lds.S 2005-01-25 18:47:17.650995000 -0500 @@ -73,6 +73,7 @@ SECTIONS . = ALIGN(8); SECURITY_INIT + GRSECURITY_INIT . = ALIGN(64); __per_cpu_start = .; diff -urNp linux-2.6.10/arch/cris/arch-v10/vmlinux.lds.S linux-2.6.10-grs/arch/cris/arch-v10/vmlinux.lds.S --- linux-2.6.10/arch/cris/arch-v10/vmlinux.lds.S 2004-12-24 16:34:32.000000000 -0500 +++ linux-2.6.10-grs/arch/cris/arch-v10/vmlinux.lds.S 2005-01-25 18:47:17.650995000 -0500 @@ -83,6 +83,7 @@ SECTIONS __con_initcall_end = .; } SECURITY_INIT + GRSECURITY_INIT .init.ramfs : { __initramfs_start = .; diff -urNp linux-2.6.10/arch/h8300/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/h8300/kernel/vmlinux.lds.S --- linux-2.6.10/arch/h8300/kernel/vmlinux.lds.S 2004-12-24 16:35:00.000000000 -0500 +++ linux-2.6.10-grs/arch/h8300/kernel/vmlinux.lds.S 2005-01-25 18:47:17.651995000 -0500 @@ -88,6 +88,7 @@ SECTIONS RODATA #if defined(CONFIG_ROMKERNEL) SECURITY_INIT + GRSECURITY_INIT #endif ROEND = .; #if defined(CONFIG_ROMKERNEL) @@ -142,6 +143,7 @@ SECTIONS } #if defined(CONFIG_RAMKERNEL) SECURITY_INIT + GRSECURITY_INIT #endif __begin_data = LOADADDR(.data); .bss : diff -urNp linux-2.6.10/arch/i386/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/i386/kernel/vmlinux.lds.S --- linux-2.6.10/arch/i386/kernel/vmlinux.lds.S 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-grs/arch/i386/kernel/vmlinux.lds.S 2005-01-25 18:47:17.651995000 -0500 @@ -83,6 +83,7 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + GRSECURITY_INIT . = ALIGN(4); __alt_instructions = .; .altinstructions : { *(.altinstructions) } diff -urNp linux-2.6.10/arch/m32r/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/m32r/kernel/vmlinux.lds.S --- linux-2.6.10/arch/m32r/kernel/vmlinux.lds.S 2004-12-24 16:34:26.000000000 -0500 +++ linux-2.6.10-grs/arch/m32r/kernel/vmlinux.lds.S 2005-01-25 18:47:17.651995000 -0500 @@ -97,6 +97,7 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + GRSECURITY_INIT . = ALIGN(4); __alt_instructions = .; .altinstructions : { *(.altinstructions) } diff -urNp linux-2.6.10/arch/mips/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/mips/kernel/vmlinux.lds.S --- linux-2.6.10/arch/mips/kernel/vmlinux.lds.S 2004-12-24 16:34:30.000000000 -0500 +++ linux-2.6.10-grs/arch/mips/kernel/vmlinux.lds.S 2005-01-25 18:47:17.652994000 -0500 @@ -118,6 +118,7 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + GRSECURITY_INIT . = ALIGN(4096); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } diff -urNp linux-2.6.10/arch/parisc/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/parisc/kernel/vmlinux.lds.S --- linux-2.6.10/arch/parisc/kernel/vmlinux.lds.S 2004-12-24 16:34:26.000000000 -0500 +++ linux-2.6.10-grs/arch/parisc/kernel/vmlinux.lds.S 2005-01-25 18:47:17.653994000 -0500 @@ -146,6 +146,7 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + GRSECURITY_INIT /* alternate instruction replacement. This is a mechanism x86 uses * to detect the CPU type and replace generic instruction sequences * with CPU specific ones. We don't currently do this in PA, but diff -urNp linux-2.6.10/arch/ppc/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/ppc/kernel/vmlinux.lds.S --- linux-2.6.10/arch/ppc/kernel/vmlinux.lds.S 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-grs/arch/ppc/kernel/vmlinux.lds.S 2005-01-25 18:47:17.653994000 -0500 @@ -120,6 +120,7 @@ SECTIONS __con_initcall_end = .; SECURITY_INIT + GRSECURITY_INIT __start___ftr_fixup = .; __ftr_fixup : { *(__ftr_fixup) } diff -urNp linux-2.6.10/arch/ppc64/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/ppc64/kernel/vmlinux.lds.S --- linux-2.6.10/arch/ppc64/kernel/vmlinux.lds.S 2004-12-24 16:35:23.000000000 -0500 +++ linux-2.6.10-grs/arch/ppc64/kernel/vmlinux.lds.S 2005-01-25 18:47:17.654994000 -0500 @@ -81,6 +81,7 @@ SECTIONS } SECURITY_INIT + GRSECURITY_INIT . = ALIGN(4096); .init.ramfs : { diff -urNp linux-2.6.10/arch/s390/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/s390/kernel/vmlinux.lds.S --- linux-2.6.10/arch/s390/kernel/vmlinux.lds.S 2004-12-24 16:34:31.000000000 -0500 +++ linux-2.6.10-grs/arch/s390/kernel/vmlinux.lds.S 2005-01-25 18:47:17.654994000 -0500 @@ -94,6 +94,7 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + GRSECURITY_INIT . = ALIGN(256); __initramfs_start = .; .init.ramfs : { *(.init.initramfs) } diff -urNp linux-2.6.10/arch/sh/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/sh/kernel/vmlinux.lds.S --- linux-2.6.10/arch/sh/kernel/vmlinux.lds.S 2004-12-24 16:34:58.000000000 -0500 +++ linux-2.6.10-grs/arch/sh/kernel/vmlinux.lds.S 2005-01-25 18:47:17.654994000 -0500 @@ -91,6 +91,7 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + GRSECURITY_INIT __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; diff -urNp linux-2.6.10/arch/sh64/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/sh64/kernel/vmlinux.lds.S --- linux-2.6.10/arch/sh64/kernel/vmlinux.lds.S 2004-12-24 16:34:01.000000000 -0500 +++ linux-2.6.10-grs/arch/sh64/kernel/vmlinux.lds.S 2005-01-25 18:47:17.655994000 -0500 @@ -122,6 +122,7 @@ SECTIONS .con_initcall.init : C_PHYS(.con_initcall.init) { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + GRSECURITY_INIT __initramfs_start = .; .init.ramfs : C_PHYS(.init.ramfs) { *(.init.ramfs) } __initramfs_end = .; diff -urNp linux-2.6.10/arch/sparc/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/sparc/kernel/vmlinux.lds.S --- linux-2.6.10/arch/sparc/kernel/vmlinux.lds.S 2004-12-24 16:33:51.000000000 -0500 +++ linux-2.6.10-grs/arch/sparc/kernel/vmlinux.lds.S 2005-01-25 18:47:17.655994000 -0500 @@ -62,6 +62,7 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + GRSECURITY_INIT . = ALIGN(4096); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } diff -urNp linux-2.6.10/arch/sparc64/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/sparc64/kernel/vmlinux.lds.S --- linux-2.6.10/arch/sparc64/kernel/vmlinux.lds.S 2004-12-24 16:35:25.000000000 -0500 +++ linux-2.6.10-grs/arch/sparc64/kernel/vmlinux.lds.S 2005-01-25 18:47:17.656994000 -0500 @@ -68,6 +68,7 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + GRSECURITY_INIT . = ALIGN(8192); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } diff -urNp linux-2.6.10/arch/x86_64/kernel/vmlinux.lds.S linux-2.6.10-grs/arch/x86_64/kernel/vmlinux.lds.S --- linux-2.6.10/arch/x86_64/kernel/vmlinux.lds.S 2004-12-24 16:33:50.000000000 -0500 +++ linux-2.6.10-grs/arch/x86_64/kernel/vmlinux.lds.S 2005-01-25 18:47:17.656994000 -0500 @@ -108,6 +108,7 @@ SECTIONS .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; SECURITY_INIT + GRSECURITY_INIT . = ALIGN(8); __alt_instructions = .; .altinstructions : { *(.altinstructions) } diff -urNp linux-2.6.10/drivers/char/keyboard.c linux-2.6.10-grs/drivers/char/keyboard.c --- linux-2.6.10/drivers/char/keyboard.c 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-grs/drivers/char/keyboard.c 2005-01-25 20:46:06.348314000 -0500 @@ -40,6 +40,7 @@ #include <linux/vt_kern.h> #include <linux/sysrq.h> #include <linux/input.h> +#include <linux/grsecurity.h> static void kbd_disconnect(struct input_handle *handle); extern void ctrl_alt_del(void); @@ -82,16 +83,9 @@ typedef void (k_handler_fn)(struct vc_da static k_handler_fn K_HANDLERS; static k_handler_fn *k_handler[16] = { K_HANDLERS }; -#define FN_HANDLERS\ - fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ - fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ - fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ - fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ - fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num - typedef void (fn_handler_fn)(struct vc_data *vc, struct pt_regs *regs); -static fn_handler_fn FN_HANDLERS; -static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; +static fn_handler_fn _KBD_FN_HANDLERS; +static fn_handler_fn *fn_handler[] = { _KBD_FN_HANDLERS }; /* * Variables exported for vt_ioctl.c @@ -605,6 +599,10 @@ static void k_spec(struct vc_data *vc, u kbd->kbdmode == VC_MEDIUMRAW) && value != KVAL(K_SAK)) return; /* SAK is allowed even in raw mode */ +#ifdef CONFIG_GRSECURITY + if (gr_keyboard_handler(value)) + return; +#endif fn_handler[value](vc, regs); } diff -urNp linux-2.6.10/drivers/pci/proc.c linux-2.6.10-grs/drivers/pci/proc.c --- linux-2.6.10/drivers/pci/proc.c 2004-12-24 16:34:58.000000000 -0500 +++ linux-2.6.10-grs/drivers/pci/proc.c 2005-01-25 21:01:26.312458000 -0500 @@ -12,6 +12,9 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/smp_lock.h> +#ifdef CONFIG_GRSECURITY +# include <linux/grsecurity.h> +#endif #include <asm/uaccess.h> #include <asm/byteorder.h> @@ -565,7 +568,19 @@ static struct file_operations proc_pci_o static void legacy_proc_init(void) { - struct proc_dir_entry * entry = create_proc_entry("pci", 0, NULL); + struct proc_dir_entry * entry = NULL; +#ifdef CONFIG_GRSECURITY + int error; + error = gr_proc_pci_legacy_init(&entry); + /* + * If this returns 0, we generate the entry as normal. + * If it returns non-zero, we assume entry was or will not be + * generated + */ + if (!error) +#else + entry = create_proc_entry("pci", 0, NULL); +#endif if (entry) entry->proc_fops = &proc_pci_operations; } @@ -592,8 +607,17 @@ static struct file_operations proc_bus_p static int __init pci_proc_init(void) { - struct proc_dir_entry *entry; + struct proc_dir_entry *entry = NULL; struct pci_dev *dev = NULL; +#ifdef CONFIG_GRSECURITY + int error; + /* + * Same deal as gr_proc_pci_legacy_init() + * a 0 here means "Make your own", otherwise it's filled for us. + */ + error = gr_proc_pci_init(&proc_bus_pci_dir); + if (!error) +#endif proc_bus_pci_dir = proc_mkdir("pci", proc_bus); entry = create_proc_entry("devices", 0, proc_bus_pci_dir); if (entry) diff -urNp linux-2.6.10/fs/namei.c linux-2.6.10-grs/fs/namei.c --- linux-2.6.10/fs/namei.c 2004-12-24 16:34:30.000000000 -0500 +++ linux-2.6.10-grs/fs/namei.c 2005-01-25 21:39:42.065019000 -0500 @@ -28,6 +28,9 @@ #include <linux/syscalls.h> #include <linux/mount.h> #include <linux/audit.h> +#ifdef CONFIG_GRSECURITY +# include <linux/grsecurity.h> +#endif #include <asm/namei.h> #include <asm/uaccess.h> @@ -497,6 +500,9 @@ static inline int do_follow_link(struct BUG_ON(nd->depth >= MAX_NESTED_LINKS); cond_resched(); err = security_inode_follow_link(dentry, nd); +#ifdef CONFIG_GRSECURITY + err = gr_inode_follow_link(dentry, nd); +#endif if (err) goto loop; current->link_count++; @@ -581,20 +587,20 @@ int follow_down(struct vfsmount **mnt, s { return __follow_down(mnt,dentry); } - + static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry) { while(1) { struct vfsmount *parent; struct dentry *old = *dentry; - read_lock(¤t->fs->lock); + read_lock(¤t->fs->lock); if (*dentry == current->fs->root && - *mnt == current->fs->rootmnt) { - read_unlock(¤t->fs->lock); + *mnt == current->fs->rootmnt) { + read_unlock(¤t->fs->lock); break; } - read_unlock(¤t->fs->lock); + read_unlock(¤t->fs->lock); spin_lock(&dcache_lock); if (*dentry != (*mnt)->mnt_root) { *dentry = dget((*dentry)->d_parent); @@ -630,7 +636,7 @@ struct path { * It _is_ time-critical. */ static int do_lookup(struct nameidata *nd, struct qstr *name, - struct path *path) + struct path *path) { struct vfsmount *mnt = nd->mnt; struct dentry *dentry = __d_lookup(nd->dentry, name); @@ -676,7 +682,7 @@ int fastcall link_path_walk(const char * struct inode *inode; int err; unsigned int lookup_flags = nd->flags; - + while (*name=='/') name++; if (!*name) @@ -696,7 +702,7 @@ int fastcall link_path_walk(const char * if (err == -EAGAIN) { err = permission(inode, MAY_EXEC, nd); } - if (err) + if (err) break; this.name = name; @@ -814,7 +820,7 @@ last_component: follow_mount(&next.mnt, &next.dentry); inode = next.dentry->d_inode; if ((lookup_flags & LOOKUP_FOLLOW) - && inode && inode->i_op && inode->i_op->follow_link) { + && inode && inode->i_op && inode->i_op->follow_link) { mntget(next.mnt); err = do_follow_link(next.dentry, nd); dput(next.dentry); @@ -853,7 +859,7 @@ return_reval: * We may need to check the cached dentry for staleness. */ if (nd->dentry && nd->dentry->d_sb && - (nd->dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) { + (nd->dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) { err = -ESTALE; /* Note: we do not d_invalidate() */ if (!nd->dentry->d_op->d_revalidate(nd->dentry, nd)) @@ -969,10 +975,10 @@ int fastcall path_lookup(const char *nam current->total_link_count = 0; retval = link_path_walk(name, nd); if (unlikely(current->audit_context - && nd && nd->dentry && nd->dentry->d_inode)) + && nd && nd->dentry && nd->dentry->d_inode)) audit_inode(name, - nd->dentry->d_inode->i_ino, - nd->dentry->d_inode->i_rdev); + nd->dentry->d_inode->i_ino, + nd->dentry->d_inode->i_rdev); return retval; } @@ -1123,7 +1129,7 @@ static inline int may_delete(struct inod if (IS_APPEND(dir)) return -EPERM; if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)|| - IS_IMMUTABLE(victim->d_inode)) + IS_IMMUTABLE(victim->d_inode)) return -EPERM; if (isdir) { if (!S_ISDIR(victim->d_inode->i_mode)) @@ -1148,7 +1154,7 @@ static inline int may_delete(struct inod * 4. We can't do it if dir is immutable (done in permission()) */ static inline int may_create(struct inode *dir, struct dentry *child, - struct nameidata *nd) + struct nameidata *nd) { if (child->d_inode) return -EEXIST; @@ -1169,10 +1175,10 @@ static inline int lookup_flags(unsigned if (f & O_NOFOLLOW) retval &= ~LOOKUP_FOLLOW; - + if ((f & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) retval &= ~LOOKUP_FOLLOW; - + if (f & O_DIRECTORY) retval |= LOOKUP_DIRECTORY; @@ -1258,7 +1264,7 @@ int may_open(struct nameidata *nd, int a if (S_ISLNK(inode->i_mode)) return -ELOOP; - + if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE)) return -EISDIR; @@ -1272,7 +1278,7 @@ int may_open(struct nameidata *nd, int a * can write to them even if the filesystem is read-only. */ if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { - flag &= ~O_TRUNC; + flag &= ~O_TRUNC; } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { if (nd->mnt->mnt_flags & MNT_NODEV) return -EACCES; @@ -1313,7 +1319,7 @@ int may_open(struct nameidata *nd, int a error = locks_verify_locked(inode); if (!error) { DQUOT_INIT(inode); - + error = do_truncate(dentry, 0); } put_write_access(inode); @@ -1584,21 +1590,21 @@ asmlinkage long sys_mknod(const char __u mode &= ~current->fs->umask; if (!IS_ERR(dentry)) { switch (mode & S_IFMT) { - case 0: case S_IFREG: - error = vfs_create(nd.dentry->d_inode,dentry,mode,&nd); - break; - case S_IFCHR: case S_IFBLK: - error = vfs_mknod(nd.dentry->d_inode,dentry,mode, - new_decode_dev(dev)); - break; - case S_IFIFO: case S_IFSOCK: - error = vfs_mknod(nd.dentry->d_inode,dentry,mode,0); - break; - case S_IFDIR: - error = -EPERM; - break; - default: - error = -EINVAL; + case 0: case S_IFREG: + error = vfs_create(nd.dentry->d_inode,dentry,mode,&nd); + break; + case S_IFCHR: case S_IFBLK: + error = vfs_mknod(nd.dentry->d_inode,dentry,mode, + new_decode_dev(dev)); + break; + case S_IFIFO: case S_IFSOCK: + error = vfs_mknod(nd.dentry->d_inode,dentry,mode,0); + break; + case S_IFDIR: + error = -EPERM; + break; + default: + error = -EINVAL; } dput(dentry); } @@ -1685,14 +1691,14 @@ void dentry_unhash(struct dentry *dentry dget(dentry); spin_lock(&dcache_lock); switch (atomic_read(&dentry->d_count)) { - default: - spin_unlock(&dcache_lock); - shrink_dcache_parent(dentry); - spin_lock(&dcache_lock); - if (atomic_read(&dentry->d_count) != 2) - break; - case 2: - __d_drop(dentry); + default: + spin_unlock(&dcache_lock); + shrink_dcache_parent(dentry); + spin_lock(&dcache_lock); + if (atomic_read(&dentry->d_count) != 2) + break; + case 2: + __d_drop(dentry); } spin_unlock(&dcache_lock); } @@ -1837,7 +1843,7 @@ asmlinkage long sys_unlink(const char __ if (inode) atomic_inc(&inode->i_count); error = vfs_unlink(nd.dentry->d_inode, dentry); - exit2: +exit2: dput(dentry); } up(&nd.dentry->d_inode->i_sem); @@ -1983,7 +1989,15 @@ asmlinkage long sys_link(const char __us new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { +#ifdef CONFIG_GRSECURITY + error = gr_inode_hardlink(new_dentry, &old_nd, &nd, to); + if (!error) +#endif error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); +#ifdef CONFIG_GRSECURITY + if (!error) + gr_inode_handle_create(new_dentry, nd.mnt); +#endif dput(new_dentry); } up(&nd.dentry->d_inode->i_sem); diff -urNp linux-2.6.10/fs/proc/array.c linux-2.6.10-grs/fs/proc/array.c --- linux-2.6.10/fs/proc/array.c 2004-12-24 16:35:00.000000000 -0500 +++ linux-2.6.10-grs/fs/proc/array.c 2005-01-25 22:52:50.399890000 -0500 @@ -73,6 +73,9 @@ #include <linux/highmem.h> #include <linux/file.h> #include <linux/times.h> +#ifdef CONFIG_GRSECURITY +# include <linux/grsecurity.h> +#endif #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -303,6 +306,7 @@ int proc_pid_status(struct task_struct * static int do_task_stat(struct task_struct *task, char * buffer, int whole) { unsigned long vsize, eip, esp, wchan = ~0UL; + unsigned long start_code, end_code, start_stack; long priority, nice; int tty_pgrp = -1, tty_nr = 0; sigset_t sigign, sigcatch; @@ -394,6 +398,37 @@ static int do_task_stat(struct task_stru /* convert nsec -> ticks */ start_time = nsec_to_clock_t(start_time); + /* + * This is to set up for grsecurity hooks + */ + if (mm) { + start_code = mm->start_code; + end_code = mm->end_code; + start_stack = mm->start_stack; + } + else + start_code = end_code = start_stack = 0; +#ifdef CONFIG_GRSECURITY + /* + * GrSecurity gets a crack at protecting this information. + * No need to pass mm; we can use get_task_mm() if it's needed. + * + * If the gr_proc_task_stat() hooks return 0, they may have altered + * one, some, or all of the passed pieces of data. Each registered + * module has a chance to knock some off this way. + * + * If the gr_proc_task_stat() hooks return non-zero, then a NULL + * string is returned. + */ + if (gr_proc_task_stat(&eip, &esp, &wchan, + &start_code, &end_code, &start_stack, + task)) { + buffer[0] = '\0'; + res = 0; + goto out; + } + +#endif res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n", @@ -422,9 +457,9 @@ static int do_task_stat(struct task_stru vsize, mm ? mm->rss : 0, /* you might want to shift this left 3 */ rsslim, - mm ? mm->start_code : 0, - mm ? mm->end_code : 0, - mm ? mm->start_stack : 0, + start_code, + end_code, + start_stack, esp, eip, /* The signal information here is obsolete. @@ -442,6 +477,7 @@ static int do_task_stat(struct task_stru task_cpu(task), task->rt_priority, task->policy); +out: if(mm) mmput(mm); return res; diff -urNp linux-2.6.10/fs/proc/base.c linux-2.6.10-grs/fs/proc/base.c --- linux-2.6.10/fs/proc/base.c 2004-12-24 16:35:00.000000000 -0500 +++ linux-2.6.10-grs/fs/proc/base.c 2005-01-26 16:06:14.283329000 -0500 @@ -31,6 +31,9 @@ #include <linux/kallsyms.h> #include <linux/mount.h> #include <linux/security.h> +#ifdef CONFIG_GRSECURITY +# include <linux/grsecurity.h> +#endif #include <linux/ptrace.h> /* @@ -473,9 +476,22 @@ out: static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) { - if (generic_permission(inode, mask, NULL) != 0) - return -EACCES; - return proc_check_root(inode); + int ret; + if (generic_permission(inode, mask, NULL) != 0) { + ret = -EACCES; + goto out; + } + ret = proc_check_root(inode); +#ifdef CONFIG_GRSECURITY + if (ret) + goto out; + + /*you can proc_task(inode) from within the call*/ + ret = gr_proc_permission(inode); +#endif + +out: + return ret; } extern struct seq_operations proc_pid_maps_op; @@ -961,6 +977,14 @@ static struct inode *proc_pid_make_inode inode->i_uid = task->euid; inode->i_gid = task->egid; } +#ifdef CONFIG_GRSECURITY + if (gr_proc_pid_make_inode(task, inode)) { + ei->task = NULL; + ei->type = 0; + put_task_struct(task); + goto out_unlock; + } +#endif security_task_to_inode(task, inode); out: @@ -994,6 +1018,9 @@ static int pid_revalidate(struct dentry inode->i_uid = 0; inode->i_gid = 0; } +#ifdef CONFIG_GRSECURITY + gr_proc_pid_revalidate(task, inode); +#endif security_task_to_inode(task, inode); return 1; } @@ -1573,7 +1600,6 @@ struct dentry *proc_pid_lookup(struct in inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO); - if (!inode) { put_task_struct(task); goto out; @@ -1584,6 +1610,26 @@ struct dentry *proc_pid_lookup(struct in inode->i_nlink = 3; inode->i_flags|=S_IMMUTABLE; +#ifdef CONFIG_GRSECURITY + /* + * Allows us to hide a task or prevent users from viewing + * other tasks, as well as modify inode. + * + * Remember to return 0 unless you're hiding this task! + */ + if (gr_proc_pid_lookup(task,inode)) { + struct proc_inode *ei; + ei = PROC_I(inode); + ei->task = NULL; + ei->type = 0; + ei->pde = NULL; + iput(inode); + inode = NULL; + put_task_struct(task); + goto out; + } +#endif + dentry->d_op = &pid_base_dentry_operations; died = 0; @@ -1682,6 +1728,10 @@ static int get_tgid_list(int index, unsi int tgid = p->pid; if (!pid_alive(p)) continue; +#ifdef CONFIG_GRSECURITY + if (gr_proc_get_tgid_list(p)) + continue; +#endif if (--index >= 0) continue; tgids[nr_tgids] = tgid; diff -urNp linux-2.6.10/fs/proc/generic.c linux-2.6.10-grs/fs/proc/generic.c --- linux-2.6.10/fs/proc/generic.c 2004-12-24 16:35:40.000000000 -0500 +++ linux-2.6.10-grs/fs/proc/generic.c 2005-01-26 21:50:06.154068000 -0500 @@ -662,6 +662,26 @@ void free_proc_entry(struct proc_dir_ent } /* + * Find a proc entry + * Duplicated from remove_proc_entry() + */ +struct proc_dir_entry **get_proc_entry(const char *name, struct proc_dir_entry *parent) { + struct proc_dir_entry **p; + const char *fn = name; + int len; + if (!parent && xlate_proc_name(name, &parent, &fn) != 0) + goto out; + len = strlen(fn); + for (p = &parent->subdir; *p; p=&(*p)->next ) { + if (!proc_match(len, fn, *p)) + continue; + return p; + } +out: + return NULL; +} + +/* * Remove a /proc entry and free it if it's not currently in use. * If it is in use, we set the 'deleted' flag. */ @@ -698,3 +718,7 @@ void remove_proc_entry(const char *name, out: return; } + +EXPORT_SYMBOL(proc_mkdir_mode); +EXPORT_SYMBOL(remove_proc_entry); +EXPORT_SYMBOL(get_proc_entry); diff -urNp linux-2.6.10/fs/proc/inode.c linux-2.6.10-grs/fs/proc/inode.c --- linux-2.6.10/fs/proc/inode.c 2004-12-24 16:35:28.000000000 -0500 +++ linux-2.6.10-grs/fs/proc/inode.c 2005-01-26 16:31:31.652654000 -0500 @@ -16,6 +16,9 @@ #include <linux/module.h> #include <linux/parser.h> #include <linux/smp_lock.h> +#ifdef CONFIG_GRSECURITY +# include <linux/grsecurity.h> +#endif #include <asm/system.h> #include <asm/uaccess.h> @@ -222,6 +225,13 @@ struct inode *proc_get_inode(struct supe if (de->proc_fops) inode->i_fop = de->proc_fops; } +#ifdef CONFIG_GRSECURITY + /* + * XXX + * Do we want to goto out_fail if not zero? + */ + gr_proc_get_inode(inode, de); +#endif out: return inode; diff -urNp linux-2.6.10/fs/proc/proc_misc.c linux-2.6.10-grs/fs/proc/proc_misc.c --- linux-2.6.10/fs/proc/proc_misc.c 2004-12-24 16:34:00.000000000 -0500 +++ linux-2.6.10-grs/fs/proc/proc_misc.c 2005-01-26 20:03:46.733690000 -0500 @@ -647,4 +647,11 @@ void __init proc_misc_init(void) entry->proc_fops = &ppc_htab_operations; } #endif +#ifdef CONFIG_GRSECURITY + /* + * The GrSecurity framework gets passed proc_root so it can try to + * remove or alter some entries. + */ + //gr_proc_misc_init(&proc_root); +#endif } diff -urNp linux-2.6.10/fs/proc/task_mmu.c linux-2.6.10-grs/fs/proc/task_mmu.c --- linux-2.6.10/fs/proc/task_mmu.c 2004-12-24 16:34:01.000000000 -0500 +++ linux-2.6.10-grs/fs/proc/task_mmu.c 2005-01-25 22:52:22.907070000 -0500 @@ -1,8 +1,12 @@ +#include <linux/config.h> #include <linux/mm.h> #include <linux/hugetlb.h> #include <linux/seq_file.h> #include <asm/elf.h> #include <asm/uaccess.h> +#ifdef CONFIG_GRSECURITY +# include <linux/grsecurity.h> +#endif char *task_mem(struct mm_struct *mm, char *buffer) { @@ -53,6 +57,7 @@ static int show_map(struct seq_file *m, unsigned long ino = 0; dev_t dev = 0; int len; + unsigned long vm_start, vm_end, pg_off, dev_mj, dev_mn; if (file) { struct inode *inode = map->vm_file->f_dentry->d_inode; @@ -60,15 +65,41 @@ static int show_map(struct seq_file *m, ino = inode->i_ino; } + vm_start = map->vm_start; + vm_end = map->vm_end; + pg_off = map->vm_pgoff << PAGE_SHIFT; + dev_mj = MAJOR(dev); + dev_mn = MINOR(dev); +#ifdef CONFIG_GRSECURITY + { + int error; + /* + * Same deal as do_task_stat() in array.c + * We get a crack at nulling these things out. + * + * Getting non-null back means we return from here. + * + * Getting ENOMSG is a special case: we return silently from here, + * i.e. without an error but without doing anything, for ENOMSG. + */ + error = gr_proc_show_map(&vm_start, &vm_end, &pg_off, + &dev_mj, &dev_mn, &ino, m); + if (error) { + if (error == -ENOMSG) + return 0; + return error; + } + } +#endif seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n", - map->vm_start, - map->vm_end, + vm_start, + vm_end, flags & VM_READ ? 'r' : '-', flags & VM_WRITE ? 'w' : '-', flags & VM_EXEC ? 'x' : '-', flags & VM_MAYSHARE ? 's' : 'p', - map->vm_pgoff << PAGE_SHIFT, - MAJOR(dev), MINOR(dev), ino, &len); + pg_off, + (unsigned int)dev_mj, (unsigned int)dev_mn, ino, &len); if (map->vm_file) { len = 25 + sizeof(void*) * 6 - len; diff -urNp linux-2.6.10/include/asm-generic/vmlinux.lds.h linux-2.6.10-grs/include/asm-generic/vmlinux.lds.h --- linux-2.6.10/include/asm-generic/vmlinux.lds.h 2004-12-24 16:33:50.000000000 -0500 +++ linux-2.6.10-grs/include/asm-generic/vmlinux.lds.h 2005-01-25 18:47:17.662993000 -0500 @@ -1,3 +1,4 @@ +#include <linux/config.h> #ifndef LOAD_OFFSET #define LOAD_OFFSET 0 #endif @@ -79,6 +80,17 @@ VMLINUX_SYMBOL(__security_initcall_end) = .; \ } +#ifdef CONFIG_GRSECURITY +#define GRSECURITY_INIT \ + .grsecurity_initcall.init : { \ + VMLINUX_SYMBOL(__grsecurity_initcall_start) = .; \ + *(.grsecurity_initcall.init) \ + VMLINUX_SYMBOL(__grsecurity_initcall_end) = .; \ + } +#else +#define GRSECURITY_INIT +#endif + #define SCHED_TEXT \ VMLINUX_SYMBOL(__sched_text_start) = .; \ *(.sched.text) \ diff -urNp linux-2.6.10/include/linux/grsecurity.h linux-2.6.10-grs/include/linux/grsecurity.h --- linux-2.6.10/include/linux/grsecurity.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/include/linux/grsecurity.h 2005-01-26 16:25:10.400613000 -0500 @@ -0,0 +1,272 @@ +/* + * Linux GrSecurity plug + * + * Copyright (C) 2005 John Moser <nigelenkiat_private> + * Copyright (C) 2005 Brad Spengler + * + * Derived from security.h which is: + * Copyright (C) 2001 WireX Communications, Inc <chrisat_private> + * Copyright (C) 2001 Greg Kroah-Hartman <gregat_private> + * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalleyat_private> + * Copyright (C) 2001 James Morris <jmorrisat_private> + * Copyright (C) 2001 Silicon Graphics, Inc. (Trust Technology Group) + * + * 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. + * + * Due to this file being licensed under the GPL there is controversy over + * whether this permits you to write a module that #includes this file + * without placing your module under the GPL. Please consult a lawyer for + * advice before doing this. + * + */ + +#ifndef __LINUX_GRSECURITY_H +#define __LINUX_GRSECURITY_H + +#ifdef CONFIG_GRSECURITY + +#include <linux/config.h> +#include <linux/fs.h> +#include <linux/binfmts.h> +#include <linux/signal.h> +#include <linux/resource.h> +#include <linux/sem.h> +#include <linux/shm.h> +#include <linux/msg.h> +#include <linux/sched.h> +#include <linux/proc_fs.h> + +#define GRSECURITY_FRAMEWORK_VERSION "2.0.0" + +struct grsecurity_operations; +/* global variables */ +extern struct grsecurity_operations *grsecurity_ops; +extern rwlock_t gr_ops_lock; + +int __init grsecurity_init(void); +int register_grsecurity(struct grsecurity_operations *ops); +int unregister_grsecurity(struct grsecurity_operations *ops); + +/** + * struct grsecurity_operations - main grsecurity structure + * + * --GrSecurity hooks for program execution operations-- + * + * + * --GrSecurity hooks for keyboard operations-- + * + * @keyboard_handler: + * Check permissions for k_spec() + * @value contains the index of the function to call from k_spec() + * + * --GrSecurity hooks for /proc-- + * + * @proc_permission: + * Permission check to access an inode in /proc + * @inode is the inode + * Return value of 0 allows this + * Return value of non-zero denies this access + * @proc_pid_make_inode: + * Handle creation in pid_make_inode(). + * @task is the task + * @inode is the created inode + * Return value is ignored at the hooks, but a non-zero return value + * tells the GrSecurity framework to STOP processing other modules. + * @proc_pid_revalidate: + * Handle revalidation in pid_revalidate(). + * @task is the task + * @inode is the inode + * Return value of 0 tells the system to handle as normal. + * Return value of non-zero tells the GrSecurity framework to STOP + * processing other modules, and prevents the normal inode->i_{uid,gid} + * changes from being made. + * @proc_pid_lookup: + * Handle look-up of tasks in /proc, and allow hiding of the task and + * altering of the inode in /proc. + * @task is the task to be validated. + * @inode is the inode that will appear in /proc + * Return value of 0 leaves the task visible. + * Return value of non-zero hides the task. + * @proc_get_tgid_list: + * Handle get_tgid_list() in fs/proc/base.c + * @task is the task that information is being requested for + * Return value of 0 allows this task to be processed + * Return value of non-zero hides information about this task + * @proc_get_inode: + * Handles getting an inode entry, allowing attributes of the inode + * to be changed. + * @inode is the inode + * @de is the directory entry + * Return value of 0 allows the inode (modified or not) to be visible + * Return value of non-zero does nothing; in the future, the inode will + * be hidden. + * @proc_task_stat: + * Handle /proc task stat information, replacing anything you want to + * obscure. The hooks will prevent you from re-adding any information + * another module set to NULL; but there should be enough information + * in @task to regenerate that data, so rely on @task rather than the + * other passed data. + * @eip is eip + * @esp is esp + * @wchan is wchan + * @start_code is start_code + * @end_code is end_code + * @start_stack is start_stack + * @task is the task passed to do_task_stat() + * Returns 0 whether or not any of the passed fields have been altered. + * Returns an error to indicate that do_task_stat() should just return + * NULL without revealing information. + * @proc_show_map: + * Handle /proc/<pid>/maps file for map showing. Again, use @m to get + * at the data we pass pointers to; other modules may NULL these and + * that will be protected even if your module de-NULLs them. + * @vm_start is the vm_start + * @vm_end is vm_end, + * @vm_pgoff + * @dev_mj is the major for the device of file-backed mappings + * @dev_mn is the minor for the device of file-backed mappings + * @ino is the inode for file-backed mappings + * @m is the struct seq_file passed to show_map() + * Returns 0 whether or not any of the passed fields have been altered + * Returns an error to refuse the show_map() + * Returns ENOMSG to skip showing anything, yet return from show_map() + * with no error. + * @proc_pci_legacy_init: + * Handle PCI legacy_proc_init() + * @entry is a pointer to a pointer to a proc_dir_entry structure. + * Returns 0 if nothing. + * Returns 1 and optionally fills entry if this module is handling or + * forbidding the creation of a /proc entry + * @proc_pci_init: + * Handle PCI pci_proc_init() + * @proc_bus_pci_dir is a pointer to proc_bus_pci_dir in + * drivers/pci/proc.c + * Returns 0 if nothing. + * Returns 1 and fills proc_bus_pci_dir if the module affects this. + * + * --GrSecurity hooks for inode operations-- + * + * @inode_follow_link: + * Check permission to following a symlink. + * @dentry contains the dentry structure for the link. + * @nd contains the nameidata structure for the parent directory. + * Return 0 if permission is granted. + * @inode_hardlink: + * Check permission to create a hardlink. + * @new_dentry contains the newly created dentry + * @old_nd contains the nameidata structure for the target of the hardlink + * @nd contains the nameidata structure for the parent + * @to contains the path to hardlink into + * Return 0 if permission is granted. + * @inode_handle_create: + * Handle the creation of a new inode, i.e. for ACL systems to track new + * inodes. + * @new_dentry is the newly created dentry + * @mnt is the vfsmount for the nameidata for the parent + * No return value + */ + +struct grsecurity_operations { + /*doubly linked list*/ + struct grsecurity_operations + *next; + struct grsecurity_operations + *prev; + /*end back and forward pointers*/ + /*KEYBOARD FUNCTIONS*/ + int (*keyboard_handler) (const int value); + /*--PROC FUNCTIONS--*/ + int (*proc_permission) (const struct inode *inode); + int (*proc_pid_make_inode) (const struct task_struct *task, + struct inode *inode); + int (*proc_pid_revalidate) (const struct task_struct *task, + struct inode *inode); + int (*proc_pid_lookup) (const struct task_struct *task, + struct inode *inode); + int (*proc_get_tgid_list) (const struct task_struct *task); + int (*proc_get_inode) (struct inode *inode, + const struct proc_dir_entry *de); + int (*proc_task_stat) (unsigned long *eip, + unsigned long *esp, + unsigned long *wchan, + unsigned long *start_code, + unsigned long *end_code, + unsigned long *start_stack, + struct task_struct *task); + int (*proc_show_map) (unsigned long *vm_start, + unsigned long *vm_end, + unsigned long *vm_pgoff, + unsigned long *dev_mj, + unsigned long *dev_mn, + unsigned long *ino, + struct seq_file *m); + int (*proc_pci_legacy_init) (const struct proc_dir_entry **entry); + int (*proc_pci_init) (struct proc_dir_entry **proc_bus_pci_dir); + /*--INODE FUNCTIONS--*/ + int (*inode_follow_link) (const struct dentry *dentry, + const struct nameidata *nd); + int (*inode_hardlink) (const struct dentry *new_dentry, + const struct nameidata *old_nd, + const struct nameidata *nd, + const char *to); + void (*inode_handle_create) (const struct dentry *new_dentry, + const struct vfsmount *mnt); + +}; + +int gr_keyboard_handler(const int value); + +int gr_proc_permission(const struct inode *inode); + +int gr_proc_pid_make_inode(const struct task_struct *task, + struct inode *inode); + +int gr_proc_pid_revalidate(const struct task_struct *task, + struct inode *inode); + +int gr_proc_pid_lookup(const struct task_struct *task, + struct inode *inode); + +int gr_proc_get_tgid_list(const struct task_struct *task); + +int gr_proc_get_inode(struct inode *inode, + const struct proc_dir_entry *de); + +int gr_proc_task_stat(unsigned long *eip, + unsigned long *esp, + unsigned long *wchan, + unsigned long *start_code, + unsigned long *end_code, + unsigned long *start_stack, + struct task_struct *task); + +int gr_proc_show_map (unsigned long *vm_start, + unsigned long *vm_end, + unsigned long *vm_pgoff, + unsigned long *dev_mj, + unsigned long *dev_mn, + unsigned long *ino, + struct seq_file *m); + +int gr_proc_pci_legacy_init(const struct proc_dir_entry **entry); + +int gr_proc_pci_init(struct proc_dir_entry **proc_bus_pci_dir); + +int gr_inode_follow_link(const struct dentry *dentry, + const struct nameidata *nd); + +int gr_inode_hardlink (const struct dentry *new_dentry, + const struct nameidata *old_nd, + const struct nameidata *nd, + const char *to); + +void gr_inode_handle_create (const struct dentry *new_dentry, + const struct vfsmount *mnt); + +#endif /* CONFIG_GRSECURITY */ + +#endif /* ! __LINUX_GRSECURITY_H */ + diff -urNp linux-2.6.10/include/linux/init.h linux-2.6.10-grs/include/linux/init.h --- linux-2.6.10/include/linux/init.h 2004-12-24 16:33:50.000000000 -0500 +++ linux-2.6.10-grs/include/linux/init.h 2005-01-25 18:47:17.663993000 -0500 @@ -66,6 +66,9 @@ typedef void (*exitcall_t)(void); extern initcall_t __con_initcall_start, __con_initcall_end; extern initcall_t __security_initcall_start, __security_initcall_end; +#ifdef CONFIG_GRSECURITY +extern initcall_t __grsecurity_initcall_start, __grsecurity_initcall_end; +#endif /* Defined in init/main.c */ extern char saved_command_line[]; @@ -107,6 +110,11 @@ extern char saved_command_line[]; static initcall_t __initcall_##fn \ __attribute_used__ __attribute__((__section__(".security_initcall.init"))) = fn +#ifdef CONFIG_GRSECURITY +#define grsecurity_initcall(fn) \ + static initcall_t __grinitcall_##fn \ + __attribute_used__ __attribute__((__section__(".grsecurity_initcall.init"))) = fn +#endif struct obs_kernel_param { const char *str; int (*setup_func)(char *); @@ -179,6 +187,9 @@ void __init parse_early_param(void); #define late_initcall(fn) module_init(fn) #define security_initcall(fn) module_init(fn) +#ifdef CONFIG_GRSECURITY +#define grsecurity_initcall(fn) module_init(fn) +#endif /* These macros create a dummy inline: gcc 2.9x does not count alias as usage, hence the `unused function' warning when __init functions diff -urNp linux-2.6.10/include/linux/keyboard.h linux-2.6.10-grs/include/linux/keyboard.h --- linux-2.6.10/include/linux/keyboard.h 2004-12-24 16:34:00.000000000 -0500 +++ linux-2.6.10-grs/include/linux/keyboard.h 2005-01-25 20:44:41.020286000 -0500 @@ -3,6 +3,13 @@ #include <linux/wait.h> +#define _KBD_FN_HANDLERS\ + fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ + fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ + fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ + fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ + fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num + #define KG_SHIFT 0 #define KG_CTRL 2 #define KG_ALT 3 diff -urNp linux-2.6.10/include/linux/proc_fs.h linux-2.6.10-grs/include/linux/proc_fs.h --- linux-2.6.10/include/linux/proc_fs.h 2004-12-24 16:35:50.000000000 -0500 +++ linux-2.6.10-grs/include/linux/proc_fs.h 2005-01-26 21:23:44.367536000 -0500 @@ -100,6 +100,7 @@ char *task_mem(struct mm_struct *, char extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent); extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent); +extern struct proc_dir_entry **get_proc_entry(const char *name, struct proc_dir_entry *parent); extern struct vfsmount *proc_mnt; extern int proc_fill_super(struct super_block *,void *,int); diff -urNp linux-2.6.10/init/main.c linux-2.6.10-grs/init/main.c --- linux-2.6.10/init/main.c 2004-12-24 16:34:01.000000000 -0500 +++ linux-2.6.10-grs/init/main.c 2005-01-25 20:55:10.851537000 -0500 @@ -34,6 +34,9 @@ #include <linux/kmod.h> #include <linux/kernel_stat.h> #include <linux/security.h> +#ifdef CONFIG_GRSECURITY +# include <linux/grsecurity.h> +#endif #include <linux/workqueue.h> #include <linux/profile.h> #include <linux/rcupdate.h> @@ -565,6 +568,9 @@ asmlinkage void __init start_kernel(void buffer_init(); unnamed_dev_init(); security_init(); +#ifdef CONFIG_GRSECURITY + grsecurity_init(); +#endif vfs_caches_init(num_physpages); radix_tree_init(); signals_init(); diff -urNp linux-2.6.10/security/grsecurity/dummy/gr_dummy1.c linux-2.6.10-grs/security/grsecurity/dummy/gr_dummy1.c --- linux-2.6.10/security/grsecurity/dummy/gr_dummy1.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/dummy/gr_dummy1.c 2005-01-26 22:18:32.222836000 -0500 @@ -0,0 +1,66 @@ +/* + * These are dummy modules. + * + * Copyright (C) 2005 John Moser <nigelenkiat_private> + * + * LICENSE: GPLv2 + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/config.h> +#include <linux/grsecurity.h> + +#define DUMMY_NAME "GR_DUMMY_MODULE_1" + + +static int dummy_proc_show_map (unsigned long *vm_start, + unsigned long *vm_end, + unsigned long *vm_pgoff, + unsigned long *dev_mj, + unsigned long *dev_mn, + unsigned long *ino, + struct seq_file *m) { + printk(KERN_INFO "***GrSecurity stacking test in " DUMMY_NAME "***\n"); + return 0; +} + +static +struct grsecurity_operations sec_ops = { + .proc_show_map = dummy_proc_show_map, +}; + +static int __init +dummy_m_init(void) +{ + /* register ourselves with the security framework */ + if (register_grsecurity (&sec_ops)) { + printk (KERN_INFO + " Failure registering " DUMMY_NAME + " module with the kernel\n"); + return -EINVAL; + } + + printk (KERN_INFO " " DUMMY_NAME " module initialized.\n"); + + return 0; +} + +static void __exit +dummy_m_exit(void) +{ + /* remove ourselves from the security framework */ + if (unregister_grsecurity (&sec_ops)) { + printk (KERN_INFO "Failure unregistering " DUMMY_NAME + " module with the kernel\n"); + } + + printk (KERN_INFO DUMMY_NAME " Plug module removed\n"); +} + +grsecurity_initcall(dummy_m_init); +module_exit(dummy_m_exit); + +MODULE_AUTHOR("John Moser"); +MODULE_DESCRIPTION(DUMMY_NAME " module"); +MODULE_LICENSE("GPL"); diff -urNp linux-2.6.10/security/grsecurity/dummy/gr_dummy2.c linux-2.6.10-grs/security/grsecurity/dummy/gr_dummy2.c --- linux-2.6.10/security/grsecurity/dummy/gr_dummy2.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/dummy/gr_dummy2.c 2005-01-26 22:18:42.047343000 -0500 @@ -0,0 +1,66 @@ +/* + * These are dummy modules. + * + * Copyright (C) 2005 John Moser <nigelenkiat_private> + * + * LICENSE: GPLv2 + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/config.h> +#include <linux/grsecurity.h> + +#define DUMMY_NAME "GR_DUMMY_MODULE_2" + + +static int dummy_proc_show_map (unsigned long *vm_start, + unsigned long *vm_end, + unsigned long *vm_pgoff, + unsigned long *dev_mj, + unsigned long *dev_mn, + unsigned long *ino, + struct seq_file *m) { + printk(KERN_INFO "***GrSecurity stacking test in " DUMMY_NAME "***\n"); + return 0; +} + +static +struct grsecurity_operations sec_ops = { + .proc_show_map = dummy_proc_show_map, +}; + +static int __init +dummy_m_init(void) +{ + /* register ourselves with the security framework */ + if (register_grsecurity (&sec_ops)) { + printk (KERN_INFO + " Failure registering " DUMMY_NAME + " module with the kernel\n"); + return -EINVAL; + } + + printk (KERN_INFO " " DUMMY_NAME " module initialized.\n"); + + return 0; +} + +static void __exit +dummy_m_exit(void) +{ + /* remove ourselves from the security framework */ + if (unregister_grsecurity (&sec_ops)) { + printk (KERN_INFO "Failure unregistering " DUMMY_NAME + " module with the kernel\n"); + } + + printk (KERN_INFO DUMMY_NAME " Plug module removed\n"); +} + +grsecurity_initcall(dummy_m_init); +module_exit(dummy_m_exit); + +MODULE_AUTHOR("John Moser"); +MODULE_DESCRIPTION(DUMMY_NAME " module"); +MODULE_LICENSE("GPL"); diff -urNp linux-2.6.10/security/grsecurity/dummy/gr_dummy3.c linux-2.6.10-grs/security/grsecurity/dummy/gr_dummy3.c --- linux-2.6.10/security/grsecurity/dummy/gr_dummy3.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/dummy/gr_dummy3.c 2005-01-26 22:18:53.915538000 -0500 @@ -0,0 +1,66 @@ +/* + * These are dummy modules. + * + * Copyright (C) 2005 John Moser <nigelenkiat_private> + * + * LICENSE: GPLv2 + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/config.h> +#include <linux/grsecurity.h> + +#define DUMMY_NAME "GR_DUMMY_MODULE_3" + + +static int dummy_proc_show_map (unsigned long *vm_start, + unsigned long *vm_end, + unsigned long *vm_pgoff, + unsigned long *dev_mj, + unsigned long *dev_mn, + unsigned long *ino, + struct seq_file *m) { + printk(KERN_INFO "***GrSecurity stacking test in " DUMMY_NAME "***\n"); + return 0; +} + +static +struct grsecurity_operations sec_ops = { + .proc_show_map = dummy_proc_show_map, +}; + +static int __init +dummy_m_init(void) +{ + /* register ourselves with the security framework */ + if (register_grsecurity (&sec_ops)) { + printk (KERN_INFO + " Failure registering " DUMMY_NAME + " module with the kernel\n"); + return -EINVAL; + } + + printk (KERN_INFO " " DUMMY_NAME " module initialized.\n"); + + return 0; +} + +static void __exit +dummy_m_exit(void) +{ + /* remove ourselves from the security framework */ + if (unregister_grsecurity (&sec_ops)) { + printk (KERN_INFO "Failure unregistering " DUMMY_NAME + " module with the kernel\n"); + } + + printk (KERN_INFO DUMMY_NAME " Plug module removed\n"); +} + +grsecurity_initcall(dummy_m_init); +module_exit(dummy_m_exit); + +MODULE_AUTHOR("John Moser"); +MODULE_DESCRIPTION(DUMMY_NAME " module"); +MODULE_LICENSE("GPL"); diff -urNp linux-2.6.10/security/grsecurity/dummy/Kconfig linux-2.6.10-grs/security/grsecurity/dummy/Kconfig --- linux-2.6.10/security/grsecurity/dummy/Kconfig 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/dummy/Kconfig 2005-01-26 22:15:42.878580000 -0500 @@ -0,0 +1,16 @@ +# +# GrSecurity Dummy Module stuff +# + +config GRSECURITY_DUMMY_TESTS + tristate "Enable Dummy Test Modules" + depends on GRSECURITY + help + This option causes three test modules to be built, or built in, + to test stacking. This is only for testing. These modules are + called gr_dummy1, gr_dummy2, and gr_dummy3. + + When loaded, the dummy modules printk() at each mapping output, + so they can be tested by catting /proc/self/maps and checking + dmesg. This can produce a lot of output, so use these only for + testing and debugging. diff -urNp linux-2.6.10/security/grsecurity/dummy/Makefile linux-2.6.10-grs/security/grsecurity/dummy/Makefile --- linux-2.6.10/security/grsecurity/dummy/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/dummy/Makefile 2005-01-26 22:16:19.672987000 -0500 @@ -0,0 +1,9 @@ +# +# Makefile for the grsecurity dummy tests +# + + + +obj-$(CONFIG_GRSECURITY_DUMMY_TESTS) = gr_dummy1.o gr_dummy2.o gr_dummy3.o + + diff -urNp linux-2.6.10/security/grsecurity/grfunctions.c linux-2.6.10-grs/security/grsecurity/grfunctions.c --- linux-2.6.10/security/grsecurity/grfunctions.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/grfunctions.c 2005-01-26 21:02:18.609457000 -0500 @@ -0,0 +1,302 @@ +/* + * GrSecurity Plug functions + * + * Derived from GrSecurity and mimicing the LSM code + * + * Copyright (C) 2005 John Moser <nigelenkiat_private> + * Copyright (C) 2001-2005 Brad Spengler + * + * Derived partially from security.c which is: + * Copyright (C) 2001 WireX Communications, Inc <chrisat_private> + * Copyright (C) 2001-2002 Greg Kroah-Hartman <gregat_private> + * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalleyat_private> + * + * 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. + */ + +/* + * GrSecurity modules self-stack in the following way: + * + * error = 0; + * for (i = grsecurity_ops; i; i = i->next) { + * error = i->requested_operation(data); + * if (error) + * break; + * } + * return error; + * + * So we need no dummy module or anything. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> + +#include <linux/grsecurity.h> + +/* + * if grsecurity_ops is null, this will simply fall through + * with no error. Otherwise it'll check each registered module + * and return an error if one denies access. + * + * This occurs in a gr_ops_lock read_lock() + * + * We need C99 variadic macros to do this + */ +#define _GRSECURITY_CHECK(function,...) \ +do {\ + struct grsecurity_operations *ops; \ + int e = 0; \ + read_lock(&gr_ops_lock); \ + for (ops = grsecurity_ops; ops; ops = ops->next) { \ + if (ops->function) \ + e = ops->function ( __VA_ARGS__ ) ; \ + if (e) \ + break; \ + } \ + read_unlock(&gr_ops_lock); \ + return e; \ +} while(0) + +/* + * if grsecurity_ops is null, this will simply fall through + * with no error. Otherwise it'll check each registered module + * and try to do what's there for this. + * + * This occurs in a gr_ops_lock read_lock() + * + * We need C99 variadic macros to do this + */ +#define _GRSECURITY_DO(function,...) \ +do {\ + struct grsecurity_operations *ops; \ + read_lock(&gr_ops_lock); \ + for (ops = grsecurity_ops; ops; ops = ops->next) { \ + if ( ops->function ) \ + ops->function ( __VA_ARGS__ ) ; \ + } \ + read_unlock(&gr_ops_lock); \ +} while(0) + +/* + * --KEYBOARD_FUNCTIONS-- + */ +int gr_keyboard_handler(const int value) { + _GRSECURITY_CHECK(keyboard_handler, + value); +} +EXPORT_SYMBOL_GPL(gr_keyboard_handler); + +/* + * --PROC FUNCTIONS-- + */ +int gr_proc_permission(const struct inode *inode) { + _GRSECURITY_CHECK(proc_permission, + inode); +} +EXPORT_SYMBOL_GPL(gr_proc_permission); + +int gr_proc_pid_make_inode(const struct task_struct *task, + struct inode *inode) { + _GRSECURITY_CHECK(proc_pid_make_inode, + task, inode); +} +EXPORT_SYMBOL_GPL(gr_proc_pid_make_inode); + +int gr_proc_pid_revalidate(const struct task_struct *task, + struct inode *inode) { + _GRSECURITY_CHECK(proc_pid_revalidate, + task, inode); +} +EXPORT_SYMBOL_GPL(gr_proc_pid_revalidate); + +int gr_proc_pid_lookup(const struct task_struct *task, + struct inode *inode) { + _GRSECURITY_CHECK(proc_pid_lookup, + task, inode); +} +EXPORT_SYMBOL_GPL(gr_proc_pid_lookup); + +int gr_proc_get_tgid_list(const struct task_struct *task) { + _GRSECURITY_CHECK(proc_get_tgid_list, + task); +} +EXPORT_SYMBOL_GPL(gr_proc_get_tgid_list); + +int gr_proc_get_inode(struct inode *inode, + const struct proc_dir_entry *de) { + _GRSECURITY_CHECK(proc_get_inode, + inode, de); +} +EXPORT_SYMBOL_GPL(gr_proc_get_inode); + +/* + * These next two are implemented special so that they don't allow a module to + * de-NULL variables and reveal information hidden by other modules. + */ +int gr_proc_task_stat(unsigned long *eip, + unsigned long *esp, + unsigned long *wchan, + unsigned long *start_code, + unsigned long *end_code, + unsigned long *start_stack, + struct task_struct *task) { + unsigned long my_eip, my_esp, my_wchan, + my_start_code, my_end_code, my_start_stack; + struct grsecurity_operations *ops; + int e = 0; + read_lock(&gr_ops_lock); + for (ops = grsecurity_ops; ops; ops = ops->next) { + if (ops->proc_task_stat) { + /* + * Here's how we deter revealing of stomped + * information. + * + * Normally, a module should assume passed vars to + * contain valid data, and not touch them unless it + * wants to obscure the data. + * + * There's enough information to add the data back + * once another module obscures it. To prevent this, + * all values are stored before calling the module's + * code. Afterwards, anything null is transfered + * back. + */ + my_eip = *eip; + my_esp = *esp; + my_wchan = *wchan; + my_start_code = *start_code; + my_end_code = *end_code; + my_start_stack = *start_stack; + /*here's the actual call*/ + e = ops->proc_task_stat(eip, esp, wchan, + start_code, end_code, start_stack, task); + /* + * And here's where we recheck and re-clear anything + * that was put back after another module clears it + */ + *eip = my_eip ? *eip : 0; + *esp = my_esp ? *esp : 0; + *wchan = my_wchan ? *wchan : 0; + *start_code = my_start_code ? *start_code : 0; + *end_code = my_end_code ? *end_code : 0; + *start_stack = my_start_stack ? *start_stack : 0; + /*and if it returned an error, we break*/ + if (e) + break; + } + } + read_unlock(&gr_ops_lock); + return e; +} +EXPORT_SYMBOL_GPL(gr_proc_task_stat); + +int gr_proc_show_map (unsigned long *vm_start, + unsigned long *vm_end, + unsigned long *vm_pgoff, + unsigned long *dev_mj, + unsigned long *dev_mn, + unsigned long *ino, + struct seq_file *m) { + unsigned long my_vm_start, my_vm_end, my_vm_pgoff, + my_dev_mj, my_dev_mn, my_ino; + struct grsecurity_operations *ops; + int e = 0; + read_lock(&gr_ops_lock); + for (ops = grsecurity_ops; ops; ops = ops->next) { + if (ops->proc_show_map) { + /* + * Info replacement tracking again + */ + my_vm_start = *vm_start; + my_vm_end = *vm_end; + my_vm_pgoff = *vm_pgoff; + my_dev_mj = *dev_mj; + my_dev_mn = *dev_mn; + my_ino = *ino; + /*here's the actual call*/ + e = ops->proc_show_map(vm_start, vm_end, vm_pgoff, + dev_mj, dev_mn, ino, m); + /* + * And here's where we recheck and re-clear anything + * that was put back after another module clears it + */ + *vm_start = my_vm_start ? *vm_start : 0; + *vm_end = my_vm_end ? *vm_end : 0; + *vm_pgoff = my_vm_pgoff ? *vm_pgoff : 0; + *dev_mj = my_dev_mj ? *dev_mj : 0; + *dev_mn = my_dev_mn ? *dev_mn : 0; + *ino = my_ino ? *ino : 0; + /*and if it returned an error, we break*/ + if (e) + break; + } + } + read_unlock(&gr_ops_lock); + return e; +} +EXPORT_SYMBOL_GPL(gr_proc_show_map); + +int gr_proc_pci_legacy_init(const struct proc_dir_entry **entry) { + _GRSECURITY_CHECK(proc_pci_legacy_init, + entry); +} +EXPORT_SYMBOL_GPL(gr_proc_pci_legacy_init); + +int gr_proc_pci_init(struct proc_dir_entry **proc_bus_pci_dir) { + _GRSECURITY_CHECK(proc_pci_init, + proc_bus_pci_dir); +} +EXPORT_SYMBOL_GPL(gr_proc_pci_init); + +/* + * --INODE FUNCTIONS-- + */ +int gr_inode_follow_link(const struct dentry *dentry, + const struct nameidata *nd) { + _GRSECURITY_CHECK(inode_follow_link, + dentry, nd); +} +EXPORT_SYMBOL_GPL(gr_inode_follow_link); + +int gr_inode_hardlink (const struct dentry *new_dentry, + const struct nameidata *old_nd, + const struct nameidata *nd, + const char *to) { + _GRSECURITY_CHECK(inode_hardlink, + new_dentry, old_nd, nd, to); +} +EXPORT_SYMBOL_GPL(gr_inode_hardlink); + +void gr_inode_handle_create (const struct dentry *new_dentry, + const struct vfsmount *mnt) { + _GRSECURITY_DO(inode_handle_create, + new_dentry, mnt); +} +EXPORT_SYMBOL_GPL(gr_inode_handle_create); + + + + +/** + * capable - calls the currently loaded security modules' capable() functions + * with the specified capability + * @cap: the requested capability level. + * + * This function calls the currently loaded security modules' capable() + * functions with a pointer to the current task and the specified @cap value. + * + * This allows the security module to implement the capable function call + * however it chooses to. + */ +#if 0 +int capable(int cap) +{ + gr_capable(current, cap); +} +EXPORT_SYMBOL(capable); +#endif diff -urNp linux-2.6.10/security/grsecurity/grsecurity.c linux-2.6.10-grs/security/grsecurity/grsecurity.c --- linux-2.6.10/security/grsecurity/grsecurity.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/grsecurity.c 2005-01-26 23:26:06.672660000 -0500 @@ -0,0 +1,184 @@ +/* + * GrSecurity plug functions + * + * Derived from GrSecurity and mimicing the LSM code + * + * Copyright (C) 2005 John Moser <nigelenkiat_private> + * Copyright (C) 2001-2005 Brad Spengler + * + * Derived partially from security.c which is: + * Copyright (C) 2001 WireX Communications, Inc <chrisat_private> + * Copyright (C) 2001-2002 Greg Kroah-Hartman <gregat_private> + * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalleyat_private> + * + * 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. + */ + +/* + * GrSecurity modules self-stack in the following way: + * + * error = 0; + * for (i = grsecurity_ops; i; i = i->next) { + * error = i->requested_operation(data); + * if (error) + * break; + * } + * return error; + * + * So we need no dummy module or anything. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> + +#include <linux/grsecurity.h> + +#define GRSECURITY_FRAMEWORK_VERSION "2.0.0" + +struct grsecurity_operations *grsecurity_ops = NULL; /* Initialized to NULL */ +/* + * Somewhat finegrained locking + * + * We use a read_lock() when we're executing a check, and a write_lock() when + * we're registering/unregistering a module. Because registering and + * unregistering should be rare in production, we should usually just be in a + * read_lock(), which is non-blocking without a pending write_lock(). + */ +rwlock_t gr_ops_lock = RW_LOCK_UNLOCKED; + +static inline int verify(struct grsecurity_operations *ops) +{ + /* verify the grsecurity_operations structure exists */ + if (!ops) + return -EINVAL; + return 0; +} + +/* + * This uses whatever is put into the __grsecurity_initcall section of vmlinuz + * to initialize any security modules supplying grsecurity_initcall(init_fcn) + * symbols. + */ +static void __init do_grsecurity_initcalls(void) +{ + initcall_t *call; + unsigned int i=0; + printk(KERN_INFO " GrSecurity Frameworki" // v" GRSECURITY_FRAMEWORK_VERSION + " initializing built-in modules...\n"); + call = &__grsecurity_initcall_start; + while (call < &__grsecurity_initcall_end) { + (*call) (); + call++; + i++; + } + printk(KERN_INFO " GrSecurity Framework" // v" GRSECURITY_FRAMEWORK_VERSION + " initialized %u modules\n",i); +} + +/** + * grsecurity_init - initializes the grsecurity framework + * + * This should be called early in the kernel initialization sequence. + */ +int __init grsecurity_init(void) +{ + + printk(KERN_INFO "GrSecurity Framework v" GRSECURITY_FRAMEWORK_VERSION + " initialized\n"); + do_grsecurity_initcalls(); + + return 0; +} + +/** + * register_security - registers a grsecurity framework with the kernel + * @ops: a pointer to the struct grsecurity_options that is to be registered + * + * This function is to allow a grsecurity module to register itself with the + * kernel grsecurity subsystem. Some rudimentary checking is done on the @ops + * value passed to this function. A call to unregister_grsecurity() should be + * done to remove this grsecurity_options structure from the kernel. + */ +int register_grsecurity(struct grsecurity_operations *ops) +{ + if (verify(ops)) { + printk(KERN_DEBUG "%s could not verify " + "grsecurity_operations structure.\n", __FUNCTION__); + return -EINVAL; + } + + /*lock and load*/ + write_lock(&gr_ops_lock); + /*The easy way: Load at the top*/ + if (grsecurity_ops) { + ops->next = grsecurity_ops; + ops->next->prev = ops; + } + ops->prev = NULL; + grsecurity_ops = ops; + write_unlock(&gr_ops_lock); + + return 0; +} + +/** + * unregister_grsecurity - unregisters a grsecurity framework with the kernel + * @ops: a pointer to the struct security_options that is to be registered + * + * This function removes a struct security_operations variable that had + * previously been registered with a successful call to register_security(). + * + * If @ops does not match the valued previously passed to register_security() + * an error is returned. Otherwise the default security options is set to the + * the dummy_security_ops structure, and 0 is returned. + */ +int unregister_grsecurity(struct grsecurity_operations *ops) +{ + struct grsecurity_operations *i = NULL; + if (!ops) + goto err; + printk(KERN_INFO "Unregistering a GR module...\n"); + /*lock and unload*/ + write_lock(&gr_ops_lock); + /*locate and destroy*/ + for (i = grsecurity_ops; i; i = i->next) { + /*skip if this isn't ops*/ + if (i != ops) + continue; + /*first, pinch*/ + if (i->next) + i->next->prev = i->prev; + if (i->prev) + i->prev->next = i->next; + /*If this is the first module, it has to fix the head*/ + if (i == grsecurity_ops) + grsecurity_ops = i->next; + /*now, leave, with non-NULL i*/ + break; + } + write_unlock(&gr_ops_lock); + /* + * if the above finished (or ops was null), we have a NULL i. This + * means we failed to find the ops structure, so we give an error. + */ +err: + if (!i) { + printk(KERN_INFO "%s: trying to unregister " + "a grsecurity_opts structure that is not " + "registered, failing.\n", __FUNCTION__); + return -EINVAL; + } + + return 0; +} + + +EXPORT_SYMBOL_GPL(register_grsecurity); +EXPORT_SYMBOL_GPL(unregister_grsecurity); +//EXPORT_SYMBOL_GPL(grsecurity_ops); + diff -urNp linux-2.6.10/security/grsecurity/Kconfig linux-2.6.10-grs/security/grsecurity/Kconfig --- linux-2.6.10/security/grsecurity/Kconfig 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/Kconfig 2005-01-26 22:16:38.793080000 -0500 @@ -0,0 +1,13 @@ +config GRSECURITY + bool "Enable GrSecurity derived hooks" + help + This option enables a security framework derived from + the GrSecurity project. The framework is enough to + implement GrSecurity. + + This framework uses reduced APIs to use less stack space. + +source security/grsecurity/dummy/Kconfig + +source security/grsecurity/kernsec/Kconfig + diff -urNp linux-2.6.10/security/grsecurity/kernsec/Kconfig linux-2.6.10-grs/security/grsecurity/kernsec/Kconfig --- linux-2.6.10/security/grsecurity/kernsec/Kconfig 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/kernsec/Kconfig 2005-01-26 20:38:33.676426000 -0500 @@ -0,0 +1,120 @@ +# +# GrSecurity KERNSEC stuff +# + +menu "Kernel Security" + depends on GRSECURITY + +config GRSECURITY_KERNSEC + tristate "Enable GrSecurity derived kernel security" + depends on GRSECURITY + help + This allows you to enable code taken from GrSecurity to + enhance the security of the system. + + Careful testing is recommended in a production environment; + but if nothing breaks, you should say Y to everything here. + +config GRKERNSEC_PROC + bool "/proc Restrictions" + depends on GRSECURITY_KERNSEC && PROC_FS + help + Setting this allows you to select restrictions on the /proc + filesystem to prevent information leaking. It also controls + the keyboard driver to prevent information leaking from + magic sysrq keys. + +config GRKERNSEC_PROC_USER + bool "Restrict /proc to user" + depends on GRKERNSEC_PROC + help + If you say Y here, users will only be able to view their own + processes, except for root with CAP_SYS_ADMIN. Users will also + be restricted from viewing viewing network-related information, + except for root with the CAP_NET_ADMIN capability. Kernel + symbol and module information is restricted to root with + CAP_SYS_MODULE. + +config GRKERNSEC_PROC_GROUP_ACCESS + bool "Give group access to /proc" + depends on GRKERNSEC_PROC_USER + help + This relaxes some /proc restrictions to allow a group to access + the restricted /proc information--without any special caps. + The group is set below. + +config GRKERNSEC_PROC_GID + int "Group" + depends on GRKERNSEC_PROC_GROUP_ACCESS + default 1000 + help + This is the group for GRKERNSEC_PROC_GROUP_ACCESS. + +config GRKERNSEC_PROC_GROUP_ACCESS_CAPS + bool "Require caps for /proc group access" + depends on GRKERNSEC_PROC_GROUP_ACCESS + help + Saying Y here will cause /proc access for GRKERNSEC_PROC_GROUP + to still require caps. This means that the process must start + as root and move to another user in the /proc group to have + access. + +config GRKERNSEC_PROC_MEMMAP + bool "Remove addresses from /proc/<pid>/[maps|stat]" + depends on GRKERNSEC_PROC + help + If you say Y here, the /proc/<pid>/maps and /proc/<pid>/stat + files will give no information about the addresses of the + mappings for a task, except to users with UID 0 and + CAP_SYS_PTRACE. This is useful for systems which deploy ASLR, + such as that supplied by PaX, as it closes up an information + leak to local attackers. + + Certain debugging systems may rely on this information, most + notably those which report errors in Java JREs. An option + should be added with your ASLR system to disable the + randomizations per-binary, and to disable this obscurity + function for non-randomized tasks. + +config GRKERNSEC_LINK_RESTR + bool "Linking Restrictions" + depends on GRSECURITY_KERNSEC + help + Setting this allows you to enable symlink and hardlink + policy restrictions which can prevent race conditions in + world-writable +t directories. + +config GRKERNSEC_SYMLINK_RESTR + bool "Symlink Restrictions" + depends on GRKERNSEC_LINK_RESTR + help + This option adds a failure (EACCES) to dereference a + symlink at the intersection of the following conditions: + + - The symlink is owned by a different user than the + process + - The symlink is not owned by the same user as the + directory it is in + - The directory the symlink is in is writable by + "others" + - The directory the symlink is in has the mode +t + ("sticky") + + By combining this with 'Hardlink Restrictions' or an + isolated /tmp directorly (such as with a tmpfs mounted + on /tmp), race conditions in /tmp can be prevented. + + Even with an isolated /tmp, 'Hardlink Restrictions' are + necessary to prevent races within /tmp. More generally + speaking, 'Symlink Restrictions' will not prevent races + on the same file system. + +config GRKERNSEC_HARDLINK_RESTR + bool "Hardlink Restrictions" + depends on GRKERNSEC_LINK_RESTR + help + This option adds a failure (EACCES) to make a hardlink + to a file you don't own, unless you have CAP_FOWNER and + are root. + +endmenu diff -urNp linux-2.6.10/security/grsecurity/kernsec/kernsec.h linux-2.6.10-grs/security/grsecurity/kernsec/kernsec.h --- linux-2.6.10/security/grsecurity/kernsec/kernsec.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/kernsec/kernsec.h 2005-01-26 16:28:04.557137000 -0500 @@ -0,0 +1,80 @@ +/* + * security/grsecurity/kernsec/kernsec.h + * GrSecurity KERNSEC header + * + * Copyright (C) 2005 John Moser <nigelenkiat_private> + * Copyright (C) 2005 Brad Spengler + * + * LICENSE: GPLv2 + */ +#ifndef _KERNSEC__H_ +#define _KERNSEC__H_ +/* + * figure out what to delete from here + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/config.h> +#include <linux/grsecurity.h> +#include <linux/fs.h> +#include <linux/namei.h> + +#define GRKS_MY_NAME "kernsec" +#define GRKS_MY_FNAME "GrSecurity Kernel Security" + +#if defined(CONFIG_GRKERNSEC_PROC) +int grks_keyboard_handler(const int value); + +int grks_proc_pci_legacy_init(const struct proc_dir_entry **entry); + +int grks_proc_pci_init(struct proc_dir_entry **proc_bus_pci_dir); + +int grks_proc_pid_make_inode(const struct task_struct *task, + struct inode *inode); + +int grks_proc_pid_revalidate(const struct task_struct *task, + struct inode *inode); + +int grks_proc_pid_lookup(const struct task_struct *task, + struct inode *inode); + +int grks_proc_get_tgid_list(const struct task_struct *task); + +int grks_proc_get_inode(struct inode *inode, + const struct proc_dir_entry *de); + +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP +int grks_proc_task_stat(unsigned long *eip, + unsigned long *esp, + unsigned long *wchan, + unsigned long *start_code, + unsigned long *end_code, + unsigned long *start_stack, + struct task_struct *task); + +int grks_proc_show_map (unsigned long *vm_start, + unsigned long *vm_end, + unsigned long *vm_pgoff, + unsigned long *dev_mj, + unsigned long *dev_mn, + unsigned long *ino, + struct seq_file *m); +#endif /*CONFIG_GRKERNSEC_PROC_MEMMAP*/ +#endif /*CONFIG_GRKERNSEC_PROC*/ + +#ifdef CONFIG_GRKERNSEC_SYMLINK_RESTR +int +grks_follow_link(const struct dentry *dentry, + const struct nameidata *nd); +#endif + +#if defined(CONFIG_GRKERNSEC_HARDLINK_RESTR) +int +grks_handle_hardlink (const struct dentry *new_dentry, + const struct nameidata *old_nd, + const struct nameidata *nd, + const char *to); +#endif + +#endif /*_KERNSEC__H_*/ diff -urNp linux-2.6.10/security/grsecurity/kernsec/kernsec_main.c linux-2.6.10-grs/security/grsecurity/kernsec/kernsec_main.c --- linux-2.6.10/security/grsecurity/kernsec/kernsec_main.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/kernsec/kernsec_main.c 2005-01-26 21:52:37.932994000 -0500 @@ -0,0 +1,76 @@ +/* + * security/grsecurity/kernsec/kernsec.c + * GrSecurity KERNSEC + * + * Copyright (C) 2005 John Moser <nigelenkiat_private> + * Copyright (C) 2005 Brad Spengler + * + * LICENSE: GPLv2 + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/config.h> +#include <linux/grsecurity.h> +#include <linux/fs.h> +#include "kernsec.h" + + +static +struct grsecurity_operations sec_ops = { +#if defined(CONFIG_GRKERNSEC_PROC) + .keyboard_handler = grks_keyboard_handler, + .proc_pci_legacy_init = grks_proc_pci_legacy_init, + .proc_pci_init = grks_proc_pci_init, + .proc_pid_make_inode = grks_proc_pid_make_inode, + .proc_pid_revalidate = grks_proc_pid_revalidate, + .proc_pid_lookup = grks_proc_pid_lookup, + .proc_get_tgid_list = grks_proc_get_tgid_list, + .proc_get_inode = grks_proc_get_inode, +# ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + .proc_task_stat = grks_proc_task_stat, + .proc_show_map = grks_proc_show_map, +# endif /*CONFIG_GRKERNSEC_PROC_MEMMAP*/ +#endif /*CONFIG_GRKERNSEC_PROC*/ +#ifdef CONFIG_GRKERNSEC_SYMLINK_RESTR + .inode_follow_link = grks_follow_link, +#endif +#ifdef CONFIG_GRKERNSEC_HARDLINK_RESTR + .inode_hardlink = grks_handle_hardlink, +#endif +}; + +static int __init +kernsec_m_init(void) +{ + /* register ourselves with the security framework */ + if (register_grsecurity (&sec_ops)) { + printk (KERN_INFO + " Failure registering " GRKS_MY_FNAME + " module with the kernel\n"); + return -EINVAL; + } + + printk (KERN_INFO " " GRKS_MY_FNAME " module initialized.\n"); + + return 0; +} + +static void __exit +kernsec_m_exit(void) +{ + /* remove ourselves from the security framework */ + if (unregister_grsecurity (&sec_ops)) { + printk (KERN_INFO "Failure unregistering " GRKS_MY_FNAME + " module with the kernel\n"); + } + + printk (KERN_INFO GRKS_MY_FNAME " Plug module removed\n"); +} + +grsecurity_initcall(kernsec_m_init); +module_exit(kernsec_m_exit); + +MODULE_AUTHOR("John Moser, using the work of Brad Spengler as a reference"); +MODULE_DESCRIPTION(GRKS_MY_FNAME " module"); +MODULE_LICENSE("GPL"); diff -urNp linux-2.6.10/security/grsecurity/kernsec/link_restr.c linux-2.6.10-grs/security/grsecurity/kernsec/link_restr.c --- linux-2.6.10/security/grsecurity/kernsec/link_restr.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/kernsec/link_restr.c 2005-01-25 18:47:23.654082000 -0500 @@ -0,0 +1,62 @@ +/* + * security/grsecurity/kernsec/link_restr.c + * GrSecurity KERNSEC linking restrictions + * + * Copyright (C) 2005 John Moser <nigelenkiat_private> + * Copyright (C) 2005 Brad Spengler + * + * LICENSE: GPLv2 + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/config.h> +#include <linux/grsecurity.h> +#include <linux/fs.h> + +#include "kernsec.h" + +#ifdef CONFIG_GRKERNSEC_SYMLINK_RESTR +/* + * If the parent's inode mode is S_ISVTX (sticky, +t) and o+w (world-writable), + * and the parent's owner (i_uid) != the inode's owner, + * and the inode isn't owned by the owner of current, + * deny access. + */ +int +grks_follow_link(const struct dentry *dentry, + const struct nameidata *nd) { + struct inode *inode = dentry->d_inode; + struct inode *parent = dentry->d_parent->d_inode; + + if (S_ISLNK(inode->i_mode) && + (parent->i_mode & S_ISVTX) && (parent->i_uid != inode->i_uid) && + (parent->i_mode & S_IWOTH) && (current->fsuid != inode->i_uid)) { + return -EACCES; + } + return 0; +} +#endif + +#if defined(CONFIG_GRKERNSEC_HARDLINK_RESTR) +/* + * Fails in certain cases for a number of reasons I don't yet understand + */ +int +grks_handle_hardlink (const struct dentry *new_dentry, + const struct nameidata *old_nd, + const struct nameidata *nd, + const char *to) { + struct inode *inode = old_nd->dentry->d_inode; + int mode = inode->i_mode; + if (current->fsuid != inode->i_uid && + (!S_ISREG(mode) || (mode & S_ISUID) || + ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) || + (generic_permission(inode, MAY_READ | MAY_WRITE, NULL))) && + !capable(CAP_FOWNER) && current->uid) { + return -EPERM; + } + return 0; +} +#endif + diff -urNp linux-2.6.10/security/grsecurity/kernsec/Makefile linux-2.6.10-grs/security/grsecurity/kernsec/Makefile --- linux-2.6.10/security/grsecurity/kernsec/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/kernsec/Makefile 2005-01-26 20:53:16.017290000 -0500 @@ -0,0 +1,12 @@ +# +# Makefile for the grsecurity kernsec code +# + + +kernsec-objs-$(CONFIG_GRKERNSEC_LINK_RESTR) := link_restr.o +kernsec-objs-$(CONFIG_GRKERNSEC_PROC) += proc_prot.o +kernsec-objs := kernsec_main.o $(kernsec-objs-y) + +obj-$(CONFIG_GRSECURITY_KERNSEC) = kernsec.o + + diff -urNp linux-2.6.10/security/grsecurity/kernsec/proc_prot.c linux-2.6.10-grs/security/grsecurity/kernsec/proc_prot.c --- linux-2.6.10/security/grsecurity/kernsec/proc_prot.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/kernsec/proc_prot.c 2005-01-26 20:31:32.315483000 -0500 @@ -0,0 +1,166 @@ +/* + * security/grsecurity/kernsec/proc.c + * GrSecurity KERNSEC proc restrictions and protections + * + * Copyright (C) 2005 John Moser <nigelenkiat_private> + * Copyright (C) 2005 Brad Spengler + * + * LICENSE: GPLv2 + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/config.h> +#include <linux/grsecurity.h> +#include <linux/fs.h> +#include <linux/keyboard.h> +#include <linux/proc_fs.h> + +#include "kernsec.h" + +enum { +_KBD_FN_HANDLERS +}; + +/* + * handle keyboard stuff, prevent magicsysrq from leaking info. + */ +int +grks_keyboard_handler(const int value) { + if (value == fn_show_state || value == fn_show_ptregs || + value == fn_show_mem) + return -EACCES; + return 0; +} + +int grks_proc_pci_legacy_init(const struct proc_dir_entry **entry) { + *entry = create_proc_entry("pci", S_IRUSR +#ifdef CONFIG_GRKERNSEC_PROC_GROUP_ACCESS + | S_IRGRP +#endif + , NULL); + /*Returns nonzero on alter*/ + return 1; +} + +int grks_proc_pci_init(struct proc_dir_entry **proc_bus_pci_dir) { + *proc_bus_pci_dir = proc_mkdir_mode("pci", S_IRUSR | S_IXUSR +#ifdef CONFIG_GRKERNSEC_PROC_GROUP_ACCESS + | S_IRGRP | S_IXGRP +#endif + , proc_bus); + /*returns nonzero on alter*/ + return 1; +} + +static int local_proc_pid_task_check(const struct task_struct *task) { +#if defined(CONFIG_GRKERNSEC_PROC_USER) + if ( ((current->uid || !capable(CAP_SYS_ADMIN)) + && (task->uid != current->uid)) +# if defined(CONFIG_GRKERNSEC_PROC_GROUP_ACCESS) + && !in_group_p(CONFIG_GRKERNSEC_PROC_GID) +#endif /*defined(CONFIG_GRKERNSEC_PROC_GROUP_ACCESS)*/ + ) { + return -ENOENT; + } +#endif /*defined(CONFIG_GRKERNSEC_PROC_USER)*/ + return 0; +} + +/* + * used for making an inode AND for proc_pid_revalidate + */ +int grks_proc_pid_make_inode(const struct task_struct *task, + struct inode *inode) { + inode->i_uid = task->euid; +#ifdef CONFIG_GRKERNSEC_PROC_GROUP_ACCESS + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#else + inode->i_gid = task->egid; +#endif /*CONFIG_GRKERNSEC_PROC_GROUP_ACCESS*/ + /*next we validate if you can see the task*/ + return local_proc_pid_task_check(task); +} + +int grks_proc_pid_revalidate(const struct task_struct *task, + struct inode *inode) { +#ifdef CONFIG_GRKERNSEC_PROC_GROUP_ACCESS + if (inode->i_uid) + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#endif /*CONFIG_GRKERNSEC_PROC_GROUP_ACCESS*/ + return 0; +} + +/* + * This logic is hell when you consider adding PROC_GID with + * caps, AS AN OPTION. + */ +int grks_proc_pid_lookup(const struct task_struct *task, + struct inode *inode) { + int error = 0; + error = local_proc_pid_task_check(task); + if (error) + goto out; +#ifdef CONFIG_GRKERNSEC_PROC_USER + inode->i_mode = S_IFDIR|S_IRUSR|S_IXUSR; +#endif +#ifdef CONFIG_GRKERNSEC_PROC_GROUP_ACCESS + inode->i_mode = S_IFDIR|S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP; + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#endif /*CONFIG_GRKERNSEC_PROC_GROUP_ACCESS*/ +out: + return error; +} + +int grks_proc_get_tgid_list(const struct task_struct *task) { + return local_proc_pid_task_check(task); +} + +int grks_proc_get_inode(struct inode *inode, + const struct proc_dir_entry *de) { +#ifdef CONFIG_GRKERNSEC_PROC_GROUP_ACCESS + if (de && de->mode) + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#endif + return 0; +} + +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP +int grks_proc_task_stat(unsigned long *eip, + unsigned long *esp, + unsigned long *wchan, + unsigned long *start_code, + unsigned long *end_code, + unsigned long *start_stack, + struct task_struct *task) { + /*unless root with CAP_SYS_PTRACE, hide this info*/ + if ( !capable(CAP_SYS_PTRACE) || current->uid ) { + *eip = + *esp = + *wchan = + *start_code = + *end_code = + *start_stack = 0; + } + return 0; +} + +int grks_proc_show_map (unsigned long *vm_start, + unsigned long *vm_end, + unsigned long *vm_pgoff, + unsigned long *dev_mj, + unsigned long *dev_mn, + unsigned long *ino, + struct seq_file *m) { + /*unless root with CAP_SYS_PTRACE, hide this info*/ + if ( !capable(CAP_SYS_PTRACE) || current->uid ) { + *vm_start = + *vm_end = + *vm_pgoff = + *dev_mj = + *dev_mn = + *ino = 0; + } + return 0; +} +#endif /*CONFIG_GRKERNSEC_PROC_MEMMAP*/ diff -urNp linux-2.6.10/security/grsecurity/Makefile linux-2.6.10-grs/security/grsecurity/Makefile --- linux-2.6.10/security/grsecurity/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.10-grs/security/grsecurity/Makefile 2005-01-26 22:16:57.559227000 -0500 @@ -0,0 +1,11 @@ +# +# Makefile for the grsecurity security code +# + +obj-y = grsecurity.o grfunctions.o + +#subdir-$(CONFIG_GRSECURITY_KERNSEC) += kernsec/ +# if we -y the kernsecs +# Do we need to just obj- this wtf +obj-$(CONFIG_GRSECURITY_KERNSEC) += kernsec/ +obj-$(CONFIG_GRSECURITY_DUMMY_TESTS) += dummy/ diff -urNp linux-2.6.10/security/Kconfig linux-2.6.10-grs/security/Kconfig --- linux-2.6.10/security/Kconfig 2004-12-24 16:35:21.000000000 -0500 +++ linux-2.6.10-grs/security/Kconfig 2005-01-25 18:47:17.664993000 -0500 @@ -86,5 +86,7 @@ config SECURITY_SECLVL source security/selinux/Kconfig +source security/grsecurity/Kconfig + endmenu diff -urNp linux-2.6.10/security/Makefile linux-2.6.10-grs/security/Makefile --- linux-2.6.10/security/Makefile 2004-12-24 16:35:23.000000000 -0500 +++ linux-2.6.10-grs/security/Makefile 2005-01-25 18:47:17.665992000 -0500 @@ -17,3 +17,5 @@ obj-$(CONFIG_SECURITY_SELINUX) += selin obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o + +obj-$(CONFIG_GRSECURITY) += grsecurity/
This archive was generated by hypermail 2.1.3 : Thu Jan 27 2005 - 20:49:09 PST