![[LWN Logo]](/images/lcorner.png) |
|
![[LWN.net]](/images/Included.png) |
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