New module: tpe
From: | Niki Rahimi <narahimi@us.ibm.com> | |
To: | linux-security-module@wirex.com | |
Subject: | New module: tpe | |
Date: | Wed, 14 May 2003 11:28:49 -0600 |
Hello Everyone, I have finally finished up the new LSM for Trusted Path Execution (TPE) and would like to submit the patch for your consideration. It is attached below. Please feel free to contact me regarding the module. I am eager to hear back from you all. Regards, Niki (See attached file: tpe.diff) Niki A. Rahimi LTC Security Development narahimi@us.ibm.com (512)838-5399diff -Naur linux-2.5.59/security/Kconfig linux-2.5.59-tpe/security/Kconfig --- linux-2.5.59/security/Kconfig 2003-05-12 09:45:38.000000000 -0500 +++ linux-2.5.59-tpe/security/Kconfig 2003-05-12 09:40:31.000000000 -0500 @@ -158,6 +158,20 @@ If you're unsure, answer N. +config SECURITY_TPE + tristate "Trusted Path Execution (EXPERIMENTAL)" + depends SECURITY && EXPERIMENTAL + help + The TPE module enforces a check on the running of executables. + It will not allow execution if the program is located in a + "trusted path" and the current user is "untrusted". A trusted + path is one which is root owned and neither group nor other + writeable. A user is considered trusted if their uid is added + to a trusted list in memory. Root is trusted, by default. + Contact Niki A. Rahimi <narahimi@us.ibm.com> for more info. + + If you're unsure, answer N. + source security/lids/Kconfig endmenu diff -Naur linux-2.5.59/security/Makefile linux-2.5.59-tpe/security/Makefile --- linux-2.5.59/security/Makefile 2003-05-12 09:45:38.000000000 -0500 +++ linux-2.5.59-tpe/security/Makefile 2003-05-12 09:40:38.000000000 -0500 @@ -26,6 +26,7 @@ obj-$(CONFIG_SECURITY_CAPABILITIES) += capability.o obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o obj-$(CONFIG_SECURITY_OWLSM) += owlsm.o +obj-$(CONFIG_SECURITY_TPE) += tpe.o ifeq ($(CONFIG_SECURITY_DTE),y) obj-$(CONFIG_SECURITY_DTE) += dte/built-in.o endif diff -Naur linux-2.5.59/security/kern_tpe.h linux-2.5.59-tpe/security/kern_tpe.h --- linux-2.5.59/security/kern_tpe.h 1969-12-31 18:00:00.000000000 -0600 +++ linux-2.5.59-tpe/security/kern_tpe.h 2003-05-12 09:40:18.000000000 -0500 @@ -0,0 +1,198 @@ +/* + * Trusted path ACL implementation created as a Loadable Security Module. + * This project is an abstraction of the original Trusted Path Execution + * patch to OpenBSD, which was created by route|daemon9 and Mike Schiffman. + * For the original OpenBSD write-up, see Phrack Magazine, issue 54, + * article 6 at http://www.phrack.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.* + * + * A path is considered trusted if the parent directory is owned by root + * and is neither group nor world writeable. A user is considered trusted + * if she/he is on the kernels trust list, as created by this module. An + * untrusted user attempting to run an executable in an untrusted path + * will be denied execution. + * + * Copyright (c) 1998 route|daemon9 and Mike D. Schiffman + * Copyright (c) 2003 IBM Corp. <narahimi@us.ibm.com> + * + */ + +#ifndef __KERN_TPE_H +#define __KERN_TPE_H + +#include <linux/types.h> +#include <asm/uaccess.h> + +/* + * syscall stuff + */ +#define TPE_ACL_SIZE 82 /* Maximum number of users in the list + * plus two. This was an original + * component of TPE. This will be + * fixed later on. + */ + +#define TPE_INITIALIZER -1 /* A UID that isn't used */ + +#define ACK 1 /* positive acknowledgement */ +#define NACK -1 /* negative acknowledgement */ +#define DUP 3 /* duplicate id return for tpe_add */ + +#define LESS(X, Y) (X < Y) +#define SWAP(X, Y) (X ^= Y, Y ^= X, X ^= Y) +#define COMPSWAP(X, Y) if (LESS(Y, X)) SWAP(X, Y) + +void tpe_sort(int, int); +int tpe_search(uid_t, int, int); + +/* + * Verify the path. + */ +#define TRUSTED_PATH(mode, uid) \ +(!(mode & (S_IWGRP | S_IWOTH)) && (uid == 0)) + +static uid_t tpe_acl[TPE_ACL_SIZE]; /* trusted user list */ +static int tpe_acl_candidates; /* number of users on the list */ + +/* + * Verify the user. This macro is passed the user's ID from the + * tpe_bprm_set_security hook. + */ + +#define TRUSTED_USER(UID) (tpe_verify(UID) == ACK) + +/* Initialize the array with default values (TPE_INITIALIZER). */ + +void tpe_init (void) +{ + memset(tpe_acl, TPE_INITIALIZER, sizeof(uid_t) * TPE_ACL_SIZE); + printk(KERN_INFO "tpe_acl list created\n"); + tpe_acl_candidates = 1; + tpe_acl[0] = 0; +} + +/* Attempt to add a candidate to the list. */ +int tpe_add (uid_t add_candidate) +{ + int retval = 0; + + /* Full list. */ + if (tpe_acl_candidates == (TPE_ACL_SIZE - 2)) { + printk(KERN_INFO "Unable to add user %d. List is full.\n", + add_candidate); + return -EFAULT; + } + + if (add_candidate == 0) { + printk(KERN_INFO "tpe: Invalid userid. Cannot add.\n"); + return -EFAULT; + } + + /* Don't add duplicates */ + if ((tpe_search(add_candidate, 0, tpe_acl_candidates)) == NACK) { + /* Add to the end of the list, then sort. */ + tpe_acl_candidates++; + tpe_acl[tpe_acl_candidates] = add_candidate; + tpe_acl[tpe_acl_candidates + 1] = '\0'; /* terminate array */ + tpe_sort(0, tpe_acl_candidates); + printk(KERN_INFO "tpe: UID %d added to trust list\n", + add_candidate); + } else { + printk(KERN_INFO "tpe: duplicate UID %d not added\n", + add_candidate); + return -EFAULT; + } + return retval; +} + +/* Attempt to remove a candidate from the list. Only fails if the entry is */ +/* not there. */ +int tpe_remove (uid_t rem_candidate) +{ + int n; + int retval = 0; + if (tpe_acl_candidates == 0) { + /* Empty list */ + return -EFAULT; + } + if (rem_candidate == 0) { + printk(KERN_INFO "tpe: Invalid userid. Cannot remove.\n"); + return -EFAULT; + } + + if ((n= tpe_search(rem_candidate, 0, tpe_acl_candidates)) != NACK) { + /* Remove candidate (mark slot as unused), resort the list. */ + tpe_acl[n] = TPE_INITIALIZER; + tpe_acl_candidates--; + tpe_sort(0, tpe_acl_candidates); + printk(KERN_INFO "tpe: UID %d removed from trust list\n", + rem_candidate); + return retval; + } + /* Not found. */ + printk(KERN_INFO "tpe: UID %d not found in trust list\n", + rem_candidate); + return -EFAULT; +} + +/* Verify a candidate user. */ + +int tpe_verify (uid_t candidate) +{ + if ((tpe_search(candidate, 0, tpe_acl_candidates)) != NACK) { + return (ACK); + } + return (NACK); +} + + +/* Insertion sort the list. */ +void tpe_sort (int low, int high) /* (list low element, list high element) */ +{ + int i,j,n; + /* Standard insertion sort. */ + for (i = low + 1; i <= high; i++) { + COMPSWAP(tpe_acl[low], tpe_acl[i]); + } + + for (i = low + 2; i <= high; i++) { + j = i; + n = tpe_acl[i]; + while (LESS(n, tpe_acl[j - 1])) { + tpe_acl[j] = tpe_acl[j - 1]; + j--; + } + tpe_acl[j] = n; + } +} + +/* Locate a uid in the list, standard recursive binary search, running in */ +/* worst case of lg N. */ +int tpe_search (uid_t candidate, int low, int high) +{ + /* (candidate user to search for, list low elem, list high elem) */ + int n; + /* Standard binary search. XXX - should be iterative. */ + n = (low + high) / 2; + + if (low > high) { + return (NACK); + } + if (candidate == tpe_acl[n]) { + return (n); + } + if (low == high) { + return (NACK); + } + if (LESS(candidate, tpe_acl[n])) { + return (tpe_search(candidate, low, n-1)); + } else { + return (tpe_search(candidate, n + 1, high)); + } +} + +#endif /* __KERN_TPE_H */ diff -Naur linux-2.5.59/security/tpe.c linux-2.5.59-tpe/security/tpe.c --- linux-2.5.59/security/tpe.c 1969-12-31 18:00:00.000000000 -0600 +++ linux-2.5.59-tpe/security/tpe.c 2003-05-12 09:40:12.000000000 -0500 @@ -0,0 +1,676 @@ +/* + * Trusted Path Execution Security Module + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module is an attempt to bring Trusted Path Execution (TPE) to the + * Linux kernel. TPE originated as a kernel patch to OpenBSD 2.4 by + * route|daemon9 and Mike Schifman (see Phrack 54). We have modified the + * original project to fit within the constraints of the LSM framework + * and so it should be noted that this is not the same project. Also, + * the module makes use of a pseudo filesystem approach created by + * Greg Kroah-Hartman for his work on pcihotplug. + * + * Also, thanks and credit to Serge Hallyn for his help on getting the bugs + * out of this module. + * + * Copyright (C) 1998 route|daemon9 and Mike D. Schiffman + * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (C) 2003 IBM Corp. <narahimi@us.ibm.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/security.h> +#include <linux/skbuff.h> +#include <linux/netlink.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <asm/uaccess.h> +#include <linux/pagemap.h> +#include <linux/namei.h> +#include <linux/vfs.h> +#include <linux/mount.h> +#include <linux/string.h> + +#include "kern_tpe.h" + +/* Beginning of my implementation of Greg Kroah-Hartman's + * pseudofs approach for tpefs. + */ + +#define dbg(fmt, arg...) \ +do { if (1) printk(KERN_DEBUG "%s: " fmt , "tpe" , ## arg); } while (0) + +#define TPEFS_MAGIC 0x84295178 +static struct super_operations tpefs_ops; +static struct file_operations default_file_operations; +static struct inode_operations tpefs_dir_inode_operations; +static struct vfsmount *tpefs_mount; +static int tpefs_mount_count; +static spinlock_t tpe_mount_lock; +static spinlock_t tpe_list_lock; +static int secondary; + +struct tpe_dents { + struct dentry *d; + struct tpe_dents *next; +}; + +struct dentry *trustedlistadd_dentry = NULL; +struct dentry *trustedlistdel_dentry = NULL; + +struct tpe_dents * tpe_dents = NULL; + +static struct inode *tpefs_get_inode (struct super_block *sb, int mode, +dev_t dev) +{ + struct inode *inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = NODEV; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_fop = &default_file_operations; + break; + case S_IFDIR: + inode->i_op = &tpefs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + inode->i_nlink++; + break; + } + } + return inode; +} + +static int tpefs_mknod(struct inode *dir, struct dentry *dentry, +int mode, dev_t dev) +{ + struct inode *inode = tpefs_get_inode(dir->i_sb, mode, dev); + int error = -ENOSPC; + + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); + error = 0; + } + return error; +} + +static int tpefs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + return tpefs_mknod(dir, dentry, mode | S_IFDIR, 0); +} + +static int tpefs_create (struct inode *dir, struct dentry *dentry, int mode) +{ + return tpefs_mknod(dir, dentry, mode | S_IFREG, 0); +} + +static inline int tpefs_positive (struct dentry *dentry) +{ + return dentry->d_inode && !d_unhashed(dentry); +} + +static int tpefs_empty (struct dentry *dentry) +{ + struct list_head *list; + spin_lock(&dcache_lock); + list_for_each(list, &dentry->d_subdirs) { + struct dentry *de = list_entry(list, struct dentry, d_child); + if (tpefs_positive(de)) { + spin_unlock(&dcache_lock); + return 0; + } + } + spin_unlock(&dcache_lock); + return 1; +} + +static int tpefs_unlink(struct inode *dir, struct dentry *dentry) +{ + int error = -ENOTEMPTY; + if (tpefs_empty(dentry)) { + struct inode *inode = dentry->d_inode; + inode->i_nlink--; + dput(dentry); + error = 0; + } + return error; +} + +#define tpefs_rmdir tpefs_unlink + +static ssize_t default_read_file (struct file *file, char *buf, size_t count, +loff_t *ppos) +{ + return 0; +} + +static ssize_t default_write_file (struct file *file, const char *buf, +size_t count, loff_t *ppos) +{ + return count; +} + +static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) +{ + loff_t retval = -EINVAL; + + switch(orig) { + case 0: + if (offset > 0) { + file->f_pos = offset; + retval = file->f_pos; + } + break; + case 1: + if ((offset + file->f_pos) > 0) { + file->f_pos += offset; + retval = file->f_pos; + } + break; + default: + break; + } + return retval; +} + +static int default_open (struct inode *inode, struct file *filp) +{ + if (inode->u.generic_ip) { + filp->private_data = inode->u.generic_ip; + } + return 0; +} + +static struct file_operations default_file_operations = { + read: default_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, +}; + +static ssize_t trustedlistadd_read_file(struct file *file, char *buf, +size_t count, loff_t *offset); +static ssize_t trustedlistadd_write_file(struct file *file, const char *ubuff, +size_t count, loff_t *offset); + +static struct file_operations trustedlistadd_file_operations = { + read: trustedlistadd_read_file, + write: trustedlistadd_write_file, + open: default_open, + llseek: default_file_lseek, +}; + +static ssize_t trustedlistdel_write_file(struct file *file, const char *ubuff, +size_t count, loff_t *offset); + +static struct file_operations trustedlistdel_file_operations = { + read: default_read_file, + write: trustedlistdel_write_file, + open: default_open, + llseek: default_file_lseek, +}; + +static struct inode_operations tpefs_dir_inode_operations = { + create: tpefs_create, + lookup: simple_lookup, + unlink: tpefs_unlink, + mkdir: tpefs_mkdir, + rmdir: tpefs_rmdir, + mknod: tpefs_mknod, +}; + +static struct super_operations tpefs_ops = { + statfs: simple_statfs, + drop_inode: generic_delete_inode, +}; + +static int tpefs_fill_super (struct super_block *sb, void *data, int silent) +{ + struct inode *inode; + struct dentry *root; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = TPEFS_MAGIC; + sb->s_op = &tpefs_ops; + inode = tpefs_get_inode(sb, S_IFDIR | 0755, 0); + + if (!inode) { + dbg("%s: could not get inode!\n",__FUNCTION__); + return -ENOMEM; + } + + root = d_alloc_root(inode); + if (!root) { + dbg("%s: could not get root dentry!\n",__FUNCTION__); + iput(inode); + return -ENOMEM; + } + sb->s_root = root; + return 0; +} + +static struct super_block *tpefs_get_sb(struct file_system_type *fs_type, +int flags, char *dev_name, void *data) +{ + return get_sb_single(fs_type, flags, data, tpefs_fill_super); +} + +static struct file_system_type tpefs_fs_type = { +.owner = THIS_MODULE, +.name = "tpefs", +.get_sb = tpefs_get_sb, +.kill_sb = kill_litter_super, +}; + +static int mount_internal (void) +{ + struct vfsmount *mnt; + + printk(KERN_INFO "mount_internal, tpefs_mount_count is %d\n", + tpefs_mount_count); + spin_lock (&tpe_mount_lock); + if (tpefs_mount) { + mntget(tpefs_mount); + ++tpefs_mount_count; + spin_unlock (&tpe_mount_lock); + goto go_ahead; + } + + spin_unlock (&tpe_mount_lock); + mnt = kern_mount (&tpefs_fs_type); + if (IS_ERR(mnt)) { + printk(KERN_INFO "could not mount the fs...erroring out!\n"); + return -ENODEV; + } + spin_lock (&tpe_mount_lock); + if (!tpefs_mount) { + tpefs_mount = mnt; + ++tpefs_mount_count; + spin_unlock (&tpe_mount_lock); + goto go_ahead; + } + + mntget(tpefs_mount); + ++tpefs_mount_count; + spin_unlock (&tpe_mount_lock); + mntput(mnt); + +go_ahead: + printk(KERN_INFO "tpefs_mount_count = %d\n", tpefs_mount_count); + return 0; +} + +static void remove_mount (void) +{ + struct vfsmount *mnt; + + spin_lock (&tpe_mount_lock); + mnt = tpefs_mount; + --tpefs_mount_count; + if (!tpefs_mount_count) { + tpefs_mount = NULL; + } + + spin_unlock (&tpe_mount_lock); + mntput(mnt); + dbg("tpefs_mount_count = %d\n", tpefs_mount_count); +} + +static int tpefs_create_by_name (const char *name, mode_t mode, + struct dentry *parent, struct dentry **dentry) +{ + struct dentry *d = NULL; + struct qstr qstr; + int error; + + if (tpefs_mount && tpefs_mount->mnt_sb) { + parent = tpefs_mount->mnt_sb->s_root; + } + + if (!parent) { + printk(KERN_INFO "Ah! can not find a parent!\n"); + return -EFAULT; + } + + *dentry = NULL; + qstr.name = name; + qstr.len = strlen(name); + qstr.hash = full_name_hash(name,qstr.len); + + parent = dget(parent); + + down(&parent->d_inode->i_sem); + + d = lookup_hash(&qstr,parent); + + error = PTR_ERR(d); + if (!IS_ERR(d)) { + switch(mode & S_IFMT) { + case 0: + case S_IFREG: + error = vfs_create(parent->d_inode,d,mode); + break; + case S_IFDIR: + error = vfs_mkdir(parent->d_inode,d,mode); + break; + default: + printk(KERN_INFO "cannot create special files\n"); + } + *dentry = d; + } + up(&parent->d_inode->i_sem); + + dput(parent); + return error; +} + +static struct dentry *fs_create_file (const char * name, mode_t mode, + struct dentry *parent, void *data, + struct file_operations *fops) +{ + struct dentry *dentry; + int error; + + printk(KERN_INFO "creating file '%s'\n",name); + + error = tpefs_create_by_name(name,mode,parent,&dentry); + if (error) { + dentry = NULL; + } else { + if (dentry->d_inode) { + if (data) { + dentry->d_inode->u.generic_ip = data; + } + if (fops) { + dentry->d_inode->i_fop = fops; + } + } + } + + return dentry; +} + +static void fs_remove_file (struct dentry *dentry) +{ + struct dentry *parent = dentry->d_parent; + + if (!parent || !parent->d_inode) { + return; + } + + down(&parent->d_inode->i_sem); + if (tpefs_positive(dentry)) { + if (dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode)) { + vfs_rmdir(parent->d_inode,dentry); + } else { + vfs_unlink(parent->d_inode,dentry); + } + } + + dput(dentry); + } + up(&parent->d_inode->i_sem); +} + +#if defined(CONFIG_SECURITY_TPE_MODULE) +#define MY_NAME THIS_MODULE->name +#else +#define MY_NAME "tpe" +#endif + +static ssize_t trustedlistadd_read_file (struct file *file, char *buf, +size_t count, loff_t *offset) +{ + int retval; + int i; + int len; + int pagelen; + unsigned char *page; + char buffer[400]; + + if (*offset < 0) { + return -EINVAL; + } + if (count <= 0) { + return 0; + } + if (*offset != 0) { + return 0; + } + + page = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!page) { + return -ENOMEM; + } + + if (tpe_acl == NULL) { + printk(KERN_INFO "empty acl list\n"); + return -ENODATA; + } + + buffer[0] = '\0'; + printk(KERN_INFO "%d trusted user(s): \n", tpe_acl_candidates); + for (i=0; i < tpe_acl_candidates; i++) { + printk(KERN_INFO "%d ", tpe_acl[i]); + len += sprintf(page, "%d\n", tpe_acl[i]); + strcat(buffer, page); + } + printk(KERN_INFO "\n"); + + pagelen = sizeof(buffer); + printk(KERN_INFO "%d buffer size\n", pagelen); + + len = (sizeof(int) * (tpe_acl_candidates - 1)) + sizeof(short); + if (copy_to_user(buf, buffer, len)) { + printk(KERN_INFO "Problem with copy_to_user\n"); + retval = -EFAULT; + goto exit; + } + *offset += len; + retval = len; + +exit: + free_page((unsigned long)page); + return retval; +} + +static ssize_t trustedlistadd_write_file (struct file *file, const char *ubuff, +size_t count, loff_t *offset) +{ + char *buf; + int retval = 0; + unsigned long add_candidate; + + if (*offset < 0) { + return -EINVAL; + } + if (count <= 0) { + return 0; + } + if (*offset != 0) { + return 0; + } + + buf = kmalloc(count + 1, GFP_KERNEL); + if (!buf) { + return -ENOMEM; + } + memset(buf, 0x00, count + 1); + + if (copy_from_user ((void *)buf, (void *)ubuff, count)) { + retval = -EFAULT; + } + + add_candidate = simple_strtoul(buf, NULL, 10); + dbg ("add_candidate = %d\n", (int)add_candidate); + + printk(KERN_INFO "value of add_candidate is %d.\n", (int)add_candidate); + retval = tpe_add(add_candidate); + return retval; + +} + +static ssize_t trustedlistdel_write_file (struct file *file, const char *ubuff, +size_t count, loff_t *offset) +{ + char *buf; + int retval = 0; + unsigned long rem_candidate; + + if (*offset < 0) { + return -EINVAL; + } + if (count <= 0) { + return 0; + } + if (*offset != 0) { + return 0; + } + + buf = kmalloc (count + 1, GFP_KERNEL); + if (!buf) { + return -ENOMEM; + } + memset(buf, 0x00, count + 1); + + if (copy_from_user ((void *)buf, (void *)ubuff, count)) { + retval = -EFAULT; + } + + rem_candidate = simple_strtoul(buf, NULL, 10); + dbg ("rem_candidate = %d\n", (int)rem_candidate); + + printk(KERN_INFO "value of rem_candidate is %d.\n", (int)rem_candidate); + retval = tpe_remove(rem_candidate); + return retval; + +} + +/* Module code */ + +static int tpe_bprm_set_security (struct linux_binprm *bprm) +{ + uid_t pthuid = bprm->file->f_dentry->d_parent->d_inode->i_uid; + mode_t pthmode = bprm->file->f_dentry->d_parent->d_inode->i_mode; + if((!TRUSTED_PATH(pthmode, pthuid)) && (!TRUSTED_USER(current->euid))) { + printk (KERN_INFO "An attempt to run an executable " + "by an untrusted user was made in a trusted " + "path. Access denied.\n"); + return -EACCES; + } + return 0; +} + +struct security_operations tpe_security_ops = { + bprm_set_security: tpe_bprm_set_security, +}; + +static int __init tpe_module_init (void) +{ + int retval, mntret; + /* register ourselves with the security framework */ + if (register_security (&tpe_security_ops)) { + printk (KERN_INFO + "Failure registering tpe module with the kernel\n"); + /* try registering with primary module */ + if (mod_reg_security (MY_NAME, &tpe_security_ops)) { + printk (KERN_INFO "Failure registering tpe module " + "with primary security module.\n"); + return -EINVAL; + } + secondary = 1; + } + /* register tpe filesystem */ + + spin_lock_init(&tpe_mount_lock); + spin_lock_init(&tpe_list_lock); + + printk(KERN_INFO "registering filesystem.\n"); + retval = register_filesystem(&tpefs_fs_type); + if (retval) { + printk(KERN_INFO "register_filesystem failed with %d\n", retval); + return retval; + } + + /* Routine to get Kernel to mount tpefs internally */ + mntret = mount_internal(); + if (mntret) { + printk(KERN_INFO "failed to get fsmount error %d\n", retval); + } + + /* create a file user can read and write to */ + + trustedlistadd_dentry = fs_create_file("trustedlistadd", + S_IFREG | S_IRUGO | S_IWUSR, + NULL, NULL, + &trustedlistadd_file_operations); + + trustedlistdel_dentry = fs_create_file("trustedlistdel", + S_IFREG | S_IRUGO | S_IWUSR, + NULL, NULL, + &trustedlistdel_file_operations); + tpe_dents = (struct tpe_dents *)kmalloc(sizeof(struct tpe_dents), + GFP_KERNEL); + tpe_dents->d = trustedlistadd_dentry; + tpe_dents->next = (struct tpe_dents *)kmalloc(sizeof(struct tpe_dents), + GFP_KERNEL); + + tpe_dents->next->d = trustedlistdel_dentry; + tpe_dents->next->next = NULL; + + printk(KERN_INFO "tpe LSM initialized\n"); + tpe_init(); + printk(KERN_INFO "Trusted path execution initialized.\n"); + return 0; +} + +static void __exit tpe_exit (void) +{ + /* remove ourselves from the security framework */ + if (secondary) { + if (mod_unreg_security (MY_NAME, &tpe_security_ops)) + printk (KERN_INFO "Failure unregistering tpe module " + "with primary module.\n"); + return; + } + fs_remove_file(trustedlistdel_dentry); + fs_remove_file(trustedlistadd_dentry); + remove_mount(); + + /* unregister tpe filesystem */ + unregister_filesystem(&tpefs_fs_type); + + if (unregister_security (&tpe_security_ops)) { + printk (KERN_INFO + "Failure unregistering tpe module with the kernel\n"); + } + +} + +module_init (tpe_module_init); +module_exit (tpe_exit); + +MODULE_DESCRIPTION("LSM implementation of Trusted Path Execution"); +MODULE_LICENSE("GPL"); diff -Naur linux-2.5.59/Documentation/lsm-tpe-readme.txt linux-2.5.59-tpe/Documentation/lsm-tpe-readme.txt --- linux-2.5.59/Documentation/lsm-tpe-readme.txt 1969-12-31 18:00:00.000000000 -0600 +++ linux-2.5.59-tpe/Documentation/lsm-tpe-readme.txt 2003-05-12 09:40:03.000000000 -0500 @@ -0,0 +1,53 @@ +Trusted Path Execution LSM +Copyright (C) 2003 IBM Corp. <narahimi@us.ibm.com> +Author: Niki A. Rahimi +This file is distributed according to the GNU General Public License. +This module was tested on the Linux kernel 2.5.59. + +The purpose of the Trusted Path Execution Linux Security Module is to enable a +check in the Linux kernel to limit the running of executables in trusted paths +so that the potential for malicious code to be run on the system is reduced. +A trusted path is one in which the parent directory of a file is owned by root +and is neither group nor other writeable. +The module relies on a kernel hook which checks to see if the given path is +trusted or not. This check takes place directly upon an attempt to execute the +code. +The module also creates a Trusted Path access control list and utilizes a +userspace tool to add or remove users to the list. A user on the list is +considered trusted. By default, root is hard coded onto this list. +Thus if user A attempts to run an executable in path A, the following scenarios +can play out: + +1. Trusted user, trusted path = User is able to run the executable. +2. Trusted user, untrusted path = User is able to run the executable. +3. Untrusted user, trusted path = User is able to run the executable. +4. Untrusted user, untrusted path = User is not able to run the executable. + +In short, if the path and user are both untrusted, execution will be denied. + +In order to actually modify the access control list for TPE, the module uses +a pseudo filesystem called tpefs. The tpefs contains two files; trustedlistadd +and trustedlistdel. Performing read and write operations on the aforementioned +files creates a user to system interface that will alter the trusted list. See +"Modifying the Trusted List" below for the methods of altering the list using +these files. +Note: The two file approach was utilized rather than a single file in order to +keep the code and administration of the module simple for both the kernel and +the user. + +Installation: +1. Recompile the kernel to include LSM and TPE as a module. +2. insmod tpe.ko +3. mount -t tpefs none <pathofchoice> +4. See "Modifying the Trusted List" below for instructions on how to add/delete +users to/from the list. + +Modifying the Trusted List: +Adding a user: echo <uid> > trustedlistadd +Deleting a user: echo <uid> > trustedlistdel +Show list to userspace: cat trustedlistadd + +Note: The above methods utilizing echo and cat are good examples of how to +alter the list. If the user is so interested, they may utilize other methods +of read/write on the files in order to perform similar actions on the list. +One example might be doing a "more trustedlistadd" in order to show the list. _______________________________________________ linux-security-module mailing list linux-security-module@mail.wirex.com http://mail.wirex.com/mailman/listinfo/linux-security-module