| From: |
| "Michael A. Halcrow" <mahalcro@us.ibm.com> |
| To: |
| linux-security-module@wirex.com |
| Subject: |
| [PATCH] BSD Secure Levels LSM |
| Date: |
| Thu, 20 Nov 2003 16:37:39 -0600 |
Attached are patches against the 2.6.0-test kernel to implement BSD
Secure Levels as an LSM. seclvl-hooks.diff contains requisite hooks
to implement some of the Secure Levels policies. Note that a settime
hook currently exists in the LSM BK tree. It is not, however, in the
kernel tree, and our patches apply to that tree. seclvl.diff contains
the module code and the modifications to the Kconfig file to provide
the config menu option.
To address the fact that some administrators may wish to perform
certain operations disallowed by the seclvl module, we have provided
functionality whereby the administrator can, at the time that he loads
the module, specify an executable that, when executed, will reduce the
secure level to 0. It is assumed that the administrator, should he
choose to use this feature, will employ additional security measures
(i.e., stacking another module), to prevent it from being abused.
Please take some time to look this over and provide feedback. It is
meant to be nothing more than a lightweight security measure that an
administrator who is already familiar with BSD Secure Levels can just
pop into the kernel with reasonable expectations that he will get
equivalent functionality.
Mike Halcrow
Security Software Engineer, IBM Linux Technology Center
--- linux-2.6.0-test9_orig/security/Kconfig 2003-10-25 13:44:05.000000000 -0500
+++ linux-2.6.0-test9/security/Kconfig 2003-10-28 17:03:10.000000000 -0600
@@ -46,5 +46,11 @@
source security/selinux/Kconfig
+config SECURITY_SECLVL
+ tristate "BSD SecureLevel"
+ depends on SECURITY!=n
+ help
+ Implements BSD Secure Levels as an LSM.
+
endmenu
diff -Nur linux-2.6.0-test9_orig/security/Makefile linux-2.6.0-test9/security/Makefile
--- linux-2.6.0-test9_orig/security/Makefile 2003-10-25 13:44:08.000000000 -0500
+++ linux-2.6.0-test9/security/Makefile 2003-10-28 17:03:10.000000000 -0600
@@ -17,3 +17,4 @@
endif
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o
diff -Nur linux-2.6.0-test9_orig/security/capability.mod.c linux-2.6.0-test9/security/capability.mod.c
--- linux-2.6.0-test9_orig/security/seclvl.c 1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.0-test9/security/seclvl.c 2003-11-19 11:00:00.000000000 -0600
@@ -0,0 +1,563 @@
+/**
+ * LSM SecureLevel module for Linux.
+ * Based on LSM dummy.c and owlsm.c
+ *
+ * Maintainers:
+ * Michael A. Halcrow <mike@halcrow.us>
+ * Kent Yoder <yoder1@us.ibm.com>
+ * Jerone Young <jeroney@us.ibm.com>
+ * Serge Hallyn <hallyn@cs.wm.edu>
+ *
+ * Copyright (C) 2001 WireX Communications, Inc <chris@wirex.com>
+ * Copyright (C) 2001 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com>
+ * Copyright (C) 2002 International Business Machines <robb@austin.ibm.com>
+ *
+ * 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.
+ */
+
+/**
+ * Changelog:
+ * 11/13/2003 Updated by Michael A. Halcrow:
+ * 1. Polished up code and comments for first patch submission to
+ * LSM dev.
+ *
+ * 10/23/2003 Updated by Serge Hallyn:
+ * 1. Fixed settime hook which was being activated on seclvl>=1,
+ * not seclvl > 1, as it should be.
+ * 2. (perhaps temp) Removed the secondary_ops support. We can
+ * add that back in later when all is fixed. In the
+ * mean time it's a distraction.
+ * 3. Removed dentry-related code. We're not using it, and we
+ * could not submit something with that in it.
+ *
+ * 10/20/2003 Updated by Serge Hallyn:
+ * 1. Optimistically re-based the patch off three new LSM hooks
+ * whose re-introduction this project will hopefully
+ * justify
+ * 2. Replaced the sysctl interface with a simple proc file, to
+ * avoid the need to patch include/linux/sysctl.h
+ * 3. Capabilities code fix.
+ * 4. Removed unused hooks.
+ *
+ * 9/2003 Bulk of functionality written by Michael A. Halcrow
+ *
+ * 4/2003 Updated by Kent Yoder
+ *
+ * 4/2003 Updated by Jerone Young
+ *
+ * 4/2003 Created by Robb Romans
+ */
+
+/**
+ * Potential furture enhancements:
+ * - Let the administrator pass in a password as a module parameter
+ * that reduces the secure level when written to /proc/seclvl.
+ * - Export a kill_seclvl function to the rest of the kernel to allow
+ * other modules to disable or change the seclvl (i.e., rootplug
+ * could reduce the seclvl).
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/netlink.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/capability.h>
+#include <linux/time.h>
+#include <linux/proc_fs.h>
+
+/**
+ * The actual security level. Ranges between -1 and 2 inclusive.
+ */
+static int seclvl = 0;
+
+/**
+ * Optional pathname which can be executed to bring seclvl to 0
+ * (for safe boot). Defaults to NULL, meaning there is no escape.
+ */
+static char* magicpath = NULL;
+MODULE_PARM( magicpath, "s" );
+MODULE_PARM_DESC( magicpath, "Pathname that sets seclvl=0 when executed.\n");
+
+/* dentry for said pathname */
+struct dentry* magicdentry = NULL;
+
+/**
+ * flag to keep track of how we were registered
+ */
+static int secondary;
+
+/**
+ * Verifies that the requested secure level is valid, given the current
+ * secure level.
+ */
+int seclvl_sanity( int reqlvl )
+{
+ if( ( reqlvl < -1 ) || ( reqlvl > 2 ) ) {
+ printk( KERN_WARNING "Attempt to set seclvl out of range: "
+ "[%d]\n", reqlvl );
+ return -EINVAL;
+ }
+ if( ( seclvl == 0 ) && ( reqlvl == -1 ) )
+ return 0;
+ if( reqlvl < seclvl ) {
+ printk( KERN_WARNING "Attempt to lower seclvl to [%d]\n",
+ reqlvl );
+ return -EPERM;
+ }
+ return 0;
+}
+
+int do_seclvl_advance( int );
+
+/**
+ * Handlers for reading and writing our /proc/seclvl file.
+ */
+static int seclvl_read_proc( char* page, char** start,
+ off_t off, int count,
+ int* eof, void* data)
+{
+ int len;
+ len = snprintf( page, 4, "%d\n", seclvl );
+ *eof = 1;
+ return len;
+}
+
+/**
+ * Handle writes to /proc/seclvl
+ */
+static int seclvl_write_proc( struct file* file, const char* buf,
+ unsigned long len, void* data )
+{
+ char mybuf[4];
+ char* tmp;
+ unsigned long val, mylen = len;
+ if( mylen > 3 )
+ mylen = 3;
+ if( copy_from_user( mybuf, buf, mylen ) )
+ return -EFAULT;
+ val = simple_strtol(mybuf, &tmp, 10);
+ if( seclvl_sanity( val ) ) {
+ printk( KERN_WARNING "Illegal secure level requested: [%d]\n",
+ (int)val );
+ return -EPERM;
+ }
+ if( do_seclvl_advance( val ) ) {
+ printk( KERN_ERR "Failure advancing security level to %lu\n",
+ val );
+ }
+ return len;
+}
+
+/**
+ * Is this redundant with CAP_SYS_PTRACE? --serge
+ */
+static int seclvl_ptrace( struct task_struct* parent,
+ struct task_struct* child )
+{
+ if( seclvl >= 0 ) {
+ if( child->pid == 1 ) {
+ printk( KERN_WARNING "Attempt to ptrace the init "
+ "process dissallowed in secure level %d\n",
+ seclvl );
+ return -EPERM;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Capability checks for seclvl. The majority of the policy
+ * enforcement for seclvl takes place here.
+ */
+static int seclvl_capable( struct task_struct* tsk, int cap )
+{
+ /* init can do anything it wants */
+ if( tsk->pid == 1 ) {
+ return 0;
+ }
+
+ switch( seclvl ) {
+ case 2:
+ /* fall through */
+ case 1:
+ if( cap == CAP_LINUX_IMMUTABLE ) {
+ printk( KERN_WARNING "Attempt to modify a file with "
+ "S_IMMUTABLE and/or S_APPEND file attributes "
+ "in secure level %d denied\n", seclvl );
+ return -EPERM;
+ } else if( cap==CAP_SYS_RAWIO ) { // Somewhat broad...
+ printk( KERN_WARNING "Attempt to perform raw I/O "
+ "while in secure level %d denied\n", seclvl );
+ return -EPERM;
+ } else if( cap == CAP_NET_ADMIN ) {
+ printk( KERN_WARNING "Attempt to perform network "
+ "administrative task while in secure level "
+ "%d denied\n", seclvl );
+ return -EPERM;
+ } else if( cap == CAP_SETUID ) {
+ printk( KERN_WARNING "Attempt to setuid while in "
+ "secure level %d denied\n", seclvl );
+ return -EPERM;
+ }
+ break;
+ case 0:
+ /* fall through */
+ case -1:
+ /* fall through */
+ default: break;
+ }
+ /* from dummy.c */
+ if( cap_is_fs_cap( cap ) ? tsk->fsuid == 0 : tsk->euid == 0 )
+ return 0; /* capability granted */
+ printk( KERN_WARNING "Capability denied\n" );
+ return -EPERM; /* capability denied */
+}
+
+/**
+ * Module loading policy enforcement in seclvl >= 1
+ */
+static int seclvl_module_load( struct module* mod )
+{
+ if( seclvl >= 1 ) {
+ printk( KERN_WARNING "Attempt to perform module load in "
+ "secure level %d denied: current->pid = [%d], "
+ "current->group_leader->pid = [%d]\n", seclvl,
+ current->pid, current->group_leader->pid );
+ return -EPERM;
+ }
+ return 0;
+}
+
+/**
+ * Module deletion policy enforcement in seclvl >= 1
+ */
+static int seclvl_module_delete( struct module* mod )
+{
+ if( seclvl >= 1 ) {
+ printk( KERN_WARNING "Attempt to unload a module in secure "
+ "level %d denied: current->pid = [%d], "
+ "current->group_leader->pid = [%d]\n", seclvl,
+ current->pid, current->group_leader->pid );
+ return -EPERM;
+ }
+ return 0;
+}
+
+/**
+ * Disallow reversing the clock in seclvl > 1
+ */
+static int seclvl_settime( struct timespec* tv )
+{
+ struct timespec now;
+ if( seclvl > 1 ) {
+ now = current_kernel_time();
+ if( tv->tv_sec < now.tv_sec ||
+ ( tv->tv_sec == now.tv_sec &&
+ tv->tv_nsec < now.tv_nsec ) ) {
+ printk( KERN_WARNING "Attempt to decrement time in "
+ "secure level %d denied: current->pid = [%d],"
+ "current->group_leader->pid = [%d]\n", seclvl,
+ current->pid, current->group_leader->pid );
+ return -EPERM;
+ } /* if attempt to decrement time */
+ } /* if seclvl > 1 */
+ return 0;
+}
+
+/**
+ * This function gives the administrator the option of breaking out of
+ * Secure Levels by executing a file of his choice. It is assumed
+ * that, if an administrator chooses to use this feature, he is
+ * employing additional security measures to prevent an attacker from
+ * using this to circumvent the security policies of the system.
+ */
+static int seclvl_bprm_set_security( struct linux_binprm* bprm )
+{
+ if( !magicdentry )
+ return 0;
+ if( bprm->file->f_dentry->d_inode == magicdentry->d_inode ) {
+ printk( KERN_WARNING "%s called: reset seclvl=0\n",
+ bprm->filename );
+ seclvl = 0;
+ }
+ return 0;
+}
+
+int is_mounted( struct inode* inode )
+{
+ struct list_head* super_blocks;
+ struct list_head* p;
+ super_blocks = ¤t->fs->rootmnt->mnt_sb->s_list;
+ list_for_each( p, super_blocks ) {
+ struct super_block* s = sb_entry( p );
+ if( s && s->s_bdev && ( s->s_bdev->bd_inode == inode ) )
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Security for writes to block devices is regulated by this seclvl
+ * function.
+ */
+static int seclvl_inode_permission( struct inode* inode, int mask,
+ struct nameidata* nd)
+{
+ /*
+ * For now deny all writes to block devices in seclvl 1 & 2.
+ * We really want to only do that in 2. In seclvl 1, we only
+ * want to deny write to *mounted* block devices.
+ */
+ if( current->pid == 1 )
+ return 0;
+ if( S_ISBLK( inode->i_mode ) && ( mask & MAY_WRITE ) ) {
+ switch( seclvl ) {
+ case 2:
+ printk( KERN_WARNING "Write to block device denied "
+ "in secure level [%d]\n", seclvl );
+ return -EPERM;
+ case 1:
+ if( is_mounted( inode ) ) {
+ printk( KERN_WARNING "Write to mounted block "
+ "device denied in secure level [%d]\n",
+ seclvl );
+ return -EPERM;
+ }
+ if( MAJOR( inode->i_rdev ) == 1 ) {
+ if( MINOR( inode->i_rdev ) == 1 ||
+ MINOR( inode->i_rdev ) == 2 ) {
+ printk( KERN_WARNING
+ "Attempt to write /dev/mem "
+ "or /dev/kmem in secure "
+ "level [%d]\n", seclvl );
+ return -EPERM;
+ } /* if device is /dev/mem or /dev/kmem */
+ } /* if memory device */
+ } /* switch seclvl */
+ } /* If attempting to write to block device */
+ return 0;
+}
+
+/**
+ * The SUID and SGID bits cannot be set in seclvl >= 1
+ */
+static int seclvl_inode_setattr( struct dentry* dentry, struct iattr* iattr )
+{
+ if( seclvl > 0 ) {
+ if( iattr->ia_valid & ATTR_MODE )
+ if( iattr->ia_mode & S_ISUID ||
+ iattr->ia_mode & S_ISGID ) {
+ printk( KERN_WARNING "Attempt to modify SUID "
+ "or SGID bit denied in seclvl [%d]\n",
+ seclvl );
+ return -EPERM;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Cannot unmount in secure level 2
+ */
+static int seclvl_umount( struct vfsmount* mnt, int flags )
+{
+ if( current->pid == 1 ) {
+ return 0;
+ }
+ if( seclvl == 2 ) {
+ printk( KERN_WARNING "Attempt to unmount in secure level "
+ "%d\n", seclvl );
+ return -EPERM;
+ }
+ return 0;
+}
+
+/* I know dummy has this, but I'm not convinced we want this. */
+static void seclvl_task_reparent_to_init( struct task_struct* p )
+{
+ p->euid = p->fsuid = 0;
+ return;
+}
+
+static int seclvl_register( const char* name, struct security_operations* ops )
+{
+ return -EINVAL;
+}
+
+static int seclvl_unregister(const char* name,
+ struct security_operations* ops )
+{
+ return -EINVAL;
+}
+
+static struct security_operations seclvl_ops = {
+ .ptrace = seclvl_ptrace,
+ .capable = seclvl_capable,
+ .bprm_set_security = seclvl_bprm_set_security,
+ .inode_permission = seclvl_inode_permission,
+ .inode_setattr = seclvl_inode_setattr,
+ .module_load = seclvl_module_load,
+ .module_delete = seclvl_module_delete,
+ .settime = seclvl_settime,
+ .sb_umount = seclvl_umount,
+ .task_reparent_to_init = seclvl_task_reparent_to_init,
+ .register_security = seclvl_register,
+ .unregister_security = seclvl_unregister,
+};
+
+#if defined(CONFIG_SECURITY_SECLVL_MODULE)
+#define MY_NAME THIS_MODULE->name
+#else
+#define MY_NAME "seclvl"
+#endif
+
+/**
+ * Register our proc file
+ */
+int seclvl_proc_register( void )
+{
+ struct proc_dir_entry* entry;
+ entry = create_proc_entry( "seclvl", S_IFREG | S_IRUGO, &proc_root );
+ if( !entry )
+ return -ENOMEM;
+ entry->owner = THIS_MODULE;
+ entry->read_proc = seclvl_read_proc;
+ entry->write_proc = seclvl_write_proc;
+ return 0;
+}
+
+void seclvl_proc_unregister( void )
+{
+ remove_proc_entry( "seclvl", &proc_root );
+}
+
+/**
+ * security level advancement rules:
+ * Valid levels are -1 through 2, inclusive.
+ * From -1, stuck. [ in case compiled into kernel ]
+ * From 0 or above, can only increment.
+ */
+int do_seclvl_advance( int newlvl )
+{
+ if( newlvl <= seclvl ) {
+ printk( KERN_WARNING "Cannot advance to seclvl [%d]\n",
+ newlvl );
+ return -EINVAL;
+ }
+ if( newlvl > 2 ) {
+ printk( KERN_WARNING "Cannot advance to seclvl [%d]\n",
+ newlvl );
+ return -EINVAL;
+ }
+ if( seclvl == -1 ) {
+ printk( KERN_WARNING "Not allowed to advance to seclvl [%d]\n",
+ newlvl );
+ return -EPERM;
+ }
+ seclvl = newlvl;
+ return 0;
+}
+
+/* Module parameter that defines the initial secure level */
+static int initlvl = 1;
+
+MODULE_PARM( initlvl, "i" );
+MODULE_PARM_DESC( initlvl, "Initial secure level (defaults to 1)" );
+
+/**
+ * Initialize the seclvl module.
+ */
+static int __init seclvl_init( void ) {
+ int ret = -EINVAL;
+
+ if( initlvl < -1 || initlvl > 2 ) {
+ printk( KERN_ERR "Error: bad initial securelevel (%d).\n",
+ initlvl);
+ goto out;
+ }
+ seclvl = initlvl;
+
+ if( magicpath ) {
+ struct nameidata nd;
+ ret = path_lookup( magicpath, LOOKUP_FOLLOW, &nd );
+ if( ret ) {
+ /*
+ * Better not to load, or to potentially mess up
+ * filesystem by loading?
+ * Maybe in these days of jfs's, we should load?
+ */
+ printk( KERN_ERR "Seclvl: Bad filename [%s] specified"
+ " for seclvl escape.\n"
+ "Seclvl NOT LOADED (%d).\n",
+ magicpath, ret);
+ goto out;
+ }
+ magicdentry = dget( nd.dentry );
+ path_release( &nd );
+ ret = -EINVAL;
+ }
+
+ /* register the proc entry */
+ if( seclvl_proc_register() ) {
+ printk( KERN_INFO "seclvl: Failed to register proc entry."
+ " Init module exiting." );
+ goto out_dput;
+ }
+ /* register ourselves with the security framework */
+ if( register_security( &seclvl_ops ) ) {
+ printk( KERN_INFO
+ "seclvl: Failure registering with the kernel.\n" );
+ /* try registering with primary module */
+ if( mod_reg_security( MY_NAME, &seclvl_ops ) ) {
+ printk( KERN_INFO "seclvl: Failure registering "
+ "with primary security module.\n" );
+ goto out_unregister_proc;
+ } /* if primary module registered */
+ secondary = 1;
+ } /* if we registered ourselves with the security framework */
+ printk( KERN_INFO "seclvl: initialized.\n" );
+
+ ret = 0;
+ goto out;
+
+out_unregister_proc:
+ seclvl_proc_unregister();
+out_dput:
+ if( magicdentry ) {
+ dput( magicdentry );
+ magicdentry = NULL;
+ }
+out:
+ return ret;
+}
+
+/**
+ * Remove the seclvl module.
+ */
+static void __exit seclvl_exit( void )
+{
+ if( magicdentry ) {
+ dput( magicdentry );
+ magicdentry = NULL;
+ }
+ seclvl_proc_unregister();
+ if( unregister_security( &seclvl_ops ) ) {
+ printk( KERN_INFO
+ "seclvl: Failure unregistering with the kernel\n" );
+ }
+}
+
+module_init( seclvl_init );
+module_exit( seclvl_exit );
+
+MODULE_AUTHOR( "Michael A. Halcrow <mike@halcrow.us>" );
+MODULE_DESCRIPTION( "LSM implementation of the *BSD Secure Levels" );
+MODULE_LICENSE( "GPL" );
diff -Pru linux-2.6.0-test7/include/linux/security.h linux-2.6.0-test7-hooks/include/linux/security.h
--- linux-2.6.0-test7/include/linux/security.h 2003-10-08 14:24:26.000000000 -0500
+++ linux-2.6.0-test7-hooks/include/linux/security.h 2003-10-20 11:47:53.000000000 -0500
@@ -91,6 +91,24 @@
*
* Security hooks for program execution operations.
*
+ *
+ * @settime:
+ * Check permission to reset the system time.
+ * @tv contains the new time
+ * Return 0 if permission is granted
+ *
+ * @module_load:
+ * Check permission for the current process to load the kernel
+ * module @mod.
+ * @mod is the module whose deletion has been requested. Is
+ * only the @mod->name trustworthy?
+ * Return 0 if permission is granted.
+ * @module_delete:
+ * Check permission for the current process to unload the kernel
+ * module @mod.
+ * @mod is the module whose deletion has been requested.
+ * Return 0 if permission is granted.
+ *
* @bprm_alloc_security:
* Allocate and attach a security structure to the @bprm->security field.
* The security field is initialized to NULL when the bprm structure is
@@ -997,6 +1015,11 @@
int (*syslog) (int type);
int (*vm_enough_memory) (long pages);
+ int (*settime) (struct timespec *tv);
+
+ int (*module_load) (struct module *mod);
+ int (*module_delete) (struct module *mod);
+
int (*bprm_alloc_security) (struct linux_binprm * bprm);
void (*bprm_free_security) (struct linux_binprm * bprm);
void (*bprm_compute_creds) (struct linux_binprm * bprm);
@@ -1250,6 +1273,21 @@
return security_ops->vm_enough_memory(pages);
}
+static inline int security_settime(struct timespec *tv)
+{
+ return security_ops->settime(tv);
+}
+
+static inline int security_module_load(struct module *mod)
+{
+ return security_ops->module_load(mod);
+}
+
+static inline int security_module_delete(struct module *mod)
+{
+ return security_ops->module_delete(mod);
+}
+
static inline int security_bprm_alloc (struct linux_binprm *bprm)
{
return security_ops->bprm_alloc_security (bprm);
@@ -1916,6 +1954,21 @@
return cap_vm_enough_memory(pages);
}
+static inline int security_settime(struct timespec *tv)
+{
+ return 0;
+}
+
+static inline int security_module_load(struct module *mod)
+{
+ return 0;
+}
+
+static inline int security_module_delete(struct module *mod)
+{
+ return 0;
+}
+
static inline int security_bprm_alloc (struct linux_binprm *bprm)
{
return 0;
diff -Pru linux-2.6.0-test7/kernel/module.c linux-2.6.0-test7-hooks/kernel/module.c
--- linux-2.6.0-test7/kernel/module.c 2003-10-08 14:24:26.000000000 -0500
+++ linux-2.6.0-test7-hooks/kernel/module.c 2003-10-20 11:47:53.000000000 -0500
@@ -36,6 +36,7 @@
#include <asm/semaphore.h>
#include <asm/pgalloc.h>
#include <asm/cacheflush.h>
+#include <linux/security.h>
#if 0
#define DEBUGP printk
@@ -660,6 +661,7 @@
struct module *mod;
char name[MODULE_NAME_LEN];
int ret, forced = 0;
+ int err;
if (!capable(CAP_SYS_MODULE))
return -EPERM;
@@ -677,6 +679,12 @@
goto out;
}
+ err = security_module_delete(mod);
+ if (err) {
+ ret = -EPERM;
+ goto out;
+ }
+
if (!list_empty(&mod->modules_which_use_me)) {
/* Other modules depend on us: get rid of them first. */
ret = -EWOULDBLOCK;
@@ -1451,6 +1459,12 @@
}
mod = (void *)sechdrs[modindex].sh_addr;
+ err = security_module_load(mod);
+ if (err) {
+ err = -EPERM;
+ goto free_hdr;
+ }
+
/* Optional sections */
exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
diff -Pru linux-2.6.0-test7/kernel/time.c linux-2.6.0-test7-hooks/kernel/time.c
--- linux-2.6.0-test7/kernel/time.c 2003-10-08 14:24:02.000000000 -0500
+++ linux-2.6.0-test7-hooks/kernel/time.c 2003-10-20 11:47:53.000000000 -0500
@@ -29,6 +29,7 @@
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
+#include <linux/security.h>
/*
* The timezone where the local system is located. Used as a default by some
@@ -140,10 +141,11 @@
int do_sys_settimeofday(struct timespec *tv, struct timezone *tz)
{
static int firsttime = 1;
+ int err;
if (!capable(CAP_SYS_TIME))
return -EPERM;
-
+
if (tz) {
/* SMP safe, global irq locking makes it work. */
sys_tz = *tz;
@@ -153,6 +155,11 @@
warp_clock();
}
}
+
+ err = security_settime(tv);
+ if (err)
+ return -EPERM;
+
if (tv)
{
/* SMP safe, again the code in arch/foo/time.c should
diff -Pru linux-2.6.0-test7/security/dummy.c linux-2.6.0-test7-hooks/security/dummy.c
--- linux-2.6.0-test7/security/dummy.c 2003-10-08 14:24:02.000000000 -0500
+++ linux-2.6.0-test7-hooks/security/dummy.c 2003-10-20 11:47:53.000000000 -0500
@@ -148,6 +148,21 @@
return -ENOMEM;
}
+static int dummy_settime (struct timespec *tv)
+{
+ return 0;
+}
+
+static int dummy_module_load (struct module *mod)
+{
+ return 0;
+}
+
+static int dummy_module_delete (struct module *mod)
+{
+ return 0;
+}
+
static int dummy_bprm_alloc_security (struct linux_binprm *bprm)
{
return 0;
@@ -845,6 +860,9 @@
set_to_dummy_if_null(ops, sysctl);
set_to_dummy_if_null(ops, syslog);
set_to_dummy_if_null(ops, vm_enough_memory);
+ set_to_dummy_if_null(ops, settime);
+ set_to_dummy_if_null(ops, module_load);
+ set_to_dummy_if_null(ops, module_delete);
set_to_dummy_if_null(ops, bprm_alloc_security);
set_to_dummy_if_null(ops, bprm_free_security);
set_to_dummy_if_null(ops, bprm_compute_creds);