From: Greg KH <greg@wirex.com> To: linux-security-module@wirex.com Subject: 2001_04_22 patch against 2.4.3 Date: Mon, 23 Apr 2001 09:29:09 -0700 Here's the latest patch that people have been asking about. It does not have any of the capabilities functionality moved into a module yet, as Chris hasn't checked any of that work into our tree (hint :) It is basically my previous patch, with a few changes that people suggested. I haven't done much to add much more than those suggestions at this time. Hopefully I can get to the LIDS and RSBAC needs this week. I'm also working today to get a web site up for the project. thanks, greg k-h # This is a BitKeeper generated patch for the following project: # Project Name: Linux 2.4.x # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.2.1.3 -> 1.34 # arch/i386/boot/compressed/Makefile 1.1 -> 1.2 # include/linux/elf.h 1.2.1.1 -> 1.4 # fs/super.c 1.3.1.1 -> 1.10 # kernel/sys.c 1.1.1.1 -> 1.7 # arch/i386/config.in 1.2 -> 1.3 # mm/memory.c 1.4 -> 1.6 # arch/i386/kernel/ioport.c 1.1 -> 1.5 # fs/inode.c 1.4 -> 1.5 # arch/i386/kernel/ptrace.c 1.1.1.1 -> 1.6 # include/linux/sysctl.h 1.1.1.1 -> 1.4 # kernel/Makefile 1.1 -> 1.3 # kernel/sysctl.c 1.2 -> 1.4 # include/linux/fs.h 1.3.1.1 -> 1.8 # mm/filemap.c 1.3.1.1 -> 1.10 # kernel/fork.c 1.3.1.1 -> 1.9 # fs/file_table.c 1.1 -> 1.6 # Makefile 1.2.1.2 -> 1.6 # fs/open.c 1.2 -> 1.7 # fs/read_write.c 1.2 -> 1.8 # Documentation/Configure.help 1.2.1.2 -> 1.6 # include/linux/sched.h 1.2.1.2 -> 1.6 # fs/Makefile 1.2.1.1 -> 1.6 # init/main.c 1.2 -> 1.4 # fs/attr.c 1.1 -> 1.2 # arch/i386/kernel/entry.S 1.1 -> 1.3 # fs/binfmt_elf.c 1.2.1.1 -> 1.11 # kernel/exit.c 1.2 -> 1.4 # fs/namei.c 1.2 -> 1.4 # fs/stat.c 1.1 -> 1.2 # kernel/module.c 1.2 -> 1.8 # (new) -> 1.3 security/Config.in # (new) -> 1.12 include/linux/security.h # (new) -> 1.9 kernel/security.c # (new) -> 1.2 kernel/capability_plug.c # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 01/03/31 greg@soap.int.wirex.com 1.15 # Merge # -------------------------------------------- # 01/04/04 greg@blue.int.wirex.com 1.16 # super.c got rid of #defines # read_write.c got rid of #defines # immunix_scaffold.c tweaked # open.c got rid of #defines # file_table.c got rid of defines # binfmt_elf.c got rid of #defined # Makefile moved immunix_scaffold.o to aloways be compiled in # -------------------------------------------- # 01/04/06 greg@blue.int.wirex.com 1.17 # More removals of #ifdefs # -------------------------------------------- # 01/04/09 greg@blue.int.wirex.com 1.18 # removed all codomain_ops checks throughout the code, adding a dummy scaffolding of # empty functions to handle it when there isn't a codomain or crypomark module loaded. # -------------------------------------------- # 01/04/09 greg@blue.int.wirex.com 1.19 # turned off the logging for every process ran :( # Fixed memory leak. # -------------------------------------------- # 01/04/11 greg@desk.kroah.org 1.20 # first cut at moving some of the subdomain specific logic into a more generic type of interface # -------------------------------------------- # 01/04/12 greg@blue.int.wirex.com 1.21 # changed lots of subdomin specific logic with a more generic security call structure. # -------------------------------------------- # 01/04/12 greg@blue.int.wirex.com 1.22 # more cleanups from subdomain logic to generic logic. # -------------------------------------------- # 01/04/13 greg@blue.int.wirex.com 1.23 # Added the capability plug framework to the makefiles and the config. # -------------------------------------------- # 01/04/13 greg@blue.int.wirex.com 1.24 # removed WireX specific options from Configure.help and # removed the immunix.h and immunix_scaffold.c files from the tree. # -------------------------------------------- # 01/04/13 chris@figure1.int.wirex.com 1.22.1.1 # Changed to per kernel object stuff. # -------------------------------------------- # 01/04/13 chris@figure1.int.wirex.com 1.25 # Merge bk://zeus/work/bk/linux # into figure1.int.wirex.com:/home/chris/bitkeeper/linux-2.4 # -------------------------------------------- # 01/04/13 chris@figure1.int.wirex.com 1.26 # got rid of copyright # -------------------------------------------- # 01/04/16 greg@desk.kroah.org 1.27 # Got security.h to compile properly # fixes due to security_ops structure changes # Will OOPS, do not try to run, security.c needs lots of changes, you have been warned :) # -------------------------------------------- # 01/04/18 greg@desk.kroah.org 1.28 # fixed a spelling error in security.h # added the rest of the stub functions for security.c so the kernel does not oops anymore. # -------------------------------------------- # 01/04/18 greg@desk.kroah.org 1.29 # added i_security to the struct inode and the hooks to create and destroy it. # -------------------------------------------- # 01/04/18 greg@desk.kroah.org 1.30 # added hooks to the kernel for all of the inode_ops functions. # -------------------------------------------- # 01/04/18 steve@kryten.int.wirex.com 1.31 # changed dep_tristate to tristate (dep_tristate broke make xconfig) # -------------------------------------------- # 01/04/19 greg@blue.int.wirex.com 1.32 # added hooks for: # attach_pathlabel # # added paramaters for: # create_module # init_module # delete_module # mount # -------------------------------------------- # 01/04/19 greg@blue.int.wirex.com 1.33 # Added check for return value of inode_ops->truncate # -------------------------------------------- # 01/04/19 greg@blue.int.wirex.com 1.34 # added hook for sys_umount # -------------------------------------------- # diff -Nru a/Makefile b/Makefile --- a/Makefile Mon Apr 23 09:04:14 2001 +++ b/Makefile Mon Apr 23 09:04:14 2001 @@ -227,6 +227,10 @@ include arch/$(ARCH)/Makefile + +# if we have a StackGuard compiler, then we need to turn off the canary death handler stuff +CFLAGS += $(shell if $(CC) -fno-canary-all-functions -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-canary-all-functions"; fi) +CFLAGS += $(shell if $(CC) -mno-terminator-canary -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mno-terminator-canary"; fi) export CPPFLAGS CFLAGS AFLAGS diff -Nru a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile --- a/arch/i386/boot/compressed/Makefile Mon Apr 23 09:04:14 2001 +++ b/arch/i386/boot/compressed/Makefile Mon Apr 23 09:04:14 2001 @@ -12,6 +12,10 @@ CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS ZLDFLAGS = -e startup_32 +# if we have a StackGuard compiler, then we need to turn off the canary death handler stuff +CFLAGS += $(shell if $(CC) -fno-canary-all-functions -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-canary-all-functions"; fi) +CFLAGS += $(shell if $(CC) -mno-terminator-canary -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mno-terminator-canary"; fi) + # # ZIMAGE_OFFSET is the load offset of the compression loader # BZIMAGE_OFFSET is the load offset of the high loaded compression loader diff -Nru a/arch/i386/config.in b/arch/i386/config.in --- a/arch/i386/config.in Mon Apr 23 09:04:14 2001 +++ b/arch/i386/config.in Mon Apr 23 09:04:14 2001 @@ -367,3 +367,6 @@ #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu + +source security/Config.in + diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S --- a/arch/i386/kernel/entry.S Mon Apr 23 09:04:14 2001 +++ b/arch/i386/kernel/entry.S Mon Apr 23 09:04:14 2001 @@ -656,3 +656,4 @@ .rept NR_syscalls-221 .long SYMBOL_NAME(sys_ni_syscall) .endr + diff -Nru a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c --- a/arch/i386/kernel/ioport.c Mon Apr 23 09:04:14 2001 +++ b/arch/i386/kernel/ioport.c Mon Apr 23 09:04:14 2001 @@ -14,6 +14,7 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/stddef.h> +#include <linux/security.h> /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value) @@ -56,11 +57,19 @@ { struct thread_struct * t = ¤t->thread; struct tss_struct * tss = init_tss + smp_processor_id(); + int retval; if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32)) return -EINVAL; if (turn_on && !capable(CAP_SYS_RAWIO)) return -EPERM; + + /* check that we have permission to do this */ + retval = security_ops->ioperm(); + if (retval) { + return retval; + } + /* * If it's the first ioperm() call in this thread's lifetime, set the * IO bitmap up. ioperm() is much less timing critical than clone(), @@ -103,6 +112,7 @@ struct pt_regs * regs = (struct pt_regs *) &unused; unsigned int level = regs->ebx; unsigned int old = (regs->eflags >> 12) & 3; + int retval; if (level > 3) return -EINVAL; @@ -111,6 +121,13 @@ if (!capable(CAP_SYS_RAWIO)) return -EPERM; } + + /* check that we have permission to do this */ + retval = security_ops->ioperm(); + if (retval) { + return retval; + } + regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12); return 0; } diff -Nru a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c --- a/arch/i386/kernel/ptrace.c Mon Apr 23 09:04:14 2001 +++ b/arch/i386/kernel/ptrace.c Mon Apr 23 09:04:14 2001 @@ -13,6 +13,7 @@ #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/user.h> +#include <linux/security.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -139,6 +140,12 @@ struct task_struct *child; struct user * dummy = NULL; int i, ret; + + /* check that we have permission to do this */ + ret = security_ops->ptrace(); + if (ret) { + return ret; + } lock_kernel(); ret = -EPERM; diff -Nru a/fs/attr.c b/fs/attr.c --- a/fs/attr.c Mon Apr 23 09:04:14 2001 +++ b/fs/attr.c Mon Apr 23 09:04:14 2001 @@ -11,6 +11,7 @@ #include <linux/smp_lock.h> #include <linux/dnotify.h> #include <linux/fcntl.h> +#include <linux/security.h> /* Taken over from the old code... */ @@ -120,9 +121,11 @@ attr->ia_mtime = now; lock_kernel(); - if (inode->i_op && inode->i_op->setattr) - error = inode->i_op->setattr(dentry, attr); - else { + if (inode->i_op && inode->i_op->setattr) { + error = security_ops->inode_ops->setattr(dentry, attr); + if (!error) + error = inode->i_op->setattr(dentry, attr); + } else { error = inode_change_ok(inode, attr); if (!error) inode_setattr(inode, attr); diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c --- a/fs/binfmt_elf.c Mon Apr 23 09:04:14 2001 +++ b/fs/binfmt_elf.c Mon Apr 23 09:04:14 2001 @@ -39,6 +39,7 @@ #define DLINFO_ITEMS 13 #include <linux/elf.h> +#include <linux/security.h> static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_elf_library(struct file*); @@ -651,6 +652,17 @@ elf_brk = k; } set_fs(old_fs); + + /* Shell scripts get checked in binfmt_script.c */ + if (!bprm->sh_bang) { + retval = security_ops->file_ops->permission (bprm->file, MAY_EXEC); + if (retval) { + kfree(elf_interpreter); + kfree(elf_phdata); + send_sig(SIGKILL, current, 0); + return retval; + } + } elf_entry += load_bias; elf_bss += load_bias; diff -Nru a/fs/file_table.c b/fs/file_table.c --- a/fs/file_table.c Mon Apr 23 09:04:14 2001 +++ b/fs/file_table.c Mon Apr 23 09:04:14 2001 @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/smp_lock.h> +#include <linux/security.h> /* sysctl tunables... */ struct files_stat_struct files_stat = {0, 0, NR_FILE}; @@ -106,6 +107,8 @@ locks_remove_flock(file); if (file->f_op && file->f_op->release) file->f_op->release(inode, file); + security_ops->file_ops->free_security (file); + fops_put(file->f_op); file->f_dentry = NULL; file->f_vfsmnt = NULL; diff -Nru a/fs/inode.c b/fs/inode.c --- a/fs/inode.c Mon Apr 23 09:04:14 2001 +++ b/fs/inode.c Mon Apr 23 09:04:14 2001 @@ -13,6 +13,7 @@ #include <linux/quotaops.h> #include <linux/slab.h> #include <linux/cache.h> +#include <linux/security.h> /* * New inode.c implementation. @@ -389,6 +390,7 @@ bdput(inode->i_bdev); inode->i_bdev = NULL; } + security_ops->inode_ops->free_security(inode->i_security); inode->i_state = I_CLEAR; } @@ -615,6 +617,7 @@ inode->i_data.host = inode; inode->i_data.gfp_mask = GFP_HIGHUSER; inode->i_mapping = &inode->i_data; + inode->i_security = security_ops->inode_ops->alloc_security(); } /** diff -Nru a/fs/namei.c b/fs/namei.c --- a/fs/namei.c Mon Apr 23 09:04:14 2001 +++ b/fs/namei.c Mon Apr 23 09:04:14 2001 @@ -22,6 +22,7 @@ #include <linux/pagemap.h> #include <linux/dcache.h> #include <linux/dnotify.h> +#include <linux/security.h> #include <asm/uaccess.h> #include <asm/unaligned.h> @@ -182,8 +183,13 @@ int permission(struct inode * inode,int mask) { + int retval; + + retval = security_ops->inode_ops->permission(inode, mask); + if (retval) + return retval; + if (inode->i_op && inode->i_op->permission) { - int retval; lock_kernel(); retval = inode->i_op->permission(inode, mask); unlock_kernel(); @@ -311,9 +317,12 @@ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) { - int err; + int err = -ELOOP; if (current->link_count >= 8) goto loop; + err = security_ops->inode_ops->follow_link(dentry, nd); + if (err) + goto loop; current->link_count++; UPDATE_ATIME(dentry->d_inode); err = dentry->d_inode->i_op->follow_link(dentry, nd); @@ -321,7 +330,7 @@ return err; loop: path_release(nd); - return -ELOOP; + return err; } static inline int __follow_up(struct vfsmount **mnt, struct dentry **base) @@ -435,6 +444,8 @@ if (current->link_count) lookup_flags = LOOKUP_FOLLOW; + security_ops->inode_ops->attach_pathlabel(nd->dentry, nd->mnt); + /* At this point we know we have a real path component. */ for(;;) { unsigned long hash; @@ -530,6 +541,9 @@ err = -ENOTDIR; if (!inode->i_op->lookup) break; + + security_ops->inode_ops->attach_pathlabel(nd->dentry, nd->mnt); + continue; /* here ends the main loop */ @@ -584,6 +598,7 @@ if (!inode->i_op || !inode->i_op->lookup) break; } + security_ops->inode_ops->attach_pathlabel(nd->dentry, nd->mnt); goto return_base; no_inode: err = -ENOENT; @@ -911,6 +926,10 @@ if (!dir->i_op || !dir->i_op->create) goto exit_lock; + error = security_ops->inode_ops->create(dir, dentry, mode); + if (error) + goto exit_lock; + DQUOT_INIT(dir); lock_kernel(); error = dir->i_op->create(dir, dentry, mode); @@ -989,6 +1008,7 @@ /* Negative dentry, just create the file */ if (!dentry->d_inode) { error = vfs_create(dir->d_inode, dentry, mode); + security_ops->inode_ops->attach_pathlabel(dentry, nd->mnt); up(&dir->d_inode->i_sem); dput(nd->dentry); nd->dentry = dentry; @@ -998,7 +1018,8 @@ acc_mode = 0; flag &= ~O_TRUNC; goto ok; - } + } else + security_ops->inode_ops->attach_pathlabel(dentry, nd->mnt); /* * It already exists. @@ -1040,6 +1061,8 @@ if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE)) goto exit; + security_ops->inode_ops->attach_pathlabel(dentry, nd->mnt); + error = permission(inode,acc_mode); if (error) goto exit; @@ -1123,6 +1146,9 @@ * stored in nd->last.name and we will have to putname() it when we * are done. Procfs-like symlinks just set LAST_BIND. */ + error = security_ops->inode_ops->follow_link(dentry, nd); + if (error) + goto exit_dput; UPDATE_ATIME(dentry->d_inode); error = dentry->d_inode->i_op->follow_link(dentry, nd); dput(dentry); @@ -1191,6 +1217,10 @@ if (!dir->i_op || !dir->i_op->mknod) goto exit_lock; + error = security_ops->inode_ops->mknod(dir, dentry, mode, dev); + if (error) + goto exit_lock; + DQUOT_INIT(dir); lock_kernel(); error = dir->i_op->mknod(dir, dentry, mode, dev); @@ -1235,6 +1265,7 @@ default: error = -EINVAL; } + security_ops->inode_ops->attach_pathlabel(dentry, nd.mnt); dput(dentry); } up(&nd.dentry->d_inode->i_sem); @@ -1258,6 +1289,10 @@ if (!dir->i_op || !dir->i_op->mkdir) goto exit_lock; + error = security_ops->inode_ops->mkdir(dir, dentry, mode); + if (error) + goto exit_lock; + DQUOT_INIT(dir); mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask; lock_kernel(); @@ -1290,6 +1325,7 @@ error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); + security_ops->inode_ops->attach_pathlabel(dentry, nd.mnt); dput(dentry); } up(&nd.dentry->d_inode->i_sem); @@ -1349,11 +1385,14 @@ else if (d_mountpoint(dentry)) error = -EBUSY; else { - lock_kernel(); - error = dir->i_op->rmdir(dir, dentry); - unlock_kernel(); - if (!error) - dentry->d_inode->i_flags |= S_DEAD; + error = security_ops->inode_ops->rmdir(dir, dentry); + if (!error) { + lock_kernel(); + error = dir->i_op->rmdir(dir, dentry); + unlock_kernel(); + if (!error) + dentry->d_inode->i_flags |= S_DEAD; + } } double_up(&dir->i_zombie, &dentry->d_inode->i_zombie); if (!error) { @@ -1420,11 +1459,14 @@ if (d_mountpoint(dentry)) error = -EBUSY; else { - lock_kernel(); - error = dir->i_op->unlink(dir, dentry); - unlock_kernel(); - if (!error) - d_delete(dentry); + error = security_ops->inode_ops->unlink(dir, dentry); + if (!error) { + lock_kernel(); + error = dir->i_op->unlink(dir, dentry); + unlock_kernel(); + if (!error) + d_delete(dentry); + } } } } @@ -1490,6 +1532,10 @@ if (!dir->i_op || !dir->i_op->symlink) goto exit_lock; + error = security_ops->inode_ops->symlink(dir, dentry, oldname); + if (error) + goto exit_lock; + DQUOT_INIT(dir); lock_kernel(); error = dir->i_op->symlink(dir, dentry, oldname); @@ -1564,6 +1610,10 @@ if (!dir->i_op || !dir->i_op->link) goto exit_lock; + error = security_ops->inode_ops->link(old_dentry, dir, new_dentry); + if (error) + goto exit_lock; + DQUOT_INIT(dir); lock_kernel(); error = dir->i_op->link(old_dentry, dir, new_dentry); @@ -1693,6 +1743,10 @@ if (error) return error; + error = security_ops->inode_ops->rename(old_dir, old_dentry, new_dir, new_dentry); + if (error) + return error; + DQUOT_INIT(old_dir); DQUOT_INIT(new_dir); down(&old_dir->i_sb->s_vfs_rename_sem); @@ -1758,6 +1812,10 @@ if (!old_dir->i_op || !old_dir->i_op->rename) return -EPERM; + + error = security_ops->inode_ops->rename(old_dir, old_dentry, new_dir, new_dentry); + if (error) + return error; DQUOT_INIT(old_dir); DQUOT_INIT(new_dir); diff -Nru a/fs/open.c b/fs/open.c --- a/fs/open.c Mon Apr 23 09:04:14 2001 +++ b/fs/open.c Mon Apr 23 09:04:14 2001 @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/tty.h> +#include <linux/security.h> #include <asm/uaccess.h> @@ -663,6 +664,8 @@ } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); + f->f_security = security_ops->file_ops->alloc_security (f); + return f; cleanup_all: diff -Nru a/fs/read_write.c b/fs/read_write.c --- a/fs/read_write.c Mon Apr 23 09:04:14 2001 +++ b/fs/read_write.c Mon Apr 23 09:04:14 2001 @@ -11,6 +11,7 @@ #include <linux/uio.h> #include <linux/smp_lock.h> #include <linux/dnotify.h> +#include <linux/security.h> #include <asm/uaccess.h> @@ -129,8 +130,11 @@ if (!ret) { ssize_t (*read)(struct file *, char *, size_t, loff_t *); ret = -EINVAL; - if (file->f_op && (read = file->f_op->read) != NULL) - ret = read(file, buf, count, &file->f_pos); + if (file->f_op && (read = file->f_op->read) != NULL) { + ret = security_ops->file_ops->permission (file, MAY_READ); + if (!ret) + ret = read(file, buf, count, &file->f_pos); + } } } if (ret > 0) @@ -156,8 +160,11 @@ if (!ret) { ssize_t (*write)(struct file *, const char *, size_t, loff_t *); ret = -EINVAL; - if (file->f_op && (write = file->f_op->write) != NULL) - ret = write(file, buf, count, &file->f_pos); + if (file->f_op && (write = file->f_op->write) != NULL) { + ret = security_ops->file_ops->permission (file, MAY_WRITE); + if (!ret) + ret = write(file, buf, count, &file->f_pos); + } } } if (ret > 0) @@ -283,8 +290,11 @@ if (!file) goto bad_file; 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); + (file->f_op->readv || file->f_op->read)) { + ret = security_ops->file_ops->permission (file, MAY_READ); + if (!ret) + ret = do_readv_writev(VERIFY_WRITE, file, vector, count); + } fput(file); bad_file: @@ -303,8 +313,11 @@ if (!file) goto bad_file; 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); + (file->f_op->writev || file->f_op->write)) { + ret = security_ops->file_ops->permission (file, MAY_WRITE); + if (!ret) + ret = do_readv_writev(VERIFY_READ, file, vector, count); + } fput(file); bad_file: @@ -337,6 +350,11 @@ goto out; if (pos < 0) goto out; + + ret = security_ops->file_ops->permission (file, MAY_READ); + if (ret) + goto out; + ret = read(file, buf, count, &pos); if (ret > 0) inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_ACCESS); @@ -367,6 +385,10 @@ if (!file->f_op || !(write = file->f_op->write)) goto out; if (pos < 0) + goto out; + + ret = security_ops->file_ops->permission (file, MAY_WRITE); + if (ret) goto out; ret = write(file, buf, count, &pos); diff -Nru a/fs/stat.c b/fs/stat.c --- a/fs/stat.c Mon Apr 23 09:04:14 2001 +++ b/fs/stat.c Mon Apr 23 09:04:14 2001 @@ -9,6 +9,7 @@ #include <linux/file.h> #include <linux/smp_lock.h> #include <linux/highuid.h> +#include <linux/security.h> #include <asm/uaccess.h> @@ -18,9 +19,14 @@ static __inline__ int do_revalidate(struct dentry *dentry) { + int error; struct inode * inode = dentry->d_inode; - if (inode->i_op && inode->i_op->revalidate) + if (inode->i_op && inode->i_op->revalidate) { + error = security_ops->inode_ops->revalidate(dentry); + if (error) + return error; return inode->i_op->revalidate(dentry); + } return 0; } @@ -257,8 +263,11 @@ error = -EINVAL; if (inode->i_op && inode->i_op->readlink && !(error = do_revalidate(nd.dentry))) { - UPDATE_ATIME(inode); - error = inode->i_op->readlink(nd.dentry, buf, bufsiz); + error = security_ops->inode_ops->readlink(nd.dentry, buf, bufsiz); + if (!error) { + UPDATE_ATIME(inode); + error = inode->i_op->readlink(nd.dentry, buf, bufsiz); + } } path_release(&nd); } diff -Nru a/fs/super.c b/fs/super.c --- a/fs/super.c Mon Apr 23 09:04:14 2001 +++ b/fs/super.c Mon Apr 23 09:04:14 2001 @@ -37,6 +37,7 @@ #include <linux/nfs_fs.h> #include <linux/nfs_fs_sb.h> #include <linux/nfs_mount.h> +#include <linux/security.h> #include <linux/kmod.h> #define __NO_VERSION__ @@ -1137,6 +1138,11 @@ retval = -EPERM; if (!capable(CAP_SYS_ADMIN) && current->uid!=nd.mnt->mnt_owner) goto dput_and_out; + + retval = security_ops->umount(name, flags); + if (retval) { + return retval; + } dput(nd.dentry); /* puts nd.mnt */ @@ -1427,6 +1433,12 @@ unsigned long type_page; unsigned long dev_page; char *dir_page; + + /* check that we have permission to do this */ + retval = security_ops->mount(dev_name, dir_name, type, flags, data); + if (retval) { + return retval; + } retval = copy_mount_options (type, &type_page); if (retval < 0) diff -Nru a/include/linux/elf.h b/include/linux/elf.h --- a/include/linux/elf.h Mon Apr 23 09:04:14 2001 +++ b/include/linux/elf.h Mon Apr 23 09:04:14 2001 @@ -510,7 +510,7 @@ #define SHN_HIRESERVE 0xffff #define SHN_MIPS_ACCOMON 0xff00 -typedef struct { +typedef struct elf32_shdr { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; @@ -597,6 +597,7 @@ #define elfhdr elf32_hdr #define elf_phdr elf32_phdr #define elf_note elf32_note +#define elf_shdr elf32_shdr #else @@ -604,6 +605,7 @@ #define elfhdr elf64_hdr #define elf_phdr elf64_phdr #define elf_note elf64_note +#define elf_shdr elf64_shdr #endif diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Mon Apr 23 09:04:14 2001 +++ b/include/linux/fs.h Mon Apr 23 09:04:14 2001 @@ -439,6 +439,7 @@ atomic_t i_writecount; unsigned int i_attr_flags; + void *i_security; __u32 i_generation; union { struct minix_inode_info minix_i; @@ -495,6 +496,8 @@ /* needed for tty driver, and maybe others */ void *private_data; + + void *f_security; }; extern spinlock_t files_lock; #define file_list_lock() spin_lock(&files_lock); diff -Nru a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h Mon Apr 23 09:04:14 2001 +++ b/include/linux/sched.h Mon Apr 23 09:04:14 2001 @@ -393,6 +393,8 @@ void *notifier_data; sigset_t *notifier_mask; + void *security; + /* Thread group tracking */ u32 parent_exec_id; u32 self_exec_id; diff -Nru a/include/linux/security.h b/include/linux/security.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/security.h Mon Apr 23 09:04:14 2001 @@ -0,0 +1,152 @@ +/* + * Linux Security plug + * + * 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. + * + * 2001_Apr_12 greg k-h + * created based on original immunix.h code + * + * cmw hacked for capabilites (eeww!) + */ + +#ifndef __LINUX_SECURITY_H +#define __LINUX_SECURITY_H + + +#define SECURITY_SCAFFOLD_VERSION "1.0.0" + +#ifdef __KERNEL__ + +#include <linux/fs.h> + + +/* Security plug operations */ +#define SECURITY_INTERFACE_VERSION 0x00000101 /* change this every time the security_operations structure changes */ + +struct inode_security_ops { + void * (* alloc_security) (void); // create per inode security stuff + void (* free_security) (void *i_security); // free it + + int (* create) (struct inode *dir, struct dentry *dentry, int mode); + int (* link) (struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry); + int (* unlink) (struct inode *dir, struct dentry *dentry); + int (* symlink) (struct inode *dir, struct dentry *dentry, const char *old_name); + int (* mkdir) (struct inode *dir, struct dentry *dentry, int mode); + int (* rmdir) (struct inode *dir, struct dentry *dentry); + int (* mknod) (struct inode *dir, struct dentry *dentry, int mode, dev_t dev); + int (* rename) (struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry); + int (* readlink) (struct dentry *dentry, char *buf, int bufsiz); + int (* follow_link) (struct dentry *dentry, struct nameidata *nd); + int (* truncate) (struct inode *inode); + int (* permission) (struct inode *inode, int mask); + int (* revalidate) (struct dentry *dentry); + int (* setattr) (struct dentry *dentry, struct iattr *attr); // CAP_CHOWN + void (* attach_pathlabel)(struct dentry *dentry, struct vfsmount *mnt); // DTE project needs this +}; + +struct file_security_ops { + int (* permission) (struct file *, int); + void * (* alloc_security) (struct file *); + void (* free_security) (struct file *); + /* cmw: essentially copied from struct file_operations */ + int (* llseek) (struct file *); + int (* read) (struct file *); + int (* write) (struct file *); + int (* ioctl) (struct file *); // need more than file* + int (* mmap) (struct file *); + int (* lock) (struct file *); + int (* readv) (struct file *); + int (* writev) (struct file *); +}; + +struct task_security_ops { + int (* create) (void); + void * (* alloc_security) (void); // create per process security stuff + void (* free_security) (void *); // free it + int (* setuid) (void); // CAP_SETUID + int (* setgid) (void); // CAP_SETGID + int (* setpriority) (void); // CAP_NICE + int (* kill) (void); // CAP_KILL +}; + +struct socket_security_ops { +}; + +struct module_security_ops { + int (* create_module) (const char *name_user, size_t size); // CAP_SYS_MODULE + int (* init_module) (const char *name_user, struct module *mod_user); // CAP_SYS_MODULE + int (* delete_module) (const char *name_user); // CAP_SYS_MODULE +}; + +struct msg_queue_security_ops { + int (* create) (key_t key); // can i create + int (* permission) (void); // CAP_SYS_ADMIN + int (* setmaxqbytes) (void); // CAP_SYS_RESOURCE + int (* setattr) (void); // can i set attributes + int (* delete) (void); // can i delete +}; + +struct shm_security_ops { + int (* create) (key_t key); + int (* permission) (void); + int (* setattr) (void); + int (* delete) (void); +}; + + +struct security_operations { + int version; + + /* syscalls that are checked for permissions */ + int (* sethostname) (void); + int (* setdomainname) (void); + int (* reboot) (void); // CAP_SYS_BOOT + int (* mount) (char * dev_name, char * dir_name, + char * type, unsigned long flags, + void * data); // part of CAP_SYS_ADMIN + int (* umount) (char * name, int flags); // part of CAP_SYS_ADMIN + int (* ioperm) (void); // part of CAP_RAWIO + int (* iopl) (void); // part of CAP_RAWIO + int (* ptrace) (void); // CAP_PTRACE + int (* setcapability) (void); // CAP_SETPCAP + + /* cmw: this should allow you to know if two permissions + * stuctures are the same, subset, or superset + * returns 0 when same, 1 when perm1 is superset of perm2 and + * -1 when perm1 is subset of perm2...hmmm what if they have no + * relation? need better type than void* ;-/ + * at least subset is needed for capabilities + */ + int (* perm_comp) (void * perm1, void * perm2); + void (* init_perm) (void * perm); + int (* change_perm) (void * perm); + + struct inode_security_ops * inode_ops; + struct file_security_ops * file_ops; + struct task_security_ops * task_ops; + struct socket_security_ops * socket_ops; + struct module_security_ops * module_ops; + struct msg_queue_security_ops * msg_queue_ops; + struct shm_security_ops * shm_ops; + +}; + + +/* prototypes */ +extern int security_scaffolding_startup (void); +extern int register_security (struct security_operations *ops); +extern int unregister_security (struct security_operations *ops); + +/* global variables */ +extern struct security_operations *security_ops; + + +#endif /* __KERNEL__ */ + +#endif /* ! __LINUX_SECURITY_H */ + + diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h --- a/include/linux/sysctl.h Mon Apr 23 09:04:14 2001 +++ b/include/linux/sysctl.h Mon Apr 23 09:04:14 2001 @@ -117,6 +117,10 @@ KERN_OVERFLOWGID=47, /* int: overflow GID */ KERN_SHMPATH=48, /* string: path to shm fs */ KERN_HOTPLUG=49, /* string: path to hotplug policy agent */ + +/* Don't ifdef this -- user level programs use it */ + KERN_CODOMAIN=69, /* struct: subdomain stuff */ + KERN_COD_PARANOID=70, /* int: paranoid mode */ }; @@ -643,6 +647,8 @@ extern ctl_handler sysctl_string; extern ctl_handler sysctl_intvec; extern ctl_handler sysctl_jiffies; + +extern ctl_handler sysctl_codomain; /* diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Mon Apr 23 09:04:14 2001 +++ b/init/main.c Mon Apr 23 09:04:14 2001 @@ -27,6 +27,7 @@ #include <linux/hdreg.h> #include <linux/iobuf.h> #include <linux/bootmem.h> +#include <linux/security.h> #include <asm/io.h> #include <asm/bugs.h> @@ -595,6 +596,8 @@ #endif check_bugs(); printk("POSIX conformance testing by UNIFIX\n"); + + security_scaffolding_startup(); /* * We count on the initial thread going ok diff -Nru a/kernel/Makefile b/kernel/Makefile --- a/kernel/Makefile Mon Apr 23 09:04:14 2001 +++ b/kernel/Makefile Mon Apr 23 09:04:14 2001 @@ -14,11 +14,13 @@ obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ sysctl.o acct.o capability.o ptrace.o timer.o user.o \ - signal.o sys.o kmod.o context.o + signal.o sys.o kmod.o context.o \ + security.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_CAPABILITIES) += capability_plug.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is diff -Nru a/kernel/capability_plug.c b/kernel/capability_plug.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/kernel/capability_plug.c Mon Apr 23 09:04:14 2001 @@ -0,0 +1,45 @@ +/* + * Capabilities Security plug + * + * 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. + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/security.h> +#include <linux/mm.h> +#include <asm/uaccess.h> + + +static struct security_operations capability_ops; + +static int __init capability_plug_init (void) +{ + /* register ourselves with the security framework */ + if (register_security (&capability_ops)) { + printk (KERN_INFO "Failure registering capabilities with the kernel\n"); + return -EINVAL; + } + return 0; +} + + +static void __exit capability_plug_exit (void) +{ + /* remove ourselves from the security framework */ + if (unregister_security (&capability_ops)) { + printk (KERN_INFO "Failuer unretistering capabilities with the kernel\n"); + } +} + + +module_init (capability_plug_init); +module_exit (capability_plug_exit); + diff -Nru a/kernel/exit.c b/kernel/exit.c --- a/kernel/exit.c Mon Apr 23 09:04:14 2001 +++ b/kernel/exit.c Mon Apr 23 09:04:14 2001 @@ -10,6 +10,7 @@ #include <linux/smp_lock.h> #include <linux/module.h> #include <linux/tty.h> +#include <linux/security.h> #ifdef CONFIG_BSD_PROCESS_ACCT #include <linux/acct.h> #endif @@ -43,6 +44,7 @@ task_unlock(p); #endif atomic_dec(&p->user->processes); + security_ops->task_ops->free_security(p->security); free_uid(p->user); unhash_process(p); diff -Nru a/kernel/fork.c b/kernel/fork.c --- a/kernel/fork.c Mon Apr 23 09:04:14 2001 +++ b/kernel/fork.c Mon Apr 23 09:04:14 2001 @@ -18,6 +18,7 @@ #include <linux/smp_lock.h> #include <linux/module.h> #include <linux/vmalloc.h> +#include <linux/security.h> #include <asm/pgtable.h> #include <asm/pgalloc.h> @@ -640,6 +641,8 @@ p->lock_depth = -1; /* -1 = no lock */ p->start_time = jiffies; + p->security = security_ops->task_ops->alloc_security(); + retval = -ENOMEM; /* copy all the process information */ if (copy_files(clone_flags, p)) diff -Nru a/kernel/module.c b/kernel/module.c --- a/kernel/module.c Mon Apr 23 09:04:14 2001 +++ b/kernel/module.c Mon Apr 23 09:04:14 2001 @@ -9,6 +9,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/kmod.h> +#include <linux/security.h> /* * Originally by Anonymous (as far as I know...) @@ -296,9 +297,17 @@ long namelen, error; struct module *mod; unsigned long flags; + int result; if (!capable(CAP_SYS_MODULE)) return -EPERM; + + /* check that we have permission to do this */ + result = security_ops->module_ops->create_module(name_user, size); + if (result) { + return result; + } + lock_kernel(); if ((namelen = get_mod_name(name_user, &name)) < 0) { error = namelen; @@ -351,9 +360,17 @@ long namelen, n_namelen, i, error; unsigned long mod_user_size; struct module_ref *dep; + int result; if (!capable(CAP_SYS_MODULE)) return -EPERM; + + /* check that we have permission to do this */ + result = security_ops->module_ops->init_module(name_user, mod_user); + if (result) { + return result; + } + lock_kernel(); if ((namelen = get_mod_name(name_user, &name)) < 0) { error = namelen; @@ -605,9 +622,16 @@ char *name; long error; int something_changed; + int result; if (!capable(CAP_SYS_MODULE)) return -EPERM; + + /* check that we have permission to do this */ + result = security_ops->module_ops->delete_module(name_user); + if (result) { + return result; + } lock_kernel(); if (name_user) { diff -Nru a/kernel/security.c b/kernel/security.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/kernel/security.c Mon Apr 23 09:04:14 2001 @@ -0,0 +1,264 @@ +/* + * Linux Security plug + * + * 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. + * + * 2001_Apr_18 greg k-h + * fleshed out with current security.h stubs + * + * 2001_Apr_12 greg k-h + * created based on original immunix_scaffold.c code + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/malloc.h> +#include <linux/smp_lock.h> +#include <linux/security.h> + +#include <linux/module.h> +#include <linux/sysctl.h> + + + + +struct security_operations *security_ops; /* Initialized to NULL */ + + +/* Stub functions for the default security function pointers in case no security model is loaded */ +static int dummy_sethostname (void) {return 0;} +static int dummy_setdomainname (void) {return 0;} +static int dummy_reboot (void) {return 0;} +static int dummy_mount (char * dev_name, char * dir_name, char * type, unsigned long flags, void * data) {return 0;} +static int dummy_umount (char * name, int flags) {return 0;} +static int dummy_ioperm (void) {return 0;} +static int dummy_iopl (void) {return 0;} +static int dummy_ptrace (void) {return 0;} +static int dummy_setcapablity (void) {return 0;} +static int dummy_perm_comp (void * perm1, void * perm2) {return 0;} +static void dummy_init_perm (void * perm) {return;} +static int dummy_change_perm (void * perm) {return 0;} + +static void *dummy_inode_alloc_security (void) {return NULL;} +static void dummy_inode_free_security (void *i_security) {return;} +static int dummy_inode_create (struct inode *inode, struct dentry *dentry, int mask) {return 0;} +static int dummy_inode_link (struct dentry *old_dentry, struct inode *inode, struct dentry *new_dentry) {return 0;} +static int dummy_inode_unlink (struct inode *inode, struct dentry *dentry) {return 0;} +static int dummy_inode_symlink (struct inode *inode, struct dentry *dentry, const char *name) {return 0;} +static int dummy_inode_mkdir (struct inode *inode, struct dentry *dentry, int mask) {return 0;} +static int dummy_inode_rmdir (struct inode *inode, struct dentry *dentry) {return 0;} +static int dummy_inode_mknod (struct inode *inode, struct dentry *dentry, int major, int minor) {return 0;} +static int dummy_inode_rename (struct inode *old_inode, struct dentry *old_dentry, struct inode *new_inode, struct dentry *new_dentry) {return 0;} +static int dummy_inode_readlink (struct dentry *dentry, char *name, int mask) {return 0;} +static int dummy_inode_follow_link (struct dentry *dentry, struct nameidata *nameidata) {return 0;} +static int dummy_inode_truncate (struct inode *inode) {return 0;} +static int dummy_inode_permission (struct inode *inode, int mask) {return 0;} +static int dummy_inode_revalidate (struct dentry *inode) {return 0;} +static int dummy_inode_setattr (struct dentry *dentry, struct iattr *iattr) {return 0;} +static void dummy_inode_attach_pathlabel(struct dentry *dentry, struct vfsmount *mnt) {return;} + +static int dummy_file_permission (struct file *file, int mask) {return 0;} +static void * dummy_file_alloc_security (struct file *file) {return NULL;} +static void dummy_file_free_security (struct file *file) {return;} +static int dummy_file_llseek (struct file *file) {return 0;} +static int dummy_file_read (struct file *file) {return 0;} +static int dummy_file_write (struct file *file) {return 0;} +static int dummy_file_ioctl (struct file *file) {return 0;} +static int dummy_file_mmap (struct file *file) {return 0;} +static int dummy_file_lock (struct file *file) {return 0;} +static int dummy_file_readv (struct file *file) {return 0;} +static int dummy_file_writev (struct file *file) {return 0;} + +static int dummy_task_create (void) {return 0;} +static void * dummy_task_alloc_security (void) {return NULL;} +static void dummy_task_free_security (void *data) {return;} +static int dummy_task_setuid (void) {return 0;} +static int dummy_task_setgid (void) {return 0;} +static int dummy_task_setpriority (void) {return 0;} +static int dummy_task_kill (void) {return 0;} + +static int dummy_module_create_module (const char *name_user, size_t size) {return 0;} +static int dummy_module_init_module (const char *name_user, struct module *mod_user) {return 0;} +static int dummy_module_delete_module (const char *name_user) {return 0;} + +static int dummy_msg_queue_create (key_t key) {return 0;} +static int dummy_msg_queue_permission (void) {return 0;} +static int dummy_msg_queue_setmaxqbytes (void) {return 0;} +static int dummy_msg_queue_setattr (void) {return 0;} +static int dummy_msg_queue_delete (void) {return 0;} + +static int dummy_shm_create (key_t key) {return 0;} +static int dummy_shm_permission (void) {return 0;} +static int dummy_shm_setattr (void) {return 0;} +static int dummy_shm_delete (void) {return 0;} + + +static struct inode_security_ops dummy_inode_ops = { + alloc_security: dummy_inode_alloc_security, + free_security: dummy_inode_free_security, + create: dummy_inode_create, + link: dummy_inode_link, + unlink: dummy_inode_unlink, + symlink: dummy_inode_symlink, + mkdir: dummy_inode_mkdir, + rmdir: dummy_inode_rmdir, + mknod: dummy_inode_mknod, + rename: dummy_inode_rename, + readlink: dummy_inode_readlink, + follow_link: dummy_inode_follow_link, + truncate: dummy_inode_truncate, + permission: dummy_inode_permission, + revalidate: dummy_inode_revalidate, + setattr: dummy_inode_setattr, + attach_pathlabel:dummy_inode_attach_pathlabel, +}; + +static struct file_security_ops dummy_file_ops = { + permission: dummy_file_permission, + alloc_security: dummy_file_alloc_security, + free_security: dummy_file_free_security, + llseek: dummy_file_llseek, + read: dummy_file_read, + write: dummy_file_write, + ioctl: dummy_file_ioctl, + mmap: dummy_file_mmap, + lock: dummy_file_lock, + readv: dummy_file_readv, + writev: dummy_file_writev, +}; + +static struct task_security_ops dummy_task_ops = { + create: dummy_task_create, + alloc_security: dummy_task_alloc_security, + free_security: dummy_task_free_security, + setuid: dummy_task_setuid, + setgid: dummy_task_setgid, + setpriority: dummy_task_setpriority, + kill: dummy_task_kill, +}; + +static struct socket_security_ops dummy_socket_ops = {}; + +static struct module_security_ops dummy_module_ops = { + create_module: dummy_module_create_module, + init_module: dummy_module_init_module, + delete_module: dummy_module_delete_module, + +}; + +static struct msg_queue_security_ops dummy_msg_queue_ops = { + create: dummy_msg_queue_create, + permission: dummy_msg_queue_permission, + setmaxqbytes: dummy_msg_queue_setmaxqbytes, + setattr: dummy_msg_queue_setattr, + delete: dummy_msg_queue_delete, +}; + +static struct shm_security_ops dummy_shm_ops = { + create: dummy_shm_create, + permission: dummy_shm_permission, + setattr: dummy_shm_setattr, + delete: dummy_shm_delete, +}; + +static struct security_operations dummy_security_ops = { + version: SECURITY_INTERFACE_VERSION, + + sethostname: dummy_sethostname, + setdomainname: dummy_setdomainname, + reboot: dummy_reboot, + mount: dummy_mount, + umount: dummy_umount, + ioperm: dummy_ioperm, + iopl: dummy_iopl, + ptrace: dummy_ptrace, + setcapability: dummy_setcapablity, + perm_comp: dummy_perm_comp, + init_perm: dummy_init_perm, + change_perm: dummy_change_perm, + + inode_ops: &dummy_inode_ops, + file_ops: &dummy_file_ops, + task_ops: &dummy_task_ops, + socket_ops: &dummy_socket_ops, + module_ops: &dummy_module_ops, + msg_queue_ops: &dummy_msg_queue_ops, + shm_ops: &dummy_shm_ops, +}; + + + +/** + * security_scaffolding_startup - initialzes the security scaffolding framework + * + */ +int security_scaffolding_startup (void) +{ + printk (KERN_INFO "Security Scaffold v" SECURITY_SCAFFOLD_VERSION " initialized\n"); + + security_ops = &dummy_security_ops; + + return 0; +} + + +/** + * register_security - registers a security framework with the kernel + */ +int register_security (struct security_operations *ops) +{ + /* verify the version of the structure matches what we think it should be */ + if (ops->version != SECURITY_INTERFACE_VERSION) { + printk (KERN_INFO "Mismatched version of security_operation structure used, " __FUNCTION__ " failed."); + return -EINVAL; + } + + if (ops != &dummy_security_ops) { + printk (KERN_INFO "There is already a security framework initialized, " __FUNCTION__ " failed."); + return -EINVAL; + } + + /* Perform a little sanity checking on our inputs */ + if ( !ops || + !ops->inode_ops || + !ops->file_ops || + !ops->task_ops || + !ops->socket_ops || + !ops->module_ops || + !ops->msg_queue_ops || + !ops->shm_ops + ) { + printk (KERN_INFO "Not enough functions specified in the security_operation structure, " __FUNCTION__ " failed."); + return -EINVAL ; + } + + security_ops = ops; + + return 0 ; +} + + +/** + * unregister_security - unregisters a security framework with the kernel + */ +int unregister_security (struct security_operations *ops) +{ + if (ops != security_ops) { + printk (KERN_INFO __FUNCTION__ ": trying to unregister a security_opts structure that is not registered, failing."); + return -EINVAL; + } + + security_ops = &dummy_security_ops; + + return 0; +} + +EXPORT_SYMBOL(register_security); +EXPORT_SYMBOL(unregister_security); + diff -Nru a/kernel/sys.c b/kernel/sys.c --- a/kernel/sys.c Mon Apr 23 09:04:14 2001 +++ b/kernel/sys.c Mon Apr 23 09:04:14 2001 @@ -14,6 +14,7 @@ #include <linux/prctl.h> #include <linux/init.h> #include <linux/highuid.h> +#include <linux/security.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -269,11 +270,18 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void * arg) { char buffer[256]; + int result; /* We only trust the superuser with rebooting the system. */ if (!capable(CAP_SYS_BOOT)) return -EPERM; + /* check that we have permission to do this */ + result = security_ops->reboot(); + if (result) { + return result; + } + /* For safety, we require "magic" arguments. */ if (magic1 != LINUX_REBOOT_MAGIC1 || (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && @@ -1030,6 +1038,13 @@ return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; + + /* check that we have permission to do this */ + errno = security_ops->sethostname(); + if (errno) { + return errno; + } + down_write(&uts_sem); errno = -EFAULT; if (!copy_from_user(system_utsname.nodename, name, len)) { @@ -1069,6 +1084,12 @@ return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; + + /* check that we have permission to do this */ + errno = security_ops->setdomainname(); + if (errno) { + return errno; + } down_write(&uts_sem); errno = -EFAULT; diff -Nru a/mm/filemap.c b/mm/filemap.c --- a/mm/filemap.c Mon Apr 23 09:04:14 2001 +++ b/mm/filemap.c Mon Apr 23 09:04:14 2001 @@ -21,6 +21,7 @@ #include <linux/swapctl.h> #include <linux/init.h> #include <linux/mm.h> +#include <linux/security.h> #include <asm/pgalloc.h> #include <asm/uaccess.h> @@ -1311,6 +1312,10 @@ if (retval) goto fput_in; + retval = security_ops->file_ops->permission (in_file, MAY_READ); + if (retval) + goto fput_in; + /* * Get output file, and verify that it is ok.. */ @@ -1327,6 +1332,10 @@ retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count); if (retval) goto fput_out; + + retval = security_ops->file_ops->permission (out_file, MAY_WRITE); + if (retval) + goto fput_in; retval = 0; if (count) { diff -Nru a/mm/memory.c b/mm/memory.c --- a/mm/memory.c Mon Apr 23 09:04:14 2001 +++ b/mm/memory.c Mon Apr 23 09:04:14 2001 @@ -44,6 +44,7 @@ #include <linux/iobuf.h> #include <linux/highmem.h> #include <linux/pagemap.h> +#include <linux/security.h> #include <asm/pgalloc.h> #include <asm/uaccess.h> @@ -969,8 +970,10 @@ out_unlock: spin_unlock(&mapping->i_shared_lock); truncate_inode_pages(mapping, offset); - if (inode->i_op && inode->i_op->truncate) - inode->i_op->truncate(inode); + if (inode->i_op && inode->i_op->truncate) { + if (!security_ops->inode_ops->truncate(inode)) + inode->i_op->truncate(inode); + } return; do_expand: @@ -986,8 +989,10 @@ } } inode->i_size = offset; - if (inode->i_op && inode->i_op->truncate) - inode->i_op->truncate(inode); + if (inode->i_op && inode->i_op->truncate) { + if (!security_ops->inode_ops->truncate(inode)) + inode->i_op->truncate(inode); + } out: return; } diff -Nru a/security/Config.in b/security/Config.in --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/security/Config.in Mon Apr 23 09:04:14 2001 @@ -0,0 +1,8 @@ +# +# Security configuration +# +mainmenu_option next_comment +comment 'Security options' +tristate ' Capabilities Support' CONFIG_CAPABILITIES + +endmenu