Merge branch 'master' into next
authorJames Morris <jmorris@namei.org>
Mon, 10 Aug 2009 22:33:01 +0000 (08:33 +1000)
committerJames Morris <jmorris@namei.org>
Mon, 10 Aug 2009 22:33:01 +0000 (08:33 +1000)
32 files changed:
fs/locks.c
include/linux/cred.h
include/linux/lsm_audit.h
include/linux/mm.h
include/linux/sched.h
include/linux/security.h
kernel/ptrace.c
kernel/sysctl.c
lib/is_single_threaded.c
mm/Kconfig
mm/mmap.c
mm/nommu.c
security/Kconfig
security/Makefile
security/capability.c
security/commoncap.c
security/keys/proc.c
security/keys/process_keys.c
security/min_addr.c [new file with mode: 0644]
security/security.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/avc.h
security/selinux/ss/services.c
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/tomoyo/common.c
security/tomoyo/common.h
security/tomoyo/domain.c
security/tomoyo/tomoyo.c
security/tomoyo/tomoyo.h

index b6440f5..52366e8 100644 (file)
@@ -1591,7 +1591,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
        if (can_sleep)
                lock->fl_flags |= FL_SLEEP;
 
-       error = security_file_lock(filp, cmd);
+       error = security_file_lock(filp, lock->fl_type);
        if (error)
                goto out_free;
 
index 4fa9996..b3c76e8 100644 (file)
@@ -186,7 +186,8 @@ static inline struct cred *get_new_cred(struct cred *cred)
  */
 static inline const struct cred *get_cred(const struct cred *cred)
 {
-       return get_new_cred((struct cred *) cred);
+       struct cred *nonconst_cred = (struct cred *) cred;
+       return get_new_cred(nonconst_cred);
 }
 
 /**
index e461b2c..a5514a3 100644 (file)
@@ -66,16 +66,19 @@ struct common_audit_data {
                } key_struct;
 #endif
        } u;
-       const char *function;
        /* this union contains LSM specific data */
        union {
+#ifdef CONFIG_SECURITY_SMACK
                /* SMACK data */
                struct smack_audit_data {
+                       const char *function;
                        char *subject;
                        char *object;
                        char *request;
                        int result;
                } smack_audit_data;
+#endif
+#ifdef CONFIG_SECURITY_SELINUX
                /* SELinux data */
                struct {
                        u32 ssid;
@@ -86,7 +89,8 @@ struct common_audit_data {
                        struct av_decision *avd;
                        int result;
                } selinux_audit_data;
-       } lsm_priv;
+#endif
+       };
        /* these callback will be implemented by a specific LSM */
        void (*lsm_pre_audit)(struct audit_buffer *, void *);
        void (*lsm_post_audit)(struct audit_buffer *, void *);
@@ -104,7 +108,7 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
 /* Initialize an LSM audit data structure. */
 #define COMMON_AUDIT_DATA_INIT(_d, _t) \
        { memset((_d), 0, sizeof(struct common_audit_data)); \
-        (_d)->type = LSM_AUDIT_DATA_##_t; (_d)->function = __func__; }
+        (_d)->type = LSM_AUDIT_DATA_##_t; }
 
 void common_lsm_audit(struct common_audit_data *a);
 
index ba3a7cb..9a72cc7 100644 (file)
@@ -34,8 +34,6 @@ extern int sysctl_legacy_va_layout;
 #define sysctl_legacy_va_layout 0
 #endif
 
-extern unsigned long mmap_min_addr;
-
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -575,19 +573,6 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
 }
 
 /*
- * If a hint addr is less than mmap_min_addr change hint to be as
- * low as possible but still greater than mmap_min_addr
- */
-static inline unsigned long round_hint_to_min(unsigned long hint)
-{
-       hint &= PAGE_MASK;
-       if (((void *)hint != NULL) &&
-           (hint < mmap_min_addr))
-               return PAGE_ALIGN(mmap_min_addr);
-       return hint;
-}
-
-/*
  * Some inline functions in vmstat.h depend on page_zone()
  */
 #include <linux/vmstat.h>
index 3ab08e4..94990a8 100644 (file)
@@ -2076,7 +2076,7 @@ static inline unsigned long wait_task_inactive(struct task_struct *p,
 #define for_each_process(p) \
        for (p = &init_task ; (p = next_task(p)) != &init_task ; )
 
-extern bool is_single_threaded(struct task_struct *);
+extern bool current_is_single_threaded(void);
 
 /*
  * Careful: do_each_thread/while_each_thread is a double loop so
index 5eff459..57ead99 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/resource.h>
 #include <linux/sem.h>
 #include <linux/shm.h>
+#include <linux/mm.h> /* PAGE_ALIGN */
 #include <linux/msg.h>
 #include <linux/sched.h>
 #include <linux/key.h>
@@ -52,7 +53,7 @@ struct audit_krule;
 extern int cap_capable(struct task_struct *tsk, const struct cred *cred,
                       int cap, int audit);
 extern int cap_settime(struct timespec *ts, struct timezone *tz);
-extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
+extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
 extern int cap_ptrace_traceme(struct task_struct *parent);
 extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
 extern int cap_capset(struct cred *new, const struct cred *old,
@@ -66,6 +67,9 @@ extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
 extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
 extern int cap_inode_need_killpriv(struct dentry *dentry);
 extern int cap_inode_killpriv(struct dentry *dentry);
+extern int cap_file_mmap(struct file *file, unsigned long reqprot,
+                        unsigned long prot, unsigned long flags,
+                        unsigned long addr, unsigned long addr_only);
 extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags);
 extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                          unsigned long arg4, unsigned long arg5);
@@ -92,6 +96,7 @@ extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
 extern int cap_netlink_recv(struct sk_buff *skb, int cap);
 
 extern unsigned long mmap_min_addr;
+extern unsigned long dac_mmap_min_addr;
 /*
  * Values used in the task_security_ops calls
  */
@@ -116,6 +121,21 @@ struct request_sock;
 #define LSM_UNSAFE_PTRACE      2
 #define LSM_UNSAFE_PTRACE_CAP  4
 
+/*
+ * If a hint addr is less than mmap_min_addr change hint to be as
+ * low as possible but still greater than mmap_min_addr
+ */
+static inline unsigned long round_hint_to_min(unsigned long hint)
+{
+       hint &= PAGE_MASK;
+       if (((void *)hint != NULL) &&
+           (hint < mmap_min_addr))
+               return PAGE_ALIGN(mmap_min_addr);
+       return hint;
+}
+extern int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp,
+                                void __user *buffer, size_t *lenp, loff_t *ppos);
+
 #ifdef CONFIG_SECURITY
 
 struct security_mnt_opts {
@@ -1209,7 +1229,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @alter contains the flag indicating whether changes are to be made.
  *     Return 0 if permission is granted.
  *
- * @ptrace_may_access:
+ * @ptrace_access_check:
  *     Check permission before allowing the current process to trace the
  *     @child process.
  *     Security modules may also want to perform a process tracing check
@@ -1224,7 +1244,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     Check that the @parent process has sufficient permission to trace the
  *     current process before allowing the current process to present itself
  *     to the @parent process for tracing.
- *     The parent process will still have to undergo the ptrace_may_access
+ *     The parent process will still have to undergo the ptrace_access_check
  *     checks before it is allowed to trace this one.
  *     @parent contains the task_struct structure for debugger process.
  *     Return 0 if permission is granted.
@@ -1336,7 +1356,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
 struct security_operations {
        char name[SECURITY_NAME_MAX + 1];
 
-       int (*ptrace_may_access) (struct task_struct *child, unsigned int mode);
+       int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
        int (*ptrace_traceme) (struct task_struct *parent);
        int (*capget) (struct task_struct *target,
                       kernel_cap_t *effective,
@@ -1617,7 +1637,7 @@ extern int security_module_enable(struct security_operations *ops);
 extern int register_security(struct security_operations *ops);
 
 /* Security operations */
-int security_ptrace_may_access(struct task_struct *child, unsigned int mode);
+int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
 int security_ptrace_traceme(struct task_struct *parent);
 int security_capget(struct task_struct *target,
                    kernel_cap_t *effective,
@@ -1798,10 +1818,10 @@ static inline int security_init(void)
        return 0;
 }
 
-static inline int security_ptrace_may_access(struct task_struct *child,
+static inline int security_ptrace_access_check(struct task_struct *child,
                                             unsigned int mode)
 {
-       return cap_ptrace_may_access(child, mode);
+       return cap_ptrace_access_check(child, mode);
 }
 
 static inline int security_ptrace_traceme(struct task_struct *parent)
@@ -2197,9 +2217,7 @@ static inline int security_file_mmap(struct file *file, unsigned long reqprot,
                                     unsigned long addr,
                                     unsigned long addr_only)
 {
-       if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO))
-               return -EACCES;
-       return 0;
+       return cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
 }
 
 static inline int security_file_mprotect(struct vm_area_struct *vma,
index 082c320..307c285 100644 (file)
@@ -152,7 +152,7 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
        if (!dumpable && !capable(CAP_SYS_PTRACE))
                return -EPERM;
 
-       return security_ptrace_may_access(task, mode);
+       return security_ptrace_access_check(task, mode);
 }
 
 bool ptrace_may_access(struct task_struct *task, unsigned int mode)
index 98e0232..58be760 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/acpi.h>
 #include <linux/reboot.h>
 #include <linux/ftrace.h>
+#include <linux/security.h>
 #include <linux/slow-work.h>
 #include <linux/perf_counter.h>
 
@@ -1306,10 +1307,10 @@ static struct ctl_table vm_table[] = {
        {
                .ctl_name       = CTL_UNNUMBERED,
                .procname       = "mmap_min_addr",
-               .data           = &mmap_min_addr,
-               .maxlen         = sizeof(unsigned long),
+               .data           = &dac_mmap_min_addr,
+               .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = &mmap_min_addr_handler,
        },
 #ifdef CONFIG_NUMA
        {
index f1ed2fe..bd2bea9 100644 (file)
 
 #include <linux/sched.h>
 
-/**
- * is_single_threaded - Determine if a thread group is single-threaded or not
- * @p: A task in the thread group in question
- *
- * This returns true if the thread group to which a task belongs is single
- * threaded, false if it is not.
+/*
+ * Returns true if the task does not share ->mm with another thread/process.
  */
-bool is_single_threaded(struct task_struct *p)
+bool current_is_single_threaded(void)
 {
-       struct task_struct *g, *t;
-       struct mm_struct *mm = p->mm;
+       struct task_struct *task = current;
+       struct mm_struct *mm = task->mm;
+       struct task_struct *p, *t;
+       bool ret;
 
-       if (atomic_read(&p->signal->count) != 1)
-               goto no;
+       if (atomic_read(&task->signal->live) != 1)
+               return false;
 
-       if (atomic_read(&p->mm->mm_users) != 1) {
-               read_lock(&tasklist_lock);
-               do_each_thread(g, t) {
-                       if (t->mm == mm && t != p)
-                               goto no_unlock;
-               } while_each_thread(g, t);
-               read_unlock(&tasklist_lock);
-       }
+       if (atomic_read(&mm->mm_users) == 1)
+               return true;
 
-       return true;
+       ret = false;
+       rcu_read_lock();
+       for_each_process(p) {
+               if (unlikely(p->flags & PF_KTHREAD))
+                       continue;
+               if (unlikely(p == task->group_leader))
+                       continue;
+
+               t = p;
+               do {
+                       if (unlikely(t->mm == mm))
+                               goto found;
+                       if (likely(t->mm))
+                               break;
+                       /*
+                        * t->mm == NULL. Make sure next_thread/next_task
+                        * will see other CLONE_VM tasks which might be
+                        * forked before exiting.
+                        */
+                       smp_rmb();
+               } while_each_thread(p, t);
+       }
+       ret = true;
+found:
+       rcu_read_unlock();
 
-no_unlock:
-       read_unlock(&tasklist_lock);
-no:
-       return false;
+       return ret;
 }
index c948d4c..fe5f674 100644 (file)
@@ -225,9 +225,9 @@ config DEFAULT_MMAP_MIN_ADDR
          For most ia64, ppc64 and x86 users with lots of address space
          a value of 65536 is reasonable and should cause no problems.
          On arm and other archs it should not be higher than 32768.
-         Programs which use vm86 functionality would either need additional
-         permissions from either the LSM or the capabilities module or have
-         this protection disabled.
+         Programs which use vm86 functionality or have some need to map
+         this low address space will need CAP_SYS_RAWIO or disable this
+         protection by setting the value to 0.
 
          This value can be changed after boot using the
          /proc/sys/vm/mmap_min_addr tunable.
index 34579b2..8101de4 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -88,9 +88,6 @@ int sysctl_overcommit_ratio = 50;     /* default is 50% */
 int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
 struct percpu_counter vm_committed_as;
 
-/* amount of vm to protect from userspace access */
-unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
-
 /*
  * Check that a process has enough memory to allocate a new virtual
  * mapping. 0 means there is enough memory for the allocation to
index 53cab10..28754c4 100644 (file)
@@ -69,9 +69,6 @@ int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
 int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS;
 int heap_stack_gap = 0;
 
-/* amount of vm to protect from userspace access */
-unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
-
 atomic_long_t mmap_pages_allocated;
 
 EXPORT_SYMBOL(mem_map);
index d23c839..9c60c34 100644 (file)
@@ -113,6 +113,22 @@ config SECURITY_ROOTPLUG
 
          If you are unsure how to answer this question, answer N.
 
+config LSM_MMAP_MIN_ADDR
+       int "Low address space for LSM to from user allocation"
+       depends on SECURITY && SECURITY_SELINUX
+       default 65535
+       help
+         This is the portion of low virtual memory which should be protected
+         from userspace allocation.  Keeping a user from writing to low pages
+         can help reduce the impact of kernel NULL pointer bugs.
+
+         For most ia64, ppc64 and x86 users with lots of address space
+         a value of 65536 is reasonable and should cause no problems.
+         On arm and other archs it should not be higher than 32768.
+         Programs which use vm86 functionality or have some need to map
+         this low address space will need the permission specific to the
+         systems running LSM.
+
 source security/selinux/Kconfig
 source security/smack/Kconfig
 source security/tomoyo/Kconfig
index c67557c..b56e7f9 100644 (file)
@@ -8,7 +8,7 @@ subdir-$(CONFIG_SECURITY_SMACK)         += smack
 subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 
 # always enable default capabilities
-obj-y          += commoncap.o
+obj-y          += commoncap.o min_addr.o
 
 # Object file lists
 obj-$(CONFIG_SECURITY)                 += security.o capability.o
index 21b6cea..ec05730 100644 (file)
@@ -330,15 +330,6 @@ static int cap_file_ioctl(struct file *file, unsigned int command,
        return 0;
 }
 
-static int cap_file_mmap(struct file *file, unsigned long reqprot,
-                        unsigned long prot, unsigned long flags,
-                        unsigned long addr, unsigned long addr_only)
-{
-       if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO))
-               return -EACCES;
-       return 0;
-}
-
 static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
                             unsigned long prot)
 {
@@ -863,7 +854,7 @@ struct security_operations default_security_ops = {
 
 void security_fixup_ops(struct security_operations *ops)
 {
-       set_to_cap_if_null(ops, ptrace_may_access);
+       set_to_cap_if_null(ops, ptrace_access_check);
        set_to_cap_if_null(ops, ptrace_traceme);
        set_to_cap_if_null(ops, capget);
        set_to_cap_if_null(ops, capset);
index 48b7e02..fe30751 100644 (file)
@@ -101,7 +101,7 @@ int cap_settime(struct timespec *ts, struct timezone *tz)
 }
 
 /**
- * cap_ptrace_may_access - Determine whether the current process may access
+ * cap_ptrace_access_check - Determine whether the current process may access
  *                        another
  * @child: The process to be accessed
  * @mode: The mode of attachment.
@@ -109,7 +109,7 @@ int cap_settime(struct timespec *ts, struct timezone *tz)
  * Determine whether a process may access another, returning 0 if permission
  * granted, -ve if denied.
  */
-int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)
+int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
        int ret = 0;
 
@@ -984,3 +984,33 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
                cap_sys_admin = 1;
        return __vm_enough_memory(mm, pages, cap_sys_admin);
 }
+
+/*
+ * cap_file_mmap - check if able to map given addr
+ * @file: unused
+ * @reqprot: unused
+ * @prot: unused
+ * @flags: unused
+ * @addr: address attempting to be mapped
+ * @addr_only: unused
+ *
+ * If the process is attempting to map memory below mmap_min_addr they need
+ * CAP_SYS_RAWIO.  The other parameters to this function are unused by the
+ * capability security module.  Returns 0 if this mapping should be allowed
+ * -EPERM if not.
+ */
+int cap_file_mmap(struct file *file, unsigned long reqprot,
+                 unsigned long prot, unsigned long flags,
+                 unsigned long addr, unsigned long addr_only)
+{
+       int ret = 0;
+
+       if (addr < dac_mmap_min_addr) {
+               ret = cap_capable(current, current_cred(), CAP_SYS_RAWIO,
+                                 SECURITY_CAP_AUDIT);
+               /* set PF_SUPERPRIV if it turns out we allow the low mmap */
+               if (ret == 0)
+                       current->flags |= PF_SUPERPRIV;
+       }
+       return ret;
+}
index 769f9bd..39793c7 100644 (file)
@@ -120,6 +120,7 @@ static int proc_keys_open(struct inode *inode, struct file *file)
 }
 
 static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
+       __acquires(key_serial_lock)
 {
        struct rb_node *_p;
        loff_t pos = *_pos;
@@ -144,6 +145,7 @@ static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
 }
 
 static void proc_keys_stop(struct seq_file *p, void *v)
+       __releases(key_serial_lock)
 {
        spin_unlock(&key_serial_lock);
 }
@@ -257,6 +259,7 @@ static int proc_key_users_open(struct inode *inode, struct file *file)
 }
 
 static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
+       __acquires(key_user_lock)
 {
        struct rb_node *_p;
        loff_t pos = *_pos;
@@ -281,6 +284,7 @@ static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
 }
 
 static void proc_key_users_stop(struct seq_file *p, void *v)
+       __releases(key_user_lock)
 {
        spin_unlock(&key_user_lock);
 }
index 276d278..ed929af 100644 (file)
@@ -702,7 +702,7 @@ long join_session_keyring(const char *name)
        /* only permit this if there's a single thread in the thread group -
         * this avoids us having to adjust the creds on all threads and risking
         * ENOMEM */
-       if (!is_single_threaded(current))
+       if (!current_is_single_threaded())
                return -EMLINK;
 
        new = prepare_creds();
diff --git a/security/min_addr.c b/security/min_addr.c
new file mode 100644 (file)
index 0000000..14cc7b3
--- /dev/null
@@ -0,0 +1,49 @@
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/security.h>
+#include <linux/sysctl.h>
+
+/* amount of vm to protect from userspace access by both DAC and the LSM*/
+unsigned long mmap_min_addr;
+/* amount of vm to protect from userspace using CAP_SYS_RAWIO (DAC) */
+unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
+/* amount of vm to protect from userspace using the LSM = CONFIG_LSM_MMAP_MIN_ADDR */
+
+/*
+ * Update mmap_min_addr = max(dac_mmap_min_addr, CONFIG_LSM_MMAP_MIN_ADDR)
+ */
+static void update_mmap_min_addr(void)
+{
+#ifdef CONFIG_LSM_MMAP_MIN_ADDR
+       if (dac_mmap_min_addr > CONFIG_LSM_MMAP_MIN_ADDR)
+               mmap_min_addr = dac_mmap_min_addr;
+       else
+               mmap_min_addr = CONFIG_LSM_MMAP_MIN_ADDR;
+#else
+       mmap_min_addr = dac_mmap_min_addr;
+#endif
+}
+
+/*
+ * sysctl handler which just sets dac_mmap_min_addr = the new value and then
+ * calls update_mmap_min_addr() so non MAP_FIXED hints get rounded properly
+ */
+int mmap_min_addr_handler(struct ctl_table *table, int write, struct file *filp,
+                         void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int ret;
+
+       ret = proc_doulongvec_minmax(table, write, filp, buffer, lenp, ppos);
+
+       update_mmap_min_addr();
+
+       return ret;
+}
+
+int __init init_mmap_min_addr(void)
+{
+       update_mmap_min_addr();
+
+       return 0;
+}
+pure_initcall(init_mmap_min_addr);
index dc7674f..4501c5e 100644 (file)
@@ -124,9 +124,9 @@ int register_security(struct security_operations *ops)
 
 /* Security operations */
 
-int security_ptrace_may_access(struct task_struct *child, unsigned int mode)
+int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
-       return security_ops->ptrace_may_access(child, mode);
+       return security_ops->ptrace_access_check(child, mode);
 }
 
 int security_ptrace_traceme(struct task_struct *parent)
index b2ab608..236aaa2 100644 (file)
@@ -137,7 +137,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
  * @tclass: target security class
  * @av: access vector
  */
-void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
        const char **common_pts = NULL;
        u32 common_base = 0;
@@ -970,3 +970,9 @@ u32 avc_policy_seqno(void)
 {
        return avc_cache.latest_notif;
 }
+
+void avc_disable(void)
+{
+       if (avc_node_cachep)
+               kmem_cache_destroy(avc_node_cachep);
+}
index 15c2a08..5dee883 100644 (file)
@@ -1854,12 +1854,12 @@ static inline u32 open_file_to_av(struct file *file)
 
 /* Hook functions begin here. */
 
-static int selinux_ptrace_may_access(struct task_struct *child,
+static int selinux_ptrace_access_check(struct task_struct *child,
                                     unsigned int mode)
 {
        int rc;
 
-       rc = cap_ptrace_may_access(child, mode);
+       rc = cap_ptrace_access_check(child, mode);
        if (rc)
                return rc;
 
@@ -2938,11 +2938,6 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
        const struct cred *cred = current_cred();
        struct inode *inode = file->f_path.dentry->d_inode;
 
-       if (!mask) {
-               /* No permission to check.  Existence test. */
-               return 0;
-       }
-
        /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
        if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
                mask |= MAY_APPEND;
@@ -2953,10 +2948,20 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
 
 static int selinux_file_permission(struct file *file, int mask)
 {
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct file_security_struct *fsec = file->f_security;
+       struct inode_security_struct *isec = inode->i_security;
+       u32 sid = current_sid();
+
        if (!mask)
                /* No permission to check.  Existence test. */
                return 0;
 
+       if (sid == fsec->sid && fsec->isid == isec->sid &&
+           fsec->pseqno == avc_policy_seqno())
+               /* No change since dentry_open check. */
+               return 0;
+
        return selinux_revalidate_file_permission(file, mask);
 }
 
@@ -3029,9 +3034,21 @@ static int selinux_file_mmap(struct file *file, unsigned long reqprot,
        int rc = 0;
        u32 sid = current_sid();
 
-       if (addr < mmap_min_addr)
+       /*
+        * notice that we are intentionally putting the SELinux check before
+        * the secondary cap_file_mmap check.  This is such a likely attempt
+        * at bad behaviour/exploit that we always want to get the AVC, even
+        * if DAC would have also denied the operation.
+        */
+       if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
                rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
                                  MEMPROTECT__MMAP_ZERO, NULL);
+               if (rc)
+                       return rc;
+       }
+
+       /* do DAC check on address space usage */
+       rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only);
        if (rc || addr_only)
                return rc;
 
@@ -5182,7 +5199,7 @@ static int selinux_setprocattr(struct task_struct *p,
 
                /* Only allow single threaded processes to change context */
                error = -EPERM;
-               if (!is_single_threaded(p)) {
+               if (!current_is_single_threaded()) {
                        error = security_bounded_transition(tsec->sid, sid);
                        if (error)
                                goto abort_change;
@@ -5310,7 +5327,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
 static struct security_operations selinux_ops = {
        .name =                         "selinux",
 
-       .ptrace_may_access =            selinux_ptrace_may_access,
+       .ptrace_access_check =          selinux_ptrace_access_check,
        .ptrace_traceme =               selinux_ptrace_traceme,
        .capget =                       selinux_capget,
        .capset =                       selinux_capset,
@@ -5678,6 +5695,9 @@ int selinux_disable(void)
        selinux_disabled = 1;
        selinux_enabled = 0;
 
+       /* Try to destroy the avc node cache */
+       avc_disable();
+
        /* Reset security_ops to the secondary module, dummy or capability. */
        security_ops = secondary_ops;
 
index d12ff1a..ae4c3a0 100644 (file)
@@ -127,13 +127,13 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
                     u32 events, u32 ssid, u32 tsid,
                     u16 tclass, u32 perms);
 
-/* Shows permission in human readable form */
-void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
-
 /* Exported to selinuxfs */
 int avc_get_hash_stats(char *page);
 extern unsigned int avc_cache_threshold;
 
+/* Attempt to free avc node cache */
+void avc_disable(void);
+
 #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
 DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats);
 #endif
index 500e6f7..ff17820 100644 (file)
  *
  *  Added validation of kernel classes and permissions
  *
+ * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ *  Added support for bounds domain and audit messaged on masked permissions
+ *
+ * Copyright (C) 2008, 2009 NEC Corporation
  * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
  * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
  * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
@@ -279,6 +284,95 @@ mls_ops:
 }
 
 /*
+ * security_dump_masked_av - dumps masked permissions during
+ * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
+ */
+static int dump_masked_av_helper(void *k, void *d, void *args)
+{
+       struct perm_datum *pdatum = d;
+       char **permission_names = args;
+
+       BUG_ON(pdatum->value < 1 || pdatum->value > 32);
+
+       permission_names[pdatum->value - 1] = (char *)k;
+
+       return 0;
+}
+
+static void security_dump_masked_av(struct context *scontext,
+                                   struct context *tcontext,
+                                   u16 tclass,
+                                   u32 permissions,
+                                   const char *reason)
+{
+       struct common_datum *common_dat;
+       struct class_datum *tclass_dat;
+       struct audit_buffer *ab;
+       char *tclass_name;
+       char *scontext_name = NULL;
+       char *tcontext_name = NULL;
+       char *permission_names[32];
+       int index, length;
+       bool need_comma = false;
+
+       if (!permissions)
+               return;
+
+       tclass_name = policydb.p_class_val_to_name[tclass - 1];
+       tclass_dat = policydb.class_val_to_struct[tclass - 1];
+       common_dat = tclass_dat->comdatum;
+
+       /* init permission_names */
+       if (common_dat &&
+           hashtab_map(common_dat->permissions.table,
+                       dump_masked_av_helper, permission_names) < 0)
+               goto out;
+
+       if (hashtab_map(tclass_dat->permissions.table,
+                       dump_masked_av_helper, permission_names) < 0)
+               goto out;
+
+       /* get scontext/tcontext in text form */
+       if (context_struct_to_string(scontext,
+                                    &scontext_name, &length) < 0)
+               goto out;
+
+       if (context_struct_to_string(tcontext,
+                                    &tcontext_name, &length) < 0)
+               goto out;
+
+       /* audit a message */
+       ab = audit_log_start(current->audit_context,
+                            GFP_ATOMIC, AUDIT_SELINUX_ERR);
+       if (!ab)
+               goto out;
+
+       audit_log_format(ab, "op=security_compute_av reason=%s "
+                        "scontext=%s tcontext=%s tclass=%s perms=",
+                        reason, scontext_name, tcontext_name, tclass_name);
+
+       for (index = 0; index < 32; index++) {
+               u32 mask = (1 << index);
+
+               if ((mask & permissions) == 0)
+                       continue;
+
+               audit_log_format(ab, "%s%s",
+                                need_comma ? "," : "",
+                                permission_names[index]
+                                ? permission_names[index] : "????");
+               need_comma = true;
+       }
+       audit_log_end(ab);
+out:
+       /* release scontext/tcontext */
+       kfree(tcontext_name);
+       kfree(scontext_name);
+
+       return;
+}
+
+/*
  * security_boundary_permission - drops violated permissions
  * on boundary constraint.
  */
@@ -347,28 +441,12 @@ static void type_attribute_bounds_av(struct context *scontext,
        }
 
        if (masked) {
-               struct audit_buffer *ab;
-               char *stype_name
-                       = policydb.p_type_val_to_name[source->value - 1];
-               char *ttype_name
-                       = policydb.p_type_val_to_name[target->value - 1];
-               char *tclass_name
-                       = policydb.p_class_val_to_name[tclass - 1];
-
                /* mask violated permissions */
                avd->allowed &= ~masked;
 
-               /* notice to userspace via audit message */
-               ab = audit_log_start(current->audit_context,
-                                    GFP_ATOMIC, AUDIT_SELINUX_ERR);
-               if (!ab)
-                       return;
-
-               audit_log_format(ab, "av boundary violation: "
-                                "source=%s target=%s tclass=%s",
-                                stype_name, ttype_name, tclass_name);
-               avc_dump_av(ab, tclass, masked);
-               audit_log_end(ab);
+               /* audit masked permissions */
+               security_dump_masked_av(scontext, tcontext,
+                                       tclass, masked, "bounds");
        }
 }
 
@@ -480,7 +558,7 @@ static int context_struct_compute_av(struct context *scontext,
                if ((constraint->permissions & (avd->allowed)) &&
                    !constraint_expr_eval(scontext, tcontext, NULL,
                                          constraint->expr)) {
-                       avd->allowed = (avd->allowed) & ~(constraint->permissions);
+                       avd->allowed &= ~(constraint->permissions);
                }
                constraint = constraint->next;
        }
@@ -499,8 +577,8 @@ static int context_struct_compute_av(struct context *scontext,
                                break;
                }
                if (!ra)
-                       avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION |
-                                                       PROCESS__DYNTRANSITION);
+                       avd->allowed &= ~(PROCESS__TRANSITION |
+                                         PROCESS__DYNTRANSITION);
        }
 
        /*
@@ -687,6 +765,26 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
                }
                index = type->bounds;
        }
+
+       if (rc) {
+               char *old_name = NULL;
+               char *new_name = NULL;
+               int length;
+
+               if (!context_struct_to_string(old_context,
+                                             &old_name, &length) &&
+                   !context_struct_to_string(new_context,
+                                             &new_name, &length)) {
+                       audit_log(current->audit_context,
+                                 GFP_ATOMIC, AUDIT_SELINUX_ERR,
+                                 "op=security_bounded_transition "
+                                 "result=denied "
+                                 "oldcontext=%s newcontext=%s",
+                                 old_name, new_name);
+               }
+               kfree(new_name);
+               kfree(old_name);
+       }
 out:
        read_unlock(&policy_rwlock);
 
index 243bec1..c6e9aca 100644 (file)
@@ -275,7 +275,7 @@ static inline void smk_ad_init(struct smk_audit_info *a, const char *func,
 {
        memset(a, 0, sizeof(*a));
        a->a.type = type;
-       a->a.function = func;
+       a->a.smack_audit_data.function = func;
 }
 
 static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
index 513dc1a..0f9ac81 100644 (file)
@@ -240,8 +240,9 @@ static inline void smack_str_from_perm(char *string, int access)
 static void smack_log_callback(struct audit_buffer *ab, void *a)
 {
        struct common_audit_data *ad = a;
-       struct smack_audit_data *sad = &ad->lsm_priv.smack_audit_data;
-       audit_log_format(ab, "lsm=SMACK fn=%s action=%s", ad->function,
+       struct smack_audit_data *sad = &ad->smack_audit_data;
+       audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
+                        ad->smack_audit_data.function,
                         sad->result ? "denied" : "granted");
        audit_log_format(ab, " subject=");
        audit_log_untrustedstring(ab, sad->subject);
@@ -274,11 +275,11 @@ void smack_log(char *subject_label, char *object_label, int request,
        if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
                return;
 
-       if (a->function == NULL)
-               a->function = "unknown";
+       if (a->smack_audit_data.function == NULL)
+               a->smack_audit_data.function = "unknown";
 
        /* end preparing the audit data */
-       sad = &a->lsm_priv.smack_audit_data;
+       sad = &a->smack_audit_data;
        smack_str_from_perm(request_buffer, request);
        sad->subject = subject_label;
        sad->object  = object_label;
index 0023182..c243a2b 100644 (file)
@@ -91,7 +91,7 @@ struct inode_smack *new_inode_smack(char *smack)
  */
 
 /**
- * smack_ptrace_may_access - Smack approval on PTRACE_ATTACH
+ * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH
  * @ctp: child task pointer
  * @mode: ptrace attachment mode
  *
@@ -99,13 +99,13 @@ struct inode_smack *new_inode_smack(char *smack)
  *
  * Do the capability checks, and require read and write.
  */
-static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode)
+static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
 {
        int rc;
        struct smk_audit_info ad;
        char *sp, *tsp;
 
-       rc = cap_ptrace_may_access(ctp, mode);
+       rc = cap_ptrace_access_check(ctp, mode);
        if (rc != 0)
                return rc;
 
@@ -2464,7 +2464,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
        /*
         * Perfectly reasonable for this to be NULL
         */
-       if (sip == NULL || sip->sin_family != PF_INET)
+       if (sip == NULL || sip->sin_family != AF_INET)
                return 0;
 
        return smack_netlabel_send(sock->sk, sip);
@@ -3032,7 +3032,7 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 struct security_operations smack_ops = {
        .name =                         "smack",
 
-       .ptrace_may_access =            smack_ptrace_may_access,
+       .ptrace_access_check =          smack_ptrace_access_check,
        .ptrace_traceme =               smack_ptrace_traceme,
        .syslog =                       smack_syslog,
 
index fdd1f4b..3c8bd8e 100644 (file)
@@ -1285,6 +1285,36 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
 }
 
 /**
+ * tomoyo_delete_domain - Delete a domain.
+ *
+ * @domainname: The name of domain.
+ *
+ * Returns 0.
+ */
+static int tomoyo_delete_domain(char *domainname)
+{
+       struct tomoyo_domain_info *domain;
+       struct tomoyo_path_info name;
+
+       name.name = domainname;
+       tomoyo_fill_path_info(&name);
+       down_write(&tomoyo_domain_list_lock);
+       /* Is there an active domain? */
+       list_for_each_entry(domain, &tomoyo_domain_list, list) {
+               /* Never delete tomoyo_kernel_domain */
+               if (domain == &tomoyo_kernel_domain)
+                       continue;
+               if (domain->is_deleted ||
+                   tomoyo_pathcmp(domain->domainname, &name))
+                       continue;
+               domain->is_deleted = true;
+               break;
+       }
+       up_write(&tomoyo_domain_list_lock);
+       return 0;
+}
+
+/**
  * tomoyo_write_domain_policy - Write domain policy.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
index 6d6ba09..31df541 100644 (file)
@@ -339,8 +339,6 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain);
 const char *tomoyo_get_msg(const bool is_enforce);
 /* Convert single path operation to operation name. */
 const char *tomoyo_sp2keyword(const u8 operation);
-/* Delete a domain. */
-int tomoyo_delete_domain(char *data);
 /* Create "alias" entry in exception policy. */
 int tomoyo_write_alias_policy(char *data, const bool is_delete);
 /*
index 1d8b169..fcf52ac 100644 (file)
@@ -717,38 +717,6 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete)
        return tomoyo_update_alias_entry(data, cp, is_delete);
 }
 
-/* Domain create/delete handler. */
-
-/**
- * tomoyo_delete_domain - Delete a domain.
- *
- * @domainname: The name of domain.
- *
- * Returns 0.
- */
-int tomoyo_delete_domain(char *domainname)
-{
-       struct tomoyo_domain_info *domain;
-       struct tomoyo_path_info name;
-
-       name.name = domainname;
-       tomoyo_fill_path_info(&name);
-       down_write(&tomoyo_domain_list_lock);
-       /* Is there an active domain? */
-       list_for_each_entry(domain, &tomoyo_domain_list, list) {
-               /* Never delete tomoyo_kernel_domain */
-               if (domain == &tomoyo_kernel_domain)
-                       continue;
-               if (domain->is_deleted ||
-                   tomoyo_pathcmp(domain->domainname, &name))
-                       continue;
-               domain->is_deleted = true;
-               break;
-       }
-       up_write(&tomoyo_domain_list_lock);
-       return 0;
-}
-
 /**
  * tomoyo_find_or_assign_new_domain - Create a domain.
  *
@@ -818,13 +786,11 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
 /**
  * tomoyo_find_next_domain - Find a domain.
  *
- * @bprm:           Pointer to "struct linux_binprm".
- * @next_domain:    Pointer to pointer to "struct tomoyo_domain_info".
+ * @bprm: Pointer to "struct linux_binprm".
  *
  * Returns 0 on success, negative value otherwise.
  */
-int tomoyo_find_next_domain(struct linux_binprm *bprm,
-                           struct tomoyo_domain_info **next_domain)
+int tomoyo_find_next_domain(struct linux_binprm *bprm)
 {
        /*
         * This function assumes that the size of buffer returned by
@@ -946,9 +912,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm,
                tomoyo_set_domain_flag(old_domain, false,
                                       TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED);
  out:
+       if (!domain)
+               domain = old_domain;
+       bprm->cred->security = domain;
        tomoyo_free(real_program_name);
        tomoyo_free(symlink_program_name);
-       *next_domain = domain ? domain : old_domain;
        tomoyo_free(tmp);
        return retval;
 }
index 3194d09..35a13e7 100644 (file)
@@ -61,14 +61,8 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
         * Execute permission is checked against pathname passed to do_execve()
         * using current domain.
         */
-       if (!domain) {
-               struct tomoyo_domain_info *next_domain = NULL;
-               int retval = tomoyo_find_next_domain(bprm, &next_domain);
-
-               if (!retval)
-                       bprm->cred->security = next_domain;
-               return retval;
-       }
+       if (!domain)
+               return tomoyo_find_next_domain(bprm);
        /*
         * Read permission is checked against interpreters using next domain.
         * '1' is the result of open_to_namei_flags(O_RDONLY).
index 0fd588a..cd6ba0b 100644 (file)
@@ -31,8 +31,7 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain,
                            struct path *path2);
 int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
                                    struct file *filp);
-int tomoyo_find_next_domain(struct linux_binprm *bprm,
-                           struct tomoyo_domain_info **next_domain);
+int tomoyo_find_next_domain(struct linux_binprm *bprm);
 
 /* Index numbers for Access Controls. */