2002-09-26 20:22:07

by Greg KH

[permalink] [raw]
Subject: [RFC] LSM changes for 2.5.38

Hi,

Here are some patches against the latest 2.5 BK tree that add some
further LSM hooks and documentation to the tree. There is also one
minor change to fs/inode.c to allow security modules more information
about newly created inodes.

These changesets can be found at bk://lsm.bkbits.net/linus-2.5 and I'll
be attaching the individual patches as responses to this email for those
who don't want to mess with bitkeeper.

If anyone has any questions or comments on these patches, please let us
know. Otherwise I'll be sending them off to Linus in a few days.

thanks,

greg k-h


Documentation/DocBook/Makefile | 2
Documentation/DocBook/kernel-api.tmpl | 5
Documentation/DocBook/lsm.tmpl | 285 +++++++++++++++++++++++++++++++++
arch/i386/kernel/ioport.c | 14 +
arch/ia64/ia32/sys_ia32.c | 7
fs/inode.c | 2
include/linux/ipc.h | 1
include/linux/msg.h | 1
include/linux/security.h | 291 ++++++++++++++++++++++++++++++++++
ipc/msg.c | 57 ++++++
ipc/sem.c | 43 ++++-
ipc/shm.c | 55 ++++++
ipc/util.c | 3
kernel/printk.c | 4
kernel/sys.c | 35 ++--
kernel/sysctl.c | 5
kernel/time.c | 6
mm/oom_kill.c | 6
mm/swapfile.c | 10 +
security/capability.c | 210 ++++++++++++++++++++++++
security/dummy.c | 210 ++++++++++++++++++++++++
21 files changed, 1227 insertions(+), 25 deletions(-)
-----

[email protected], 2002-09-26 13:13:36-07:00, [email protected]
LSM: added the LSM documentation to the tree.

Documentation/DocBook/Makefile | 2
Documentation/DocBook/kernel-api.tmpl | 5
Documentation/DocBook/lsm.tmpl | 285 ++++++++++++++++++++++++++++++++++
3 files changed, 291 insertions(+), 1 deletion(-)
------

[email protected], 2002-09-26 13:05:47-07:00, [email protected]
[PATCH] LSM: inode.c init modification

On Thu, 19 Sep 2002, Greg KH wrote:

> Yes, and explaining the fine points of inode_init() and
> inode_alloc_security() and why they are different, might be a bit tough.
>
> {sigh}, well if there's no other way (and I can't think of one right
> now), but I really don't like it...

Here's a patch that attempt to support the same functionality without
inserting hooks into filesystem-specific code. This patch permits the
security module to perform initialization of the inode security state
based on the superblock information, enabling SELinux to initialize
pipe, devpts, and shm inodes without relying on inode_precondition to
catch them on first use.

This is achieved simply by moving the initialization of inode->i_sb
before the call to inode_alloc_security, enabling the
inode_alloc_security hook function to perform the allocation and
initialization for such inodes. No new hooks are required.

fs/inode.c | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)
------

[email protected], 2002-09-26 11:56:46-07:00, [email protected]
[PATCH] LSM: misc hooks addition

The patch below (relative to the LSM IPC hooks patch) adds the LSM hooks
for miscellaneous system operations (module_*, sethostname, setdomainname,
reboot, ioperm/iopl, sysctl, swapon/swapoff, syslog, settime). It also
replaces the hardcoded capability tests in the OOM killer code with
appropriate calls to the LSM capable hook, preserving the original behavior
as long as the capabilities module is enabled.

arch/i386/kernel/ioport.c | 14 +++++-
arch/ia64/ia32/sys_ia32.c | 7 +++
include/linux/security.h | 106 ++++++++++++++++++++++++++++++++++++++++++++++
kernel/printk.c | 4 +
kernel/sys.c | 35 ++++++++++-----
kernel/sysctl.c | 5 ++
kernel/time.c | 6 ++
mm/oom_kill.c | 6 +-
mm/swapfile.c | 10 ++++
security/capability.c | 79 ++++++++++++++++++++++++++++++++++
security/dummy.c | 79 ++++++++++++++++++++++++++++++++++
11 files changed, 337 insertions(+), 14 deletions(-)
------

[email protected], 2002-09-26 11:56:14-07:00, [email protected]
[PATCH] LSM: SysV IPC hooks addition

The patch below adds the LSM hooks for System V IPC to the 2.5.38 kernel.

include/linux/ipc.h | 1
include/linux/msg.h | 1
include/linux/security.h | 185 +++++++++++++++++++++++++++++++++++++++++++++++
ipc/msg.c | 57 +++++++++++++-
ipc/sem.c | 43 ++++++++++
ipc/shm.c | 55 +++++++++++++
ipc/util.c | 3
security/capability.c | 131 +++++++++++++++++++++++++++++++++
security/dummy.c | 131 +++++++++++++++++++++++++++++++++
9 files changed, 598 insertions(+), 9 deletions(-)
------


2002-09-26 20:25:40

by Greg KH

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

Copied linux-fsdevel, as it touches the core fs code.


# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.613 -> 1.614
# fs/inode.c 1.69 -> 1.70
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/09/26 [email protected] 1.614
# [PATCH] LSM: inode.c init modification
#
# On Thu, 19 Sep 2002, Greg KH wrote:
#
# > Yes, and explaining the fine points of inode_init() and
# > inode_alloc_security() and why they are different, might be a bit tough.
# >
# > {sigh}, well if there's no other way (and I can't think of one right
# > now), but I really don't like it...
#
# Here's a patch that attempt to support the same functionality without
# inserting hooks into filesystem-specific code. This patch permits the
# security module to perform initialization of the inode security state
# based on the superblock information, enabling SELinux to initialize
# pipe, devpts, and shm inodes without relying on inode_precondition to
# catch them on first use.
#
# This is achieved simply by moving the initialization of inode->i_sb
# before the call to inode_alloc_security, enabling the
# inode_alloc_security hook function to perform the allocation and
# initialization for such inodes. No new hooks are required.
# --------------------------------------------
#
diff -Nru a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c Thu Sep 26 13:23:52 2002
+++ b/fs/inode.c Thu Sep 26 13:23:52 2002
@@ -101,6 +101,7 @@
if (inode) {
struct address_space * const mapping = &inode->i_data;

+ inode->i_sb = sb;
inode->i_security = NULL;
if (security_ops->inode_alloc_security(inode)) {
if (inode->i_sb->s_op->destroy_inode)
@@ -109,7 +110,6 @@
kmem_cache_free(inode_cachep, (inode));
return NULL;
}
- inode->i_sb = sb;
inode->i_dev = sb->s_dev;
inode->i_blkbits = sb->s_blocksize_bits;
inode->i_flags = 0;

2002-09-26 20:23:58

by Greg KH

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.612 -> 1.613
# kernel/sys.c 1.28 -> 1.29
# kernel/sysctl.c 1.30 -> 1.31
# include/linux/security.h 1.4 -> 1.5
# mm/swapfile.c 1.56 -> 1.57
# security/dummy.c 1.7 -> 1.8
# kernel/time.c 1.7 -> 1.8
# security/capability.c 1.6 -> 1.7
# arch/i386/kernel/ioport.c 1.3 -> 1.4
# mm/oom_kill.c 1.16 -> 1.17
# arch/ia64/ia32/sys_ia32.c 1.19 -> 1.20
# kernel/printk.c 1.14 -> 1.15
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/09/26 [email protected] 1.613
# [PATCH] LSM: misc hooks addition
#
# The patch below (relative to the LSM IPC hooks patch) adds the LSM hooks
# for miscellaneous system operations (module_*, sethostname, setdomainname,
# reboot, ioperm/iopl, sysctl, swapon/swapoff, syslog, settime). It also
# replaces the hardcoded capability tests in the OOM killer code with
# appropriate calls to the LSM capable hook, preserving the original behavior
# as long as the capabilities module is enabled.
# --------------------------------------------
#
diff -Nru a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c
--- a/arch/i386/kernel/ioport.c Thu Sep 26 13:23:55 2002
+++ b/arch/i386/kernel/ioport.c Thu Sep 26 13:23:55 2002
@@ -14,6 +14,7 @@
#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/slab.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)
@@ -62,7 +63,12 @@
return -EINVAL;
if (turn_on && !capable(CAP_SYS_RAWIO))
return -EPERM;
-
+
+ ret = security_ops->ioperm(from, num, turn_on);
+ if (ret) {
+ return ret;
+ }
+
tss = init_tss + get_cpu();

/*
@@ -116,6 +122,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;
@@ -124,6 +131,11 @@
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
}
+ retval = security_ops->iopl(old, level);
+ if (retval) {
+ return retval;
+ }
+
regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12);
return 0;
}
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c Thu Sep 26 13:23:55 2002
+++ b/arch/ia64/ia32/sys_ia32.c Thu Sep 26 13:23:55 2002
@@ -49,6 +49,7 @@
#include <linux/ptrace.h>
#include <linux/stat.h>
#include <linux/ipc.h>
+#include <linux/security.h>

#include <asm/types.h>
#include <asm/uaccess.h>
@@ -3184,6 +3185,7 @@
unsigned int old;
unsigned long addr;
mm_segment_t old_fs = get_fs ();
+ int retval;

if (level != 3)
return(-EINVAL);
@@ -3193,6 +3195,11 @@
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
}
+ retval = security_ops->iopl(old,level);
+ if (retval) {
+ return retval;
+ }
+
set_fs(KERNEL_DS);
fd = sys_open("/dev/mem", O_SYNC | O_RDWR, 0);
set_fs(old_fs);
diff -Nru a/include/linux/security.h b/include/linux/security.h
--- a/include/linux/security.h Thu Sep 26 13:23:55 2002
+++ b/include/linux/security.h Thu Sep 26 13:23:55 2002
@@ -6,6 +6,7 @@
* Copyright (C) 2001 Networks Associates Technology, Inc <[email protected]>
* Copyright (C) 2001 James Morris <[email protected]>
* Copyright (C) 2001 Silicon Graphics, Inc. (Trust Technology Group)
+ * Copyright (C) 2002 International Business Machines <[email protected]>
*
* 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
@@ -32,6 +33,7 @@
#include <linux/sysctl.h>
#include <linux/shm.h>
#include <linux/msg.h>
+#include <linux/time.h>

/*
* Values used in the task_security_ops calls
@@ -572,6 +574,26 @@
* is being reparented to the init task.
* @p contains the task_struct for the kernel thread.
*
+ * Security hooks for kernel module operations.
+ *
+ * @module_create:
+ * Check the permission before allocating space for a module.
+ * @name contains the module name.
+ * @size contains the module size.
+ * Return 0 if permission is granted.
+ * @module_initialize:
+ * Check permission before initializing a module.
+ * @mod contains a pointer to the module being initialized.
+ * Return 0 if permission is granted.
+ * @module_delete:
+ * Check permission before removing a module.
+ * @mod contains a pointer to the module being deleted.
+ * Return 0 if permission is granted.
+ *
+ * These are the hooks for kernel module operations. All hooks are called with
+ * the big kernel lock held, and @delete_module is also called with the
+ * unload_lock held.
+ *
* Security hooks affecting all System V IPC operations.
*
* @ipc_permission:
@@ -725,6 +747,34 @@
* @alter contains the flag indicating whether changes are to be made.
* Return 0 if permission is granted.
*
+ * @sethostname:
+ * Check permission before the hostname is set to @hostname.
+ * @hostname contains the new hostname
+ * Return 0 if permission is granted.
+ * @setdomainname:
+ * Check permission before the domainname is set to @domainname.
+ * @domainname contains the new domainname
+ * Return 0 if permission is granted.
+ * @reboot:
+ * Check permission before rebooting or enabling/disabling the
+ * Ctrl-Alt-Del key sequence.
+ * The values for @cmd are defined in the reboot(2) manual page.
+ * @cmd contains the reboot command.
+ * Return 0 if permission is granted.
+ * @ioperm:
+ * Check permission before setting port input/output permissions for the
+ * process for @num bytes starting from the port address @from to the
+ * value @turn_on.
+ * @from contains the starting port address.
+ * @num contains the number of bytes starting from @from.
+ * @turn_on contains the permissions value.
+ * Return 0 if permission is granted.
+ * @iopl:
+ * Check permission before changing the I/O privilege level of the current
+ * process from @old to @level.
+ * @old contains the old level.
+ * @level contains the new level.
+ * Return 0 if permission is granted.
* @ptrace:
* Check permission before allowing the @parent process to trace the
* @child process.
@@ -775,6 +825,12 @@
* is NULL.
* @file contains the file structure for the accounting file (may be NULL).
* Return 0 if permission is granted.
+ * @sysctl:
+ * Check permission before accessing the @table sysctl variable in the
+ * manner specified by @op.
+ * @table contains the ctl_table structure for the sysctl variable.
+ * @op contains the operation (001 = search, 002 = write, 004 = read).
+ * Return 0 if permission is granted.
* @capable:
* Check whether the @tsk process has the @cap capability.
* @tsk contains the task_struct for the process.
@@ -795,6 +851,42 @@
* @args contains the call arguments (user space pointer).
* The module should return -ENOSYS if it does not implement any new
* system calls.
+ * @swapon:
+ * Check permission before enabling swapping to the file or block device
+ * identified by @swap.
+ * @swap contains the swap_info_struct structure for the swap file and device.
+ * Return 0 if permission is granted.
+ * @swapoff:
+ * Check permission before disabling swapping to the file or block device
+ * identified by @swap.
+ * @swap contains the swap_info_struct structure for the swap file and device.
+ * Return 0 if permission is granted.
+ * @quotactl:
+ * Check permission before performing the quota operation identified by
+ * @cmd for the specified @type, @id, and @sb. The @sb parameter may be
+ * NULL, e.g. for the Q_SYNC and Q_GETSTATS commands.
+ * @cmd contains the command value.
+ * @type contains the type of quota (USRQUOTA or GRPQUOTA).
+ * @id contains the user or group identifier.
+ * @sb contains the super_block structure for the filesystem (may be NULL).
+ * Return 0 if permission is granted.
+ * @quota_on:
+ * Check permission before enabling quotas for a file system using @f as
+ * the quota file.
+ * @f contains the open file for storing quotas.
+ * Return 0 if permission is granted.
+ * @syslog:
+ * Check permission before accessing the kernel message ring or changing
+ * logging to the console.
+ * See the syslog(2) manual page for an explanation of the @type values.
+ * @type contains the type of action.
+ * Return 0 if permission is granted.
+ * @settime:
+ * Check permission to change the system time.
+ * struct timeval and timezone are defined in include/linux/time.h
+ * @tv contains new time
+ * @tz contains new timezone
+ * Return 0 if permission is granted.
*
* @register_security:
* allow module stacking.
@@ -808,6 +900,11 @@
* This is the main security structure.
*/
struct security_operations {
+ int (*sethostname) (char *hostname);
+ int (*setdomainname) (char *domainname);
+ int (*reboot) (unsigned int cmd);
+ int (*ioperm) (unsigned long from, unsigned long num, int turn_on);
+ int (*iopl) (unsigned int old, unsigned int level);
int (*ptrace) (struct task_struct * parent, struct task_struct * child);
int (*capget) (struct task_struct * target,
kernel_cap_t * effective,
@@ -821,11 +918,16 @@
kernel_cap_t * inheritable,
kernel_cap_t * permitted);
int (*acct) (struct file * file);
+ int (*sysctl) (ctl_table * table, int op);
int (*capable) (struct task_struct * tsk, int cap);
int (*sys_security) (unsigned int id, unsigned call,
unsigned long *args);
+ int (*swapon) (struct swap_info_struct * swap);
+ int (*swapoff) (struct swap_info_struct * swap);
int (*quotactl) (int cmds, int type, int id, struct super_block * sb);
int (*quota_on) (struct file * f);
+ int (*syslog) (int type);
+ int (*settime) (struct timeval *tv, struct timezone *tz);

int (*bprm_alloc_security) (struct linux_binprm * bprm);
void (*bprm_free_security) (struct linux_binprm * bprm);
@@ -938,6 +1040,10 @@
unsigned long arg5);
void (*task_kmod_set_label) (void);
void (*task_reparent_to_init) (struct task_struct * p);
+
+ int (*module_create) (const char *name, size_t size);
+ int (*module_initialize) (struct module * mod);
+ int (*module_delete) (const struct module * mod);

int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
int (*ipc_getinfo) (int id, int cmd);
diff -Nru a/kernel/printk.c b/kernel/printk.c
--- a/kernel/printk.c Thu Sep 26 13:23:55 2002
+++ b/kernel/printk.c Thu Sep 26 13:23:55 2002
@@ -175,6 +175,10 @@
char *lbuf = NULL;
int error = 0;

+ error = security_ops->syslog(type);
+ if( error )
+ return error;
+
switch (type) {
case 0: /* Close log */
break;
diff -Nru a/kernel/sys.c b/kernel/sys.c
--- a/kernel/sys.c Thu Sep 26 13:23:55 2002
+++ b/kernel/sys.c Thu Sep 26 13:23:55 2002
@@ -349,11 +349,17 @@
asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void * arg)
{
char buffer[256];
+ int retval;

/* We only trust the superuser with rebooting the system. */
if (!capable(CAP_SYS_BOOT))
return -EPERM;

+ retval = security_ops->reboot(cmd);
+ if (retval) {
+ return retval;
+ }
+
/* For safety, we require "magic" arguments. */
if (magic1 != LINUX_REBOOT_MAGIC1 ||
(magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A &&
@@ -1130,18 +1136,23 @@

asmlinkage long sys_sethostname(char *name, int len)
{
+ char nodename[__NEW_UTS_LEN+1];
int errno;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (len < 0 || len > __NEW_UTS_LEN)
return -EINVAL;
+ if (copy_from_user(nodename, name, len))
+ return -EFAULT;
+ nodename[len] = 0;
+
+ errno = security_ops->sethostname(nodename);
+ if (errno)
+ return errno;
+
down_write(&uts_sem);
- errno = -EFAULT;
- if (!copy_from_user(system_utsname.nodename, name, len)) {
- system_utsname.nodename[len] = 0;
- errno = 0;
- }
+ memcpy(system_utsname.nodename, nodename, len+1);
up_write(&uts_sem);
return errno;
}
@@ -1169,19 +1180,23 @@
*/
asmlinkage long sys_setdomainname(char *name, int len)
{
+ char domainname[__NEW_UTS_LEN+1];
int errno;

if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (len < 0 || len > __NEW_UTS_LEN)
return -EINVAL;
+ if (copy_from_user(domainname, name, len))
+ return -EFAULT;
+ domainname[len] = 0;
+
+ errno = security_ops->setdomainname(domainname);
+ if (errno)
+ return errno;

down_write(&uts_sem);
- errno = -EFAULT;
- if (!copy_from_user(system_utsname.domainname, name, len)) {
- errno = 0;
- system_utsname.domainname[len] = 0;
- }
+ memcpy(system_utsname.domainname, domainname, len+1);
up_write(&uts_sem);
return errno;
}
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c Thu Sep 26 13:23:55 2002
+++ b/kernel/sysctl.c Thu Sep 26 13:23:55 2002
@@ -427,6 +427,11 @@

static inline int ctl_perm(ctl_table *table, int op)
{
+ int error;
+ error = security_ops->sysctl(table, op);
+ if(error) {
+ return error;
+ }
return test_perm(table->mode, op);
}

diff -Nru a/kernel/time.c b/kernel/time.c
--- a/kernel/time.c Thu Sep 26 13:23:55 2002
+++ b/kernel/time.c Thu Sep 26 13:23:55 2002
@@ -27,6 +27,7 @@
#include <linux/timex.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
+#include <linux/security.h>

#include <asm/uaccess.h>

@@ -147,9 +148,14 @@
int do_sys_settimeofday(struct timeval *tv, struct timezone *tz)
{
static int firsttime = 1;
+ int error = 0;

if (!capable(CAP_SYS_TIME))
return -EPERM;
+
+ error = security_ops->settime(tv, tz);
+ if (error)
+ return error;

if (tz) {
/* SMP safe, global irq locking makes it work. */
diff -Nru a/mm/oom_kill.c b/mm/oom_kill.c
--- a/mm/oom_kill.c Thu Sep 26 13:23:55 2002
+++ b/mm/oom_kill.c Thu Sep 26 13:23:55 2002
@@ -88,7 +88,7 @@
* Superuser processes are usually more important, so we make it
* less likely that we kill those.
*/
- if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_ADMIN) ||
+ if (!security_ops->capable(p,CAP_SYS_ADMIN) ||
p->uid == 0 || p->euid == 0)
points /= 4;

@@ -98,7 +98,7 @@
* tend to only have this flag set on applications they think
* of as important.
*/
- if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO))
+ if (!security_ops->capable(p,CAP_SYS_RAWIO))
points /= 4;
#ifdef DEBUG
printk(KERN_DEBUG "OOMkill: task %d (%s) got %d points\n",
@@ -149,7 +149,7 @@
p->flags |= PF_MEMALLOC | PF_MEMDIE;

/* This process has hardware access, be more careful. */
- if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO)) {
+ if (!security_ops->capable(p,CAP_SYS_RAWIO)) {
force_sig(SIGTERM, p);
} else {
force_sig(SIGKILL, p);
diff -Nru a/mm/swapfile.c b/mm/swapfile.c
--- a/mm/swapfile.c Thu Sep 26 13:23:55 2002
+++ b/mm/swapfile.c Thu Sep 26 13:23:55 2002
@@ -964,6 +964,13 @@
}
prev = type;
}
+
+ err = security_ops->swapoff(p);
+ if (err) {
+ swap_list_unlock();
+ goto out_dput;
+ }
+
err = -EINVAL;
if (type < 0) {
swap_list_unlock();
@@ -1136,6 +1143,9 @@
}

p->swap_file = swap_file;
+ error = security_ops->swapon(p);
+ if (error)
+ goto bad_swap_2;

error = -EINVAL;
if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) {
diff -Nru a/security/capability.c b/security/capability.c
--- a/security/capability.c Thu Sep 26 13:23:55 2002
+++ b/security/capability.c Thu Sep 26 13:23:55 2002
@@ -22,6 +22,31 @@
/* flag to keep track of how we were registered */
static int secondary;

+static int cap_sethostname (char *hostname)
+{
+ return 0;
+}
+
+static int cap_setdomainname (char *domainname)
+{
+ return 0;
+}
+
+static int cap_reboot (unsigned int cmd)
+{
+ return 0;
+}
+
+static int cap_ioperm (unsigned long from, unsigned long num, int turn_on)
+{
+ return 0;
+}
+
+static int cap_iopl (unsigned int old, unsigned int level)
+{
+ return 0;
+}
+
static int cap_capable (struct task_struct *tsk, int cap)
{
/* Derived from include/linux/sched.h:capable. */
@@ -37,6 +62,16 @@
return -ENOSYS;
}

+static int cap_swapon (struct swap_info_struct *swap)
+{
+ return 0;
+}
+
+static int cap_swapoff (struct swap_info_struct *swap)
+{
+ return 0;
+}
+
static int cap_quotactl (int cmds, int type, int id, struct super_block *sb)
{
return 0;
@@ -47,6 +82,16 @@
return 0;
}

+static int cap_syslog (int type)
+{
+ return 0;
+}
+
+static int cap_settime (struct timeval *tv, struct timezone *tz)
+{
+ return 0;
+}
+
static int cap_ptrace (struct task_struct *parent, struct task_struct *child)
{
/* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
@@ -110,6 +155,11 @@
return 0;
}

+static int cap_sysctl (ctl_table * table, int op)
+{
+ return 0;
+}
+
static int cap_bprm_alloc_security (struct linux_binprm *bprm)
{
return 0;
@@ -679,6 +729,21 @@
return;
}

+static int cap_module_create (const char *name_user, size_t size)
+{
+ return 0;
+}
+
+static int cap_module_initialize (struct module *mod_user)
+{
+ return 0;
+}
+
+static int cap_module_delete (const struct module *mod)
+{
+ return 0;
+}
+
static int cap_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
{
return 0;
@@ -796,15 +861,25 @@
}

static struct security_operations capability_ops = {
+ .sethostname = cap_sethostname,
+ .setdomainname = cap_setdomainname,
+ .reboot = cap_reboot,
+ .ioperm = cap_ioperm,
+ .iopl = cap_iopl,
.ptrace = cap_ptrace,
.capget = cap_capget,
.capset_check = cap_capset_check,
.capset_set = cap_capset_set,
.acct = cap_acct,
+ .sysctl = cap_sysctl,
.capable = cap_capable,
.sys_security = cap_sys_security,
+ .swapon = cap_swapon,
+ .swapoff = cap_swapoff,
.quotactl = cap_quotactl,
.quota_on = cap_quota_on,
+ .syslog = cap_syslog,
+ .settime = cap_settime,

.bprm_alloc_security = cap_bprm_alloc_security,
.bprm_free_security = cap_bprm_free_security,
@@ -887,6 +962,10 @@
.task_prctl = cap_task_prctl,
.task_kmod_set_label = cap_task_kmod_set_label,
.task_reparent_to_init = cap_task_reparent_to_init,
+
+ .module_create = cap_module_create,
+ .module_initialize = cap_module_initialize,
+ .module_delete = cap_module_delete,

.ipc_permission = cap_ipc_permission,
.ipc_getinfo = cap_ipc_getinfo,
diff -Nru a/security/dummy.c b/security/dummy.c
--- a/security/dummy.c Thu Sep 26 13:23:55 2002
+++ b/security/dummy.c Thu Sep 26 13:23:55 2002
@@ -19,6 +19,31 @@
#include <linux/skbuff.h>
#include <linux/netlink.h>

+static int dummy_sethostname (char *hostname)
+{
+ return 0;
+}
+
+static int dummy_setdomainname (char *domainname)
+{
+ return 0;
+}
+
+static int dummy_reboot (unsigned int cmd)
+{
+ return 0;
+}
+
+static int dummy_ioperm (unsigned long from, unsigned long num, int turn_on)
+{
+ return 0;
+}
+
+static int dummy_iopl (unsigned int old, unsigned int level)
+{
+ return 0;
+}
+
static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
{
return 0;
@@ -61,12 +86,27 @@
return -EPERM;
}

+static int dummy_sysctl (ctl_table * table, int op)
+{
+ return 0;
+}
+
static int dummy_sys_security (unsigned int id, unsigned int call,
unsigned long *args)
{
return -ENOSYS;
}

+static int dummy_swapon (struct swap_info_struct *swap)
+{
+ return 0;
+}
+
+static int dummy_swapoff (struct swap_info_struct *swap)
+{
+ return 0;
+}
+
static int dummy_quotactl (int cmds, int type, int id, struct super_block *sb)
{
return 0;
@@ -77,6 +117,16 @@
return 0;
}

+static int dummy_syslog (int type)
+{
+ return 0;
+}
+
+static int dummy_settime (struct timeval *tv, struct timezone *tz)
+{
+ return 0;
+}
+
static int dummy_bprm_alloc_security (struct linux_binprm *bprm)
{
return 0;
@@ -493,6 +543,21 @@
return;
}

+static int dummy_module_create (const char *name_user, size_t size)
+{
+ return 0;
+}
+
+static int dummy_module_initialize (struct module *mod_user)
+{
+ return 0;
+}
+
+static int dummy_module_delete (const struct module *mod)
+{
+ return 0;
+}
+
static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
{
return 0;
@@ -610,15 +675,25 @@
}

struct security_operations dummy_security_ops = {
+ .sethostname = dummy_sethostname,
+ .setdomainname = dummy_setdomainname,
+ .reboot = dummy_reboot,
+ .ioperm = dummy_ioperm,
+ .iopl = dummy_iopl,
.ptrace = dummy_ptrace,
.capget = dummy_capget,
.capset_check = dummy_capset_check,
.capset_set = dummy_capset_set,
.acct = dummy_acct,
.capable = dummy_capable,
+ .sysctl = dummy_sysctl,
.sys_security = dummy_sys_security,
+ .swapon = dummy_swapon,
+ .swapoff = dummy_swapoff,
.quotactl = dummy_quotactl,
.quota_on = dummy_quota_on,
+ .syslog = dummy_syslog,
+ .settime = dummy_settime,

.bprm_alloc_security = dummy_bprm_alloc_security,
.bprm_free_security = dummy_bprm_free_security,
@@ -701,6 +776,10 @@
.task_prctl = dummy_task_prctl,
.task_kmod_set_label = dummy_task_kmod_set_label,
.task_reparent_to_init = dummy_task_reparent_to_init,
+
+ .module_create = dummy_module_create,
+ .module_initialize = dummy_module_initialize,
+ .module_delete = dummy_module_delete,

.ipc_permission = dummy_ipc_permission,
.ipc_getinfo = dummy_ipc_getinfo,

2002-09-26 20:25:58

by Greg KH

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.614 -> 1.615
# Documentation/DocBook/kernel-api.tmpl 1.19 -> 1.20
# Documentation/DocBook/Makefile 1.30 -> 1.31
# (new) -> 1.1 Documentation/DocBook/lsm.tmpl
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/09/26 [email protected] 1.615
# LSM: added the LSM documentation to the tree.
# --------------------------------------------
#
diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
--- a/Documentation/DocBook/Makefile Thu Sep 26 13:23:49 2002
+++ b/Documentation/DocBook/Makefile Thu Sep 26 13:23:49 2002
@@ -11,7 +11,7 @@
kernel-locking.sgml via-audio.sgml mousedrivers.sgml \
deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
writing_usb_driver.sgml scsidrivers.sgml sis900.sgml \
- kernel-api.sgml
+ kernel-api.sgml lsm.sgml

###
# The build process is as follows (targets):
diff -Nru a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
--- a/Documentation/DocBook/kernel-api.tmpl Thu Sep 26 13:23:49 2002
+++ b/Documentation/DocBook/kernel-api.tmpl Thu Sep 26 13:23:49 2002
@@ -185,6 +185,11 @@
!Efs/devfs/base.c
</chapter>

+ <chapter id="security">
+ <title>Security Framework</title>
+!Esecurity/security.c
+ </chapter>
+
<chapter id="pmfuncs">
<title>Power Management</title>
!Ekernel/pm.c
diff -Nru a/Documentation/DocBook/lsm.tmpl b/Documentation/DocBook/lsm.tmpl
--- /dev/null Wed Dec 31 16:00:00 1969
+++ b/Documentation/DocBook/lsm.tmpl Thu Sep 26 13:23:49 2002
@@ -0,0 +1,285 @@
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+<article class="whitepaper" id="LinuxSecurityModule" lang="en">
+ <artheader>
+ <title>Linux Security Modules: General Security Hooks for Linux</title>
+ <authorgroup>
+ <author>
+ <firstname>Stephen</firstname>
+ <surname>Smalley</surname>
+ <affiliation>
+ <orgname>NAI Labs</orgname>
+ <address><email>[email protected]</email></address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Timothy</firstname>
+ <surname>Fraser</surname>
+ <affiliation>
+ <orgname>NAI Labs</orgname>
+ <address><email>[email protected]</email></address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Chris</firstname>
+ <surname>Vance</surname>
+ <affiliation>
+ <orgname>NAI Labs</orgname>
+ <address><email>[email protected]</email></address>
+ </affiliation>
+ </author>
+ </authorgroup
+ </artheader>
+
+<sect1><title>Introduction</title>
+
+<para>
+In March 2001, the National Security Agency (NSA) gave a presentation
+about Security-Enhanced Linux (SELinux) at the 2.5 Linux Kernel
+Summit. SELinux is an implementation of flexible and fine-grained
+nondiscretionary access controls in the Linux kernel, originally
+implemented as its own particular kernel patch. Several other
+security projects (e.g. RSBAC, Medusa) have also developed flexible
+access control architectures for the Linux kernel, and various
+projects have developed particular access control models for Linux
+(e.g. LIDS, DTE, SubDomain). Each project has developed and
+maintained its own kernel patch to support its security needs.
+</para>
+
+<para>
+In response to the NSA presentation, Linus Torvalds made a set of
+remarks that described a security framework he would be willing to
+consider for inclusion in the mainstream Linux kernel. He described a
+general framework that would provide a set of security hooks to
+control operations on kernel objects and a set of opaque security
+fields in kernel data structures for maintaining security attributes.
+This framework could then be used by loadable kernel modules to
+implement any desired model of security. Linus also suggested the
+possibility of migrating the Linux capabilities code into such a
+module.
+</para>
+
+<para>
+The Linux Security Modules (LSM) project was started by WireX to
+develop such a framework. LSM is a joint development effort by
+several security projects, including Immunix, SELinux, SGI and Janus,
+and several individuals, including Greg Kroah-Hartman and James
+Morris, to develop a Linux kernel patch that implements this
+framework. The patch is currently tracking the 2.4 series and is
+targeted for integration into the 2.5 development series. This
+technical report provides an overview of the framework and the example
+capabilities security module provided by the LSM kernel patch.
+</para>
+
+</sect1>
+
+<sect1 id="framework"><title>LSM Framework</title>
+
+<para>
+The LSM kernel patch provides a general kernel framework to support
+security modules. In particular, the LSM framework is primarily
+focused on supporting access control modules, although future
+development is likely to address other security needs such as
+auditing. By itself, the framework does not provide any additional
+security; it merely provides the infrastructure to support security
+modules. The LSM kernel patch also moves most of the capabilities
+logic into an optional security module, with the system defaulting
+to the traditional superuser logic. This capabilities module
+is discussed further in <XRef LinkEnd="cap">.
+</para>
+
+<para>
+The LSM kernel patch adds security fields to kernel data structures
+and inserts calls to hook functions at critical points in the kernel
+code to manage the security fields and to perform access control. It
+also adds functions for registering and unregistering security
+modules, and adds a general <function>security</function> system call
+to support new system calls for security-aware applications.
+</para>
+
+<para>
+The LSM security fields are simply <type>void*</type> pointers. For
+process and program execution security information, security fields
+were added to <structname>struct task_struct</structname> and
+<structname>struct linux_binprm</structname>. For filesystem security
+information, a security field was added to
+<structname>struct super_block</structname>. For pipe, file, and socket
+security information, security fields were added to
+<structname>struct inode</structname> and
+<structname>struct file</structname>. For packet and network device security
+information, security fields were added to
+<structname>struct sk_buff</structname> and
+<structname>struct net_device</structname>. For System V IPC security
+information, security fields were added to
+<structname>struct kern_ipc_perm</structname> and
+<structname>struct msg_msg</structname>; additionally, the definitions
+for <structname>struct msg_msg</structname>, <structname>struct
+msg_queue</structname>, and <structname>struct
+shmid_kernel</structname> were moved to header files
+(<filename>include/linux/msg.h</filename> and
+<filename>include/linux/shm.h</filename> as appropriate) to allow
+the security modules to use these definitions.
+</para>
+
+<para>
+Each LSM hook is a function pointer in a global table,
+security_ops. This table is a
+<structname>security_operations</structname> structure as defined by
+<filename>include/linux/security.h</filename>. Detailed documentation
+for each hook is included in this header file. At present, this
+structure consists of a collection of substructures that group related
+hooks based on the kernel object (e.g. task, inode, file, sk_buff,
+etc) as well as some top-level hook function pointers for system
+operations. This structure is likely to be flattened in the future
+for performance. The placement of the hook calls in the kernel code
+is described by the "called:" lines in the per-hook documentation in
+the header file. The hook calls can also be easily found in the
+kernel code by looking for the string "security_ops->".
+
+</para>
+
+<para>
+Linus mentioned per-process security hooks in his original remarks as a
+possible alternative to global security hooks. However, if LSM were
+to start from the perspective of per-process hooks, then the base
+framework would have to deal with how to handle operations that
+involve multiple processes (e.g. kill), since each process might have
+its own hook for controlling the operation. This would require a
+general mechanism for composing hooks in the base framework.
+Additionally, LSM would still need global hooks for operations that
+have no process context (e.g. network input operations).
+Consequently, LSM provides global security hooks, but a security
+module is free to implement per-process hooks (where that makes sense)
+by storing a security_ops table in each process' security field and
+then invoking these per-process hooks from the global hooks.
+The problem of composition is thus deferred to the module.
+</para>
+
+<para>
+The global security_ops table is initialized to a set of hook
+functions provided by a dummy security module that provides
+traditional superuser logic. A <function>register_security</function>
+function (in <filename>security/security.c</filename>) is provided to
+allow a security module to set security_ops to refer to its own hook
+functions, and an <function>unregister_security</function> function is
+provided to revert security_ops to the dummy module hooks. This
+mechanism is used to set the primary security module, which is
+responsible for making the final decision for each hook.
+</para>
+
+<para>
+LSM also provides a simple mechanism for stacking additional security
+modules with the primary security module. It defines
+<function>register_security</function> and
+<function>unregister_security</function> hooks in the
+<structname>security_operations</structname> structure and provides
+<function>mod_reg_security</function> and
+<function>mod_unreg_security</function> functions that invoke these
+hooks after performing some sanity checking. A security module can
+call these functions in order to stack with other modules. However,
+the actual details of how this stacking is handled are deferred to the
+module, which can implement these hooks in any way it wishes
+(including always returning an error if it does not wish to support
+stacking). In this manner, LSM again defers the problem of
+composition to the module.
+</para>
+
+<para>
+Although the LSM hooks are organized into substructures based on
+kernel object, all of the hooks can be viewed as falling into two
+major categories: hooks that are used to manage the security fields
+and hooks that are used to perform access control. Examples of the
+first category of hooks include the
+<function>alloc_security</function> and
+<function>free_security</function> hooks defined for each kernel data
+structure that has a security field. These hooks are used to allocate
+and free security structures for kernel objects. The first category
+of hooks also includes hooks that set information in the security
+field after allocation, such as the <function>post_lookup</function>
+hook in <structname>struct inode_security_ops</structname>. This hook
+is used to set security information for inodes after successful lookup
+operations. An example of the second category of hooks is the
+<function>permission</function> hook in
+<structname>struct inode_security_ops</structname>. This hook checks
+permission when accessing an inode.
+</para>
+
+<para>
+LSM adds a general <function>security</function> system call that
+simply invokes the <function>sys_security</function> hook. This
+system call and hook permits security modules to implement new system
+calls for security-aware applications. The interface is similar to
+socketcall, but also has an <parameter>id</parameter> to help identify
+the security module whose call is being invoked.
+To eliminate the need for a central registry of ids,
+the recommended convention for creating the hexadecimal id value is:
+<programlisting>
+<![CDATA[
+ echo "Name_of_module" | md5sum | cut -c -8
+]]>
+</programlisting>
+C code will need to prefix this result with ``0x''.
+For example, the id for ``SGI Trusted Linux'' could be used in C as:
+<programlisting>
+<![CDATA[
+ #define SYS_SECURITY_MODID 0xc4c7be22
+]]>
+</programlisting>
+</para>
+
+</sect1>
+
+<sect1 id="cap"><title>LSM Capabilities Module</title>
+
+<para>
+The LSM kernel patch moves most of the existing POSIX.1e capabilities
+logic into an optional security module stored in the file
+<filename>security/capability.c</filename>. This change allows
+users who do not want to use capabilities to omit this code entirely
+from their kernel, instead using the dummy module for traditional
+superuser logic or any other module that they desire. This change
+also allows the developers of the capabilities logic to maintain and
+enhance their code more freely, without needing to integrate patches
+back into the base kernel.
+</para>
+
+<para>
+In addition to moving the capabilities logic, the LSM kernel patch
+could move the capability-related fields from the kernel data
+structures into the new security fields managed by the security
+modules. However, at present, the LSM kernel patch leaves the
+capability fields in the kernel data structures. In his original
+remarks, Linus suggested that this might be preferable so that other
+security modules can be easily stacked with the capabilities module
+without needing to chain multiple security structures on the security field.
+It also avoids imposing extra overhead on the capabilities module
+to manage the security fields. However, the LSM framework could
+certainly support such a move if it is determined to be desirable,
+with only a few additional changes described below.
+</para>
+
+<para>
+At present, the capabilities logic for computing process capabilities
+on <function>execve</function> and <function>set*uid</function>,
+checking capabilities for a particular process, saving and checking
+capabilities for netlink messages, and handling the
+<function>capget</function> and <function>capset</function> system
+calls have been moved into the capabilities module. There are still a
+few locations in the base kernel where capability-related fields are
+directly examined or modified, but the current version of the LSM
+patch does allow a security module to completely replace the
+assignment and testing of capabilities. These few locations would
+need to be changed if the capability-related fields were moved into
+the security field. The following is a list of known locations that
+still perform such direct examination or modification of
+capability-related fields:
+<itemizedlist>
+<listitem><para><filename>fs/open.c</filename>:<function>sys_access</function></para></listitem>
+<listitem><para><filename>fs/lockd/host.c</filename>:<function>nlm_bind_host</function></para></listitem>
+<listitem><para><filename>fs/nfsd/auth.c</filename>:<function>nfsd_setuser</function></para></listitem>
+<listitem><para><filename>fs/proc/array.c</filename>:<function>task_cap</function></para></listitem>
+</itemizedlist>
+</para>
+
+</sect1>
+
+</article>

2002-09-26 20:23:34

by Greg KH

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.611 -> 1.612
# include/linux/ipc.h 1.1 -> 1.2
# ipc/msg.c 1.6 -> 1.7
# include/linux/security.h 1.3 -> 1.4
# security/dummy.c 1.6 -> 1.7
# security/capability.c 1.5 -> 1.6
# ipc/sem.c 1.11 -> 1.12
# ipc/util.c 1.5 -> 1.6
# ipc/shm.c 1.17 -> 1.18
# include/linux/msg.h 1.2 -> 1.3
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/09/26 [email protected] 1.612
# [PATCH] LSM: SysV IPC hooks addition
#
# The patch below adds the LSM hooks for System V IPC to the 2.5.38 kernel.
# --------------------------------------------
#
diff -Nru a/include/linux/ipc.h b/include/linux/ipc.h
--- a/include/linux/ipc.h Thu Sep 26 13:23:57 2002
+++ b/include/linux/ipc.h Thu Sep 26 13:23:57 2002
@@ -63,6 +63,7 @@
gid_t cgid;
mode_t mode;
unsigned long seq;
+ void *security;
};

#endif /* __KERNEL__ */
diff -Nru a/include/linux/msg.h b/include/linux/msg.h
--- a/include/linux/msg.h Thu Sep 26 13:23:57 2002
+++ b/include/linux/msg.h Thu Sep 26 13:23:57 2002
@@ -69,6 +69,7 @@
long m_type;
int m_ts; /* message text size */
struct msg_msgseg* next;
+ void *security;
/* the actual message follows immediately */
};

diff -Nru a/include/linux/security.h b/include/linux/security.h
--- a/include/linux/security.h Thu Sep 26 13:23:57 2002
+++ b/include/linux/security.h Thu Sep 26 13:23:57 2002
@@ -572,6 +572,159 @@
* is being reparented to the init task.
* @p contains the task_struct for the kernel thread.
*
+ * Security hooks affecting all System V IPC operations.
+ *
+ * @ipc_permission:
+ * Check user, group, and other permissions for access to IPC
+ * @ipcp contains the IPC permission set
+ * @flag contains the desired (requested) permission set
+ * Return 0 if permission is granted.
+ * @ipc_getinfo:
+ * Check permission to retrieve information on previously allocated IPC
+ * resources. Called by the IPC resource control syscalls, shmctl,
+ * msgctl, semctl with a @cmd argument of: IPC_INFO, SEM_INFO, MSG_INFO,
+ * or SHM_INFO as appropriate.
+ * @id contains the resource identifier
+ * @cmd contains the operation to be performed
+ * Return 0 if permission is granted.
+ *
+ * Security hooks for individual messages held in System V IPC message queues
+ * @msg_msg_alloc_security:
+ * Allocate and attach a security structure to the msg->security field.
+ * The security field is initialized to NULL when the structure is first
+ * created.
+ * @msg contains the message structure to be modified.
+ * Return 0 if operation was successful and permission is granted.
+ * @msg_msg_free_security:
+ * Deallocate the security structure for this message.
+ * @msg contains the message structure to be modified.
+ *
+ *
+ * Security hooks for System V IPC Message Queues
+ *
+ * @msg_queue_alloc_security:
+ * Allocate and attach a security structure to the
+ * msq->q_perm.security field. The security field is initialized to
+ * NULL when the structure is first created.
+ * @msq contains the message queue structure to be modified.
+ * Return 0 if operation was successful and permission is granted.
+ * @msg_queue_free_security:
+ * Deallocate security structure for this message queue.
+ * @msq contains the message queue structure to be modified.
+ * @msg_queue_associate:
+ * Check permission when a message queue is requested through the
+ * msgget system call. This hook is only called when returning the
+ * message queue identifier for an existing message queue, not when a
+ * new message queue is created.
+ * @msq contains the message queue to act upon.
+ * @msqid contains the resource identifier.
+ * @msqflg contains the operation control flags.
+ * Return 0 if permission is granted.
+ * @msg_queue_msgctl:
+ * Check permission when a message control operation specified by @cmd
+ * is to be performed on the message queue @msq, with identifier
+ * @msqid.
+ * @msq contains the message queue to act upon.
+ * @msqid contains the resource identifier.
+ * @cmd contains the operation to be performed.
+ * Return 0 if permission is granted.
+ * @msg_queue_msgsnd:
+ * Check permission before a message, @msg, is enqueued on the message
+ * queue, @msq, whose identifier is specified by the value of @msqid.
+ * @msq contains the message queue to send message to.
+ * @msg contains the message to be enqueued.
+ * @msqid contains resource identifier.
+ * @msqflg contains operational flags.
+ * Return 0 if permission is granted.
+ * @msg_queue_msgrcv:
+ * Check permission before a message, @msg, is removed from the message
+ * queue, @msq, whose identifier is specified by the value of @msqid. The
+ * @target task structure contains a pointer to the process that will be
+ * receiving the message (not equal to the current process when inline
+ * receives are being performed).
+ * @msq contains the message queue to retrieve message from.
+ * @msg contains the message destination.
+ * @target contains the task structure for recipient process.
+ * @type contains the type of message requested.
+ * @mode contains the operational flags.
+ * Return 0 if permission is granted.
+ *
+ * Security hooks for System V Shared Memory Segments
+ *
+ * @shm_alloc_security:
+ * Allocate and attach a security structure to the shp->shm_perm.security
+ * field. The security field is initialized to NULL when the structure is
+ * first created.
+ * @shp contains the shared memory structure to be modified.
+ * Return 0 if operation was successful and permission is granted.
+ * @shm_free_security:
+ * Deallocate the security struct for this memory segment.
+ * @shp contains the shared memory structure to be modified.
+ * @shm_associate:
+ * Check permission when a shared memory region is requested through the
+ * shmget system call. This hook is only called when returning the shared
+ * memory region identifier for an existing region, not when a new shared
+ * memory region is created.
+ * @shp contains the shared memory structure to be modified.
+ * @shmid contains the resource identifier.
+ * @shmflg contains the operation control flags.
+ * Return 0 if permission is granted.
+ * @shm_shmctl:
+ * Check permission when a shared memory control operation specified by
+ * @cmd is to be performed on the shared memory region @shp, with
+ * identifier @shmid.
+ * @shp contains shared memory structure to be modified.
+ * @shmid contains the resource identifier.
+ * @cmd contains the operation to be performed.
+ * Return 0 if permission is granted.
+ * @shm_shmat:
+ * Check permissions prior to allowing the shmat system call to attach the
+ * shared memory segment @shp, identified by @shmid, to the data segment
+ * of the calling process. The attaching address is specified by @shmaddr.
+ * @shp contains the shared memory structure to be modified.
+ * @shmid contains the resource identifier.
+ * @shmaddr contains the address to attach memory region to.
+ * @shmflg contains the operational flags.
+ * Return 0 if permission is granted.
+ *
+ * Security hooks for System V Semaphores
+ *
+ * @sem_alloc_security:
+ * Allocate and attach a security structure to the sma->sem_perm.security
+ * field. The security field is initialized to NULL when the structure is
+ * first created.
+ * @sma contains the semaphore structure
+ * Return 0 if operation was successful and permission is granted.
+ * @sem_free_security:
+ * deallocate security struct for this semaphore
+ * @sma contains the semaphore structure.
+ * @sem_associate:
+ * Check permission when a semaphore is requested through the semget
+ * system call. This hook is only called when returning the semaphore
+ * identifier for an existing semaphore, not when a new one must be
+ * created.
+ * @sma contains the semaphore structure.
+ * @semid contains the resource identifier.
+ * @semflg contains the operation control flags.
+ * Return 0 if permission is granted.
+ * @sem_semctl:
+ * Check permission when a semaphore operation specified by @cmd is to be
+ * performed on the semaphore @sma, with identifier @semid.
+ * @sma contains the semaphore structure.
+ * @semid contains the resource identifier.
+ * @cmd contains the operation to be performed.
+ * Return 0 if permission is granted.
+ * @sem_semop
+ * Check permissions before performing operations on members of the
+ * semaphore set @sma, identified by @semid. If the @alter flag is
+ * nonzero, the semaphore set may be modified.
+ * @sma contains the semaphore structure.
+ * @semid contains the resource identifier.
+ * @sops contains the operations to perform.
+ * @nsops contains the number of operations to perform.
+ * @alter contains the flag indicating whether changes are to be made.
+ * Return 0 if permission is granted.
+ *
* @ptrace:
* Check permission before allowing the @parent process to trace the
* @child process.
@@ -785,6 +938,38 @@
unsigned long arg5);
void (*task_kmod_set_label) (void);
void (*task_reparent_to_init) (struct task_struct * p);
+
+ int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
+ int (*ipc_getinfo) (int id, int cmd);
+
+ int (*msg_msg_alloc_security) (struct msg_msg * msg);
+ void (*msg_msg_free_security) (struct msg_msg * msg);
+
+ int (*msg_queue_alloc_security) (struct msg_queue * msq);
+ void (*msg_queue_free_security) (struct msg_queue * msq);
+ int (*msg_queue_associate) (struct msg_queue * msq, int msqid,
+ int msqflg);
+ int (*msg_queue_msgctl) (struct msg_queue * msq, int msqid, int cmd);
+ int (*msg_queue_msgsnd) (struct msg_queue * msq,
+ struct msg_msg * msg, int msqid, int msqflg);
+ int (*msg_queue_msgrcv) (struct msg_queue * msq,
+ struct msg_msg * msg,
+ struct task_struct * target,
+ long type, int mode);
+
+ int (*shm_alloc_security) (struct shmid_kernel * shp);
+ void (*shm_free_security) (struct shmid_kernel * shp);
+ int (*shm_associate) (struct shmid_kernel * shp, int shmid, int shmflg);
+ int (*shm_shmctl) (struct shmid_kernel * shp, int shmid, int cmd);
+ int (*shm_shmat) (struct shmid_kernel * shp, int shmid,
+ char *shmaddr, int shmflg);
+
+ int (*sem_alloc_security) (struct sem_array * sma);
+ void (*sem_free_security) (struct sem_array * sma);
+ int (*sem_associate) (struct sem_array * sma, int semid, int semflg);
+ int (*sem_semctl) (struct sem_array * sma, int semid, int cmd);
+ int (*sem_semop) (struct sem_array * sma, int semid,
+ struct sembuf * sops, unsigned nsops, int alter);

/* allow module stacking */
int (*register_security) (const char *name,
diff -Nru a/ipc/msg.c b/ipc/msg.c
--- a/ipc/msg.c Thu Sep 26 13:23:57 2002
+++ b/ipc/msg.c Thu Sep 26 13:23:57 2002
@@ -89,6 +89,7 @@
static int newque (key_t key, int msgflg)
{
int id;
+ int retval;
struct msg_queue *msq;

msq = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL);
@@ -98,8 +99,16 @@
msq->q_perm.mode = (msgflg & S_IRWXUGO);
msq->q_perm.key = key;

+ msq->q_perm.security = NULL;
+ retval = security_ops->msg_queue_alloc_security(msq);
+ if (retval) {
+ kfree(msq);
+ return retval;
+ }
+
id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni);
if(id == -1) {
+ security_ops->msg_queue_free_security(msq);
kfree(msq);
return -ENOSPC;
}
@@ -120,6 +129,9 @@
static void free_msg(struct msg_msg* msg)
{
struct msg_msgseg* seg;
+
+ security_ops->msg_msg_free_security(msg);
+
seg = msg->next;
kfree(msg);
while(seg != NULL) {
@@ -145,6 +157,7 @@
return ERR_PTR(-ENOMEM);

msg->next = NULL;
+ msg->security = NULL;

if (copy_from_user(msg+1, src, alen)) {
err = -EFAULT;
@@ -174,6 +187,11 @@
len -= alen;
src = ((char*)src)+alen;
}
+
+ err = security_ops->msg_msg_alloc_security(msg);
+ if (err)
+ goto out_err;
+
return msg;

out_err:
@@ -259,6 +277,8 @@

msq = msg_rmid(id);

+ security_ops->msg_queue_free_security(msq);
+
expunge_all(msq,-EIDRM);
ss_wakeup(&msq->q_senders,1);
msg_unlock(id);
@@ -295,8 +315,12 @@
BUG();
if (ipcperms(&msq->q_perm, msgflg))
ret = -EACCES;
- else
- ret = msg_buildid(id, msq->q_perm.seq);
+ else {
+ int qid = msg_buildid(id, msq->q_perm.seq);
+ ret = security_ops->msg_queue_associate(msq, qid, msgflg);
+ if (!ret)
+ ret = qid;
+ }
msg_unlock(id);
}
up(&msg_ids.sem);
@@ -418,6 +442,11 @@
* due to padding, it's not enough
* to set all member fields.
*/
+
+ err = security_ops->ipc_getinfo(msqid, cmd);
+ if (err)
+ return err;
+
memset(&msginfo,0,sizeof(msginfo));
msginfo.msgmni = msg_ctlmni;
msginfo.msgmax = msg_ctlmax;
@@ -468,6 +497,10 @@
if (ipcperms (&msq->q_perm, S_IRUGO))
goto out_unlock;

+ err = security_ops->msg_queue_msgctl(msq, msqid, cmd);
+ if (err)
+ goto out_unlock;
+
kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm);
tbuf.msg_stime = msq->q_stime;
tbuf.msg_rtime = msq->q_rtime;
@@ -515,6 +548,11 @@
{
if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
goto out_unlock_up;
+
+ err = security_ops->msg_queue_msgctl(msq, msqid, cmd);
+ if (err)
+ goto out_unlock_up;
+
msq->q_qbytes = setbuf.qbytes;

ipcp->uid = setbuf.uid;
@@ -534,6 +572,10 @@
break;
}
case IPC_RMID:
+ err = security_ops->msg_queue_msgctl(msq, msqid, cmd);
+ if (err)
+ goto out_unlock_up;
+
freeque (msqid);
break;
}
@@ -580,7 +622,8 @@
struct msg_receiver* msr;
msr = list_entry(tmp,struct msg_receiver,r_list);
tmp = tmp->next;
- if(testmsg(msg,msr->r_msgtype,msr->r_mode)) {
+ if(testmsg(msg,msr->r_msgtype,msr->r_mode) &&
+ !security_ops->msg_queue_msgrcv(msq, msg, msr->r_tsk, msr->r_msgtype, msr->r_mode)) {
list_del(&msr->r_list);
if(msr->r_maxsize < msg->m_ts) {
msr->r_msg = ERR_PTR(-E2BIG);
@@ -631,6 +674,10 @@
if (ipcperms(&msq->q_perm, S_IWUGO))
goto out_unlock_free;

+ err = security_ops->msg_queue_msgsnd(msq, msg, msqid, msgflg);
+ if (err)
+ goto out_unlock_free;
+
if(msgsz + msq->q_cbytes > msq->q_qbytes ||
1 + msq->q_qnum > msq->q_qbytes) {
struct msg_sender s;
@@ -729,7 +776,8 @@
found_msg=NULL;
while (tmp != &msq->q_messages) {
msg = list_entry(tmp,struct msg_msg,m_list);
- if(testmsg(msg,msgtyp,mode)) {
+ if(testmsg(msg,msgtyp,mode) &&
+ !security_ops->msg_queue_msgrcv(msq, msg, current, msgtyp, mode)) {
found_msg = msg;
if(mode == SEARCH_LESSEQUAL && msg->m_type != 1) {
found_msg=msg;
@@ -747,6 +795,7 @@
err=-E2BIG;
goto out_unlock;
}
+
list_del(&msg->m_list);
msq->q_qnum--;
msq->q_rtime = CURRENT_TIME;
diff -Nru a/ipc/sem.c b/ipc/sem.c
--- a/ipc/sem.c Thu Sep 26 13:23:57 2002
+++ b/ipc/sem.c Thu Sep 26 13:23:57 2002
@@ -63,6 +63,7 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/smp_lock.h>
+#include <linux/security.h>
#include <asm/uaccess.h>
#include "util.h"

@@ -115,6 +116,7 @@
static int newary (key_t key, int nsems, int semflg)
{
int id;
+ int retval;
struct sem_array *sma;
int size;

@@ -133,8 +135,16 @@
sma->sem_perm.mode = (semflg & S_IRWXUGO);
sma->sem_perm.key = key;

+ sma->sem_perm.security = NULL;
+ retval = security_ops->sem_alloc_security(sma);
+ if (retval) {
+ ipc_free(sma, size);
+ return retval;
+ }
+
id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni);
if(id == -1) {
+ security_ops->sem_free_security(sma);
ipc_free(sma, size);
return -ENOSPC;
}
@@ -177,8 +187,12 @@
err = -EINVAL;
else if (ipcperms(&sma->sem_perm, semflg))
err = -EACCES;
- else
- err = sem_buildid(id, sma->sem_perm.seq);
+ else {
+ int semid = sem_buildid(id, sma->sem_perm.seq);
+ err = security_ops->sem_associate(sma, semid, semflg);
+ if (!err)
+ err = semid;
+ }
sem_unlock(id);
}

@@ -399,6 +413,7 @@
int size;

sma = sem_rmid(id);
+ security_ops->sem_free_security(sma);

/* Invalidate the existing undo structures for this semaphore set.
* (They will be freed without any further action in sem_exit()
@@ -453,6 +468,10 @@
struct seminfo seminfo;
int max_id;

+ err = security_ops->ipc_getinfo(semid, cmd);
+ if (err)
+ return err;
+
memset(&seminfo,0,sizeof(seminfo));
seminfo.semmni = sc_semmni;
seminfo.semmns = sc_semmns;
@@ -494,6 +513,11 @@
err = -EACCES;
if (ipcperms (&sma->sem_perm, S_IRUGO))
goto out_unlock;
+
+ err = security_ops->sem_semctl(sma, semid, cmd);
+ if (err)
+ goto out_unlock;
+
id = sem_buildid(semid, sma->sem_perm.seq);

kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
@@ -537,6 +561,11 @@
if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO))
goto out_unlock;

+ err = security_ops->sem_semctl(sma, semid, cmd);
+ if (err)
+ goto out_unlock;
+
+ err = -EACCES;
switch (cmd) {
case GETALL:
{
@@ -728,6 +757,10 @@
goto out_unlock;
}

+ err = security_ops->sem_semctl(sma, semid, cmd);
+ if (err)
+ goto out_unlock;
+
switch(cmd){
case IPC_RMID:
freeary(semid);
@@ -1004,6 +1037,12 @@
error = -EACCES;
if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
goto out_unlock_semundo_free;
+
+ error = security_ops->sem_semop(sma, semid, sops, nsops, alter);
+ if (error)
+ goto out_unlock_semundo_free;
+ error = -EACCES;
+
if (undos) {
/* Make sure we have an undo structure
* for this process and this semaphore set.
diff -Nru a/ipc/shm.c b/ipc/shm.c
--- a/ipc/shm.c Thu Sep 26 13:23:57 2002
+++ b/ipc/shm.c Thu Sep 26 13:23:57 2002
@@ -24,6 +24,7 @@
#include <linux/mman.h>
#include <linux/proc_fs.h>
#include <linux/shmem_fs.h>
+#include <linux/security.h>
#include <asm/uaccess.h>

#include "util.h"
@@ -113,6 +114,9 @@
shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
shm_rmid (shp->id);
shm_unlock(shp->id);
+
+ security_ops->shm_free_security(shp);
+
shmem_lock(shp->shm_file, 0);
fput (shp->shm_file);
kfree (shp);
@@ -185,6 +189,13 @@
shp->shm_perm.key = key;
shp->shm_flags = (shmflg & S_IRWXUGO);

+ shp->shm_perm.security = NULL;
+ error = security_ops->shm_alloc_security(shp);
+ if (error) {
+ kfree(shp);
+ return error;
+ }
+
sprintf (name, "SYSV%08x", key);
file = shmem_file_setup(name, size, VM_ACCOUNT);
error = PTR_ERR(file);
@@ -213,6 +224,7 @@
no_id:
fput(file);
no_file:
+ security_ops->shm_free_security(shp);
kfree(shp);
return error;
}
@@ -240,8 +252,12 @@
err = -EINVAL;
else if (ipcperms(&shp->shm_perm, shmflg))
err = -EACCES;
- else
- err = shm_buildid(id, shp->shm_perm.seq);
+ else {
+ int shmid = shm_buildid(id, shp->shm_perm.seq);
+ err = security_ops->shm_associate(shp, shmid, shmflg);
+ if (!err)
+ err = shmid;
+ }
shm_unlock(id);
}
up(&shm_ids.sem);
@@ -379,6 +395,10 @@
{
struct shminfo64 shminfo;

+ err = security_ops->ipc_getinfo(shmid, cmd);
+ if (err)
+ return err;
+
memset(&shminfo,0,sizeof(shminfo));
shminfo.shmmni = shminfo.shmseg = shm_ctlmni;
shminfo.shmmax = shm_ctlmax;
@@ -397,6 +417,10 @@
{
struct shm_info shm_info;

+ err = security_ops->ipc_getinfo(shmid, cmd);
+ if (err)
+ return err;
+
memset(&shm_info,0,sizeof(shm_info));
down(&shm_ids.sem);
shm_lockall();
@@ -422,6 +446,11 @@
shp = shm_lock(shmid);
if(shp==NULL)
return -EINVAL;
+
+ err = security_ops->shm_shmctl(shp, shmid, cmd);
+ if (err)
+ goto out_unlock;
+
if(cmd==SHM_STAT) {
err = -EINVAL;
if (shmid > shm_ids.max_id)
@@ -464,6 +493,11 @@
err = shm_checkid(shp,shmid);
if(err)
goto out_unlock;
+
+ err = security_ops->shm_shmctl(shp, shmid, cmd);
+ if (err)
+ goto out_unlock;
+
if(cmd==SHM_LOCK) {
shmem_lock(shp->shm_file, 1);
shp->shm_flags |= SHM_LOCKED;
@@ -494,6 +528,11 @@
err = shm_checkid(shp, shmid);
if(err)
goto out_unlock_up;
+
+ err = security_ops->shm_shmctl(shp, shmid, cmd);
+ if (err)
+ goto out_unlock_up;
+
if (current->euid != shp->shm_perm.uid &&
current->euid != shp->shm_perm.cuid &&
!capable(CAP_SYS_ADMIN)) {
@@ -523,6 +562,11 @@
err = shm_checkid(shp,shmid);
if(err)
goto out_unlock_up;
+
+ err = security_ops->shm_shmctl(shp, shmid, cmd);
+ if (err)
+ goto out_unlock_up;
+
err=-EPERM;
if (current->euid != shp->shm_perm.uid &&
current->euid != shp->shm_perm.cuid &&
@@ -613,6 +657,13 @@
shm_unlock(shmid);
return -EACCES;
}
+
+ err = security_ops->shm_shmat(shp, shmid, shmaddr, shmflg);
+ if (err) {
+ shm_unlock(shmid);
+ return err;
+ }
+
file = shp->shm_file;
size = file->f_dentry->d_inode->i_size;
shp->shm_nattch++;
diff -Nru a/ipc/util.c b/ipc/util.c
--- a/ipc/util.c Thu Sep 26 13:23:57 2002
+++ b/ipc/util.c Thu Sep 26 13:23:57 2002
@@ -19,6 +19,7 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/highuid.h>
+#include <linux/security.h>

#if defined(CONFIG_SYSVIPC)

@@ -263,7 +264,7 @@
!capable(CAP_IPC_OWNER))
return -1;

- return 0;
+ return security_ops->ipc_permission(ipcp, flag);
}

/*
diff -Nru a/security/capability.c b/security/capability.c
--- a/security/capability.c Thu Sep 26 13:23:57 2002
+++ b/security/capability.c Thu Sep 26 13:23:57 2002
@@ -679,6 +679,112 @@
return;
}

+static int cap_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
+{
+ return 0;
+}
+
+static int cap_ipc_getinfo (int id, int cmd)
+{
+ return 0;
+}
+
+static int cap_msg_msg_alloc_security (struct msg_msg *msg)
+{
+ return 0;
+}
+
+static void cap_msg_msg_free_security (struct msg_msg *msg)
+{
+ return;
+}
+
+static int cap_msg_queue_alloc_security (struct msg_queue *msq)
+{
+ return 0;
+}
+
+static void cap_msg_queue_free_security (struct msg_queue *msq)
+{
+ return;
+}
+
+static int cap_msg_queue_associate (struct msg_queue *msq, int msgid,
+ int msgflg)
+{
+ return 0;
+}
+
+static int cap_msg_queue_msgctl (struct msg_queue *msq, int msgid, int cmd)
+{
+ return 0;
+}
+
+static int cap_msg_queue_msgsnd (struct msg_queue *msq, struct msg_msg *msg,
+ int msgid, int msgflg)
+{
+ return 0;
+}
+
+static int cap_msg_queue_msgrcv (struct msg_queue *msq, struct msg_msg *msg,
+ struct task_struct *target, long type,
+ int mode)
+{
+ return 0;
+}
+
+static int cap_shm_alloc_security (struct shmid_kernel *shp)
+{
+ return 0;
+}
+
+static void cap_shm_free_security (struct shmid_kernel *shp)
+{
+ return;
+}
+
+static int cap_shm_associate (struct shmid_kernel *shp, int shmid, int shmflg)
+{
+ return 0;
+}
+
+static int cap_shm_shmctl (struct shmid_kernel *shp, int shmid, int cmd)
+{
+ return 0;
+}
+
+static int cap_shm_shmat (struct shmid_kernel *shp, int shmid, char *shmaddr,
+ int shmflg)
+{
+ return 0;
+}
+
+static int cap_sem_alloc_security (struct sem_array *sma)
+{
+ return 0;
+}
+
+static void cap_sem_free_security (struct sem_array *sma)
+{
+ return;
+}
+
+static int cap_sem_associate (struct sem_array *sma, int semid, int semflg)
+{
+ return 0;
+}
+
+static int cap_sem_semctl (struct sem_array *sma, int semid, int cmd)
+{
+ return 0;
+}
+
+static int cap_sem_semop (struct sem_array *sma, int semid, struct sembuf *sops,
+ unsigned nsops, int alter)
+{
+ return 0;
+}
+
static int cap_register (const char *name, struct security_operations *ops)
{
return -EINVAL;
@@ -781,6 +887,31 @@
.task_prctl = cap_task_prctl,
.task_kmod_set_label = cap_task_kmod_set_label,
.task_reparent_to_init = cap_task_reparent_to_init,
+
+ .ipc_permission = cap_ipc_permission,
+ .ipc_getinfo = cap_ipc_getinfo,
+
+ .msg_msg_alloc_security = cap_msg_msg_alloc_security,
+ .msg_msg_free_security = cap_msg_msg_free_security,
+
+ .msg_queue_alloc_security = cap_msg_queue_alloc_security,
+ .msg_queue_free_security = cap_msg_queue_free_security,
+ .msg_queue_associate = cap_msg_queue_associate,
+ .msg_queue_msgctl = cap_msg_queue_msgctl,
+ .msg_queue_msgsnd = cap_msg_queue_msgsnd,
+ .msg_queue_msgrcv = cap_msg_queue_msgrcv,
+
+ .shm_alloc_security = cap_shm_alloc_security,
+ .shm_free_security = cap_shm_free_security,
+ .shm_associate = cap_shm_associate,
+ .shm_shmctl = cap_shm_shmctl,
+ .shm_shmat = cap_shm_shmat,
+
+ .sem_alloc_security = cap_sem_alloc_security,
+ .sem_free_security = cap_sem_free_security,
+ .sem_associate = cap_sem_associate,
+ .sem_semctl = cap_sem_semctl,
+ .sem_semop = cap_sem_semop,

.register_security = cap_register,
.unregister_security = cap_unregister,
diff -Nru a/security/dummy.c b/security/dummy.c
--- a/security/dummy.c Thu Sep 26 13:23:57 2002
+++ b/security/dummy.c Thu Sep 26 13:23:57 2002
@@ -493,6 +493,112 @@
return;
}

+static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
+{
+ return 0;
+}
+
+static int dummy_ipc_getinfo (int id, int cmd)
+{
+ return 0;
+}
+
+static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
+{
+ return 0;
+}
+
+static void dummy_msg_msg_free_security (struct msg_msg *msg)
+{
+ return;
+}
+
+static int dummy_msg_queue_alloc_security (struct msg_queue *msq)
+{
+ return 0;
+}
+
+static void dummy_msg_queue_free_security (struct msg_queue *msq)
+{
+ return;
+}
+
+static int dummy_msg_queue_associate (struct msg_queue *msq, int msqid,
+ int msqflg)
+{
+ return 0;
+}
+
+static int dummy_msg_queue_msgctl (struct msg_queue *msq, int msqid, int cmd)
+{
+ return 0;
+}
+
+static int dummy_msg_queue_msgsnd (struct msg_queue *msq, struct msg_msg *msg,
+ int msqid, int msgflg)
+{
+ return 0;
+}
+
+static int dummy_msg_queue_msgrcv (struct msg_queue *msq, struct msg_msg *msg,
+ struct task_struct *target, long type,
+ int mode)
+{
+ return 0;
+}
+
+static int dummy_shm_alloc_security (struct shmid_kernel *shp)
+{
+ return 0;
+}
+
+static void dummy_shm_free_security (struct shmid_kernel *shp)
+{
+ return;
+}
+
+static int dummy_shm_associate (struct shmid_kernel *shp, int shmid, int shmflg)
+{
+ return 0;
+}
+
+static int dummy_shm_shmctl (struct shmid_kernel *shp, int shmid, int cmd)
+{
+ return 0;
+}
+
+static int dummy_shm_shmat (struct shmid_kernel *shp, int shmid, char *shmaddr,
+ int shmflg)
+{
+ return 0;
+}
+
+static int dummy_sem_alloc_security (struct sem_array *sma)
+{
+ return 0;
+}
+
+static void dummy_sem_free_security (struct sem_array *sma)
+{
+ return;
+}
+
+static int dummy_sem_associate (struct sem_array *sma, int semid, int semflg)
+{
+ return 0;
+}
+
+static int dummy_sem_semctl (struct sem_array *sma, int semid, int cmd)
+{
+ return 0;
+}
+
+static int dummy_sem_semop (struct sem_array *sma, int semid,
+ struct sembuf *sops, unsigned nsops, int alter)
+{
+ return 0;
+}
+
static int dummy_register (const char *name, struct security_operations *ops)
{
return -EINVAL;
@@ -595,6 +701,31 @@
.task_prctl = dummy_task_prctl,
.task_kmod_set_label = dummy_task_kmod_set_label,
.task_reparent_to_init = dummy_task_reparent_to_init,
+
+ .ipc_permission = dummy_ipc_permission,
+ .ipc_getinfo = dummy_ipc_getinfo,
+
+ .msg_msg_alloc_security = dummy_msg_msg_alloc_security,
+ .msg_msg_free_security = dummy_msg_msg_free_security,
+
+ .msg_queue_alloc_security = dummy_msg_queue_alloc_security,
+ .msg_queue_free_security = dummy_msg_queue_free_security,
+ .msg_queue_associate = dummy_msg_queue_associate,
+ .msg_queue_msgctl = dummy_msg_queue_msgctl,
+ .msg_queue_msgsnd = dummy_msg_queue_msgsnd,
+ .msg_queue_msgrcv = dummy_msg_queue_msgrcv,
+
+ .shm_alloc_security = dummy_shm_alloc_security,
+ .shm_free_security = dummy_shm_free_security,
+ .shm_associate = dummy_shm_associate,
+ .shm_shmctl = dummy_shm_shmctl,
+ .shm_shmat = dummy_shm_shmat,
+
+ .sem_alloc_security = dummy_sem_alloc_security,
+ .sem_free_security = dummy_sem_free_security,
+ .sem_associate = dummy_sem_associate,
+ .sem_semctl = dummy_sem_semctl,
+ .sem_semop = dummy_sem_semop,

.register_security = dummy_register,
.unregister_security = dummy_unregister,

2002-09-26 21:12:45

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38


> /* 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)
> @@ -62,7 +63,12 @@
> return -EINVAL;
> if (turn_on && !capable(CAP_SYS_RAWIO))
> return -EPERM;
> -
> +
> + ret = security_ops->ioperm(from, num, turn_on);
> + if (ret) {
> + return ret;
> + }
> +

Sorry, but this is bullshit (like most of the lsm changes). Either you
leave the capable in and say it's enough or you add your random hook
and remove that one. Just adding more and more hooks without thinking
gets us exactly nowhere except to an unmaintainable codebase.

Also is there a _real_ need to pass in all the arguments?

> return -EPERM;
> }
> + retval = security_ops->iopl(old, level);
> + if (retval) {
> + return retval;
> + }
> +

again (and another few times)

> + * @module_create:
> + * Check the permission before allocating space for a module.
> + * @name contains the module name.
> + * @size contains the module size.
> + * Return 0 if permission is granted.
> + * @module_initialize:
> + * Check permission before initializing a module.
> + * @mod contains a pointer to the module being initialized.
> + * Return 0 if permission is granted.

Umm, you can't tell me you deny someone to initialize a module he has
just created?

> + * @sethostname:
> + * Check permission before the hostname is set to @hostname.
> + * @hostname contains the new hostname
> + * Return 0 if permission is granted.
> + * @setdomainname:
> + * Check permission before the domainname is set to @domainname.
> + * @domainname contains the new domainname
> + * Return 0 if permission is granted.

You don't think this should maybe be just one hook?

> + * @ioperm:
> + * Check permission before setting port input/output permissions for the
> + * process for @num bytes starting from the port address @from to the
> + * value @turn_on.
> + * @from contains the starting port address.
> + * @num contains the number of bytes starting from @from.
> + * @turn_on contains the permissions value.
> + * Return 0 if permission is granted.
> + * @iopl:
> + * Check permission before changing the I/O privilege level of the current
> + * process from @old to @level.
> + * @old contains the old level.
> + * @level contains the new level.
> + * Return 0 if permission is granted.

Dito.

> + * @sysctl:
> + * Check permission before accessing the @table sysctl variable in the
> + * manner specified by @op.
> + * @table contains the ctl_table structure for the sysctl variable.
> + * @op contains the operation (001 = search, 002 = write, 004 = read).
> + * Return 0 if permission is granted.

Aha. So every LS module knows about every single sysctl in the
kernel. Common, this is silly guys (and girls if there any)!

> + * @swapon:
> + * Check permission before enabling swapping to the file or block device
> + * identified by @swap.
> + * @swap contains the swap_info_struct structure for the swap file and device.
> + * Return 0 if permission is granted.
> + * @swapoff:
> + * Check permission before disabling swapping to the file or block device
> + * identified by @swap.
> + * @swap contains the swap_info_struct structure for the swap file and device.
> + * Return 0 if permission is granted.

You might be allowed to swapon but not swapoff?

> diff -Nru a/kernel/sys.c b/kernel/sys.c
> --- a/kernel/sys.c Thu Sep 26 13:23:55 2002
> +++ b/kernel/sys.c Thu Sep 26 13:23:55 2002
> @@ -349,11 +349,17 @@
> asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void * arg)
> {
> char buffer[256];
> + int retval;
>
> /* We only trust the superuser with rebooting the system. */
> if (!capable(CAP_SYS_BOOT))
> return -EPERM;
>
> + retval = security_ops->reboot(cmd);
> + if (retval) {
> + return retval;
> + }
> +

What's the point of cmd here? Someone might be allowed to halt the
system but not reboot?

[don't of stubfs snipped]

> +static int cap_swapon (struct swap_info_struct *swap)
> +{
> + return 0;
> +}
> +
> +static int cap_swapoff (struct swap_info_struct *swap)
> +{
> + return 0;
> +}

Live would be a lot simple if an unimplemented op would behave
as returning zero..

Christoph (not speaking for SGI, just using the fastest mailserver)

2002-09-26 22:48:05

by Greg KH

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, Sep 27, 2002 at 12:32:10AM -0400, Christoph Hellwig wrote:
>
> > /* 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)
> > @@ -62,7 +63,12 @@
> > return -EINVAL;
> > if (turn_on && !capable(CAP_SYS_RAWIO))
> > return -EPERM;
> > -
> > +
> > + ret = security_ops->ioperm(from, num, turn_on);
> > + if (ret) {
> > + return ret;
> > + }
> > +
>
> Sorry, but this is bullshit (like most of the lsm changes). Either you
> leave the capable in and say it's enough or you add your random hook
> and remove that one. Just adding more and more hooks without thinking
> gets us exactly nowhere except to an unmaintainable codebase.

capable is needed to be checked, as we are not modifying the existing
permission logic.

> Also is there a _real_ need to pass in all the arguments?

I'll let Stephen answer that one, as SELinux uses it.

Oops, ok, nevermind, I don't see _any_ security module using this hook.
In fact they are using the capable(CAP_SYS_RAWIO) hook, which is exactly
what you suggest :)

I'll go remove it.

> > return -EPERM;
> > }
> > + retval = security_ops->iopl(old, level);
> > + if (retval) {
> > + return retval;
> > + }
> > +
>
> again (and another few times)

Ok, again, no one is using it. I'll go remove it (and go audit all of
the other hooks.)

> > + * @module_create:
> > + * Check the permission before allocating space for a module.
> > + * @name contains the module name.
> > + * @size contains the module size.
> > + * Return 0 if permission is granted.
> > + * @module_initialize:
> > + * Check permission before initializing a module.
> > + * @mod contains a pointer to the module being initialized.
> > + * Return 0 if permission is granted.
>
> Umm, you can't tell me you deny someone to initialize a module he has
> just created?

Bah, ok, again no one uses these either.

Consider me roasted, I'll go audit this whole thing to try to justify
every one of the hooks we ask for.

Very sorry for bothering people.

thanks,

greg k-h

2002-09-27 12:05:18

by Stephen Smalley

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38


On Fri, 27 Sep 2002, Christoph Hellwig wrote:

> Sorry, but this is bullshit (like most of the lsm changes). Either you
> leave the capable in and say it's enough or you add your random hook
> and remove that one. Just adding more and more hooks without thinking
> gets us exactly nowhere except to an unmaintainable codebase.

The LSM hooks are primarily restrictive, i.e. a security module can deny
access that would normally be granted by the existing Linux access checks.
Hence, the LSM patch does not remove existing access checks. Minimal
support for permissive behavior (granting what would normally be denied)
is provided to support modularization of the capabilities logic, but this
does not require removing the capable() calls from kernel functions. This
approach reduces the invasiveness of the patch and the likelihood of
introducing bugs into the base kernel access checking. See the LSM papers
from Usenix Security and OLS, which should be available from
lsm.immunix.org.

> Also is there a _real_ need to pass in all the arguments?

Define _real_. It is true that none of the existing open source security
modules presently use this particular hook. SELinux doesn't presently use
it, but it seems reasonable to support finer-grained control over ioperm()
than the all-or-nothing CAP_SYS_RAWIO. Is the criteria that every hook
and every parameter to every hook must be used by an existing open source
security module? If so, then yes, this hook can be dropped.

> Umm, you can't tell me you deny someone to initialize a module he has
> just created?

In sys_create_module, you only know the name and size of the module and
who is performing the operation. In sys_init_module, you actually have
information about the module available. Hence, you can make a
finer-grained decision in the module_initialize hook, and possibly deny
even after a successful module_create. As above, SELinux doesn't use
these hooks presently.

> You don't think this should maybe be just one hook?

They are different operations, with different interpretations of the
string parameter. If your security module is enforcing any kind of
restriction based on the parameter, then you need to distinguish them.
Again, not used by SELinux at present.

> Aha. So every LS module knows about every single sysctl in the
> kernel. Common, this is silly guys (and girls if there any)!

SELinux does use the sysctl hook. It assigns security labels to sysctl
variables and enforces a consistent control whether accessed via the
sysctl() call or the /proc/sys interface. The granularity at which you
distinguish the sysctl variables is configurable. For example, we assign
an individual security label to /proc/sys/kernel/modprobe to suport
fine-grained control over access to it. Most sysctl variables are grouped
into equivalence classes based on the hierarchy, but it is entirely
configurable in the security policy.

--
Stephen D. Smalley, NAI Labs
[email protected]



2002-09-27 16:30:39

by Greg KH

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, Sep 27, 2002 at 08:09:50AM -0400, Stephen Smalley wrote:
>
> > Also is there a _real_ need to pass in all the arguments?
>
> Define _real_. It is true that none of the existing open source security
> modules presently use this particular hook. SELinux doesn't presently use
> it, but it seems reasonable to support finer-grained control over ioperm()
> than the all-or-nothing CAP_SYS_RAWIO. Is the criteria that every hook
> and every parameter to every hook must be used by an existing open source
> security module? If so, then yes, this hook can be dropped.

Yes, I think that is the criteria for any security hook. So it (and
others) should be dropped.

thanks,

greg k-h

2002-09-27 16:43:32

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Thu, Sep 26, 2002 at 03:51:48PM -0700, Greg KH wrote:
> > leave the capable in and say it's enough or you add your random hook
> > and remove that one. Just adding more and more hooks without thinking
> > gets us exactly nowhere except to an unmaintainable codebase.
>
> capable is needed to be checked, as we are not modifying the existing
> permission logic.

I odn't think it makes sense to have two security checks that both
end up in the LSM code after each other..

2002-09-27 16:56:01

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, Sep 27, 2002 at 09:55:56AM -0700, Greg KH wrote:
> For cases like the module_* hooks, and the other examples you pointed
> out, I agree.
>
> For other cases, capable() is just not fine grained enough to actually
> know what is going on (like CAP_SYS_ADMIN). In those cases you need an
> extra hook to determine where in the kernel you are.

Either we make capable fine grained enough (64 or 128bit capability
vectors, I have some old code for that around and I know SGI used that
more than a year ago) or we replace the capable in those cases with hooks
entirely.

2002-09-27 16:49:55

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, Sep 27, 2002 at 08:09:50AM -0400, Stephen Smalley wrote:
>
> On Fri, 27 Sep 2002, Christoph Hellwig wrote:
>
> > Sorry, but this is bullshit (like most of the lsm changes). Either you
> > leave the capable in and say it's enough or you add your random hook
> > and remove that one. Just adding more and more hooks without thinking
> > gets us exactly nowhere except to an unmaintainable codebase.
>
> The LSM hooks are primarily restrictive, i.e. a security module can deny
> access that would normally be granted by the existing Linux access checks.

In 2.5 LSM hooks are part of the Linux access checks, and any reason to
make your patch less intrusive inb 2.4 doesn't apply anymore. Having
two checks for the same thing is indeed very bad in will cause harm
and maintaince burden in the long term. Don't do it.

> > Also is there a _real_ need to pass in all the arguments?
>
> Define _real_.

Show me a useful example that needs this argument.

> It is true that none of the existing open source security
> modules presently use this particular hook. SELinux doesn't presently use
> it, but it seems reasonable to support finer-grained control over ioperm()
> than the all-or-nothing CAP_SYS_RAWIO. Is the criteria that every hook
> and every parameter to every hook must be used by an existing open source
> security module? If so, then yes, this hook can be dropped.

Linus traditionally uses a keep it simple approach and so far that has helped
a lot to keep the system in a maintainable state. Given that these `hooks
allow plugin in large, unaudited codebases like selinux or even propritary
modules this seems even more important to me.

> In sys_create_module, you only know the name and size of the module and
> who is performing the operation. In sys_init_module, you actually have
> information about the module available. Hence, you can make a
> finer-grained decision in the module_initialize hook, and possibly deny
> even after a successful module_create. As above, SELinux doesn't use
> these hooks presently.

And WTF is the use a security policy that checks module arguments? Do
you want to disallow options that are quotes from books on the index
or not political correct enough for a US state agency?

2002-09-27 16:52:15

by Greg KH

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, Sep 27, 2002 at 05:48:49PM +0100, Christoph Hellwig wrote:
> > capable is needed to be checked, as we are not modifying the existing
> > permission logic.
>
> I odn't think it makes sense to have two security checks that both
> end up in the LSM code after each other..

For cases like the module_* hooks, and the other examples you pointed
out, I agree.

For other cases, capable() is just not fine grained enough to actually
know what is going on (like CAP_SYS_ADMIN). In those cases you need an
extra hook to determine where in the kernel you are.

thanks,

greg k-h

2002-09-27 17:21:40

by Greg KH

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, Sep 27, 2002 at 06:01:18PM +0100, Christoph Hellwig wrote:
> On Fri, Sep 27, 2002 at 09:55:56AM -0700, Greg KH wrote:
> > For cases like the module_* hooks, and the other examples you pointed
> > out, I agree.
> >
> > For other cases, capable() is just not fine grained enough to actually
> > know what is going on (like CAP_SYS_ADMIN). In those cases you need an
> > extra hook to determine where in the kernel you are.
>
> Either we make capable fine grained enough (64 or 128bit capability
> vectors, I have some old code for that around and I know SGI used that
> more than a year ago) or we replace the capable in those cases with hooks
> entirely.

I don't have a problem with either of these things, but don't see them
being completed any time soon. Unless you have some time to work on
this?

thanks,

greg k-h

2002-09-27 18:03:57

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, 27 Sep 2002 17:55:10 BST, Christoph Hellwig said:

> And WTF is the use a security policy that checks module arguments? Do
> you want to disallow options that are quotes from books on the index
> or not political correct enough for a US state agency?

How about a security policy that says:

1) Thou mayest do an 'modprobe wvlan_cs'

2) Thou mayest not do 'modprobe wvlan_cs eth=0'.

'eth=0' causes it to create the interface as 'wvlan0' 'wvlan1' etc rather
than 'eth0', 'eth1', etc. This makes a difference if you have iptables
rules that say '-i eth+' or '-i wvlan+' that implement different rulesets
for wireless and hard-wired connections.
--
Valdis Kletnieks
Computer Systems Senior Engineer
Virginia Tech


Attachments:
(No filename) (226.00 B)

2002-09-27 18:14:27

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, Sep 27, 2002 at 02:09:02PM -0400, [email protected] wrote:
> On Fri, 27 Sep 2002 17:55:10 BST, Christoph Hellwig said:
>
> > And WTF is the use a security policy that checks module arguments? Do
> > you want to disallow options that are quotes from books on the index
> > or not political correct enough for a US state agency?
>
> How about a security policy that says:
>
> 1) Thou mayest do an 'modprobe wvlan_cs'
>
> 2) Thou mayest not do 'modprobe wvlan_cs eth=0'.
>
> 'eth=0' causes it to create the interface as 'wvlan0' 'wvlan1' etc rather
> than 'eth0', 'eth1', etc. This makes a difference if you have iptables
> rules that say '-i eth+' or '-i wvlan+' that implement different rulesets
> for wireless and hard-wired connections.

So I have to download the driver source and change the parameter
to i_m_to_fscking_intelligent_for_the_nsa_eth=0?

2002-09-27 18:49:15

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, 27 Sep 2002 19:19:43 BST, Christoph Hellwig said:

> So I have to download the driver source and change the parameter
> to i_m_to_fscking_intelligent_for_the_nsa_eth=0?

By the same token, at that point you can download the kernel source and
build it without LSM. What I showed was a way to bypass the iptables
rules set up *WITHOUT REPLACING A MODULE* (which might be detected by
tripwire, or totally refused because the LSM rejects any writes in /lib/modules).



--
Valdis Kletnieks
Computer Systems Senior Engineer
Virginia Tech


Attachments:
(No filename) (226.00 B)

2002-09-27 18:55:45

by Stephen Smalley

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38


On Fri, 27 Sep 2002, Christoph Hellwig wrote:

> In 2.5 LSM hooks are part of the Linux access checks, and any reason to
> make your patch less intrusive inb 2.4 doesn't apply anymore. Having
> two checks for the same thing is indeed very bad in will cause harm
> and maintaince burden in the long term. Don't do it.

So you want to move the 'if (turn_on && !capable(CAP_SYS_RAWIO)) return
-EPERM;' from the base kernel into the security module's ioperm() hook
function, in addition to whatever additional logic the module may
implement? [Assuming for the moment that we kept the ioperm() hook, even
though that isn't likely given its current lack of use and
architecture-specific nature].

If so, what about the rest of the kernel access checking logic? Do you
want all of the permission() logic pushed into the security module's
inode_permission() hook function? Do you want the bad_signal() logic
pushed into the security module's task_kill() hook function? That kind of
change was considered and discussed on linux-security-module long ago, but
it will yield a very invasive patch for very little gain. It also
requires cleanly separating all access checking logic from functional
logic (it is sometimes fairly intertwined) and determining exactly which
is which (e.g. is enforcing a read-only mount a security behavior or a
functional behavior?).

> Show me a useful example that needs this argument.

Do you want every process that can use ioperm() to be able to access the
full range of ports accessible by that call? If not, then you need
something finer-grained than CAP_SYS_RAWIO. But as I said, we don't
presently use this hook, and it is architecture-dependent.

> And WTF is the use a security policy that checks module arguments? Do
> you want to disallow options that are quotes from books on the index
> or not political correct enough for a US state agency?

The LSM module_initialize hook is called with a pointer to the kernel's
copy of the relocated module image with the struct module header. Hence,
the security module is free to perform whatever validation it wants on
that image prior to the execution of the init function. But if the
criteria is that there must be a specific existing security module that
uses the hook, then this one will go away too.

--
Stephen D. Smalley, NAI Labs
[email protected]



2002-09-27 18:54:02

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, Sep 27, 2002 at 02:54:25PM -0400, [email protected] wrote:
> By the same token, at that point you can download the kernel source and
> build it without LSM. What I showed was a way to bypass the iptables
> rules set up *WITHOUT REPLACING A MODULE* (which might be detected by
> tripwire, or totally refused because the LSM rejects any writes in /lib/modules).

insmod doesn't require modules to be in /lib/modules. Anyway I could even change
the device name _after_ it was loaded. this is linux and not BSD..

Given that we really want to fine-grained control who's netdevice can get what
names we'd` better place a hook in dev_alloc_name.

And that's my whole point: LSM adds random hooks all over the place without
even thinking what they intend to protect.

2002-09-30 09:10:42

by Chris Wright

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

* Christoph Hellwig ([email protected]) wrote:
>
> > if (turn_on && !capable(CAP_SYS_RAWIO))
> > return -EPERM;
> > -
> > +
> > + ret = security_ops->ioperm(from, num, turn_on);
> > + if (ret) {
> > + return ret;
> > + }
> > +
>
> Sorry, but this is bullshit (like most of the lsm changes). Either you
> leave the capable in and say it's enough or you add your random hook
> and remove that one.

I agree, this is the way started, however it touches so much driver code
(not to mention core code) that it seemed likely to be rejected. I'm
all for replacing capable() calls, but it's not a consistent interface
and can't always be simply exchanged. I see no reason not to remove the
obvious ones right away.

> Just adding more and more hooks without thinking
> gets us exactly nowhere except to an unmaintainable codebase.

Your point is well-taken. Of course, we do not want to produce
unmaintainable code. The hook creation/placement has been thought about
and discussed quite a bit.

> Also is there a _real_ need to pass in all the arguments?

It was placed there as an obvious contol point over which ioports
could be accessed. We will definitely revisit this since it's not being
used.

> > + * @module_create:
> > + * Check the permission before allocating space for a module.
> > + * @name contains the module name.
> > + * @size contains the module size.
> > + * Return 0 if permission is granted.
> > + * @module_initialize:
> > + * Check permission before initializing a module.
> > + * @mod contains a pointer to the module being initialized.
> > + * Return 0 if permission is granted.
>
> Umm, you can't tell me you deny someone to initialize a module he has
> just created?

Coming from two separate system calls there is no guarantee the
callers will be in the same execution domain.

> > + * @sethostname:
> > + * Check permission before the hostname is set to @hostname.
> > + * @hostname contains the new hostname
> > + * Return 0 if permission is granted.
> > + * @setdomainname:
> > + * Check permission before the domainname is set to @domainname.
> > + * @domainname contains the new domainname
> > + * Return 0 if permission is granted.
>
> You don't think this should maybe be just one hook?

sure, uts releated hooks could be collapsed.

> You might be allowed to swapon but not swapoff?

yes, again there is no assumption the execution domains would be the
same.

> > +static int cap_swapoff (struct swap_info_struct *swap)
> > +{
> > + return 0;
> > +}
>
> Live would be a lot simple if an unimplemented op would behave
> as returning zero..

Yes, I agree. We've had a few patches that did this, nothing
committed to the LSM tree currently.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2002-09-30 14:16:09

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, 27 Sep 2002 19:59:19 BST, Christoph Hellwig said:

> insmod doesn't require modules to be in /lib/modules.

This would probably be closed by this code in sys_create_module():

/* check that we have permission to do this */
error = security_ops->module_ops->create_module(name, size);
if (error)
goto err1;

Similarly, there are other hooks that will stop renaming of the interface (I
have to admit I haven't had enough caffeine to verify whether doing a /bin/mv
to rename an interface will change the name that's presented to the iptables
rulesets), or did you have other "rename" methods in mind?

> Given that we really want to fine-grained control who's netdevice can get what
> names we'd` better place a hook in dev_alloc_name.

However, you're missing the point - I was using that as *AN EXAMPLE* of "you
might want to check what parameters are being passed". Are you prepared to
make the same sort of analysis for *EVERY* parameter of *every* module, and
every combination thereof (including interacting parameters of different
modules)?

In order to assert that the hook to check parameters in module loading is
useless, you'd have to verify that there exist *NO* modules that can have their
security status changed by changing the parameters. And even more importantly,
you'd have to make this a permanent restriction on module parameters,
which puts the onus on "getting it right" on the module author, rather than
on the LSM author who's in a better position to know what is/isn't acceptable
for his module.

> And that's my whole point: LSM adds random hooks all over the place without
> even thinking what they intend to protect.

And quite a bit of thought *did* go into it - a *LOT* of those hooks got added
along the way precisely *because* the writers of a module found that they were
trying to enforce a policy, and found it could be backdoored by means like
module parameters. Yes, there are some hooks that are unused by anything
at the current time (and there's discussion on the LSM list about pruning those
hooks), but I'll bet if you ask "why is hook XYZ in there?" on the LSM list,
somebody will be able to reply with "to close the hole of ABC".



--
Valdis Kletnieks
Computer Systems Senior Engineer
Virginia Tech


Attachments:
(No filename) (226.00 B)

2002-09-30 14:39:45

by Alan

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Mon, 2002-09-30 at 15:19, [email protected] wrote:
> On Fri, 27 Sep 2002 19:59:19 BST, Christoph Hellwig said:
>
> > insmod doesn't require modules to be in /lib/modules.
>
> This would probably be closed by this code in sys_create_module():
>
> /* check that we have permission to do this */
> error = security_ops->module_ops->create_module(name, size);
> if (error)
> goto err1;

This is part of the problem as ever. The name that is used is
meaningless. The module loader needs to make meaningful decisions. That
really means it needs to be able to see the actual loaded module. If we
go to Rusty's kernel module loader then we can fix this because we can
pass the actual module code/data block and sizes to the LSM. At that
point the LSM can do meaningful things like GPG.

In the current form you can say that module creation can only be done by
the right kind of user, and the program "insmod", but even in this case
the module name fed to the LSM seems worthless


2002-10-01 16:52:20

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Mon, Sep 30, 2002 at 10:19:18AM -0400, [email protected] wrote:
> On Fri, 27 Sep 2002 19:59:19 BST, Christoph Hellwig said:
>
> > insmod doesn't require modules to be in /lib/modules.
>
> This would probably be closed by this code in sys_create_module():
>
> /* check that we have permission to do this */
> error = security_ops->module_ops->create_module(name, size);
> if (error)
> goto err1;
>

It wouldn't. sys_create_module doesn't get the absolute path of the module passed.

> Similarly, there are other hooks that will stop renaming of the interface (I
> have to admit I haven't had enough caffeine to verify whether doing a /bin/mv
> to rename an interface will change the name that's presented to the iptables
> rulesets), or did you have other "rename" methods in mind?

For gods sake, what interface do you want to /bin/mv? network device don't have
associated special files in Linux (or BSD). I'm talking about SIOCSIFNAME.

> However, you're missing the point - I was using that as *AN EXAMPLE* of "you
> might want to check what parameters are being passed". Are you prepared to
> make the same sort of analysis for *EVERY* parameter of *every* module, and
> every combination thereof (including interacting parameters of different
> modules)?

If I wanted to implement a trusted system: yes. I you wanted and paid me
enough for it: also yes. And that's exactly my point. If you want a
trusted system you're not done by adding a few hooks in places that look
strategic, you have to a proper audit of _all_ code in your project.

Let me repeat _ALL_ code. Yes, you have to understand WTF is going on,
and that's where LSM fail miserably.

> In order to assert that the hook to check parameters in module loading is
> useless, you'd have to verify that there exist *NO* modules that can have their
> security status changed by changing the parameters.

Noooh! You got something very wrong. You (or rather the LSM people) want to
add a new feature, and they have to prove it useful. An as long as there is no
standard on what a specific string in a module option means for the kernel
in the end such a check is pretty damn useless.

> And even more importantly,
> you'd have to make this a permanent restriction on module parameters,
> which puts the onus on "getting it right" on the module author, rather than
> on the LSM author who's in a better position to know what is/isn't acceptable
> for his module.

How does the lsm author know what the option x=y means for my module? In my
module a it means print lots of nice windowish nagscreen, but in my friend
Paul's module (who works for the German BND) it means scribble all over my
disk because only someone who has stolen the notebook might be stupid
enough to use such a silly option.

See what I mean?


> And quite a bit of thought *did* go into it - a *LOT* of those hooks got added
> along the way precisely *because* the writers of a module found that they were
> trying to enforce a policy, and found it could be backdoored by means like
> module parameters.

>From my reading of the LSM lists a hgook usually got added because author A
of the unaudited module B though that it might help him in imlpementing what
he and only he thinks his module should do if it worked properly.

2002-10-01 17:08:27

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Fri, Sep 27, 2002 at 03:00:03PM -0400, Stephen Smalley wrote:
> So you want to move the 'if (turn_on && !capable(CAP_SYS_RAWIO)) return
> -EPERM;' from the base kernel into the security module's ioperm() hook
> function, in addition to whatever additional logic the module may
> implement? [Assuming for the moment that we kept the ioperm() hook, even
> though that isn't likely given its current lack of use and
> architecture-specific nature].

Exactly.
>
> If so, what about the rest of the kernel access checking logic? Do you
> want all of the permission() logic pushed into the security module's
> inode_permission() hook function?

permission() switches into per-fs code.

> Do you want the bad_signal() logic
> pushed into the security module's task_kill() hook function?

Only the capable() check. Unless of course we make uid/gid checking optional.
Which seems like a very bad idea given the mess even with just the current LSM
hooks.

> That kind of
> change was considered and discussed on linux-security-module long ago, but
> it will yield a very invasive patch for very little gain. It also
> requires cleanly separating all access checking logic from functional
> logic (it is sometimes fairly intertwined) and determining exactly which
> is which

Umm. Clean and nicely separated code is a lot of gain. Making Linux's
access clean instead of a lot more messy is a good think. Much better than
any feature addition. (Unless, of course, you get paid for adding
features..)


> (e.g. is enforcing a read-only mount a security behavior or a
> functional behavior?).

For the kernel it's a functional behavior. The administrator can chose
to apply it for security reasons, but that's policy and thus not the
kernel's issue.

>
> > Show me a useful example that needs this argument.
>
> Do you want every process that can use ioperm() to be able to access the
> full range of ports accessible by that call? If not, then you need
> something finer-grained than CAP_SYS_RAWIO. But as I said, we don't
> presently use this hook, and it is architecture-dependent.

Okay, this does actually makes sense. Point taken.

>
> > And WTF is the use a security policy that checks module arguments? Do
> > you want to disallow options that are quotes from books on the index
> > or not political correct enough for a US state agency?
>
> The LSM module_initialize hook is called with a pointer to the kernel's
> copy of the relocated module image with the struct module header. Hence,
> the security module is free to perform whatever validation it wants on
> that image prior to the execution of the init function. But if the
> criteria is that there must be a specific existing security module that
> uses the hook, then this one will go away too.

Yes, a hook without a intree user or at least a properly defined and
available out-of-tree user is pointless.

2002-10-02 17:50:17

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Tue, 01 Oct 2002 17:55:00 BST, Christoph Hellwig said:

> For gods sake, what interface do you want to /bin/mv? network device don't have
> associated special files in Linux (or BSD). I'm talking about SIOCSIFNAME.

Well, I figured that you must have meant something else, since ioctl() is
hooked, so an attacker couldn't use THAT method if the security module didn't
want him to.

Of course, that means we probably should pull that ioctl() hook too, since
obviously there's ways to bypass it. And at that point, we may as well
pull the OTHER hooks too. Hmm.. I'm starting to see a pattern here. ;)

So we shouldn't deploy a check on module parameters to prevent renaming
an interface, and we shouldn't bother having OTHER checks to stop it
because they could always load a module and bypass it - if you feel THAT
strongly that the whole concept of a security framework is that pointless,
you're free not to use it. ;)

> How does the lsm author know what the option x=y means for my module? In my

Umm.. the same way that *I* noticed that 'eth=0' has a security implication.

It seems to me that you're arguing both sides here - first you say that
a full code audit is needed so you know 'WTF is going on', and then you're
saying that it's impossible to know.

Either that, or you're saying "yes you can do a code audit, but having identified
module parameters that are *KNOWN* to be a problem, you're not allowed to stop
them".

> From my reading of the LSM lists a hgook usually got added because author A
> of the unaudited module B though that it might help him in imlpementing what
> he and only he thinks his module should do if it worked properly.

OK - so to summarize: You're saying that somebody conceives of a reasonable
security model, finds a set of 10 or 15 hooks that implement 95% of what
he needs, but there's a code path that a hook doesn't catch that lets a user
subvert the model - and then it's a *BAD THING* that the kernel be modified
to *actually solve a problem*?

Somehow, this goes against the whole spirit of the Linux kernel - I wonder
what miniscule percent of the current kernel wasn't done to solve a problem...
--
Valdis Kletnieks
Computer Systems Senior Engineer
Virginia Tech


Attachments:
(No filename) (226.00 B)

2002-10-02 18:34:14

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Wed, Oct 02, 2002 at 01:55:14PM -0400, [email protected] wrote:
> On Tue, 01 Oct 2002 17:55:00 BST, Christoph Hellwig said:
>
> > For gods sake, what interface do you want to /bin/mv? network device don't have
> > associated special files in Linux (or BSD). I'm talking about SIOCSIFNAME.
>
> Well, I figured that you must have meant something else, since ioctl() is
> hooked, so an attacker couldn't use THAT method if the security module didn't
> want him to.

Just that no 'security' module implements a special handler for it. E.g. in
selinux it ends up in

/* default case assumes that the command will go
* to the file's ioctl() function.
*/
default:
error = file_has_perm(current, file, FILE__IOCTL);

> Of course, that means we probably should pull that ioctl() hook too, since
> obviously there's ways to bypass it.

Right. an hook for ->ioctl() is completly useless. Remember that ioctl
is nothing but a magic backdoor to add syscalls. You need to do the
permission check in code that actually knows what it is doing, not in
the dispatcher.

> So we shouldn't deploy a check on module parameters to prevent renaming
> an interface, and we shouldn't bother having OTHER checks to stop it
> because they could always load a module and bypass it

You should add a check where the name isactually assigned in this case.
Not that I think a check on the device name is generally a good idea..

> - if you feel THAT
> strongly that the whole concept of a security framework is that pointless,
> you're free not to use it. ;)

You've missed the point. I never wanted to use it. I care about the crap
that it adds to the kernel which I do want to use, develop and keep
clean.

> > How does the lsm author know what the option x=y means for my module? In my
>
> Umm.. the same way that *I* noticed that 'eth=0' has a security implication.

Without ever seeing that module?

> It seems to me that you're arguing both sides here - first you say that
> a full code audit is needed so you know 'WTF is going on', and then you're
> saying that it's impossible to know.

The person who performs the audit can know it. But how often will that be
the author of the LSM module?

> OK - so to summarize: You're saying that somebody conceives of a reasonable
> security model, finds a set of 10 or 15 hooks that implement 95% of what
> he needs, but there's a code path that a hook doesn't catch that lets a user
> subvert the model - and then it's a *BAD THING* that the kernel be modified
> to *actually solve a problem*?

It's not bad to solve a problem. It's a bad idea trying to 'solve' a problem
you don';t understand fully.

> Somehow, this goes against the whole spirit of the Linux kernel - I wonder
> what miniscule percent of the current kernel wasn't done to solve a problem...

Adding random hack without resolving the underlying problem is not the
way linux kernel development usually works.

2002-10-02 22:50:21

by Seth Arnold

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Wed, Oct 02, 2002 at 07:39:40PM +0100, Christoph Hellwig wrote:
> > It seems to me that you're arguing both sides here - first you say that
> > a full code audit is needed so you know 'WTF is going on', and then you're
> > saying that it's impossible to know.
>
> The person who performs the audit can know it. But how often will that be
> the author of the LSM module?

We've said on this list a few times that it is important for security
module authors to understand the implications of their decisions.
Deciding to not mediate module parameters is a valid decision. Deciding
to mediate module parameters is a valid decision. One requires very
little thought and sidesteps the matter entirely. The other requires
quite a bit of thought and is difficult to get right -- but that is not
a problem for LSM, per se; it is for the authors of security modules.


--
http://immunix.org/


Attachments:
(No filename) (890.00 B)
(No filename) (240.00 B)
Download all attachments

2002-10-02 22:55:18

by Alan

[permalink] [raw]
Subject: Re: [RFC] LSM changes for 2.5.38

On Wed, 2002-10-02 at 23:55, Seth Arnold wrote:
> We've said on this list a few times that it is important for security
> module authors to understand the implications of their decisions.
> Deciding to not mediate module parameters is a valid decision. Deciding
> to mediate module parameters is a valid decision. One requires very
> little thought and sidesteps the matter entirely. The other requires
> quite a bit of thought and is difficult to get right -- but that is not
> a problem for LSM, per se; it is for the authors of security modules.

In many cases I disagree. Garbage in - garbage out. That goes for
security policy decisions as well as the revenue. The security modules
must get data that is sufficient to make the decision, locked correctly
and with a defined scope and lifespan.

For example passing an ascii path without thought is useless because you
would race name lookups against things like symlinks. The same goes for
audit stuff which is one of the reasons snare needs a lot of work yet


Alan