Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Sep 2009 15:55:49 +0000 (08:55 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 11 Sep 2009 15:55:49 +0000 (08:55 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (57 commits)
  binfmt_elf: fix PT_INTERP bss handling
  TPM: Fixup boot probe timeout for tpm_tis driver
  sysfs: Add labeling support for sysfs
  LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
  VFS: Factor out part of vfs_setxattr so it can be called from the SELinux hook for inode_setsecctx.
  KEYS: Add missing linux/tracehook.h #inclusions
  KEYS: Fix default security_session_to_parent()
  Security/SELinux: includecheck fix kernel/sysctl.c
  KEYS: security_cred_alloc_blank() should return int under all circumstances
  IMA: open new file for read
  KEYS: Add a keyctl to install a process's session keyring on its parent [try #6]
  KEYS: Extend TIF_NOTIFY_RESUME to (almost) all architectures [try #6]
  KEYS: Do some whitespace cleanups [try #6]
  KEYS: Make /proc/keys use keyid not numread as file position [try #6]
  KEYS: Add garbage collection for dead, revoked and expired keys. [try #6]
  KEYS: Flag dead keys to induce EKEYREVOKED [try #6]
  KEYS: Allow keyctl_revoke() on keys that have SETATTR but not WRITE perm [try #6]
  KEYS: Deal with dead-type keys appropriately [try #6]
  CRED: Add some configurable debugging [try #6]
  selinux: Support for the new TUN LSM hooks
  ...

96 files changed:
Documentation/keys.txt
arch/alpha/include/asm/thread_info.h
arch/alpha/kernel/signal.c
arch/arm/include/asm/thread_info.h
arch/arm/kernel/entry-common.S
arch/arm/kernel/signal.c
arch/avr32/include/asm/thread_info.h
arch/avr32/kernel/entry-avr32b.S
arch/avr32/kernel/signal.c
arch/cris/kernel/ptrace.c
arch/frv/kernel/signal.c
arch/h8300/include/asm/thread_info.h
arch/h8300/kernel/signal.c
arch/ia64/kernel/process.c
arch/m32r/include/asm/thread_info.h
arch/m32r/kernel/signal.c
arch/mips/include/asm/thread_info.h
arch/mips/kernel/signal.c
arch/mn10300/kernel/signal.c
arch/parisc/include/asm/thread_info.h
arch/parisc/kernel/entry.S
arch/parisc/kernel/signal.c
arch/s390/kernel/signal.c
arch/sh/kernel/signal_32.c
arch/sh/kernel/signal_64.c
arch/sparc/kernel/signal_32.c
arch/sparc/kernel/signal_64.c
arch/x86/kernel/signal.c
drivers/char/tpm/tpm_tis.c
drivers/net/tun.c
drivers/staging/comedi/comedi_fops.c
fs/locks.c
fs/namei.c
fs/nfsd/auth.c
fs/nfsd/nfssvc.c
fs/nfsd/vfs.c
fs/open.c
fs/sysfs/dir.c
fs/sysfs/inode.c
fs/sysfs/symlink.c
fs/sysfs/sysfs.h
fs/xattr.c
include/linux/cred.h
include/linux/key.h
include/linux/keyctl.h
include/linux/lsm_audit.h
include/linux/sched.h
include/linux/security.h
include/linux/xattr.h
kernel/acct.c
kernel/cred.c
kernel/exit.c
kernel/fork.c
kernel/kmod.c
kernel/ptrace.c
kernel/sysctl.c
lib/Kconfig.debug
lib/is_single_threaded.c
net/core/dev.c
net/ipv4/tcp_cong.c
security/Makefile
security/capability.c
security/commoncap.c
security/keys/Makefile
security/keys/compat.c
security/keys/gc.c [new file with mode: 0644]
security/keys/internal.h
security/keys/key.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/sysctl.c
security/lsm_audit.c
security/security.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/av_inherit.h
security/selinux/include/av_perm_to_string.h
security/selinux/include/av_permissions.h
security/selinux/include/avc.h
security/selinux/include/class_to_string.h
security/selinux/include/flask.h
security/selinux/include/netlabel.h
security/selinux/include/xfrm.h
security/selinux/netlabel.c
security/selinux/ss/services.c
security/selinux/xfrm.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 b56aacc1fff864022dbdf67aac997d54f0d14f32..e4dbbdb1bd961e7a7a582c3dbb3ada1008218218 100644 (file)
@@ -26,7 +26,7 @@ This document has the following sections:
        - Notes on accessing payload contents
        - Defining a key type
        - Request-key callback service
-       - Key access filesystem
+       - Garbage collection
 
 
 ============
@@ -113,6 +113,9 @@ Each key has a number of attributes:
 
      (*) Dead. The key's type was unregistered, and so the key is now useless.
 
+Keys in the last three states are subject to garbage collection.  See the
+section on "Garbage collection".
+
 
 ====================
 KEY SERVICE OVERVIEW
@@ -754,6 +757,26 @@ The keyctl syscall functions are:
      successful.
 
 
+ (*) Install the calling process's session keyring on its parent.
+
+       long keyctl(KEYCTL_SESSION_TO_PARENT);
+
+     This functions attempts to install the calling process's session keyring
+     on to the calling process's parent, replacing the parent's current session
+     keyring.
+
+     The calling process must have the same ownership as its parent, the
+     keyring must have the same ownership as the calling process, the calling
+     process must have LINK permission on the keyring and the active LSM module
+     mustn't deny permission, otherwise error EPERM will be returned.
+
+     Error ENOMEM will be returned if there was insufficient memory to complete
+     the operation, otherwise 0 will be returned to indicate success.
+
+     The keyring will be replaced next time the parent process leaves the
+     kernel and resumes executing userspace.
+
+
 ===============
 KERNEL SERVICES
 ===============
@@ -1231,3 +1254,17 @@ by executing:
 
 In this case, the program isn't required to actually attach the key to a ring;
 the rings are provided for reference.
+
+
+==================
+GARBAGE COLLECTION
+==================
+
+Dead keys (for which the type has been removed) will be automatically unlinked
+from those keyrings that point to them and deleted as soon as possible by a
+background garbage collector.
+
+Similarly, revoked and expired keys will be garbage collected, but only after a
+certain amount of time has passed.  This time is set as a number of seconds in:
+
+       /proc/sys/kernel/keys/gc_delay
index 60c83abfde7027832e0e7609ac7e032accb66386..5076a8860b18ff4440ee9d9187e57d696406321d 100644 (file)
@@ -75,6 +75,7 @@ register struct thread_info *__current_thread_info __asm__("$8");
 #define TIF_UAC_SIGBUS         7
 #define TIF_MEMDIE             8
 #define TIF_RESTORE_SIGMASK    9       /* restore signal mask in do_signal */
+#define TIF_NOTIFY_RESUME      10      /* callback before returning to user */
 #define TIF_FREEZE             16      /* is freezing for suspend */
 
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
@@ -82,10 +83,12 @@ register struct thread_info *__current_thread_info __asm__("$8");
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
 #define _TIF_RESTORE_SIGMASK   (1<<TIF_RESTORE_SIGMASK)
+#define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_FREEZE            (1<<TIF_FREEZE)
 
 /* Work to do on interrupt/exception return.  */
-#define _TIF_WORK_MASK         (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
+#define _TIF_WORK_MASK         (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+                                _TIF_NOTIFY_RESUME)
 
 /* Work to do on any return to userspace.  */
 #define _TIF_ALLWORK_MASK      (_TIF_WORK_MASK         \
index df65eaa84c4c41218a68121c3adce386437f6642..0932dbb1ef8eff444943645e15b0802b1d4cf5d5 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/binfmts.h>
 #include <linux/bitops.h>
 #include <linux/syscalls.h>
+#include <linux/tracehook.h>
 
 #include <asm/uaccess.h>
 #include <asm/sigcontext.h>
@@ -683,4 +684,11 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw,
 {
        if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
                do_signal(regs, sw, r0, r19);
+
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+       }
 }
index 73394e50cbca26e4198349de503fd18554f331d6..d3a39b1e6c0fc12cde0ccf4376a5d250b8232840 100644 (file)
@@ -130,11 +130,13 @@ extern void vfp_sync_state(struct thread_info *thread);
  *  TIF_SYSCALL_TRACE  - syscall trace active
  *  TIF_SIGPENDING     - signal pending
  *  TIF_NEED_RESCHED   - rescheduling necessary
+ *  TIF_NOTIFY_RESUME  - callback before returning to user
  *  TIF_USEDFPU                - FPU was used by this task this quantum (SMP)
  *  TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED
  */
 #define TIF_SIGPENDING         0
 #define TIF_NEED_RESCHED       1
+#define TIF_NOTIFY_RESUME      2       /* callback before returning to user */
 #define TIF_SYSCALL_TRACE      8
 #define TIF_POLLING_NRFLAG     16
 #define TIF_USING_IWMMXT       17
@@ -143,6 +145,7 @@ extern void vfp_sync_state(struct thread_info *thread);
 
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
+#define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
 #define _TIF_USING_IWMMXT      (1 << TIF_USING_IWMMXT)
index 8c3de1a350b5dd85bdf06b79f1dab163cd305743..7813ab782fda6796bf455a39dcc723a6236707e5 100644 (file)
@@ -51,7 +51,7 @@ fast_work_pending:
 work_pending:
        tst     r1, #_TIF_NEED_RESCHED
        bne     work_resched
-       tst     r1, #_TIF_SIGPENDING
+       tst     r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME
        beq     no_work_pending
        mov     r0, sp                          @ 'regs'
        mov     r2, why                         @ 'syscall'
index f6bc5d442782374bb99618702722dde5d37e1dc2..b76fe06d92e746b68855d42112071f69fff71c5a 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/personality.h>
 #include <linux/freezer.h>
 #include <linux/uaccess.h>
+#include <linux/tracehook.h>
 
 #include <asm/elf.h>
 #include <asm/cacheflush.h>
@@ -707,4 +708,11 @@ do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
 {
        if (thread_flags & _TIF_SIGPENDING)
                do_signal(&current->blocked, regs, syscall);
+
+       if (thread_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+       }
 }
index fc42de5ca209ac5e9de0cfca9c1f35561f740be2..fd0c5d7e933701c31166deb5f4f7269c2adb8206 100644 (file)
@@ -84,6 +84,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_MEMDIE             6
 #define TIF_RESTORE_SIGMASK    7       /* restore signal mask in do_signal */
 #define TIF_CPU_GOING_TO_SLEEP 8       /* CPU is entering sleep 0 mode */
+#define TIF_NOTIFY_RESUME      9       /* callback before returning to user */
 #define TIF_FREEZE             29
 #define TIF_DEBUG              30      /* debugging enabled */
 #define TIF_USERSPACE          31      /* true if FS sets userspace */
@@ -96,6 +97,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_MEMDIE            (1 << TIF_MEMDIE)
 #define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)
 #define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP)
+#define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
 #define _TIF_FREEZE            (1 << TIF_FREEZE)
 
 /* Note: The masks below must never span more than 16 bits! */
@@ -103,13 +105,15 @@ static inline struct thread_info *current_thread_info(void)
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK                         \
        ((1 << TIF_SIGPENDING)                  \
+        | _TIF_NOTIFY_RESUME                   \
         | (1 << TIF_NEED_RESCHED)              \
         | (1 << TIF_POLLING_NRFLAG)            \
         | (1 << TIF_BREAKPOINT)                \
         | (1 << TIF_RESTORE_SIGMASK))
 
 /* work to do on any return to userspace */
-#define _TIF_ALLWORK_MASK      (_TIF_WORK_MASK | (1 << TIF_SYSCALL_TRACE))
+#define _TIF_ALLWORK_MASK      (_TIF_WORK_MASK | (1 << TIF_SYSCALL_TRACE) | \
+                                _TIF_NOTIFY_RESUME)
 /* work to do on return from debug mode */
 #define _TIF_DBGWORK_MASK      (_TIF_WORK_MASK & ~(1 << TIF_BREAKPOINT))
 
index 009a80155d67d96b7da1ee34e60ec726abcfdb4b..169268c40ae2552df9430128e4ae6e6964249989 100644 (file)
@@ -281,7 +281,7 @@ syscall_exit_work:
        ld.w    r1, r0[TI_flags]
        rjmp    1b
 
-2:     mov     r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
+2:     mov     r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NOTIFY_RESUME
        tst     r1, r2
        breq    3f
        unmask_interrupts
index 27227561bad67a7ebea577acffa3796f5998b8ea..64f886fac2efef6ea05bd1c0703cfdf4ccb8d7d4 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/freezer.h>
+#include <linux/tracehook.h>
 
 #include <asm/uaccess.h>
 #include <asm/ucontext.h>
@@ -322,4 +323,11 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti)
 
        if (ti->flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
                do_signal(regs, &current->blocked, syscall);
+
+       if (ti->flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+       }
 }
index b326023baab28d3d8be5eee2acc472aa323256e6..48b0f3912632f98d48ae22e40945d057aa393269 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/tracehook.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -36,4 +37,11 @@ void do_notify_resume(int canrestart, struct pt_regs *regs,
        /* deal with pending signal delivery */
        if (thread_info_flags & _TIF_SIGPENDING)
                do_signal(canrestart,regs);
+
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+       }
 }
index 4a7a62c6e7833ed91a9087b3762cb3d0ba24df5f..6b0a2b6fed6a9326ab8f4d28955cda0bada96b6a 100644 (file)
@@ -572,6 +572,8 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags)
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(__frame);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
        }
 
 } /* end do_notify_resume() */
index 8bbc8b0ee45db3ad2ddb97f6c6c9be4b5550315f..70e67e47d0205eef549c4529c3ac627ac9cd2e42 100644 (file)
@@ -89,6 +89,7 @@ static inline struct thread_info *current_thread_info(void)
                                           TIF_NEED_RESCHED */
 #define TIF_MEMDIE             4
 #define TIF_RESTORE_SIGMASK    5       /* restore signal mask in do_signal() */
+#define TIF_NOTIFY_RESUME      6       /* callback before returning to user */
 #define TIF_FREEZE             16      /* is freezing for suspend */
 
 /* as above, but as bit values */
@@ -97,6 +98,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
 #define _TIF_RESTORE_SIGMASK   (1<<TIF_RESTORE_SIGMASK)
+#define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
 #define _TIF_FREEZE            (1<<TIF_FREEZE)
 
 #define _TIF_WORK_MASK         0x0000FFFE      /* work to do on interrupt/exception return */
index cf3472f7389b9467bdb483ac883e81d4414a0532..af842c369d24301e4b38861d29ffae2df0f863e7 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/tty.h>
 #include <linux/binfmts.h>
 #include <linux/freezer.h>
+#include <linux/tracehook.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
@@ -552,4 +553,11 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
 {
        if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
                do_signal(regs, NULL);
+
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+       }
 }
index 5d7c0e5b9e76f150b20269cb9ba9e2497062209a..89969e9500456e3a17212b6f20ea47d6abbc6fb3 100644 (file)
@@ -192,6 +192,8 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall)
        if (test_thread_flag(TIF_NOTIFY_RESUME)) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(&scr->pt);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
        }
 
        /* copy user rbs to kernel rbs */
index 07bb5bd00e2a0660dc3be6c0c0c4514da8ade81b..71578151a403e9353c007b849fd5e711336fc3fc 100644 (file)
@@ -149,6 +149,7 @@ static inline unsigned int get_thread_fault_code(void)
 #define TIF_NEED_RESCHED       2       /* rescheduling necessary */
 #define TIF_SINGLESTEP         3       /* restore singlestep on return to user mode */
 #define TIF_IRET               4       /* return with iret */
+#define TIF_NOTIFY_RESUME      5       /* callback before returning to user */
 #define TIF_RESTORE_SIGMASK    8       /* restore signal mask in do_signal() */
 #define TIF_USEDFPU            16      /* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG     17      /* true if poll_idle() is polling TIF_NEED_RESCHED */
@@ -160,6 +161,7 @@ static inline unsigned int get_thread_fault_code(void)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_SINGLESTEP                (1<<TIF_SINGLESTEP)
 #define _TIF_IRET              (1<<TIF_IRET)
+#define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_RESTORE_SIGMASK   (1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU           (1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
index 18124542a6ebb695444c9681996147b69ac5d6de..144b0f124fc72f08b20f93336f96da81327fe61c 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/stddef.h>
 #include <linux/personality.h>
 #include <linux/freezer.h>
+#include <linux/tracehook.h>
 #include <asm/cacheflush.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
@@ -408,5 +409,12 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
        if (thread_info_flags & _TIF_SIGPENDING)
                do_signal(regs,oldset);
 
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+       }
+
        clear_thread_flag(TIF_IRET);
 }
index f9df720d2e40e215aa0cb21561f467d6d95a2b6b..01cc1630b66cc4cf7f8f7a0159245fd72e5bf893 100644 (file)
@@ -115,6 +115,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define TIF_NEED_RESCHED       2       /* rescheduling necessary */
 #define TIF_SYSCALL_AUDIT      3       /* syscall auditing active */
 #define TIF_SECCOMP            4       /* secure computing */
+#define TIF_NOTIFY_RESUME      5       /* callback before returning to user */
 #define TIF_RESTORE_SIGMASK    9       /* restore signal mask in do_signal() */
 #define TIF_USEDFPU            16      /* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG     17      /* true if poll_idle() is polling TIF_NEED_RESCHED */
@@ -139,6 +140,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
+#define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_RESTORE_SIGMASK   (1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU           (1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
index 830c5ef9932b389cbc4ad7f1410b750721a6b070..6254041b942f9a9b56295024a0fd1320fb2da6ae 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/compiler.h>
 #include <linux/syscalls.h>
 #include <linux/uaccess.h>
+#include <linux/tracehook.h>
 
 #include <asm/abi.h>
 #include <asm/asm.h>
@@ -700,4 +701,11 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
        /* deal with pending signal delivery */
        if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
                do_signal(regs);
+
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+       }
 }
index feb2f2e810db7c785ea5a7562ac77dfb79666a79..a21f43bc68e269cf412e6ae3b0c0293c0dcd96c0 100644 (file)
@@ -568,5 +568,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(__frame);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
        }
 }
index 4ce0edfbe9694dc4daaed2253a625e9d46a25c72..ac775a76bff71508a939a08fc983d9d4b8e272f5 100644 (file)
@@ -59,6 +59,7 @@ struct thread_info {
 #define TIF_MEMDIE             5
 #define TIF_RESTORE_SIGMASK    6       /* restore saved signal mask */
 #define TIF_FREEZE             7       /* is freezing for suspend */
+#define TIF_NOTIFY_RESUME      8       /* callback before returning to user */
 
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
@@ -67,8 +68,9 @@ struct thread_info {
 #define _TIF_32BIT             (1 << TIF_32BIT)
 #define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)
 #define _TIF_FREEZE            (1 << TIF_FREEZE)
+#define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
 
-#define _TIF_USER_WORK_MASK     (_TIF_SIGPENDING | \
+#define _TIF_USER_WORK_MASK     (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | \
                                  _TIF_NEED_RESCHED | _TIF_RESTORE_SIGMASK)
 
 #endif /* __KERNEL__ */
index e552e547cb93fd88050ee800d62f2f2667b3ba5d..8c4712b74dc13b626f449e699ee31aca15701315 100644 (file)
@@ -948,7 +948,7 @@ intr_check_sig:
        /* As above */
        mfctl   %cr30,%r1
        LDREG   TI_FLAGS(%r1),%r19
-       ldi     (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r20
+       ldi     (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NOTIFY_RESUME), %r20
        and,COND(<>)    %r19, %r20, %r0
        b,n     intr_restore    /* skip past if we've nothing to do */
 
index f82544225e8e8b43b8ca76664101a849d1e8a7f7..8eb3c63c407a43e5aaac3e96654ce391cd8764a5 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/stddef.h>
 #include <linux/compat.h>
 #include <linux/elf.h>
+#include <linux/tracehook.h>
 #include <asm/ucontext.h>
 #include <asm/rt_sigframe.h>
 #include <asm/uaccess.h>
@@ -645,4 +646,11 @@ void do_notify_resume(struct pt_regs *regs, long in_syscall)
        if (test_thread_flag(TIF_SIGPENDING) ||
            test_thread_flag(TIF_RESTORE_SIGMASK))
                do_signal(regs, in_syscall);
+
+       if (test_thread_flag(TIF_NOTIFY_RESUME)) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+       }
 }
index 062bd64e65fabe1f09641a4c3e0290ae4ff013ee..6b4fef877f9d0ccf0fd28ea654b9553ab3b70df9 100644 (file)
@@ -536,4 +536,6 @@ void do_notify_resume(struct pt_regs *regs)
 {
        clear_thread_flag(TIF_NOTIFY_RESUME);
        tracehook_notify_resume(regs);
+       if (current->replacement_session_keyring)
+               key_replace_session_keyring();
 }
index b5afbec1db59ce6fb2d74cd0cd9e0fa51b879d0f..04a21883f32730bf18013031fe342e27c50b6b99 100644 (file)
@@ -640,5 +640,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
        }
 }
index 0663a0ee6021f4ab31c2bb32fd7a24fa82cd9a6a..9e5c9b1d7e9872fe3591e8520e8b7383e96e7962 100644 (file)
@@ -772,5 +772,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
        }
 }
index 181d069a2d44bdeb160125053150b894e550598b..7ce1a1005b1da4c3b13f8b87927d060376279f2a 100644 (file)
@@ -590,6 +590,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0,
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
        }
 }
 
index ec82d76dc6f2cc245ca54203dd38c35fee192ed2..647afbda7ae1f170896675dcc4603dfe5c58ec0b 100644 (file)
@@ -613,5 +613,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
        }
 }
+
index 4c578751e94ec08dc4e6ed69338947105e444654..81e58238c4ce642ed54ea3ce63c265427e1d6984 100644 (file)
@@ -869,6 +869,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
        }
 
 #ifdef CONFIG_X86_32
index aec1931608aa28e3645463735c299805a50ab2b8..0b73e4ec1addafff42a79752a666fecd4b25d665 100644 (file)
@@ -450,6 +450,12 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
                goto out_err;
        }
 
+       /* Default timeouts */
+       chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+       chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
+       chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+       chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+
        if (request_locality(chip, 0) != 0) {
                rc = -ENODEV;
                goto out_err;
@@ -457,12 +463,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
 
        vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
 
-       /* Default timeouts */
-       chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
-       chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
-       chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
-       chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
-
        dev_info(dev,
                 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
                 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
index 42b6c6319bc29824fe4e2061ee882759cfeb05c1..87214a257d2ae3431777e94e375e65bb33878828 100644 (file)
@@ -130,17 +130,10 @@ static inline struct tun_sock *tun_sk(struct sock *sk)
 static int tun_attach(struct tun_struct *tun, struct file *file)
 {
        struct tun_file *tfile = file->private_data;
-       const struct cred *cred = current_cred();
        int err;
 
        ASSERT_RTNL();
 
-       /* Check permissions */
-       if (((tun->owner != -1 && cred->euid != tun->owner) ||
-            (tun->group != -1 && !in_egroup_p(tun->group))) &&
-               !capable(CAP_NET_ADMIN))
-               return -EPERM;
-
        netif_tx_lock_bh(tun->dev);
 
        err = -EINVAL;
@@ -926,6 +919,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 
        dev = __dev_get_by_name(net, ifr->ifr_name);
        if (dev) {
+               const struct cred *cred = current_cred();
+
                if (ifr->ifr_flags & IFF_TUN_EXCL)
                        return -EBUSY;
                if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops)
@@ -935,6 +930,14 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                else
                        return -EINVAL;
 
+               if (((tun->owner != -1 && cred->euid != tun->owner) ||
+                    (tun->group != -1 && !in_egroup_p(tun->group))) &&
+                   !capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               err = security_tun_dev_attach(tun->sk);
+               if (err < 0)
+                       return err;
+
                err = tun_attach(tun, file);
                if (err < 0)
                        return err;
@@ -947,6 +950,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 
                if (!capable(CAP_NET_ADMIN))
                        return -EPERM;
+               err = security_tun_dev_create();
+               if (err < 0)
+                       return err;
 
                /* Set dev type */
                if (ifr->ifr_flags & IFF_TUN) {
@@ -989,6 +995,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                tun->sk = sk;
                container_of(sk, struct tun_sock, sk)->tun = tun;
 
+               security_tun_dev_post_create(sk);
+
                tun_net_init(dev);
 
                if (strchr(dev->name, '%')) {
index 9d7c99394ec6767a2cef94408a7913a63d6a5ec0..640f65c6ef849b6dc5182151e156513f0b1d3f51 100644 (file)
@@ -1752,12 +1752,12 @@ static int comedi_open(struct inode *inode, struct file *file)
        mutex_lock(&dev->mutex);
        if (dev->attached)
                goto ok;
-       if (!capable(CAP_SYS_MODULE) && dev->in_request_module) {
+       if (!capable(CAP_NET_ADMIN) && dev->in_request_module) {
                DPRINTK("in request module\n");
                mutex_unlock(&dev->mutex);
                return -ENODEV;
        }
-       if (capable(CAP_SYS_MODULE) && dev->in_request_module)
+       if (capable(CAP_NET_ADMIN) && dev->in_request_module)
                goto ok;
 
        dev->in_request_module = 1;
@@ -1770,8 +1770,8 @@ static int comedi_open(struct inode *inode, struct file *file)
 
        dev->in_request_module = 0;
 
-       if (!dev->attached && !capable(CAP_SYS_MODULE)) {
-               DPRINTK("not attached and not CAP_SYS_MODULE\n");
+       if (!dev->attached && !capable(CAP_NET_ADMIN)) {
+               DPRINTK("not attached and not CAP_NET_ADMIN\n");
                mutex_unlock(&dev->mutex);
                return -ENODEV;
        }
index b6440f52178fad125f3d0101d7a97f82ad2cf3ee..52366e877d7636a04078bdd14133f30be6459f5d 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 ed27bb205b7e9d13a80d240ed98385e8dcfdc384..d11f404667e962ababa87f3678a52e78c50794dd 100644 (file)
@@ -1533,9 +1533,11 @@ int may_open(struct path *path, int acc_mode, int flag)
        if (error)
                return error;
 
-       error = ima_path_check(path,
-                              acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC),
+       error = ima_path_check(path, acc_mode ?
+                              acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) :
+                              ACC_MODE(flag) & (MAY_READ | MAY_WRITE),
                               IMA_COUNT_UPDATE);
+
        if (error)
                return error;
        /*
index 5573508f707fa5cd652da4503049fa6e89c0f9f8..36fcabbf5186452023707c360fe16e3f168200a2 100644 (file)
@@ -34,6 +34,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
        int flags = nfsexp_flags(rqstp, exp);
        int ret;
 
+       validate_process_creds();
+
        /* discard any old override before preparing the new set */
        revert_creds(get_cred(current->real_cred));
        new = prepare_creds();
@@ -86,8 +88,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
        else
                new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
                                                        new->cap_permitted);
+       validate_process_creds();
        put_cred(override_creds(new));
        put_cred(new);
+       validate_process_creds();
        return 0;
 
 oom:
index 492c79b7800b5b7fcb4f8a8813b2d369a5039d7a..24d58adfe5fdc1a014caf1d92249146821fd5ca3 100644 (file)
@@ -496,7 +496,9 @@ nfsd(void *vrqstp)
                /* Lock the export hash tables for reading. */
                exp_readlock();
 
+               validate_process_creds();
                svc_process(rqstp);
+               validate_process_creds();
 
                /* Unlock export hash tables */
                exp_readunlock();
index 23341c1063bcd05fb2841dc6b49d0a91eef36293..8fa09bfbcba7f51664f3cf67e68695952f9e348b 100644 (file)
@@ -684,6 +684,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        __be32          err;
        int             host_err;
 
+       validate_process_creds();
+
        /*
         * If we get here, then the client has already done an "open",
         * and (hopefully) checked permission - so allow OWNER_OVERRIDE
@@ -740,6 +742,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
 out_nfserr:
        err = nfserrno(host_err);
 out:
+       validate_process_creds();
        return err;
 }
 
index dd98e8076024d638cb0987b57b24269d20588587..31191bf513e40ebcbd05668cc0db2bc46c1c1311 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -199,7 +199,7 @@ out:
 int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
        struct file *filp)
 {
-       int err;
+       int ret;
        struct iattr newattrs;
 
        /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
@@ -214,12 +214,14 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
        }
 
        /* Remove suid/sgid on truncate too */
-       newattrs.ia_valid |= should_remove_suid(dentry);
+       ret = should_remove_suid(dentry);
+       if (ret)
+               newattrs.ia_valid |= ret | ATTR_FORCE;
 
        mutex_lock(&dentry->d_inode->i_mutex);
-       err = notify_change(dentry, &newattrs);
+       ret = notify_change(dentry, &newattrs);
        mutex_unlock(&dentry->d_inode->i_mutex);
-       return err;
+       return ret;
 }
 
 static long do_sys_truncate(const char __user *pathname, loff_t length)
@@ -957,6 +959,8 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
        int error;
        struct file *f;
 
+       validate_creds(cred);
+
        /*
         * We must always pass in a valid mount pointer.   Historically
         * callers got away with not passing it, but we must enforce this at
index 14f2d71ea3ce8b7077b0da8774bc554b912cd0fb..0050fc40e8c9f373a3f7c61855870ad7d4a1952c 100644 (file)
@@ -760,6 +760,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 const struct inode_operations sysfs_dir_inode_operations = {
        .lookup         = sysfs_lookup,
        .setattr        = sysfs_setattr,
+       .setxattr       = sysfs_setxattr,
 };
 
 static void remove_dir(struct sysfs_dirent *sd)
index 555f0ff988df1379638d0372ebced2349db25848..2b6a8d9de73dfd0ddba64ba0113a23f6f01fc929 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/xattr.h>
+#include <linux/security.h>
 #include "sysfs.h"
 
 extern struct super_block * sysfs_sb;
@@ -35,6 +37,7 @@ static struct backing_dev_info sysfs_backing_dev_info = {
 
 static const struct inode_operations sysfs_inode_operations ={
        .setattr        = sysfs_setattr,
+       .setxattr       = sysfs_setxattr,
 };
 
 int __init sysfs_inode_init(void)
@@ -42,18 +45,37 @@ int __init sysfs_inode_init(void)
        return bdi_init(&sysfs_backing_dev_info);
 }
 
+struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd)
+{
+       struct sysfs_inode_attrs *attrs;
+       struct iattr *iattrs;
+
+       attrs = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL);
+       if (!attrs)
+               return NULL;
+       iattrs = &attrs->ia_iattr;
+
+       /* assign default attributes */
+       iattrs->ia_mode = sd->s_mode;
+       iattrs->ia_uid = 0;
+       iattrs->ia_gid = 0;
+       iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME;
+
+       return attrs;
+}
 int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
 {
        struct inode * inode = dentry->d_inode;
        struct sysfs_dirent * sd = dentry->d_fsdata;
-       struct iattr * sd_iattr;
+       struct sysfs_inode_attrs *sd_attrs;
+       struct iattr *iattrs;
        unsigned int ia_valid = iattr->ia_valid;
        int error;
 
        if (!sd)
                return -EINVAL;
 
-       sd_iattr = sd->s_iattr;
+       sd_attrs = sd->s_iattr;
 
        error = inode_change_ok(inode, iattr);
        if (error)
@@ -65,42 +87,77 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
        if (error)
                return error;
 
-       if (!sd_iattr) {
+       if (!sd_attrs) {
                /* setting attributes for the first time, allocate now */
-               sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);
-               if (!sd_iattr)
+               sd_attrs = sysfs_init_inode_attrs(sd);
+               if (!sd_attrs)
                        return -ENOMEM;
-               /* assign default attributes */
-               sd_iattr->ia_mode = sd->s_mode;
-               sd_iattr->ia_uid = 0;
-               sd_iattr->ia_gid = 0;
-               sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME;
-               sd->s_iattr = sd_iattr;
+               sd->s_iattr = sd_attrs;
+       } else {
+               /* attributes were changed at least once in past */
+               iattrs = &sd_attrs->ia_iattr;
+
+               if (ia_valid & ATTR_UID)
+                       iattrs->ia_uid = iattr->ia_uid;
+               if (ia_valid & ATTR_GID)
+                       iattrs->ia_gid = iattr->ia_gid;
+               if (ia_valid & ATTR_ATIME)
+                       iattrs->ia_atime = timespec_trunc(iattr->ia_atime,
+                                       inode->i_sb->s_time_gran);
+               if (ia_valid & ATTR_MTIME)
+                       iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime,
+                                       inode->i_sb->s_time_gran);
+               if (ia_valid & ATTR_CTIME)
+                       iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime,
+                                       inode->i_sb->s_time_gran);
+               if (ia_valid & ATTR_MODE) {
+                       umode_t mode = iattr->ia_mode;
+
+                       if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
+                               mode &= ~S_ISGID;
+                       iattrs->ia_mode = sd->s_mode = mode;
+               }
        }
+       return error;
+}
 
-       /* attributes were changed atleast once in past */
-
-       if (ia_valid & ATTR_UID)
-               sd_iattr->ia_uid = iattr->ia_uid;
-       if (ia_valid & ATTR_GID)
-               sd_iattr->ia_gid = iattr->ia_gid;
-       if (ia_valid & ATTR_ATIME)
-               sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime,
-                                               inode->i_sb->s_time_gran);
-       if (ia_valid & ATTR_MTIME)
-               sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime,
-                                               inode->i_sb->s_time_gran);
-       if (ia_valid & ATTR_CTIME)
-               sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime,
-                                               inode->i_sb->s_time_gran);
-       if (ia_valid & ATTR_MODE) {
-               umode_t mode = iattr->ia_mode;
-
-               if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
-                       mode &= ~S_ISGID;
-               sd_iattr->ia_mode = sd->s_mode = mode;
-       }
+int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+               size_t size, int flags)
+{
+       struct sysfs_dirent *sd = dentry->d_fsdata;
+       struct sysfs_inode_attrs *iattrs;
+       void *secdata;
+       int error;
+       u32 secdata_len = 0;
+
+       if (!sd)
+               return -EINVAL;
+       if (!sd->s_iattr)
+               sd->s_iattr = sysfs_init_inode_attrs(sd);
+       if (!sd->s_iattr)
+               return -ENOMEM;
+
+       iattrs = sd->s_iattr;
+
+       if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) {
+               const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
+               error = security_inode_setsecurity(dentry->d_inode, suffix,
+                                               value, size, flags);
+               if (error)
+                       goto out;
+               error = security_inode_getsecctx(dentry->d_inode,
+                                               &secdata, &secdata_len);
+               if (error)
+                       goto out;
+               if (iattrs->ia_secdata)
+                       security_release_secctx(iattrs->ia_secdata,
+                                               iattrs->ia_secdata_len);
+               iattrs->ia_secdata = secdata;
+               iattrs->ia_secdata_len = secdata_len;
 
+       } else
+               return -EINVAL;
+out:
        return error;
 }
 
@@ -146,6 +203,7 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd)
 static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
 {
        struct bin_attribute *bin_attr;
+       struct sysfs_inode_attrs *iattrs;
 
        inode->i_private = sysfs_get(sd);
        inode->i_mapping->a_ops = &sysfs_aops;
@@ -154,16 +212,20 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
        inode->i_ino = sd->s_ino;
        lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
 
-       if (sd->s_iattr) {
+       iattrs = sd->s_iattr;
+       if (iattrs) {
                /* sysfs_dirent has non-default attributes
                 * get them for the new inode from persistent copy
                 * in sysfs_dirent
                 */
-               set_inode_attr(inode, sd->s_iattr);
+               set_inode_attr(inode, &iattrs->ia_iattr);
+               if (iattrs->ia_secdata)
+                       security_inode_notifysecctx(inode,
+                                               iattrs->ia_secdata,
+                                               iattrs->ia_secdata_len);
        } else
                set_default_inode_attr(inode, sd->s_mode);
 
-
        /* initialize inode according to type */
        switch (sysfs_type(sd)) {
        case SYSFS_DIR:
index 1d897ad808e0b1d234c302bc745a3c858848ce6b..c5081ad77026e95689e58fda616dc0784b958044 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kobject.h>
 #include <linux/namei.h>
 #include <linux/mutex.h>
+#include <linux/security.h>
 
 #include "sysfs.h"
 
@@ -209,6 +210,7 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co
 }
 
 const struct inode_operations sysfs_symlink_inode_operations = {
+       .setxattr = sysfs_setxattr,
        .readlink = generic_readlink,
        .follow_link = sysfs_follow_link,
        .put_link = sysfs_put_link,
index 3fa0d98481e2253bd444c1656a50f96d35a150a7..af4c4e7482ac80cd41d9072fcf1a9150a626694c 100644 (file)
@@ -8,6 +8,8 @@
  * This file is released under the GPLv2.
  */
 
+#include <linux/fs.h>
+
 struct sysfs_open_dirent;
 
 /* type-specific structures for sysfs_dirent->s_* union members */
@@ -31,6 +33,12 @@ struct sysfs_elem_bin_attr {
        struct hlist_head       buffers;
 };
 
+struct sysfs_inode_attrs {
+       struct iattr    ia_iattr;
+       void            *ia_secdata;
+       u32             ia_secdata_len;
+};
+
 /*
  * sysfs_dirent - the building block of sysfs hierarchy.  Each and
  * every sysfs node is represented by single sysfs_dirent.
@@ -56,7 +64,7 @@ struct sysfs_dirent {
        unsigned int            s_flags;
        ino_t                   s_ino;
        umode_t                 s_mode;
-       struct iattr            *s_iattr;
+       struct sysfs_inode_attrs *s_iattr;
 };
 
 #define SD_DEACTIVATED_BIAS            INT_MIN
@@ -148,6 +156,8 @@ static inline void __sysfs_put(struct sysfs_dirent *sd)
 struct inode *sysfs_get_inode(struct sysfs_dirent *sd);
 void sysfs_delete_inode(struct inode *inode);
 int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
+int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+               size_t size, int flags);
 int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
 int sysfs_inode_init(void);
 
index 1c3d0af59ddf84c7fb51c3f5da52803d2d095e9a..6d4f6d3449fbb8f3749e86148c3ee0d3c28c26eb 100644 (file)
@@ -66,22 +66,28 @@ xattr_permission(struct inode *inode, const char *name, int mask)
        return inode_permission(inode, mask);
 }
 
-int
-vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
-               size_t size, int flags)
+/**
+ *  __vfs_setxattr_noperm - perform setxattr operation without performing
+ *  permission checks.
+ *
+ *  @dentry - object to perform setxattr on
+ *  @name - xattr name to set
+ *  @value - value to set @name to
+ *  @size - size of @value
+ *  @flags - flags to pass into filesystem operations
+ *
+ *  returns the result of the internal setxattr or setsecurity operations.
+ *
+ *  This function requires the caller to lock the inode's i_mutex before it
+ *  is executed. It also assumes that the caller will make the appropriate
+ *  permission checks.
+ */
+int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
+               const void *value, size_t size, int flags)
 {
        struct inode *inode = dentry->d_inode;
-       int error;
-
-       error = xattr_permission(inode, name, MAY_WRITE);
-       if (error)
-               return error;
+       int error = -EOPNOTSUPP;
 
-       mutex_lock(&inode->i_mutex);
-       error = security_inode_setxattr(dentry, name, value, size, flags);
-       if (error)
-               goto out;
-       error = -EOPNOTSUPP;
        if (inode->i_op->setxattr) {
                error = inode->i_op->setxattr(dentry, name, value, size, flags);
                if (!error) {
@@ -97,6 +103,29 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
                if (!error)
                        fsnotify_xattr(dentry);
        }
+
+       return error;
+}
+
+
+int
+vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+               size_t size, int flags)
+{
+       struct inode *inode = dentry->d_inode;
+       int error;
+
+       error = xattr_permission(inode, name, MAY_WRITE);
+       if (error)
+               return error;
+
+       mutex_lock(&inode->i_mutex);
+       error = security_inode_setxattr(dentry, name, value, size, flags);
+       if (error)
+               goto out;
+
+       error = __vfs_setxattr_noperm(dentry, name, value, size, flags);
+
 out:
        mutex_unlock(&inode->i_mutex);
        return error;
index 4fa9996963109dcc44edcfda3cce8100dd48f29e..24520a539c6ff18b9067b24d56dc22075c7096e2 100644 (file)
@@ -114,6 +114,13 @@ struct thread_group_cred {
  */
 struct cred {
        atomic_t        usage;
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       atomic_t        subscribers;    /* number of processes subscribed */
+       void            *put_addr;
+       unsigned        magic;
+#define CRED_MAGIC     0x43736564
+#define CRED_MAGIC_DEAD        0x44656144
+#endif
        uid_t           uid;            /* real UID of the task */
        gid_t           gid;            /* real GID of the task */
        uid_t           suid;           /* saved UID of the task */
@@ -143,7 +150,9 @@ struct cred {
 };
 
 extern void __put_cred(struct cred *);
+extern void exit_creds(struct task_struct *);
 extern int copy_creds(struct task_struct *, unsigned long);
+extern struct cred *cred_alloc_blank(void);
 extern struct cred *prepare_creds(void);
 extern struct cred *prepare_exec_creds(void);
 extern struct cred *prepare_usermodehelper_creds(void);
@@ -158,6 +167,60 @@ extern int set_security_override_from_ctx(struct cred *, const char *);
 extern int set_create_files_as(struct cred *, struct inode *);
 extern void __init cred_init(void);
 
+/*
+ * check for validity of credentials
+ */
+#ifdef CONFIG_DEBUG_CREDENTIALS
+extern void __invalid_creds(const struct cred *, const char *, unsigned);
+extern void __validate_process_creds(struct task_struct *,
+                                    const char *, unsigned);
+
+static inline bool creds_are_invalid(const struct cred *cred)
+{
+       if (cred->magic != CRED_MAGIC)
+               return true;
+       if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers))
+               return true;
+#ifdef CONFIG_SECURITY_SELINUX
+       if ((unsigned long) cred->security < PAGE_SIZE)
+               return true;
+       if ((*(u32*)cred->security & 0xffffff00) ==
+           (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))
+               return true;
+#endif
+       return false;
+}
+
+static inline void __validate_creds(const struct cred *cred,
+                                   const char *file, unsigned line)
+{
+       if (unlikely(creds_are_invalid(cred)))
+               __invalid_creds(cred, file, line);
+}
+
+#define validate_creds(cred)                           \
+do {                                                   \
+       __validate_creds((cred), __FILE__, __LINE__);   \
+} while(0)
+
+#define validate_process_creds()                               \
+do {                                                           \
+       __validate_process_creds(current, __FILE__, __LINE__);  \
+} while(0)
+
+extern void validate_creds_for_do_exit(struct task_struct *);
+#else
+static inline void validate_creds(const struct cred *cred)
+{
+}
+static inline void validate_creds_for_do_exit(struct task_struct *tsk)
+{
+}
+static inline void validate_process_creds(void)
+{
+}
+#endif
+
 /**
  * get_new_cred - Get a reference on a new set of credentials
  * @cred: The new credentials to reference
@@ -186,7 +249,9 @@ 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;
+       validate_creds(cred);
+       return get_new_cred(nonconst_cred);
 }
 
 /**
@@ -204,7 +269,7 @@ static inline void put_cred(const struct cred *_cred)
 {
        struct cred *cred = (struct cred *) _cred;
 
-       BUG_ON(atomic_read(&(cred)->usage) <= 0);
+       validate_creds(cred);
        if (atomic_dec_and_test(&(cred)->usage))
                __put_cred(cred);
 }
index e544f466d69a421cf48f2b626b0bf90d1ec22033..cd50dfa1d4c224de2a26e2d8ef3926d7fc74435e 100644 (file)
@@ -129,7 +129,10 @@ struct key {
        struct rw_semaphore     sem;            /* change vs change sem */
        struct key_user         *user;          /* owner of this key */
        void                    *security;      /* security data for this key */
-       time_t                  expiry;         /* time at which key expires (or 0) */
+       union {
+               time_t          expiry;         /* time at which key expires (or 0) */
+               time_t          revoked_at;     /* time at which key was revoked */
+       };
        uid_t                   uid;
        gid_t                   gid;
        key_perm_t              perm;           /* access permissions */
@@ -275,6 +278,8 @@ static inline key_serial_t key_serial(struct key *key)
 extern ctl_table key_sysctls[];
 #endif
 
+extern void key_replace_session_keyring(void);
+
 /*
  * the userspace interface
  */
@@ -297,6 +302,7 @@ extern void key_init(void);
 #define key_fsuid_changed(t)           do { } while(0)
 #define key_fsgid_changed(t)           do { } while(0)
 #define key_init()                     do { } while(0)
+#define key_replace_session_keyring()  do { } while(0)
 
 #endif /* CONFIG_KEYS */
 #endif /* __KERNEL__ */
index c0688eb7209396bf8ca3d5ba3202f6b8033ef981..bd383f1944fb2fde14bcd4ae5dbd6a92714168fb 100644 (file)
@@ -52,5 +52,6 @@
 #define KEYCTL_SET_TIMEOUT             15      /* set key timeout */
 #define KEYCTL_ASSUME_AUTHORITY                16      /* assume request_key() authorisation */
 #define KEYCTL_GET_SECURITY            17      /* get key security label */
+#define KEYCTL_SESSION_TO_PARENT       18      /* apply session keyring to parent process */
 
 #endif /*  _LINUX_KEYCTL_H */
index e461b2c3d711a078bddba5086ee9df5143734ef7..190c37854870f4cf201dbe8c7970eab8b2788cac 100644 (file)
@@ -33,6 +33,7 @@ struct common_audit_data {
 #define LSM_AUDIT_DATA_IPC     4
 #define LSM_AUDIT_DATA_TASK    5
 #define LSM_AUDIT_DATA_KEY     6
+#define LSM_AUDIT_NO_AUDIT     7
        struct task_struct *tsk;
        union   {
                struct {
@@ -66,16 +67,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;
@@ -83,10 +87,12 @@ struct common_audit_data {
                        u16 tclass;
                        u32 requested;
                        u32 audited;
+                       u32 denied;
                        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 +110,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 0f1ea4a6695763debe7a6e87bf586c36efcc0c76..9304027673b0ac6abb0daf0bc8128dee3db0fcda 100644 (file)
@@ -1292,6 +1292,7 @@ struct task_struct {
        struct mutex cred_guard_mutex;  /* guard against foreign influences on
                                         * credential calculations
                                         * (notably. ptrace) */
+       struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */
 
        char comm[TASK_COMM_LEN]; /* executable name excluding path
                                     - access with [gs]et_task_comm (which lock
@@ -2077,7 +2078,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 1f16eea2017b1062caf0be4540c4e0cb19a2bb27..d050b66ab9ef0415b169122590f7335714ad9b2e 100644 (file)
@@ -53,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,
@@ -653,6 +653,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     manual page for definitions of the @clone_flags.
  *     @clone_flags contains the flags indicating what should be shared.
  *     Return 0 if permission is granted.
+ * @cred_alloc_blank:
+ *     @cred points to the credentials.
+ *     @gfp indicates the atomicity of any memory allocations.
+ *     Only allocate sufficient memory and attach to @cred such that
+ *     cred_transfer() will not get ENOMEM.
  * @cred_free:
  *     @cred points to the credentials.
  *     Deallocate and clear the cred->security field in a set of credentials.
@@ -665,6 +670,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @new points to the new credentials.
  *     @old points to the original credentials.
  *     Install a new set of credentials.
+ * @cred_transfer:
+ *     @new points to the new credentials.
+ *     @old points to the original credentials.
+ *     Transfer data from original creds to new creds
  * @kernel_act_as:
  *     Set the credentials for a kernel service to act as (subjective context).
  *     @new points to the credentials to be modified.
@@ -678,6 +687,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     @inode points to the inode to use as a reference.
  *     The current task must be the one that nominated @inode.
  *     Return 0 if successful.
+ * @kernel_module_request:
+ *     Ability to trigger the kernel to automatically upcall to userspace for
+ *     userspace to load a kernel module with the given name.
+ *     Return 0 if successful.
  * @task_setuid:
  *     Check permission before setting one or more of the user identity
  *     attributes of the current process.  The @flags parameter indicates
@@ -994,6 +1007,17 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     Sets the connection's peersid to the secmark on skb.
  * @req_classify_flow:
  *     Sets the flow's sid to the openreq sid.
+ * @tun_dev_create:
+ *     Check permissions prior to creating a new TUN device.
+ * @tun_dev_post_create:
+ *     This hook allows a module to update or allocate a per-socket security
+ *     structure.
+ *     @sk contains the newly created sock structure.
+ * @tun_dev_attach:
+ *     Check permissions prior to attaching to a persistent TUN device.  This
+ *     hook can also be used by the module to update any security state
+ *     associated with the TUN device's sock structure.
+ *     @sk contains the existing sock structure.
  *
  * Security hooks for XFRM operations.
  *
@@ -1088,6 +1112,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     Return the length of the string (including terminating NUL) or -ve if
  *      an error.
  *     May also return 0 (and a NULL buffer pointer) if there is no label.
+ * @key_session_to_parent:
+ *     Forcibly assign the session keyring from a process to its parent
+ *     process.
+ *     @cred: Pointer to process's credentials
+ *     @parent_cred: Pointer to parent process's credentials
+ *     @keyring: Proposed new session keyring
+ *     Return 0 if permission is granted, -ve error otherwise.
  *
  * Security hooks affecting all System V IPC operations.
  *
@@ -1229,7 +1260,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
@@ -1244,7 +1275,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.
@@ -1351,12 +1382,47 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     audit_rule_init.
  *     @rule contains the allocated rule
  *
+ * @inode_notifysecctx:
+ *     Notify the security module of what the security context of an inode
+ *     should be.  Initializes the incore security context managed by the
+ *     security module for this inode.  Example usage:  NFS client invokes
+ *     this hook to initialize the security context in its incore inode to the
+ *     value provided by the server for the file when the server returned the
+ *     file's attributes to the client.
+ *
+ *     Must be called with inode->i_mutex locked.
+ *
+ *     @inode we wish to set the security context of.
+ *     @ctx contains the string which we wish to set in the inode.
+ *     @ctxlen contains the length of @ctx.
+ *
+ * @inode_setsecctx:
+ *     Change the security context of an inode.  Updates the
+ *     incore security context managed by the security module and invokes the
+ *     fs code as needed (via __vfs_setxattr_noperm) to update any backing
+ *     xattrs that represent the context.  Example usage:  NFS server invokes
+ *     this hook to change the security context in its incore inode and on the
+ *     backing filesystem to a value provided by the client on a SETATTR
+ *     operation.
+ *
+ *     Must be called with inode->i_mutex locked.
+ *
+ *     @dentry contains the inode we wish to set the security context of.
+ *     @ctx contains the string which we wish to set in the inode.
+ *     @ctxlen contains the length of @ctx.
+ *
+ * @inode_getsecctx:
+ *     Returns a string containing all relavent security context information
+ *
+ *     @inode we wish to set the security context of.
+ *     @ctx is a pointer in which to place the allocated security context.
+ *     @ctxlen points to the place to put the length of @ctx.
  * This is the main security structure.
  */
 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,
@@ -1483,12 +1549,15 @@ struct security_operations {
        int (*dentry_open) (struct file *file, const struct cred *cred);
 
        int (*task_create) (unsigned long clone_flags);
+       int (*cred_alloc_blank) (struct cred *cred, gfp_t gfp);
        void (*cred_free) (struct cred *cred);
        int (*cred_prepare)(struct cred *new, const struct cred *old,
                            gfp_t gfp);
        void (*cred_commit)(struct cred *new, const struct cred *old);
+       void (*cred_transfer)(struct cred *new, const struct cred *old);
        int (*kernel_act_as)(struct cred *new, u32 secid);
        int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
+       int (*kernel_module_request)(void);
        int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags);
        int (*task_fix_setuid) (struct cred *new, const struct cred *old,
                                int flags);
@@ -1556,6 +1625,10 @@ struct security_operations {
        int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
        void (*release_secctx) (char *secdata, u32 seclen);
 
+       int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
+       int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
+       int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
+
 #ifdef CONFIG_SECURITY_NETWORK
        int (*unix_stream_connect) (struct socket *sock,
                                    struct socket *other, struct sock *newsk);
@@ -1592,6 +1665,9 @@ struct security_operations {
        void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req);
        void (*inet_conn_established) (struct sock *sk, struct sk_buff *skb);
        void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl);
+       int (*tun_dev_create)(void);
+       void (*tun_dev_post_create)(struct sock *sk);
+       int (*tun_dev_attach)(struct sock *sk);
 #endif /* CONFIG_SECURITY_NETWORK */
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -1620,6 +1696,9 @@ struct security_operations {
                               const struct cred *cred,
                               key_perm_t perm);
        int (*key_getsecurity)(struct key *key, char **_buffer);
+       int (*key_session_to_parent)(const struct cred *cred,
+                                    const struct cred *parent_cred,
+                                    struct key *key);
 #endif /* CONFIG_KEYS */
 
 #ifdef CONFIG_AUDIT
@@ -1637,7 +1716,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,
@@ -1736,11 +1815,14 @@ int security_file_send_sigiotask(struct task_struct *tsk,
 int security_file_receive(struct file *file);
 int security_dentry_open(struct file *file, const struct cred *cred);
 int security_task_create(unsigned long clone_flags);
+int security_cred_alloc_blank(struct cred *cred, gfp_t gfp);
 void security_cred_free(struct cred *cred);
 int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
 void security_commit_creds(struct cred *new, const struct cred *old);
+void security_transfer_creds(struct cred *new, const struct cred *old);
 int security_kernel_act_as(struct cred *new, u32 secid);
 int security_kernel_create_files_as(struct cred *new, struct inode *inode);
+int security_kernel_module_request(void);
 int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags);
 int security_task_fix_setuid(struct cred *new, const struct cred *old,
                             int flags);
@@ -1796,6 +1878,9 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
 int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
 void security_release_secctx(char *secdata, u32 seclen);
 
+int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
+int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
+int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
 #else /* CONFIG_SECURITY */
 struct security_mnt_opts {
 };
@@ -1818,10 +1903,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)
@@ -2266,6 +2351,11 @@ static inline int security_task_create(unsigned long clone_flags)
        return 0;
 }
 
+static inline int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
+{
+       return 0;
+}
+
 static inline void security_cred_free(struct cred *cred)
 { }
 
@@ -2281,6 +2371,11 @@ static inline void security_commit_creds(struct cred *new,
 {
 }
 
+static inline void security_transfer_creds(struct cred *new,
+                                          const struct cred *old)
+{
+}
+
 static inline int security_kernel_act_as(struct cred *cred, u32 secid)
 {
        return 0;
@@ -2292,6 +2387,11 @@ static inline int security_kernel_create_files_as(struct cred *cred,
        return 0;
 }
 
+static inline int security_kernel_module_request(void)
+{
+       return 0;
+}
+
 static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2,
                                       int flags)
 {
@@ -2537,6 +2637,19 @@ static inline int security_secctx_to_secid(const char *secdata,
 static inline void security_release_secctx(char *secdata, u32 seclen)
 {
 }
+
+static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+       return -EOPNOTSUPP;
+}
+static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+       return -EOPNOTSUPP;
+}
+static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+       return -EOPNOTSUPP;
+}
 #endif /* CONFIG_SECURITY */
 
 #ifdef CONFIG_SECURITY_NETWORK
@@ -2575,6 +2688,9 @@ void security_inet_csk_clone(struct sock *newsk,
                        const struct request_sock *req);
 void security_inet_conn_established(struct sock *sk,
                        struct sk_buff *skb);
+int security_tun_dev_create(void);
+void security_tun_dev_post_create(struct sock *sk);
+int security_tun_dev_attach(struct sock *sk);
 
 #else  /* CONFIG_SECURITY_NETWORK */
 static inline int security_unix_stream_connect(struct socket *sock,
@@ -2725,6 +2841,20 @@ static inline void security_inet_conn_established(struct sock *sk,
                        struct sk_buff *skb)
 {
 }
+
+static inline int security_tun_dev_create(void)
+{
+       return 0;
+}
+
+static inline void security_tun_dev_post_create(struct sock *sk)
+{
+}
+
+static inline int security_tun_dev_attach(struct sock *sk)
+{
+       return 0;
+}
 #endif /* CONFIG_SECURITY_NETWORK */
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -2881,6 +3011,9 @@ void security_key_free(struct key *key);
 int security_key_permission(key_ref_t key_ref,
                            const struct cred *cred, key_perm_t perm);
 int security_key_getsecurity(struct key *key, char **_buffer);
+int security_key_session_to_parent(const struct cred *cred,
+                                  const struct cred *parent_cred,
+                                  struct key *key);
 
 #else
 
@@ -2908,6 +3041,13 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer)
        return 0;
 }
 
+static inline int security_key_session_to_parent(const struct cred *cred,
+                                                const struct cred *parent_cred,
+                                                struct key *key)
+{
+       return 0;
+}
+
 #endif
 #endif /* CONFIG_KEYS */
 
index d131e352cfe1f1ec9b0157625cc2db98d1b8098a..5c84af8c5f6fd7014439570a8d958f9b83eadecb 100644 (file)
@@ -49,6 +49,7 @@ struct xattr_handler {
 ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
 ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
 ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
+int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int);
 int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
 int vfs_removexattr(struct dentry *, const char *);
 
index 9f3391090b3e826d1d7cb935e58f7d01aa054b37..9a4715a2f6bf67ecfc35310bdf7e42ead2ee11c8 100644 (file)
@@ -491,13 +491,17 @@ static void do_acct_process(struct bsd_acct_struct *acct,
        u64 run_time;
        struct timespec uptime;
        struct tty_struct *tty;
+       const struct cred *orig_cred;
+
+       /* Perform file operations on behalf of whoever enabled accounting */
+       orig_cred = override_creds(file->f_cred);
 
        /*
         * First check to see if there is enough free_space to continue
         * the process accounting system.
         */
        if (!check_free_space(acct, file))
-               return;
+               goto out;
 
        /*
         * Fill the accounting struct with the needed info as recorded
@@ -578,6 +582,8 @@ static void do_acct_process(struct bsd_acct_struct *acct,
                               sizeof(acct_t), &file->f_pos);
        current->signal->rlim[RLIMIT_FSIZE].rlim_cur = flim;
        set_fs(fs);
+out:
+       revert_creds(orig_cred);
 }
 
 /**
index 1bb4d7e5d61694a6b8c01ba47f8432dcd37c828e..006fcab009d5053d628ef44075612f2a966f22be 100644 (file)
 #include <linux/cn_proc.h>
 #include "cred-internals.h"
 
+#if 0
+#define kdebug(FMT, ...) \
+       printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__)
+#else
+static inline __attribute__((format(printf, 1, 2)))
+void no_printk(const char *fmt, ...)
+{
+}
+#define kdebug(FMT, ...) \
+       no_printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__)
+#endif
+
 static struct kmem_cache *cred_jar;
 
 /*
@@ -36,6 +48,10 @@ static struct thread_group_cred init_tgcred = {
  */
 struct cred init_cred = {
        .usage                  = ATOMIC_INIT(4),
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       .subscribers            = ATOMIC_INIT(2),
+       .magic                  = CRED_MAGIC,
+#endif
        .securebits             = SECUREBITS_DEFAULT,
        .cap_inheritable        = CAP_INIT_INH_SET,
        .cap_permitted          = CAP_FULL_SET,
@@ -48,6 +64,31 @@ struct cred init_cred = {
 #endif
 };
 
+static inline void set_cred_subscribers(struct cred *cred, int n)
+{
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       atomic_set(&cred->subscribers, n);
+#endif
+}
+
+static inline int read_cred_subscribers(const struct cred *cred)
+{
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       return atomic_read(&cred->subscribers);
+#else
+       return 0;
+#endif
+}
+
+static inline void alter_cred_subscribers(const struct cred *_cred, int n)
+{
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       struct cred *cred = (struct cred *) _cred;
+
+       atomic_add(n, &cred->subscribers);
+#endif
+}
+
 /*
  * Dispose of the shared task group credentials
  */
@@ -85,9 +126,22 @@ static void put_cred_rcu(struct rcu_head *rcu)
 {
        struct cred *cred = container_of(rcu, struct cred, rcu);
 
+       kdebug("put_cred_rcu(%p)", cred);
+
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       if (cred->magic != CRED_MAGIC_DEAD ||
+           atomic_read(&cred->usage) != 0 ||
+           read_cred_subscribers(cred) != 0)
+               panic("CRED: put_cred_rcu() sees %p with"
+                     " mag %x, put %p, usage %d, subscr %d\n",
+                     cred, cred->magic, cred->put_addr,
+                     atomic_read(&cred->usage),
+                     read_cred_subscribers(cred));
+#else
        if (atomic_read(&cred->usage) != 0)
                panic("CRED: put_cred_rcu() sees %p with usage %d\n",
                      cred, atomic_read(&cred->usage));
+#endif
 
        security_cred_free(cred);
        key_put(cred->thread_keyring);
@@ -106,12 +160,90 @@ static void put_cred_rcu(struct rcu_head *rcu)
  */
 void __put_cred(struct cred *cred)
 {
+       kdebug("__put_cred(%p{%d,%d})", cred,
+              atomic_read(&cred->usage),
+              read_cred_subscribers(cred));
+
        BUG_ON(atomic_read(&cred->usage) != 0);
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       BUG_ON(read_cred_subscribers(cred) != 0);
+       cred->magic = CRED_MAGIC_DEAD;
+       cred->put_addr = __builtin_return_address(0);
+#endif
+       BUG_ON(cred == current->cred);
+       BUG_ON(cred == current->real_cred);
 
        call_rcu(&cred->rcu, put_cred_rcu);
 }
 EXPORT_SYMBOL(__put_cred);
 
+/*
+ * Clean up a task's credentials when it exits
+ */
+void exit_creds(struct task_struct *tsk)
+{
+       struct cred *cred;
+
+       kdebug("exit_creds(%u,%p,%p,{%d,%d})", tsk->pid, tsk->real_cred, tsk->cred,
+              atomic_read(&tsk->cred->usage),
+              read_cred_subscribers(tsk->cred));
+
+       cred = (struct cred *) tsk->real_cred;
+       tsk->real_cred = NULL;
+       validate_creds(cred);
+       alter_cred_subscribers(cred, -1);
+       put_cred(cred);
+
+       cred = (struct cred *) tsk->cred;
+       tsk->cred = NULL;
+       validate_creds(cred);
+       alter_cred_subscribers(cred, -1);
+       put_cred(cred);
+
+       cred = (struct cred *) tsk->replacement_session_keyring;
+       if (cred) {
+               tsk->replacement_session_keyring = NULL;
+               validate_creds(cred);
+               put_cred(cred);
+       }
+}
+
+/*
+ * Allocate blank credentials, such that the credentials can be filled in at a
+ * later date without risk of ENOMEM.
+ */
+struct cred *cred_alloc_blank(void)
+{
+       struct cred *new;
+
+       new = kmem_cache_zalloc(cred_jar, GFP_KERNEL);
+       if (!new)
+               return NULL;
+
+#ifdef CONFIG_KEYS
+       new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL);
+       if (!new->tgcred) {
+               kfree(new);
+               return NULL;
+       }
+       atomic_set(&new->tgcred->usage, 1);
+#endif
+
+       atomic_set(&new->usage, 1);
+
+       if (security_cred_alloc_blank(new, GFP_KERNEL) < 0)
+               goto error;
+
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       new->magic = CRED_MAGIC;
+#endif
+       return new;
+
+error:
+       abort_creds(new);
+       return NULL;
+}
+
 /**
  * prepare_creds - Prepare a new set of credentials for modification
  *
@@ -132,16 +264,19 @@ struct cred *prepare_creds(void)
        const struct cred *old;
        struct cred *new;
 
-       BUG_ON(atomic_read(&task->real_cred->usage) < 1);
+       validate_process_creds();
 
        new = kmem_cache_alloc(cred_jar, GFP_KERNEL);
        if (!new)
                return NULL;
 
+       kdebug("prepare_creds() alloc %p", new);
+
        old = task->cred;
        memcpy(new, old, sizeof(struct cred));
 
        atomic_set(&new->usage, 1);
+       set_cred_subscribers(new, 0);
        get_group_info(new->group_info);
        get_uid(new->user);
 
@@ -157,6 +292,7 @@ struct cred *prepare_creds(void)
 
        if (security_prepare_creds(new, old, GFP_KERNEL) < 0)
                goto error;
+       validate_creds(new);
        return new;
 
 error:
@@ -229,9 +365,12 @@ struct cred *prepare_usermodehelper_creds(void)
        if (!new)
                return NULL;
 
+       kdebug("prepare_usermodehelper_creds() alloc %p", new);
+
        memcpy(new, &init_cred, sizeof(struct cred));
 
        atomic_set(&new->usage, 1);
+       set_cred_subscribers(new, 0);
        get_group_info(new->group_info);
        get_uid(new->user);
 
@@ -250,6 +389,7 @@ struct cred *prepare_usermodehelper_creds(void)
 #endif
        if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0)
                goto error;
+       validate_creds(new);
 
        BUG_ON(atomic_read(&new->usage) != 1);
        return new;
@@ -286,6 +426,10 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
            ) {
                p->real_cred = get_cred(p->cred);
                get_cred(p->cred);
+               alter_cred_subscribers(p->cred, 2);
+               kdebug("share_creds(%p{%d,%d})",
+                      p->cred, atomic_read(&p->cred->usage),
+                      read_cred_subscribers(p->cred));
                atomic_inc(&p->cred->user->processes);
                return 0;
        }
@@ -331,6 +475,8 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
 
        atomic_inc(&new->user->processes);
        p->cred = p->real_cred = get_cred(new);
+       alter_cred_subscribers(new, 2);
+       validate_creds(new);
        return 0;
 
 error_put:
@@ -355,13 +501,20 @@ error_put:
 int commit_creds(struct cred *new)
 {
        struct task_struct *task = current;
-       const struct cred *old;
+       const struct cred *old = task->real_cred;
 
-       BUG_ON(task->cred != task->real_cred);
-       BUG_ON(atomic_read(&task->real_cred->usage) < 2);
+       kdebug("commit_creds(%p{%d,%d})", new,
+              atomic_read(&new->usage),
+              read_cred_subscribers(new));
+
+       BUG_ON(task->cred != old);
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       BUG_ON(read_cred_subscribers(old) < 2);
+       validate_creds(old);
+       validate_creds(new);
+#endif
        BUG_ON(atomic_read(&new->usage) < 1);
 
-       old = task->real_cred;
        security_commit_creds(new, old);
 
        get_cred(new); /* we will require a ref for the subj creds too */
@@ -390,12 +543,14 @@ int commit_creds(struct cred *new)
         *   cheaply with the new uid cache, so if it matters
         *   we should be checking for it.  -DaveM
         */
+       alter_cred_subscribers(new, 2);
        if (new->user != old->user)
                atomic_inc(&new->user->processes);
        rcu_assign_pointer(task->real_cred, new);
        rcu_assign_pointer(task->cred, new);
        if (new->user != old->user)
                atomic_dec(&old->user->processes);
+       alter_cred_subscribers(old, -2);
 
        sched_switch_user(task);
 
@@ -428,6 +583,13 @@ EXPORT_SYMBOL(commit_creds);
  */
 void abort_creds(struct cred *new)
 {
+       kdebug("abort_creds(%p{%d,%d})", new,
+              atomic_read(&new->usage),
+              read_cred_subscribers(new));
+
+#ifdef CONFIG_DEBUG_CREDENTIALS
+       BUG_ON(read_cred_subscribers(new) != 0);
+#endif
        BUG_ON(atomic_read(&new->usage) < 1);
        put_cred(new);
 }
@@ -444,7 +606,20 @@ const struct cred *override_creds(const struct cred *new)
 {
        const struct cred *old = current->cred;
 
-       rcu_assign_pointer(current->cred, get_cred(new));
+       kdebug("override_creds(%p{%d,%d})", new,
+              atomic_read(&new->usage),
+              read_cred_subscribers(new));
+
+       validate_creds(old);
+       validate_creds(new);
+       get_cred(new);
+       alter_cred_subscribers(new, 1);
+       rcu_assign_pointer(current->cred, new);
+       alter_cred_subscribers(old, -1);
+
+       kdebug("override_creds() = %p{%d,%d}", old,
+              atomic_read(&old->usage),
+              read_cred_subscribers(old));
        return old;
 }
 EXPORT_SYMBOL(override_creds);
@@ -460,7 +635,15 @@ void revert_creds(const struct cred *old)
 {
        const struct cred *override = current->cred;
 
+       kdebug("revert_creds(%p{%d,%d})", old,
+              atomic_read(&old->usage),
+              read_cred_subscribers(old));
+
+       validate_creds(old);
+       validate_creds(override);
+       alter_cred_subscribers(old, 1);
        rcu_assign_pointer(current->cred, old);
+       alter_cred_subscribers(override, -1);
        put_cred(override);
 }
 EXPORT_SYMBOL(revert_creds);
@@ -502,11 +685,15 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
        if (!new)
                return NULL;
 
+       kdebug("prepare_kernel_cred() alloc %p", new);
+
        if (daemon)
                old = get_task_cred(daemon);
        else
                old = get_cred(&init_cred);
 
+       validate_creds(old);
+
        *new = *old;
        get_uid(new->user);
        get_group_info(new->group_info);
@@ -526,7 +713,9 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
                goto error;
 
        atomic_set(&new->usage, 1);
+       set_cred_subscribers(new, 0);
        put_cred(old);
+       validate_creds(new);
        return new;
 
 error:
@@ -589,3 +778,95 @@ int set_create_files_as(struct cred *new, struct inode *inode)
        return security_kernel_create_files_as(new, inode);
 }
 EXPORT_SYMBOL(set_create_files_as);
+
+#ifdef CONFIG_DEBUG_CREDENTIALS
+
+/*
+ * dump invalid credentials
+ */
+static void dump_invalid_creds(const struct cred *cred, const char *label,
+                              const struct task_struct *tsk)
+{
+       printk(KERN_ERR "CRED: %s credentials: %p %s%s%s\n",
+              label, cred,
+              cred == &init_cred ? "[init]" : "",
+              cred == tsk->real_cred ? "[real]" : "",
+              cred == tsk->cred ? "[eff]" : "");
+       printk(KERN_ERR "CRED: ->magic=%x, put_addr=%p\n",
+              cred->magic, cred->put_addr);
+       printk(KERN_ERR "CRED: ->usage=%d, subscr=%d\n",
+              atomic_read(&cred->usage),
+              read_cred_subscribers(cred));
+       printk(KERN_ERR "CRED: ->*uid = { %d,%d,%d,%d }\n",
+              cred->uid, cred->euid, cred->suid, cred->fsuid);
+       printk(KERN_ERR "CRED: ->*gid = { %d,%d,%d,%d }\n",
+              cred->gid, cred->egid, cred->sgid, cred->fsgid);
+#ifdef CONFIG_SECURITY
+       printk(KERN_ERR "CRED: ->security is %p\n", cred->security);
+       if ((unsigned long) cred->security >= PAGE_SIZE &&
+           (((unsigned long) cred->security & 0xffffff00) !=
+            (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)))
+               printk(KERN_ERR "CRED: ->security {%x, %x}\n",
+                      ((u32*)cred->security)[0],
+                      ((u32*)cred->security)[1]);
+#endif
+}
+
+/*
+ * report use of invalid credentials
+ */
+void __invalid_creds(const struct cred *cred, const char *file, unsigned line)
+{
+       printk(KERN_ERR "CRED: Invalid credentials\n");
+       printk(KERN_ERR "CRED: At %s:%u\n", file, line);
+       dump_invalid_creds(cred, "Specified", current);
+       BUG();
+}
+EXPORT_SYMBOL(__invalid_creds);
+
+/*
+ * check the credentials on a process
+ */
+void __validate_process_creds(struct task_struct *tsk,
+                             const char *file, unsigned line)
+{
+       if (tsk->cred == tsk->real_cred) {
+               if (unlikely(read_cred_subscribers(tsk->cred) < 2 ||
+                            creds_are_invalid(tsk->cred)))
+                       goto invalid_creds;
+       } else {
+               if (unlikely(read_cred_subscribers(tsk->real_cred) < 1 ||
+                            read_cred_subscribers(tsk->cred) < 1 ||
+                            creds_are_invalid(tsk->real_cred) ||
+                            creds_are_invalid(tsk->cred)))
+                       goto invalid_creds;
+       }
+       return;
+
+invalid_creds:
+       printk(KERN_ERR "CRED: Invalid process credentials\n");
+       printk(KERN_ERR "CRED: At %s:%u\n", file, line);
+
+       dump_invalid_creds(tsk->real_cred, "Real", tsk);
+       if (tsk->cred != tsk->real_cred)
+               dump_invalid_creds(tsk->cred, "Effective", tsk);
+       else
+               printk(KERN_ERR "CRED: Effective creds == Real creds\n");
+       BUG();
+}
+EXPORT_SYMBOL(__validate_process_creds);
+
+/*
+ * check creds for do_exit()
+ */
+void validate_creds_for_do_exit(struct task_struct *tsk)
+{
+       kdebug("validate_creds_for_do_exit(%p,%p{%d,%d})",
+              tsk->real_cred, tsk->cred,
+              atomic_read(&tsk->cred->usage),
+              read_cred_subscribers(tsk->cred));
+
+       __validate_process_creds(tsk, __FILE__, __LINE__);
+}
+
+#endif /* CONFIG_DEBUG_CREDENTIALS */
index 869dc221733e27701c275a0bdf283404507108f6..c98ff7a8025f70fad1ce747daaeb20bca4c553bb 100644 (file)
@@ -901,6 +901,8 @@ NORET_TYPE void do_exit(long code)
 
        tracehook_report_exit(&code);
 
+       validate_creds_for_do_exit(tsk);
+
        /*
         * We're taking recursive faults here in do_exit. Safest is to just
         * leave this task alone and wait for reboot.
@@ -1009,6 +1011,8 @@ NORET_TYPE void do_exit(long code)
        if (tsk->splice_pipe)
                __free_pipe_info(tsk->splice_pipe);
 
+       validate_creds_for_do_exit(tsk);
+
        preempt_disable();
        /* causes final put_task_struct in finish_task_switch(). */
        tsk->state = TASK_DEAD;
index e6c04d462ab250b806cd2e7d76d84fd1729d121e..aab8579c6093bb5f1c63a26876d45546e25c21df 100644 (file)
@@ -152,8 +152,7 @@ void __put_task_struct(struct task_struct *tsk)
        WARN_ON(atomic_read(&tsk->usage));
        WARN_ON(tsk == current);
 
-       put_cred(tsk->real_cred);
-       put_cred(tsk->cred);
+       exit_creds(tsk);
        delayacct_tsk_free(tsk);
 
        if (!profile_handoff_task(tsk))
@@ -1297,8 +1296,7 @@ bad_fork_cleanup_put_domain:
        module_put(task_thread_info(p)->exec_domain->module);
 bad_fork_cleanup_count:
        atomic_dec(&p->cred->user->processes);
-       put_cred(p->real_cred);
-       put_cred(p->cred);
+       exit_creds(p);
 bad_fork_free:
        free_task(p);
 fork_out:
index 385c31a1bdbf3118b3d82d44b6720af727738bcb..4e8cae2e9148153c5055a91d42948e38a685c22f 100644 (file)
@@ -78,6 +78,10 @@ int __request_module(bool wait, const char *fmt, ...)
 #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */
        static int kmod_loop_msg;
 
+       ret = security_kernel_module_request();
+       if (ret)
+               return ret;
+
        va_start(args, fmt);
        ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
        va_end(args);
@@ -462,6 +466,7 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
        int retval = 0;
 
        BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
+       validate_creds(sub_info->cred);
 
        helper_lock();
        if (sub_info->path[0] == '\0')
index 082c320e4dbf0a4538b064f55814c72246852877..307c285af59e89141412181d547f0fca7d4c7073 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 58be76017fd000f3b019c0acab6d3cdeb672afda..71d8dc7f99208629b63eb73800a69ea85e119c43 100644 (file)
@@ -49,7 +49,6 @@
 #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>
 
index 12327b2bb785c256a59cb864a2c2b8976c33e5aa..fbb87cf138c516db92f9282cf0ee01c1aaa443c3 100644 (file)
@@ -653,6 +653,21 @@ config DEBUG_NOTIFIERS
          This is a relatively cheap check but if you care about maximum
          performance, say N.
 
+config DEBUG_CREDENTIALS
+       bool "Debug credential management"
+       depends on DEBUG_KERNEL
+       help
+         Enable this to turn on some debug checking for credential
+         management.  The additional code keeps track of the number of
+         pointers from task_structs to any given cred struct, and checks to
+         see that this number never exceeds the usage count of the cred
+         struct.
+
+         Furthermore, if SELinux is enabled, this also checks that the
+         security pointer in the cred struct is never seen to be invalid.
+
+         If unsure, say N.
+
 #
 # Select this config option from the architecture Kconfig, if it
 # it is preferred to always offer frame pointers as a config
index f1ed2fe76c6575b9fc7ad28fdc215f87e6a73b3e..bd2bea963364c757e90db1e47ce557a94d053c0b 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 6a94475aee8594279eb90d94cc164c5169e533c5..278d489aad3bcecadcbbc38413ba4143c507159b 100644 (file)
@@ -1031,7 +1031,7 @@ void dev_load(struct net *net, const char *name)
        dev = __dev_get_by_name(net, name);
        read_unlock(&dev_base_lock);
 
-       if (!dev && capable(CAP_SYS_MODULE))
+       if (!dev && capable(CAP_NET_ADMIN))
                request_module("%s", name);
 }
 
index e92beb9e55e0d834c3184e4b2a5c6e4faa5ea057..6428b342b16442d48864c53ee7d4f8b25fc6a42c 100644 (file)
@@ -116,7 +116,7 @@ int tcp_set_default_congestion_control(const char *name)
        spin_lock(&tcp_cong_list_lock);
        ca = tcp_ca_find(name);
 #ifdef CONFIG_MODULES
-       if (!ca && capable(CAP_SYS_MODULE)) {
+       if (!ca && capable(CAP_NET_ADMIN)) {
                spin_unlock(&tcp_cong_list_lock);
 
                request_module("tcp_%s", name);
@@ -246,7 +246,7 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
 
 #ifdef CONFIG_MODULES
        /* not found attempt to autoload module */
-       if (!ca && capable(CAP_SYS_MODULE)) {
+       if (!ca && capable(CAP_NET_ADMIN)) {
                rcu_read_unlock();
                request_module("tcp_%s", name);
                rcu_read_lock();
index b56e7f9ecbc2adf22706a849d704d8761dfa91dd..95ecc06392d73bed265e63d5a1b0f8772721f051 100644 (file)
@@ -16,9 +16,7 @@ obj-$(CONFIG_SECURITYFS)              += inode.o
 # Must precede capability.o in order to stack properly.
 obj-$(CONFIG_SECURITY_SELINUX)         += selinux/built-in.o
 obj-$(CONFIG_SECURITY_SMACK)           += smack/built-in.o
-ifeq ($(CONFIG_AUDIT),y)
-obj-$(CONFIG_SECURITY_SMACK)           += lsm_audit.o
-endif
+obj-$(CONFIG_AUDIT)                    += lsm_audit.o
 obj-$(CONFIG_SECURITY_TOMOYO)          += tomoyo/built-in.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)                += root_plug.o
 obj-$(CONFIG_CGROUP_DEVICE)            += device_cgroup.o
index 88f752e8152cbe1ea888747121181035fcb8fbbb..fce07a7bc8257e9e57afa2681d96d71d22cbb785 100644 (file)
@@ -373,6 +373,11 @@ static int cap_task_create(unsigned long clone_flags)
        return 0;
 }
 
+static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp)
+{
+       return 0;
+}
+
 static void cap_cred_free(struct cred *cred)
 {
 }
@@ -386,6 +391,10 @@ static void cap_cred_commit(struct cred *new, const struct cred *old)
 {
 }
 
+static void cap_cred_transfer(struct cred *new, const struct cred *old)
+{
+}
+
 static int cap_kernel_act_as(struct cred *new, u32 secid)
 {
        return 0;
@@ -396,6 +405,11 @@ static int cap_kernel_create_files_as(struct cred *new, struct inode *inode)
        return 0;
 }
 
+static int cap_kernel_module_request(void)
+{
+       return 0;
+}
+
 static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
 {
        return 0;
@@ -701,10 +715,26 @@ static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb)
 {
 }
 
+
+
 static void cap_req_classify_flow(const struct request_sock *req,
                                  struct flowi *fl)
 {
 }
+
+static int cap_tun_dev_create(void)
+{
+       return 0;
+}
+
+static void cap_tun_dev_post_create(struct sock *sk)
+{
+}
+
+static int cap_tun_dev_attach(struct sock *sk)
+{
+       return 0;
+}
 #endif /* CONFIG_SECURITY_NETWORK */
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -792,6 +822,20 @@ static void cap_release_secctx(char *secdata, u32 seclen)
 {
 }
 
+static int cap_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+       return 0;
+}
+
+static int cap_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+       return 0;
+}
+
+static int cap_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+       return 0;
+}
 #ifdef CONFIG_KEYS
 static int cap_key_alloc(struct key *key, const struct cred *cred,
                         unsigned long flags)
@@ -815,6 +859,13 @@ static int cap_key_getsecurity(struct key *key, char **_buffer)
        return 0;
 }
 
+static int cap_key_session_to_parent(const struct cred *cred,
+                                    const struct cred *parent_cred,
+                                    struct key *key)
+{
+       return 0;
+}
+
 #endif /* CONFIG_KEYS */
 
 #ifdef CONFIG_AUDIT
@@ -854,7 +905,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);
@@ -940,11 +991,14 @@ void security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, file_receive);
        set_to_cap_if_null(ops, dentry_open);
        set_to_cap_if_null(ops, task_create);
+       set_to_cap_if_null(ops, cred_alloc_blank);
        set_to_cap_if_null(ops, cred_free);
        set_to_cap_if_null(ops, cred_prepare);
        set_to_cap_if_null(ops, cred_commit);
+       set_to_cap_if_null(ops, cred_transfer);
        set_to_cap_if_null(ops, kernel_act_as);
        set_to_cap_if_null(ops, kernel_create_files_as);
+       set_to_cap_if_null(ops, kernel_module_request);
        set_to_cap_if_null(ops, task_setuid);
        set_to_cap_if_null(ops, task_fix_setuid);
        set_to_cap_if_null(ops, task_setgid);
@@ -992,6 +1046,9 @@ void security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, secid_to_secctx);
        set_to_cap_if_null(ops, secctx_to_secid);
        set_to_cap_if_null(ops, release_secctx);
+       set_to_cap_if_null(ops, inode_notifysecctx);
+       set_to_cap_if_null(ops, inode_setsecctx);
+       set_to_cap_if_null(ops, inode_getsecctx);
 #ifdef CONFIG_SECURITY_NETWORK
        set_to_cap_if_null(ops, unix_stream_connect);
        set_to_cap_if_null(ops, unix_may_send);
@@ -1020,6 +1077,9 @@ void security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, inet_csk_clone);
        set_to_cap_if_null(ops, inet_conn_established);
        set_to_cap_if_null(ops, req_classify_flow);
+       set_to_cap_if_null(ops, tun_dev_create);
+       set_to_cap_if_null(ops, tun_dev_post_create);
+       set_to_cap_if_null(ops, tun_dev_attach);
 #endif /* CONFIG_SECURITY_NETWORK */
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
        set_to_cap_if_null(ops, xfrm_policy_alloc_security);
@@ -1038,6 +1098,7 @@ void security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, key_free);
        set_to_cap_if_null(ops, key_permission);
        set_to_cap_if_null(ops, key_getsecurity);
+       set_to_cap_if_null(ops, key_session_to_parent);
 #endif /* CONFIG_KEYS */
 #ifdef CONFIG_AUDIT
        set_to_cap_if_null(ops, audit_rule_init);
index e3097c0a1311205cc231cee85cb012b271db1ed8..fe30751a6cd9cb8862fa7fcbd19a3b818264c934 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;
 
index 747a464943aff0ada556e903fa6750fc7b670b60..74d5447d7df7259d83f54f5af5ff176fe4b5b37f 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 obj-y := \
+       gc.o \
        key.o \
        keyring.o \
        keyctl.o \
index c766c68a63bc2078c62bf256730e05e14b36268b..792c0a611a6d115a5a272ca748af6c1804c762ef 100644 (file)
@@ -82,6 +82,9 @@ asmlinkage long compat_sys_keyctl(u32 option,
        case KEYCTL_GET_SECURITY:
                return keyctl_get_security(arg2, compat_ptr(arg3), arg4);
 
+       case KEYCTL_SESSION_TO_PARENT:
+               return keyctl_session_to_parent();
+
        default:
                return -EOPNOTSUPP;
        }
diff --git a/security/keys/gc.c b/security/keys/gc.c
new file mode 100644 (file)
index 0000000..1e616ae
--- /dev/null
@@ -0,0 +1,194 @@
+/* Key garbage collector
+ *
+ * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <keys/keyring-type.h>
+#include "internal.h"
+
+/*
+ * Delay between key revocation/expiry in seconds
+ */
+unsigned key_gc_delay = 5 * 60;
+
+/*
+ * Reaper
+ */
+static void key_gc_timer_func(unsigned long);
+static void key_garbage_collector(struct work_struct *);
+static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0);
+static DECLARE_WORK(key_gc_work, key_garbage_collector);
+static key_serial_t key_gc_cursor; /* the last key the gc considered */
+static unsigned long key_gc_executing;
+static time_t key_gc_next_run = LONG_MAX;
+
+/*
+ * Schedule a garbage collection run
+ * - precision isn't particularly important
+ */
+void key_schedule_gc(time_t gc_at)
+{
+       unsigned long expires;
+       time_t now = current_kernel_time().tv_sec;
+
+       kenter("%ld", gc_at - now);
+
+       gc_at += key_gc_delay;
+
+       if (now >= gc_at) {
+               schedule_work(&key_gc_work);
+       } else if (gc_at < key_gc_next_run) {
+               expires = jiffies + (gc_at - now) * HZ;
+               mod_timer(&key_gc_timer, expires);
+       }
+}
+
+/*
+ * The garbage collector timer kicked off
+ */
+static void key_gc_timer_func(unsigned long data)
+{
+       kenter("");
+       key_gc_next_run = LONG_MAX;
+       schedule_work(&key_gc_work);
+}
+
+/*
+ * Garbage collect pointers from a keyring
+ * - return true if we altered the keyring
+ */
+static bool key_gc_keyring(struct key *keyring, time_t limit)
+       __releases(key_serial_lock)
+{
+       struct keyring_list *klist;
+       struct key *key;
+       int loop;
+
+       kenter("%x", key_serial(keyring));
+
+       if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
+               goto dont_gc;
+
+       /* scan the keyring looking for dead keys */
+       klist = rcu_dereference(keyring->payload.subscriptions);
+       if (!klist)
+               goto dont_gc;
+
+       for (loop = klist->nkeys - 1; loop >= 0; loop--) {
+               key = klist->keys[loop];
+               if (test_bit(KEY_FLAG_DEAD, &key->flags) ||
+                   (key->expiry > 0 && key->expiry <= limit))
+                       goto do_gc;
+       }
+
+dont_gc:
+       kleave(" = false");
+       return false;
+
+do_gc:
+       key_gc_cursor = keyring->serial;
+       key_get(keyring);
+       spin_unlock(&key_serial_lock);
+       keyring_gc(keyring, limit);
+       key_put(keyring);
+       kleave(" = true");
+       return true;
+}
+
+/*
+ * Garbage collector for keys
+ * - this involves scanning the keyrings for dead, expired and revoked keys
+ *   that have overstayed their welcome
+ */
+static void key_garbage_collector(struct work_struct *work)
+{
+       struct rb_node *rb;
+       key_serial_t cursor;
+       struct key *key, *xkey;
+       time_t new_timer = LONG_MAX, limit;
+
+       kenter("");
+
+       if (test_and_set_bit(0, &key_gc_executing)) {
+               key_schedule_gc(current_kernel_time().tv_sec);
+               return;
+       }
+
+       limit = current_kernel_time().tv_sec;
+       if (limit > key_gc_delay)
+               limit -= key_gc_delay;
+       else
+               limit = key_gc_delay;
+
+       spin_lock(&key_serial_lock);
+
+       if (RB_EMPTY_ROOT(&key_serial_tree))
+               goto reached_the_end;
+
+       cursor = key_gc_cursor;
+       if (cursor < 0)
+               cursor = 0;
+
+       /* find the first key above the cursor */
+       key = NULL;
+       rb = key_serial_tree.rb_node;
+       while (rb) {
+               xkey = rb_entry(rb, struct key, serial_node);
+               if (cursor < xkey->serial) {
+                       key = xkey;
+                       rb = rb->rb_left;
+               } else if (cursor > xkey->serial) {
+                       rb = rb->rb_right;
+               } else {
+                       rb = rb_next(rb);
+                       if (!rb)
+                               goto reached_the_end;
+                       key = rb_entry(rb, struct key, serial_node);
+                       break;
+               }
+       }
+
+       if (!key)
+               goto reached_the_end;
+
+       /* trawl through the keys looking for keyrings */
+       for (;;) {
+               if (key->expiry > 0 && key->expiry < new_timer)
+                       new_timer = key->expiry;
+
+               if (key->type == &key_type_keyring &&
+                   key_gc_keyring(key, limit)) {
+                       /* the gc ate our lock */
+                       schedule_work(&key_gc_work);
+                       goto no_unlock;
+               }
+
+               rb = rb_next(&key->serial_node);
+               if (!rb) {
+                       key_gc_cursor = 0;
+                       break;
+               }
+               key = rb_entry(rb, struct key, serial_node);
+       }
+
+out:
+       spin_unlock(&key_serial_lock);
+no_unlock:
+       clear_bit(0, &key_gc_executing);
+       if (new_timer < LONG_MAX)
+               key_schedule_gc(new_timer);
+
+       kleave("");
+       return;
+
+reached_the_end:
+       key_gc_cursor = 0;
+       goto out;
+}
index 9fb679c66b8af3c90f85b7c016ff5657268685d2..24ba0307b7ad4a98382fd348a813d9722f85b444 100644 (file)
@@ -124,11 +124,18 @@ extern struct key *request_key_and_link(struct key_type *type,
                                        struct key *dest_keyring,
                                        unsigned long flags);
 
-extern key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
+extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
                                 key_perm_t perm);
+#define KEY_LOOKUP_CREATE      0x01
+#define KEY_LOOKUP_PARTIAL     0x02
+#define KEY_LOOKUP_FOR_UNLINK  0x04
 
 extern long join_session_keyring(const char *name);
 
+extern unsigned key_gc_delay;
+extern void keyring_gc(struct key *keyring, time_t limit);
+extern void key_schedule_gc(time_t expiry_at);
+
 /*
  * check to see whether permission is granted to use a key in the desired way
  */
@@ -194,6 +201,7 @@ extern long keyctl_set_timeout(key_serial_t, unsigned);
 extern long keyctl_assume_authority(key_serial_t);
 extern long keyctl_get_security(key_serial_t keyid, char __user *buffer,
                                size_t buflen);
+extern long keyctl_session_to_parent(void);
 
 /*
  * debugging key validation
index 4a1297d1ada4f41d97fd314a8848d7e132112da4..08531ad0f252129beffbf93c451d218cbce29bfb 100644 (file)
@@ -500,6 +500,7 @@ int key_negate_and_link(struct key *key,
                set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
                now = current_kernel_time();
                key->expiry = now.tv_sec + timeout;
+               key_schedule_gc(key->expiry);
 
                if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
                        awaken = 1;
@@ -642,10 +643,8 @@ struct key *key_lookup(key_serial_t id)
        goto error;
 
  found:
-       /* pretend it doesn't exist if it's dead */
-       if (atomic_read(&key->usage) == 0 ||
-           test_bit(KEY_FLAG_DEAD, &key->flags) ||
-           key->type == &key_type_dead)
+       /* pretend it doesn't exist if it is awaiting deletion */
+       if (atomic_read(&key->usage) == 0)
                goto not_found;
 
        /* this races with key_put(), but that doesn't matter since key_put()
@@ -890,6 +889,9 @@ EXPORT_SYMBOL(key_update);
  */
 void key_revoke(struct key *key)
 {
+       struct timespec now;
+       time_t time;
+
        key_check(key);
 
        /* make sure no one's trying to change or use the key when we mark it
@@ -902,6 +904,14 @@ void key_revoke(struct key *key)
            key->type->revoke)
                key->type->revoke(key);
 
+       /* set the death time to no more than the expiry time */
+       now = current_kernel_time();
+       time = now.tv_sec;
+       if (key->revoked_at == 0 || key->revoked_at > time) {
+               key->revoked_at = time;
+               key_schedule_gc(key->revoked_at);
+       }
+
        up_write(&key->sem);
 
 } /* end key_revoke() */
@@ -958,8 +968,10 @@ void unregister_key_type(struct key_type *ktype)
        for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
                key = rb_entry(_n, struct key, serial_node);
 
-               if (key->type == ktype)
+               if (key->type == ktype) {
                        key->type = &key_type_dead;
+                       set_bit(KEY_FLAG_DEAD, &key->flags);
+               }
        }
 
        spin_unlock(&key_serial_lock);
@@ -984,6 +996,8 @@ void unregister_key_type(struct key_type *ktype)
        spin_unlock(&key_serial_lock);
        up_write(&key_types_sem);
 
+       key_schedule_gc(0);
+
 } /* end unregister_key_type() */
 
 EXPORT_SYMBOL(unregister_key_type);
index 7f09fb897d2b49e1b4a1e2f96e942094b9239474..74c96852459281cab2b959a0b2db55666c7c9a7b 100644 (file)
@@ -103,7 +103,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
        }
 
        /* find the target keyring (which must be writable) */
-       keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+       keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
                goto error3;
@@ -185,7 +185,8 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
        /* get the destination keyring if specified */
        dest_ref = NULL;
        if (destringid) {
-               dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+               dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
+                                          KEY_WRITE);
                if (IS_ERR(dest_ref)) {
                        ret = PTR_ERR(dest_ref);
                        goto error3;
@@ -233,9 +234,11 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
 long keyctl_get_keyring_ID(key_serial_t id, int create)
 {
        key_ref_t key_ref;
+       unsigned long lflags;
        long ret;
 
-       key_ref = lookup_user_key(id, create, 0, KEY_SEARCH);
+       lflags = create ? KEY_LOOKUP_CREATE : 0;
+       key_ref = lookup_user_key(id, lflags, KEY_SEARCH);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error;
@@ -309,7 +312,7 @@ long keyctl_update_key(key_serial_t id,
        }
 
        /* find the target key (which must be writable) */
-       key_ref = lookup_user_key(id, 0, 0, KEY_WRITE);
+       key_ref = lookup_user_key(id, 0, KEY_WRITE);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error2;
@@ -337,10 +340,16 @@ long keyctl_revoke_key(key_serial_t id)
        key_ref_t key_ref;
        long ret;
 
-       key_ref = lookup_user_key(id, 0, 0, KEY_WRITE);
+       key_ref = lookup_user_key(id, 0, KEY_WRITE);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
-               goto error;
+               if (ret != -EACCES)
+                       goto error;
+               key_ref = lookup_user_key(id, 0, KEY_SETATTR);
+               if (IS_ERR(key_ref)) {
+                       ret = PTR_ERR(key_ref);
+                       goto error;
+               }
        }
 
        key_revoke(key_ref_to_ptr(key_ref));
@@ -363,7 +372,7 @@ long keyctl_keyring_clear(key_serial_t ringid)
        key_ref_t keyring_ref;
        long ret;
 
-       keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+       keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
                goto error;
@@ -389,13 +398,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
        key_ref_t keyring_ref, key_ref;
        long ret;
 
-       keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+       keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
                goto error;
        }
 
-       key_ref = lookup_user_key(id, 1, 0, KEY_LINK);
+       key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error2;
@@ -423,13 +432,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
        key_ref_t keyring_ref, key_ref;
        long ret;
 
-       keyring_ref = lookup_user_key(ringid, 0, 0, KEY_WRITE);
+       keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
                goto error;
        }
 
-       key_ref = lookup_user_key(id, 0, 0, 0);
+       key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error2;
@@ -465,7 +474,7 @@ long keyctl_describe_key(key_serial_t keyid,
        char *tmpbuf;
        long ret;
 
-       key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW);
+       key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW);
        if (IS_ERR(key_ref)) {
                /* viewing a key under construction is permitted if we have the
                 * authorisation token handy */
@@ -474,7 +483,8 @@ long keyctl_describe_key(key_serial_t keyid,
                        if (!IS_ERR(instkey)) {
                                key_put(instkey);
                                key_ref = lookup_user_key(keyid,
-                                                         0, 1, 0);
+                                                         KEY_LOOKUP_PARTIAL,
+                                                         0);
                                if (!IS_ERR(key_ref))
                                        goto okay;
                        }
@@ -558,7 +568,7 @@ long keyctl_keyring_search(key_serial_t ringid,
        }
 
        /* get the keyring at which to begin the search */
-       keyring_ref = lookup_user_key(ringid, 0, 0, KEY_SEARCH);
+       keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH);
        if (IS_ERR(keyring_ref)) {
                ret = PTR_ERR(keyring_ref);
                goto error2;
@@ -567,7 +577,8 @@ long keyctl_keyring_search(key_serial_t ringid,
        /* get the destination keyring if specified */
        dest_ref = NULL;
        if (destringid) {
-               dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+               dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE,
+                                          KEY_WRITE);
                if (IS_ERR(dest_ref)) {
                        ret = PTR_ERR(dest_ref);
                        goto error3;
@@ -637,7 +648,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
        long ret;
 
        /* find the key first */
-       key_ref = lookup_user_key(keyid, 0, 0, 0);
+       key_ref = lookup_user_key(keyid, 0, 0);
        if (IS_ERR(key_ref)) {
                ret = -ENOKEY;
                goto error;
@@ -700,7 +711,8 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
        if (uid == (uid_t) -1 && gid == (gid_t) -1)
                goto error;
 
-       key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
+       key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
+                                 KEY_SETATTR);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error;
@@ -805,7 +817,8 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
        if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
                goto error;
 
-       key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
+       key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
+                                 KEY_SETATTR);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error;
@@ -847,7 +860,7 @@ static long get_instantiation_keyring(key_serial_t ringid,
 
        /* if a specific keyring is nominated by ID, then use that */
        if (ringid > 0) {
-               dkref = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+               dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE);
                if (IS_ERR(dkref))
                        return PTR_ERR(dkref);
                *_dest_keyring = key_ref_to_ptr(dkref);
@@ -1083,7 +1096,8 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
        time_t expiry;
        long ret;
 
-       key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR);
+       key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL,
+                                 KEY_SETATTR);
        if (IS_ERR(key_ref)) {
                ret = PTR_ERR(key_ref);
                goto error;
@@ -1101,6 +1115,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
        }
 
        key->expiry = expiry;
+       key_schedule_gc(key->expiry);
 
        up_write(&key->sem);
        key_put(key);
@@ -1170,7 +1185,7 @@ long keyctl_get_security(key_serial_t keyid,
        char *context;
        long ret;
 
-       key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW);
+       key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW);
        if (IS_ERR(key_ref)) {
                if (PTR_ERR(key_ref) != -EACCES)
                        return PTR_ERR(key_ref);
@@ -1182,7 +1197,7 @@ long keyctl_get_security(key_serial_t keyid,
                        return PTR_ERR(key_ref);
                key_put(instkey);
 
-               key_ref = lookup_user_key(keyid, 0, 1, 0);
+               key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0);
                if (IS_ERR(key_ref))
                        return PTR_ERR(key_ref);
        }
@@ -1213,6 +1228,105 @@ long keyctl_get_security(key_serial_t keyid,
        return ret;
 }
 
+/*
+ * attempt to install the calling process's session keyring on the process's
+ * parent process
+ * - the keyring must exist and must grant us LINK permission
+ * - implements keyctl(KEYCTL_SESSION_TO_PARENT)
+ */
+long keyctl_session_to_parent(void)
+{
+       struct task_struct *me, *parent;
+       const struct cred *mycred, *pcred;
+       struct cred *cred, *oldcred;
+       key_ref_t keyring_r;
+       int ret;
+
+       keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK);
+       if (IS_ERR(keyring_r))
+               return PTR_ERR(keyring_r);
+
+       /* our parent is going to need a new cred struct, a new tgcred struct
+        * and new security data, so we allocate them here to prevent ENOMEM in
+        * our parent */
+       ret = -ENOMEM;
+       cred = cred_alloc_blank();
+       if (!cred)
+               goto error_keyring;
+
+       cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r);
+       keyring_r = NULL;
+
+       me = current;
+       write_lock_irq(&tasklist_lock);
+
+       parent = me->real_parent;
+       ret = -EPERM;
+
+       /* the parent mustn't be init and mustn't be a kernel thread */
+       if (parent->pid <= 1 || !parent->mm)
+               goto not_permitted;
+
+       /* the parent must be single threaded */
+       if (atomic_read(&parent->signal->count) != 1)
+               goto not_permitted;
+
+       /* the parent and the child must have different session keyrings or
+        * there's no point */
+       mycred = current_cred();
+       pcred = __task_cred(parent);
+       if (mycred == pcred ||
+           mycred->tgcred->session_keyring == pcred->tgcred->session_keyring)
+               goto already_same;
+
+       /* the parent must have the same effective ownership and mustn't be
+        * SUID/SGID */
+       if (pcred-> uid != mycred->euid ||
+           pcred->euid != mycred->euid ||
+           pcred->suid != mycred->euid ||
+           pcred-> gid != mycred->egid ||
+           pcred->egid != mycred->egid ||
+           pcred->sgid != mycred->egid)
+               goto not_permitted;
+
+       /* the keyrings must have the same UID */
+       if (pcred ->tgcred->session_keyring->uid != mycred->euid ||
+           mycred->tgcred->session_keyring->uid != mycred->euid)
+               goto not_permitted;
+
+       /* the LSM must permit the replacement of the parent's keyring with the
+        * keyring from this process */
+       ret = security_key_session_to_parent(mycred, pcred,
+                                            key_ref_to_ptr(keyring_r));
+       if (ret < 0)
+               goto not_permitted;
+
+       /* if there's an already pending keyring replacement, then we replace
+        * that */
+       oldcred = parent->replacement_session_keyring;
+
+       /* the replacement session keyring is applied just prior to userspace
+        * restarting */
+       parent->replacement_session_keyring = cred;
+       cred = NULL;
+       set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME);
+
+       write_unlock_irq(&tasklist_lock);
+       if (oldcred)
+               put_cred(oldcred);
+       return 0;
+
+already_same:
+       ret = 0;
+not_permitted:
+       put_cred(cred);
+       return ret;
+
+error_keyring:
+       key_ref_put(keyring_r);
+       return ret;
+}
+
 /*****************************************************************************/
 /*
  * the key control system call
@@ -1298,6 +1412,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
                                           (char __user *) arg3,
                                           (size_t) arg4);
 
+       case KEYCTL_SESSION_TO_PARENT:
+               return keyctl_session_to_parent();
+
        default:
                return -EOPNOTSUPP;
        }
index 3dba81c2eba360a615d9116e124cb36d86e89427..ac977f661a792780728e28d0f6faa374bccb5297 100644 (file)
@@ -1000,3 +1000,88 @@ static void keyring_revoke(struct key *keyring)
        }
 
 } /* end keyring_revoke() */
+
+/*
+ * Determine whether a key is dead
+ */
+static bool key_is_dead(struct key *key, time_t limit)
+{
+       return test_bit(KEY_FLAG_DEAD, &key->flags) ||
+               (key->expiry > 0 && key->expiry <= limit);
+}
+
+/*
+ * Collect garbage from the contents of a keyring
+ */
+void keyring_gc(struct key *keyring, time_t limit)
+{
+       struct keyring_list *klist, *new;
+       struct key *key;
+       int loop, keep, max;
+
+       kenter("%x", key_serial(keyring));
+
+       down_write(&keyring->sem);
+
+       klist = keyring->payload.subscriptions;
+       if (!klist)
+               goto just_return;
+
+       /* work out how many subscriptions we're keeping */
+       keep = 0;
+       for (loop = klist->nkeys - 1; loop >= 0; loop--)
+               if (!key_is_dead(klist->keys[loop], limit));
+                       keep++;
+
+       if (keep == klist->nkeys)
+               goto just_return;
+
+       /* allocate a new keyring payload */
+       max = roundup(keep, 4);
+       new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *),
+                     GFP_KERNEL);
+       if (!new)
+               goto just_return;
+       new->maxkeys = max;
+       new->nkeys = 0;
+       new->delkey = 0;
+
+       /* install the live keys
+        * - must take care as expired keys may be updated back to life
+        */
+       keep = 0;
+       for (loop = klist->nkeys - 1; loop >= 0; loop--) {
+               key = klist->keys[loop];
+               if (!key_is_dead(key, limit)) {
+                       if (keep >= max)
+                               goto discard_new;
+                       new->keys[keep++] = key_get(key);
+               }
+       }
+       new->nkeys = keep;
+
+       /* adjust the quota */
+       key_payload_reserve(keyring,
+                           sizeof(struct keyring_list) +
+                           KEYQUOTA_LINK_BYTES * keep);
+
+       if (keep == 0) {
+               rcu_assign_pointer(keyring->payload.subscriptions, NULL);
+               kfree(new);
+       } else {
+               rcu_assign_pointer(keyring->payload.subscriptions, new);
+       }
+
+       up_write(&keyring->sem);
+
+       call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
+       kleave(" [yes]");
+       return;
+
+discard_new:
+       new->nkeys = keep;
+       keyring_clear_rcu_disposal(&new->rcu);
+just_return:
+       up_write(&keyring->sem);
+       kleave(" [no]");
+}
index 769f9bdfd2b33aaeadbd7eb3efb895a364d0536a..9d01021ca0c8cdd9c25c8292daff990204ecf466 100644 (file)
@@ -91,59 +91,94 @@ __initcall(key_proc_init);
  */
 #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
 
-static struct rb_node *__key_serial_next(struct rb_node *n)
+static struct rb_node *key_serial_next(struct rb_node *n)
 {
+       struct user_namespace *user_ns = current_user_ns();
+
+       n = rb_next(n);
        while (n) {
                struct key *key = rb_entry(n, struct key, serial_node);
-               if (key->user->user_ns == current_user_ns())
+               if (key->user->user_ns == user_ns)
                        break;
                n = rb_next(n);
        }
        return n;
 }
 
-static struct rb_node *key_serial_next(struct rb_node *n)
+static int proc_keys_open(struct inode *inode, struct file *file)
 {
-       return __key_serial_next(rb_next(n));
+       return seq_open(file, &proc_keys_ops);
 }
 
-static struct rb_node *key_serial_first(struct rb_root *r)
+static struct key *find_ge_key(key_serial_t id)
 {
-       struct rb_node *n = rb_first(r);
-       return __key_serial_next(n);
-}
+       struct user_namespace *user_ns = current_user_ns();
+       struct rb_node *n = key_serial_tree.rb_node;
+       struct key *minkey = NULL;
 
-static int proc_keys_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &proc_keys_ops);
+       while (n) {
+               struct key *key = rb_entry(n, struct key, serial_node);
+               if (id < key->serial) {
+                       if (!minkey || minkey->serial > key->serial)
+                               minkey = key;
+                       n = n->rb_left;
+               } else if (id > key->serial) {
+                       n = n->rb_right;
+               } else {
+                       minkey = key;
+                       break;
+               }
+               key = NULL;
+       }
 
+       if (!minkey)
+               return NULL;
+
+       for (;;) {
+               if (minkey->user->user_ns == user_ns)
+                       return minkey;
+               n = rb_next(&minkey->serial_node);
+               if (!n)
+                       return NULL;
+               minkey = rb_entry(n, struct key, serial_node);
+       }
 }
 
 static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
+       __acquires(key_serial_lock)
 {
-       struct rb_node *_p;
-       loff_t pos = *_pos;
+       key_serial_t pos = *_pos;
+       struct key *key;
 
        spin_lock(&key_serial_lock);
 
-       _p = key_serial_first(&key_serial_tree);
-       while (pos > 0 && _p) {
-               pos--;
-               _p = key_serial_next(_p);
-       }
-
-       return _p;
+       if (*_pos > INT_MAX)
+               return NULL;
+       key = find_ge_key(pos);
+       if (!key)
+               return NULL;
+       *_pos = key->serial;
+       return &key->serial_node;
+}
 
+static inline key_serial_t key_node_serial(struct rb_node *n)
+{
+       struct key *key = rb_entry(n, struct key, serial_node);
+       return key->serial;
 }
 
 static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
 {
-       (*_pos)++;
-       return key_serial_next((struct rb_node *) v);
+       struct rb_node *n;
 
+       n = key_serial_next(v);
+       if (n)
+               *_pos = key_node_serial(n);
+       return n;
 }
 
 static void proc_keys_stop(struct seq_file *p, void *v)
+       __releases(key_serial_lock)
 {
        spin_unlock(&key_serial_lock);
 }
@@ -174,11 +209,9 @@ static int proc_keys_show(struct seq_file *m, void *v)
        /* come up with a suitable timeout value */
        if (key->expiry == 0) {
                memcpy(xbuf, "perm", 5);
-       }
-       else if (now.tv_sec >= key->expiry) {
+       } else if (now.tv_sec >= key->expiry) {
                memcpy(xbuf, "expd", 5);
-       }
-       else {
+       } else {
                timo = key->expiry - now.tv_sec;
 
                if (timo < 60)
@@ -218,9 +251,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
        seq_putc(m, '\n');
 
        rcu_read_unlock();
-
        return 0;
-
 }
 
 #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */
@@ -246,6 +277,7 @@ static struct rb_node *key_user_first(struct rb_root *r)
        struct rb_node *n = rb_first(r);
        return __key_user_next(n);
 }
+
 /*****************************************************************************/
 /*
  * implement "/proc/key-users" to provides a list of the key users
@@ -253,10 +285,10 @@ static struct rb_node *key_user_first(struct rb_root *r)
 static int proc_key_users_open(struct inode *inode, struct file *file)
 {
        return seq_open(file, &proc_key_users_ops);
-
 }
 
 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;
@@ -270,17 +302,16 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
        }
 
        return _p;
-
 }
 
 static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
 {
        (*_pos)++;
        return key_user_next((struct rb_node *) v);
-
 }
 
 static void proc_key_users_stop(struct seq_file *p, void *v)
+       __releases(key_user_lock)
 {
        spin_unlock(&key_user_lock);
 }
index 276d27882ce84394d7d6ce5b0c12d82e05f89987..5c23afb31ece464ad0165e1a3fb052a8969244c5 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/fs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
+#include <linux/security.h>
 #include <linux/user_namespace.h>
 #include <asm/uaccess.h>
 #include "internal.h"
@@ -487,7 +488,7 @@ static int lookup_user_key_possessed(const struct key *key, const void *target)
  * - don't create special keyrings unless so requested
  * - partially constructed keys aren't found unless requested
  */
-key_ref_t lookup_user_key(key_serial_t id, int create, int partial,
+key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
                          key_perm_t perm)
 {
        struct request_key_auth *rka;
@@ -503,7 +504,7 @@ try_again:
        switch (id) {
        case KEY_SPEC_THREAD_KEYRING:
                if (!cred->thread_keyring) {
-                       if (!create)
+                       if (!(lflags & KEY_LOOKUP_CREATE))
                                goto error;
 
                        ret = install_thread_keyring();
@@ -521,7 +522,7 @@ try_again:
 
        case KEY_SPEC_PROCESS_KEYRING:
                if (!cred->tgcred->process_keyring) {
-                       if (!create)
+                       if (!(lflags & KEY_LOOKUP_CREATE))
                                goto error;
 
                        ret = install_process_keyring();
@@ -642,7 +643,14 @@ try_again:
                break;
        }
 
-       if (!partial) {
+       /* unlink does not use the nominated key in any way, so can skip all
+        * the permission checks as it is only concerned with the keyring */
+       if (lflags & KEY_LOOKUP_FOR_UNLINK) {
+               ret = 0;
+               goto error;
+       }
+
+       if (!(lflags & KEY_LOOKUP_PARTIAL)) {
                ret = wait_for_key_construction(key, true);
                switch (ret) {
                case -ERESTARTSYS:
@@ -660,7 +668,8 @@ try_again:
        }
 
        ret = -EIO;
-       if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
+       if (!(lflags & KEY_LOOKUP_PARTIAL) &&
+           !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
                goto invalid_key;
 
        /* check the permissions */
@@ -702,7 +711,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();
@@ -760,3 +769,51 @@ error:
        abort_creds(new);
        return ret;
 }
+
+/*
+ * Replace a process's session keyring when that process resumes userspace on
+ * behalf of one of its children
+ */
+void key_replace_session_keyring(void)
+{
+       const struct cred *old;
+       struct cred *new;
+
+       if (!current->replacement_session_keyring)
+               return;
+
+       write_lock_irq(&tasklist_lock);
+       new = current->replacement_session_keyring;
+       current->replacement_session_keyring = NULL;
+       write_unlock_irq(&tasklist_lock);
+
+       if (!new)
+               return;
+
+       old = current_cred();
+       new->  uid      = old->  uid;
+       new-> euid      = old-> euid;
+       new-> suid      = old-> suid;
+       new->fsuid      = old->fsuid;
+       new->  gid      = old->  gid;
+       new-> egid      = old-> egid;
+       new-> sgid      = old-> sgid;
+       new->fsgid      = old->fsgid;
+       new->user       = get_uid(old->user);
+       new->group_info = get_group_info(old->group_info);
+
+       new->securebits = old->securebits;
+       new->cap_inheritable    = old->cap_inheritable;
+       new->cap_permitted      = old->cap_permitted;
+       new->cap_effective      = old->cap_effective;
+       new->cap_bset           = old->cap_bset;
+
+       new->jit_keyring        = old->jit_keyring;
+       new->thread_keyring     = key_get(old->thread_keyring);
+       new->tgcred->tgid       = old->tgcred->tgid;
+       new->tgcred->process_keyring = key_get(old->tgcred->process_keyring);
+
+       security_transfer_creds(new, old);
+
+       commit_creds(new);
+}
index b611d493c2d8be453551349f21c866bbfbb0ceac..5e05dc09e2dba0109ab931a57fecb97a4c017be9 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/sysctl.h>
 #include "internal.h"
 
+static const int zero, one = 1, max = INT_MAX;
+
 ctl_table key_sysctls[] = {
        {
                .ctl_name = CTL_UNNUMBERED,
@@ -20,7 +22,9 @@ ctl_table key_sysctls[] = {
                .data = &key_quota_maxkeys,
                .maxlen = sizeof(unsigned),
                .mode = 0644,
-               .proc_handler = &proc_dointvec,
+               .proc_handler = &proc_dointvec_minmax,
+               .extra1 = (void *) &one,
+               .extra2 = (void *) &max,
        },
        {
                .ctl_name = CTL_UNNUMBERED,
@@ -28,7 +32,9 @@ ctl_table key_sysctls[] = {
                .data = &key_quota_maxbytes,
                .maxlen = sizeof(unsigned),
                .mode = 0644,
-               .proc_handler = &proc_dointvec,
+               .proc_handler = &proc_dointvec_minmax,
+               .extra1 = (void *) &one,
+               .extra2 = (void *) &max,
        },
        {
                .ctl_name = CTL_UNNUMBERED,
@@ -36,7 +42,9 @@ ctl_table key_sysctls[] = {
                .data = &key_quota_root_maxkeys,
                .maxlen = sizeof(unsigned),
                .mode = 0644,
-               .proc_handler = &proc_dointvec,
+               .proc_handler = &proc_dointvec_minmax,
+               .extra1 = (void *) &one,
+               .extra2 = (void *) &max,
        },
        {
                .ctl_name = CTL_UNNUMBERED,
@@ -44,7 +52,19 @@ ctl_table key_sysctls[] = {
                .data = &key_quota_root_maxbytes,
                .maxlen = sizeof(unsigned),
                .mode = 0644,
-               .proc_handler = &proc_dointvec,
+               .proc_handler = &proc_dointvec_minmax,
+               .extra1 = (void *) &one,
+               .extra2 = (void *) &max,
+       },
+       {
+               .ctl_name = CTL_UNNUMBERED,
+               .procname = "gc_delay",
+               .data = &key_gc_delay,
+               .maxlen = sizeof(unsigned),
+               .mode = 0644,
+               .proc_handler = &proc_dointvec_minmax,
+               .extra1 = (void *) &zero,
+               .extra2 = (void *) &max,
        },
        { .ctl_name = 0 }
 };
index 94b868494b316dd15631d89ea49d5ced60ad99e5..500aad0ebd6acd8af2e63a7cbc8ae0965bbc5cdc 100644 (file)
@@ -220,6 +220,8 @@ static void dump_common_audit_data(struct audit_buffer *ab,
        }
 
        switch (a->type) {
+       case LSM_AUDIT_NO_AUDIT:
+               return;
        case LSM_AUDIT_DATA_IPC:
                audit_log_format(ab, " key=%d ", a->u.ipc_id);
                break;
index dc7674fbfc7a4a6fcfb132bc974f2c9480b90922..c4c673240c1c6761beadc94f3746e99d09c6a703 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)
@@ -684,6 +684,11 @@ int security_task_create(unsigned long clone_flags)
        return security_ops->task_create(clone_flags);
 }
 
+int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
+{
+       return security_ops->cred_alloc_blank(cred, gfp);
+}
+
 void security_cred_free(struct cred *cred)
 {
        security_ops->cred_free(cred);
@@ -699,6 +704,11 @@ void security_commit_creds(struct cred *new, const struct cred *old)
        security_ops->cred_commit(new, old);
 }
 
+void security_transfer_creds(struct cred *new, const struct cred *old)
+{
+       security_ops->cred_transfer(new, old);
+}
+
 int security_kernel_act_as(struct cred *new, u32 secid)
 {
        return security_ops->kernel_act_as(new, secid);
@@ -709,6 +719,11 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode)
        return security_ops->kernel_create_files_as(new, inode);
 }
 
+int security_kernel_module_request(void)
+{
+       return security_ops->kernel_module_request();
+}
+
 int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
 {
        return security_ops->task_setuid(id0, id1, id2, flags);
@@ -959,6 +974,24 @@ void security_release_secctx(char *secdata, u32 seclen)
 }
 EXPORT_SYMBOL(security_release_secctx);
 
+int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+       return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_notifysecctx);
+
+int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+       return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_setsecctx);
+
+int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+       return security_ops->inode_getsecctx(inode, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_getsecctx);
+
 #ifdef CONFIG_SECURITY_NETWORK
 
 int security_unix_stream_connect(struct socket *sock, struct socket *other,
@@ -1112,6 +1145,24 @@ void security_inet_conn_established(struct sock *sk,
        security_ops->inet_conn_established(sk, skb);
 }
 
+int security_tun_dev_create(void)
+{
+       return security_ops->tun_dev_create();
+}
+EXPORT_SYMBOL(security_tun_dev_create);
+
+void security_tun_dev_post_create(struct sock *sk)
+{
+       return security_ops->tun_dev_post_create(sk);
+}
+EXPORT_SYMBOL(security_tun_dev_post_create);
+
+int security_tun_dev_attach(struct sock *sk)
+{
+       return security_ops->tun_dev_attach(sk);
+}
+EXPORT_SYMBOL(security_tun_dev_attach);
+
 #endif /* CONFIG_SECURITY_NETWORK */
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -1218,6 +1269,13 @@ int security_key_getsecurity(struct key *key, char **_buffer)
        return security_ops->key_getsecurity(key, _buffer);
 }
 
+int security_key_session_to_parent(const struct cred *cred,
+                                  const struct cred *parent_cred,
+                                  struct key *key)
+{
+       return security_ops->key_session_to_parent(cred, parent_cred, key);
+}
+
 #endif /* CONFIG_KEYS */
 
 #ifdef CONFIG_AUDIT
index b2ab608598325bcea26430f6ebd1eac30a67ad61..e3d19014259b700e8e7fb55fae73d0f72d41330c 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;
@@ -492,23 +492,35 @@ out:
        return node;
 }
 
-static inline void avc_print_ipv6_addr(struct audit_buffer *ab,
-                                      struct in6_addr *addr, __be16 port,
-                                      char *name1, char *name2)
+/**
+ * avc_audit_pre_callback - SELinux specific information
+ * will be called by generic audit code
+ * @ab: the audit buffer
+ * @a: audit_data
+ */
+static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
 {
-       if (!ipv6_addr_any(addr))
-               audit_log_format(ab, " %s=%pI6", name1, addr);
-       if (port)
-               audit_log_format(ab, " %s=%d", name2, ntohs(port));
+       struct common_audit_data *ad = a;
+       audit_log_format(ab, "avc:  %s ",
+                        ad->selinux_audit_data.denied ? "denied" : "granted");
+       avc_dump_av(ab, ad->selinux_audit_data.tclass,
+                       ad->selinux_audit_data.audited);
+       audit_log_format(ab, " for ");
 }
 
-static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
-                                      __be16 port, char *name1, char *name2)
+/**
+ * avc_audit_post_callback - SELinux specific information
+ * will be called by generic audit code
+ * @ab: the audit buffer
+ * @a: audit_data
+ */
+static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
 {
-       if (addr)
-               audit_log_format(ab, " %s=%pI4", name1, &addr);
-       if (port)
-               audit_log_format(ab, " %s=%d", name2, ntohs(port));
+       struct common_audit_data *ad = a;
+       audit_log_format(ab, " ");
+       avc_dump_query(ab, ad->selinux_audit_data.ssid,
+                          ad->selinux_audit_data.tsid,
+                          ad->selinux_audit_data.tclass);
 }
 
 /**
@@ -532,13 +544,10 @@ static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
  */
 void avc_audit(u32 ssid, u32 tsid,
               u16 tclass, u32 requested,
-              struct av_decision *avd, int result, struct avc_audit_data *a)
+              struct av_decision *avd, int result, struct common_audit_data *a)
 {
-       struct task_struct *tsk = current;
-       struct inode *inode = NULL;
+       struct common_audit_data stack_data;
        u32 denied, audited;
-       struct audit_buffer *ab;
-
        denied = requested & ~avd->allowed;
        if (denied) {
                audited = denied;
@@ -551,144 +560,20 @@ void avc_audit(u32 ssid, u32 tsid,
                if (!(audited & avd->auditallow))
                        return;
        }
-
-       ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC);
-       if (!ab)
-               return;         /* audit_panic has been called */
-       audit_log_format(ab, "avc:  %s ", denied ? "denied" : "granted");
-       avc_dump_av(ab, tclass, audited);
-       audit_log_format(ab, " for ");
-       if (a && a->tsk)
-               tsk = a->tsk;
-       if (tsk && tsk->pid) {
-               audit_log_format(ab, " pid=%d comm=", tsk->pid);
-               audit_log_untrustedstring(ab, tsk->comm);
+       if (!a) {
+               a = &stack_data;
+               memset(a, 0, sizeof(*a));
+               a->type = LSM_AUDIT_NO_AUDIT;
        }
-       if (a) {
-               switch (a->type) {
-               case AVC_AUDIT_DATA_IPC:
-                       audit_log_format(ab, " key=%d", a->u.ipc_id);
-                       break;
-               case AVC_AUDIT_DATA_CAP:
-                       audit_log_format(ab, " capability=%d", a->u.cap);
-                       break;
-               case AVC_AUDIT_DATA_FS:
-                       if (a->u.fs.path.dentry) {
-                               struct dentry *dentry = a->u.fs.path.dentry;
-                               if (a->u.fs.path.mnt) {
-                                       audit_log_d_path(ab, "path=",
-                                                        &a->u.fs.path);
-                               } else {
-                                       audit_log_format(ab, " name=");
-                                       audit_log_untrustedstring(ab, dentry->d_name.name);
-                               }
-                               inode = dentry->d_inode;
-                       } else if (a->u.fs.inode) {
-                               struct dentry *dentry;
-                               inode = a->u.fs.inode;
-                               dentry = d_find_alias(inode);
-                               if (dentry) {
-                                       audit_log_format(ab, " name=");
-                                       audit_log_untrustedstring(ab, dentry->d_name.name);
-                                       dput(dentry);
-                               }
-                       }
-                       if (inode)
-                               audit_log_format(ab, " dev=%s ino=%lu",
-                                                inode->i_sb->s_id,
-                                                inode->i_ino);
-                       break;
-               case AVC_AUDIT_DATA_NET:
-                       if (a->u.net.sk) {
-                               struct sock *sk = a->u.net.sk;
-                               struct unix_sock *u;
-                               int len = 0;
-                               char *p = NULL;
-
-                               switch (sk->sk_family) {
-                               case AF_INET: {
-                                       struct inet_sock *inet = inet_sk(sk);
-
-                                       avc_print_ipv4_addr(ab, inet->rcv_saddr,
-                                                           inet->sport,
-                                                           "laddr", "lport");
-                                       avc_print_ipv4_addr(ab, inet->daddr,
-                                                           inet->dport,
-                                                           "faddr", "fport");
-                                       break;
-                               }
-                               case AF_INET6: {
-                                       struct inet_sock *inet = inet_sk(sk);
-                                       struct ipv6_pinfo *inet6 = inet6_sk(sk);
-
-                                       avc_print_ipv6_addr(ab, &inet6->rcv_saddr,
-                                                           inet->sport,
-                                                           "laddr", "lport");
-                                       avc_print_ipv6_addr(ab, &inet6->daddr,
-                                                           inet->dport,
-                                                           "faddr", "fport");
-                                       break;
-                               }
-                               case AF_UNIX:
-                                       u = unix_sk(sk);
-                                       if (u->dentry) {
-                                               struct path path = {
-                                                       .dentry = u->dentry,
-                                                       .mnt = u->mnt
-                                               };
-                                               audit_log_d_path(ab, "path=",
-                                                                &path);
-                                               break;
-                                       }
-                                       if (!u->addr)
-                                               break;
-                                       len = u->addr->len-sizeof(short);
-                                       p = &u->addr->name->sun_path[0];
-                                       audit_log_format(ab, " path=");
-                                       if (*p)
-                                               audit_log_untrustedstring(ab, p);
-                                       else
-                                               audit_log_n_hex(ab, p, len);
-                                       break;
-                               }
-                       }
-
-                       switch (a->u.net.family) {
-                       case AF_INET:
-                               avc_print_ipv4_addr(ab, a->u.net.v4info.saddr,
-                                                   a->u.net.sport,
-                                                   "saddr", "src");
-                               avc_print_ipv4_addr(ab, a->u.net.v4info.daddr,
-                                                   a->u.net.dport,
-                                                   "daddr", "dest");
-                               break;
-                       case AF_INET6:
-                               avc_print_ipv6_addr(ab, &a->u.net.v6info.saddr,
-                                                   a->u.net.sport,
-                                                   "saddr", "src");
-                               avc_print_ipv6_addr(ab, &a->u.net.v6info.daddr,
-                                                   a->u.net.dport,
-                                                   "daddr", "dest");
-                               break;
-                       }
-                       if (a->u.net.netif > 0) {
-                               struct net_device *dev;
-
-                               /* NOTE: we always use init's namespace */
-                               dev = dev_get_by_index(&init_net,
-                                                      a->u.net.netif);
-                               if (dev) {
-                                       audit_log_format(ab, " netif=%s",
-                                                        dev->name);
-                                       dev_put(dev);
-                               }
-                       }
-                       break;
-               }
-       }
-       audit_log_format(ab, " ");
-       avc_dump_query(ab, ssid, tsid, tclass);
-       audit_log_end(ab);
+       a->selinux_audit_data.tclass = tclass;
+       a->selinux_audit_data.requested = requested;
+       a->selinux_audit_data.ssid = ssid;
+       a->selinux_audit_data.tsid = tsid;
+       a->selinux_audit_data.audited = audited;
+       a->selinux_audit_data.denied = denied;
+       a->lsm_pre_audit = avc_audit_pre_callback;
+       a->lsm_post_audit = avc_audit_post_callback;
+       common_lsm_audit(a);
 }
 
 /**
@@ -956,7 +841,7 @@ out:
  * another -errno upon other errors.
  */
 int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
-                u32 requested, struct avc_audit_data *auditdata)
+                u32 requested, struct common_audit_data *auditdata)
 {
        struct av_decision avd;
        int rc;
@@ -970,3 +855,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 8d8b69c5664ef7f1eaa89c8a19139152ca159477..417f7c9945229175f79842c5a9637af6fd48fc1d 100644 (file)
@@ -13,8 +13,8 @@
  *                                        Eric Paris <eparis@redhat.com>
  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
  *                         <dgoeddel@trustedcs.com>
- *  Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
- *             Paul Moore <paul.moore@hp.com>
+ *  Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P.
+ *     Paul Moore <paul.moore@hp.com>
  *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
  *                    Yuichi Nakamura <ynakam@hitachisoft.jp>
  *
@@ -448,6 +448,10 @@ static int sb_finish_set_opts(struct super_block *sb)
            sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
                sbsec->flags &= ~SE_SBLABELSUPP;
 
+       /* Special handling for sysfs. Is genfs but also has setxattr handler*/
+       if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
+               sbsec->flags |= SE_SBLABELSUPP;
+
        /* Initialize the root inode. */
        rc = inode_doinit_with_dentry(root_inode, root);
 
@@ -1479,14 +1483,14 @@ static int task_has_capability(struct task_struct *tsk,
                               const struct cred *cred,
                               int cap, int audit)
 {
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        struct av_decision avd;
        u16 sclass;
        u32 sid = cred_sid(cred);
        u32 av = CAP_TO_MASK(cap);
        int rc;
 
-       AVC_AUDIT_DATA_INIT(&ad, CAP);
+       COMMON_AUDIT_DATA_INIT(&ad, CAP);
        ad.tsk = tsk;
        ad.u.cap = cap;
 
@@ -1525,12 +1529,14 @@ static int task_has_system(struct task_struct *tsk,
 static int inode_has_perm(const struct cred *cred,
                          struct inode *inode,
                          u32 perms,
-                         struct avc_audit_data *adp)
+                         struct common_audit_data *adp)
 {
        struct inode_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid;
 
+       validate_creds(cred);
+
        if (unlikely(IS_PRIVATE(inode)))
                return 0;
 
@@ -1539,7 +1545,7 @@ static int inode_has_perm(const struct cred *cred,
 
        if (!adp) {
                adp = &ad;
-               AVC_AUDIT_DATA_INIT(&ad, FS);
+               COMMON_AUDIT_DATA_INIT(&ad, FS);
                ad.u.fs.inode = inode;
        }
 
@@ -1555,9 +1561,9 @@ static inline int dentry_has_perm(const struct cred *cred,
                                  u32 av)
 {
        struct inode *inode = dentry->d_inode;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.mnt = mnt;
        ad.u.fs.path.dentry = dentry;
        return inode_has_perm(cred, inode, av, &ad);
@@ -1577,11 +1583,11 @@ static int file_has_perm(const struct cred *cred,
 {
        struct file_security_struct *fsec = file->f_security;
        struct inode *inode = file->f_path.dentry->d_inode;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = cred_sid(cred);
        int rc;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path = file->f_path;
 
        if (sid != fsec->sid) {
@@ -1612,7 +1618,7 @@ static int may_create(struct inode *dir,
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        int rc;
 
        dsec = dir->i_security;
@@ -1621,7 +1627,7 @@ static int may_create(struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
        rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
@@ -1665,7 +1671,7 @@ static int may_link(struct inode *dir,
 
 {
        struct inode_security_struct *dsec, *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        u32 av;
        int rc;
@@ -1673,7 +1679,7 @@ static int may_link(struct inode *dir,
        dsec = dir->i_security;
        isec = dentry->d_inode->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
        av = DIR__SEARCH;
@@ -1708,7 +1714,7 @@ static inline int may_rename(struct inode *old_dir,
                             struct dentry *new_dentry)
 {
        struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        u32 av;
        int old_is_dir, new_is_dir;
@@ -1719,7 +1725,7 @@ static inline int may_rename(struct inode *old_dir,
        old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
        new_dsec = new_dir->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
 
        ad.u.fs.path.dentry = old_dentry;
        rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
@@ -1761,7 +1767,7 @@ static inline int may_rename(struct inode *old_dir,
 static int superblock_has_perm(const struct cred *cred,
                               struct super_block *sb,
                               u32 perms,
-                              struct avc_audit_data *ad)
+                              struct common_audit_data *ad)
 {
        struct superblock_security_struct *sbsec;
        u32 sid = cred_sid(cred);
@@ -1855,12 +1861,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;
 
@@ -2101,7 +2107,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
        const struct task_security_struct *old_tsec;
        struct task_security_struct *new_tsec;
        struct inode_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        struct inode *inode = bprm->file->f_path.dentry->d_inode;
        int rc;
 
@@ -2139,7 +2145,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                        return rc;
        }
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path = bprm->file->f_path;
 
        if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
@@ -2232,7 +2238,7 @@ extern struct dentry *selinux_null;
 static inline void flush_unauthorized_files(const struct cred *cred,
                                            struct files_struct *files)
 {
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        struct file *file, *devnull = NULL;
        struct tty_struct *tty;
        struct fdtable *fdt;
@@ -2266,7 +2272,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
 
        /* Revalidate access to inherited open files. */
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
 
        spin_lock(&files->file_lock);
        for (;;) {
@@ -2515,7 +2521,7 @@ out:
 static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
 {
        const struct cred *cred = current_cred();
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        int rc;
 
        rc = superblock_doinit(sb, data);
@@ -2526,7 +2532,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
        if (flags & MS_KERNMOUNT)
                return 0;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = sb->s_root;
        return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
 }
@@ -2534,9 +2540,9 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
 static int selinux_sb_statfs(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry->d_sb->s_root;
        return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
@@ -2711,12 +2717,18 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        const struct cred *cred = current_cred();
+       unsigned int ia_valid = iattr->ia_valid;
+
+       /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
+       if (ia_valid & ATTR_FORCE) {
+               ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
+                             ATTR_FORCE);
+               if (!ia_valid)
+                       return 0;
+       }
 
-       if (iattr->ia_valid & ATTR_FORCE)
-               return 0;
-
-       if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
-                              ATTR_ATIME_SET | ATTR_MTIME_SET))
+       if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
+                       ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
                return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
 
        return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
@@ -2756,7 +2768,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        struct inode *inode = dentry->d_inode;
        struct inode_security_struct *isec = inode->i_security;
        struct superblock_security_struct *sbsec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 newsid, sid = current_sid();
        int rc = 0;
 
@@ -2770,7 +2782,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        if (!is_owner_or_cap(inode))
                return -EPERM;
 
-       AVC_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
        ad.u.fs.path.dentry = dentry;
 
        rc = avc_has_perm(sid, isec->sid, isec->sclass,
@@ -2915,6 +2927,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
                return rc;
 
        isec->sid = newsid;
+       isec->initialized = 1;
        return 0;
 }
 
@@ -2939,11 +2952,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;
@@ -2954,10 +2962,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);
 }
 
@@ -3219,13 +3237,30 @@ static int selinux_task_create(unsigned long clone_flags)
        return current_has_perm(current, PROCESS__FORK);
 }
 
+/*
+ * allocate the SELinux part of blank credentials
+ */
+static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
+{
+       struct task_security_struct *tsec;
+
+       tsec = kzalloc(sizeof(struct task_security_struct), gfp);
+       if (!tsec)
+               return -ENOMEM;
+
+       cred->security = tsec;
+       return 0;
+}
+
 /*
  * detach and free the LSM part of a set of credentials
  */
 static void selinux_cred_free(struct cred *cred)
 {
        struct task_security_struct *tsec = cred->security;
-       cred->security = NULL;
+
+       BUG_ON((unsigned long) cred->security < PAGE_SIZE);
+       cred->security = (void *) 0x7UL;
        kfree(tsec);
 }
 
@@ -3248,6 +3283,17 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
        return 0;
 }
 
+/*
+ * transfer the SELinux data to a blank set of creds
+ */
+static void selinux_cred_transfer(struct cred *new, const struct cred *old)
+{
+       const struct task_security_struct *old_tsec = old->security;
+       struct task_security_struct *tsec = new->security;
+
+       *tsec = *old_tsec;
+}
+
 /*
  * set the security data for a kernel service
  * - all the creation contexts are set to unlabelled
@@ -3292,6 +3338,11 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
        return 0;
 }
 
+static int selinux_kernel_module_request(void)
+{
+       return task_has_system(current, SYSTEM__MODULE_REQUEST);
+}
+
 static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
 {
        return current_has_perm(p, PROCESS__SETPGID);
@@ -3409,7 +3460,7 @@ static void selinux_task_to_inode(struct task_struct *p,
 
 /* Returns error only if unable to parse addresses */
 static int selinux_parse_skb_ipv4(struct sk_buff *skb,
-                       struct avc_audit_data *ad, u8 *proto)
+                       struct common_audit_data *ad, u8 *proto)
 {
        int offset, ihlen, ret = -EINVAL;
        struct iphdr _iph, *ih;
@@ -3490,7 +3541,7 @@ out:
 
 /* Returns error only if unable to parse addresses */
 static int selinux_parse_skb_ipv6(struct sk_buff *skb,
-                       struct avc_audit_data *ad, u8 *proto)
+                       struct common_audit_data *ad, u8 *proto)
 {
        u8 nexthdr;
        int ret = -EINVAL, offset;
@@ -3561,7 +3612,7 @@ out:
 
 #endif /* IPV6 */
 
-static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
+static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
                             char **_addrp, int src, u8 *proto)
 {
        char *addrp;
@@ -3643,7 +3694,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock,
                           u32 perms)
 {
        struct inode_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid;
        int err = 0;
 
@@ -3653,7 +3704,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock,
                goto out;
        sid = task_sid(task);
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = sock->sk;
        err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
 
@@ -3740,7 +3791,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
        if (family == PF_INET || family == PF_INET6) {
                char *addrp;
                struct inode_security_struct *isec;
-               struct avc_audit_data ad;
+               struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
@@ -3769,7 +3820,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                                      snum, &sid);
                                if (err)
                                        goto out;
-                               AVC_AUDIT_DATA_INIT(&ad, NET);
+                               COMMON_AUDIT_DATA_INIT(&ad, NET);
                                ad.u.net.sport = htons(snum);
                                ad.u.net.family = family;
                                err = avc_has_perm(isec->sid, sid,
@@ -3802,7 +3853,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                if (err)
                        goto out;
 
-               AVC_AUDIT_DATA_INIT(&ad, NET);
+               COMMON_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.sport = htons(snum);
                ad.u.net.family = family;
 
@@ -3836,7 +3887,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
        isec = SOCK_INODE(sock)->i_security;
        if (isec->sclass == SECCLASS_TCP_SOCKET ||
            isec->sclass == SECCLASS_DCCP_SOCKET) {
-               struct avc_audit_data ad;
+               struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
@@ -3861,7 +3912,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
                       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
 
-               AVC_AUDIT_DATA_INIT(&ad, NET);
+               COMMON_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.dport = htons(snum);
                ad.u.net.family = sk->sk_family;
                err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
@@ -3951,13 +4002,13 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
        struct sk_security_struct *ssec;
        struct inode_security_struct *isec;
        struct inode_security_struct *other_isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        int err;
 
        isec = SOCK_INODE(sock)->i_security;
        other_isec = SOCK_INODE(other)->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
        err = avc_has_perm(isec->sid, other_isec->sid,
@@ -3983,13 +4034,13 @@ static int selinux_socket_unix_may_send(struct socket *sock,
 {
        struct inode_security_struct *isec;
        struct inode_security_struct *other_isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        int err;
 
        isec = SOCK_INODE(sock)->i_security;
        other_isec = SOCK_INODE(other)->i_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
        err = avc_has_perm(isec->sid, other_isec->sid,
@@ -4002,7 +4053,7 @@ static int selinux_socket_unix_may_send(struct socket *sock,
 
 static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
                                    u32 peer_sid,
-                                   struct avc_audit_data *ad)
+                                   struct common_audit_data *ad)
 {
        int err;
        u32 if_sid;
@@ -4030,10 +4081,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
        struct sk_security_struct *sksec = sk->sk_security;
        u32 peer_sid;
        u32 sk_sid = sksec->sid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = skb->iif;
        ad.u.net.family = family;
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
@@ -4071,7 +4122,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        struct sk_security_struct *sksec = sk->sk_security;
        u16 family = sk->sk_family;
        u32 sk_sid = sksec->sid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
        u8 secmark_active;
        u8 peerlbl_active;
@@ -4095,7 +4146,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (!secmark_active && !peerlbl_active)
                return 0;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = skb->iif;
        ad.u.net.family = family;
        err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
@@ -4309,6 +4360,59 @@ static void selinux_req_classify_flow(const struct request_sock *req,
        fl->secid = req->secid;
 }
 
+static int selinux_tun_dev_create(void)
+{
+       u32 sid = current_sid();
+
+       /* we aren't taking into account the "sockcreate" SID since the socket
+        * that is being created here is not a socket in the traditional sense,
+        * instead it is a private sock, accessible only to the kernel, and
+        * representing a wide range of network traffic spanning multiple
+        * connections unlike traditional sockets - check the TUN driver to
+        * get a better understanding of why this socket is special */
+
+       return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
+                           NULL);
+}
+
+static void selinux_tun_dev_post_create(struct sock *sk)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+
+       /* we don't currently perform any NetLabel based labeling here and it
+        * isn't clear that we would want to do so anyway; while we could apply
+        * labeling without the support of the TUN user the resulting labeled
+        * traffic from the other end of the connection would almost certainly
+        * cause confusion to the TUN user that had no idea network labeling
+        * protocols were being used */
+
+       /* see the comments in selinux_tun_dev_create() about why we don't use
+        * the sockcreate SID here */
+
+       sksec->sid = current_sid();
+       sksec->sclass = SECCLASS_TUN_SOCKET;
+}
+
+static int selinux_tun_dev_attach(struct sock *sk)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+       u32 sid = current_sid();
+       int err;
+
+       err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
+                          TUN_SOCKET__RELABELFROM, NULL);
+       if (err)
+               return err;
+       err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
+                          TUN_SOCKET__RELABELTO, NULL);
+       if (err)
+               return err;
+
+       sksec->sid = sid;
+
+       return 0;
+}
+
 static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
 {
        int err = 0;
@@ -4353,7 +4457,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
        int err;
        char *addrp;
        u32 peer_sid;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u8 secmark_active;
        u8 netlbl_active;
        u8 peerlbl_active;
@@ -4370,7 +4474,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
        if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
                return NF_DROP;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = ifindex;
        ad.u.net.family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
@@ -4458,7 +4562,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
 {
        struct sock *sk = skb->sk;
        struct sk_security_struct *sksec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
        u8 proto;
 
@@ -4466,7 +4570,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
                return NF_ACCEPT;
        sksec = sk->sk_security;
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = ifindex;
        ad.u.net.family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
@@ -4490,7 +4594,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
        u32 secmark_perm;
        u32 peer_sid;
        struct sock *sk;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        char *addrp;
        u8 secmark_active;
        u8 peerlbl_active;
@@ -4549,7 +4653,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
                secmark_perm = PACKET__SEND;
        }
 
-       AVC_AUDIT_DATA_INIT(&ad, NET);
+       COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.netif = ifindex;
        ad.u.net.family = family;
        if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
@@ -4619,13 +4723,13 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
 static int selinux_netlink_recv(struct sk_buff *skb, int capability)
 {
        int err;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
 
        err = cap_netlink_recv(skb, capability);
        if (err)
                return err;
 
-       AVC_AUDIT_DATA_INIT(&ad, CAP);
+       COMMON_AUDIT_DATA_INIT(&ad, CAP);
        ad.u.cap = capability;
 
        return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid,
@@ -4684,12 +4788,12 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
                        u32 perms)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = ipc_perms->security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = ipc_perms->key;
 
        return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
@@ -4709,7 +4813,7 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg)
 static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -4719,7 +4823,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
 
        isec = msq->q_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
@@ -4739,12 +4843,12 @@ static void selinux_msg_queue_free_security(struct msg_queue *msq)
 static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = msq->q_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
@@ -4783,7 +4887,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
 {
        struct ipc_security_struct *isec;
        struct msg_security_struct *msec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -4804,7 +4908,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
                        return rc;
        }
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        /* Can this process write to the queue? */
@@ -4828,14 +4932,14 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 {
        struct ipc_security_struct *isec;
        struct msg_security_struct *msec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = task_sid(target);
        int rc;
 
        isec = msq->q_perm.security;
        msec = msg->security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = msq->q_perm.key;
 
        rc = avc_has_perm(sid, isec->sid,
@@ -4850,7 +4954,7 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 static int selinux_shm_alloc_security(struct shmid_kernel *shp)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -4860,7 +4964,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp)
 
        isec = shp->shm_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = shp->shm_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
@@ -4880,12 +4984,12 @@ static void selinux_shm_free_security(struct shmid_kernel *shp)
 static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = shp->shm_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = shp->shm_perm.key;
 
        return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
@@ -4942,7 +5046,7 @@ static int selinux_shm_shmat(struct shmid_kernel *shp,
 static int selinux_sem_alloc_security(struct sem_array *sma)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
        int rc;
 
@@ -4952,7 +5056,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma)
 
        isec = sma->sem_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = sma->sem_perm.key;
 
        rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
@@ -4972,12 +5076,12 @@ static void selinux_sem_free_security(struct sem_array *sma)
 static int selinux_sem_associate(struct sem_array *sma, int semflg)
 {
        struct ipc_security_struct *isec;
-       struct avc_audit_data ad;
+       struct common_audit_data ad;
        u32 sid = current_sid();
 
        isec = sma->sem_perm.security;
 
-       AVC_AUDIT_DATA_INIT(&ad, IPC);
+       COMMON_AUDIT_DATA_INIT(&ad, IPC);
        ad.u.ipc_id = sma->sem_perm.key;
 
        return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
@@ -5195,7 +5299,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;
@@ -5252,6 +5356,32 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
        kfree(secdata);
 }
 
+/*
+ *     called with inode->i_mutex locked
+ */
+static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+       return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
+}
+
+/*
+ *     called with inode->i_mutex locked
+ */
+static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+       return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
+}
+
+static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+       int len = 0;
+       len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
+                                               ctx, true);
+       if (len < 0)
+               return len;
+       *ctxlen = len;
+       return 0;
+}
 #ifdef CONFIG_KEYS
 
 static int selinux_key_alloc(struct key *k, const struct cred *cred,
@@ -5323,7 +5453,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,
@@ -5396,10 +5526,13 @@ static struct security_operations selinux_ops = {
        .dentry_open =                  selinux_dentry_open,
 
        .task_create =                  selinux_task_create,
+       .cred_alloc_blank =             selinux_cred_alloc_blank,
        .cred_free =                    selinux_cred_free,
        .cred_prepare =                 selinux_cred_prepare,
+       .cred_transfer =                selinux_cred_transfer,
        .kernel_act_as =                selinux_kernel_act_as,
        .kernel_create_files_as =       selinux_kernel_create_files_as,
+       .kernel_module_request =        selinux_kernel_module_request,
        .task_setpgid =                 selinux_task_setpgid,
        .task_getpgid =                 selinux_task_getpgid,
        .task_getsid =                  selinux_task_getsid,
@@ -5448,6 +5581,9 @@ static struct security_operations selinux_ops = {
        .secid_to_secctx =              selinux_secid_to_secctx,
        .secctx_to_secid =              selinux_secctx_to_secid,
        .release_secctx =               selinux_release_secctx,
+       .inode_notifysecctx =           selinux_inode_notifysecctx,
+       .inode_setsecctx =              selinux_inode_setsecctx,
+       .inode_getsecctx =              selinux_inode_getsecctx,
 
        .unix_stream_connect =          selinux_socket_unix_stream_connect,
        .unix_may_send =                selinux_socket_unix_may_send,
@@ -5477,6 +5613,9 @@ static struct security_operations selinux_ops = {
        .inet_csk_clone =               selinux_inet_csk_clone,
        .inet_conn_established =        selinux_inet_conn_established,
        .req_classify_flow =            selinux_req_classify_flow,
+       .tun_dev_create =               selinux_tun_dev_create,
+       .tun_dev_post_create =          selinux_tun_dev_post_create,
+       .tun_dev_attach =               selinux_tun_dev_attach,
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
        .xfrm_policy_alloc_security =   selinux_xfrm_policy_alloc,
@@ -5691,6 +5830,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 8377a4ba3b954434f98a6aefbc269c3747162347..abedcd704daef7c47ef2f392799dc80024fd7b4e 100644 (file)
@@ -15,6 +15,7 @@
    S_(SECCLASS_KEY_SOCKET, socket, 0x00400000UL)
    S_(SECCLASS_UNIX_STREAM_SOCKET, socket, 0x00400000UL)
    S_(SECCLASS_UNIX_DGRAM_SOCKET, socket, 0x00400000UL)
+   S_(SECCLASS_TUN_SOCKET, socket, 0x00400000UL)
    S_(SECCLASS_IPC, ipc, 0x00000200UL)
    S_(SECCLASS_SEM, ipc, 0x00000200UL)
    S_(SECCLASS_MSGQ, ipc, 0x00000200UL)
index 31df1d7c1aee2c0ead5536846a3ab7a46a074278..2b683ad83d21ceb42b8d16fe48f9f610398d30e2 100644 (file)
    S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read")
    S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod")
    S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console")
+   S_(SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, "module_request")
    S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown")
    S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override")
    S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search")
index d645192ee950aaf74f2693943e38cd7dda9bfdbf..0546d616ccacc2fae2fd8b5ca003d6cdc091a54f 100644 (file)
 #define UNIX_DGRAM_SOCKET__RECV_MSG               0x00080000UL
 #define UNIX_DGRAM_SOCKET__SEND_MSG               0x00100000UL
 #define UNIX_DGRAM_SOCKET__NAME_BIND              0x00200000UL
+#define TUN_SOCKET__IOCTL                         0x00000001UL
+#define TUN_SOCKET__READ                          0x00000002UL
+#define TUN_SOCKET__WRITE                         0x00000004UL
+#define TUN_SOCKET__CREATE                        0x00000008UL
+#define TUN_SOCKET__GETATTR                       0x00000010UL
+#define TUN_SOCKET__SETATTR                       0x00000020UL
+#define TUN_SOCKET__LOCK                          0x00000040UL
+#define TUN_SOCKET__RELABELFROM                   0x00000080UL
+#define TUN_SOCKET__RELABELTO                     0x00000100UL
+#define TUN_SOCKET__APPEND                        0x00000200UL
+#define TUN_SOCKET__BIND                          0x00000400UL
+#define TUN_SOCKET__CONNECT                       0x00000800UL
+#define TUN_SOCKET__LISTEN                        0x00001000UL
+#define TUN_SOCKET__ACCEPT                        0x00002000UL
+#define TUN_SOCKET__GETOPT                        0x00004000UL
+#define TUN_SOCKET__SETOPT                        0x00008000UL
+#define TUN_SOCKET__SHUTDOWN                      0x00010000UL
+#define TUN_SOCKET__RECVFROM                      0x00020000UL
+#define TUN_SOCKET__SENDTO                        0x00040000UL
+#define TUN_SOCKET__RECV_MSG                      0x00080000UL
+#define TUN_SOCKET__SEND_MSG                      0x00100000UL
+#define TUN_SOCKET__NAME_BIND                     0x00200000UL
 #define PROCESS__FORK                             0x00000001UL
 #define PROCESS__TRANSITION                       0x00000002UL
 #define PROCESS__SIGCHLD                          0x00000004UL
 #define SYSTEM__SYSLOG_READ                       0x00000002UL
 #define SYSTEM__SYSLOG_MOD                        0x00000004UL
 #define SYSTEM__SYSLOG_CONSOLE                    0x00000008UL
+#define SYSTEM__MODULE_REQUEST                    0x00000010UL
 #define CAPABILITY__CHOWN                         0x00000001UL
 #define CAPABILITY__DAC_OVERRIDE                  0x00000002UL
 #define CAPABILITY__DAC_READ_SEARCH               0x00000004UL
index d12ff1a9c0aa5e383347af29f9f03fe96e626ed2..e94e82f738188381c582d59e26aca94b867ac064 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/audit.h>
+#include <linux/lsm_audit.h>
 #include <linux/in6.h>
 #include <linux/path.h>
 #include <asm/system.h>
@@ -36,48 +37,6 @@ struct inode;
 struct sock;
 struct sk_buff;
 
-/* Auxiliary data to use in generating the audit record. */
-struct avc_audit_data {
-       char    type;
-#define AVC_AUDIT_DATA_FS   1
-#define AVC_AUDIT_DATA_NET  2
-#define AVC_AUDIT_DATA_CAP  3
-#define AVC_AUDIT_DATA_IPC  4
-       struct task_struct *tsk;
-       union   {
-               struct {
-                       struct path path;
-                       struct inode *inode;
-               } fs;
-               struct {
-                       int netif;
-                       struct sock *sk;
-                       u16 family;
-                       __be16 dport;
-                       __be16 sport;
-                       union {
-                               struct {
-                                       __be32 daddr;
-                                       __be32 saddr;
-                               } v4;
-                               struct {
-                                       struct in6_addr daddr;
-                                       struct in6_addr saddr;
-                               } v6;
-                       } fam;
-               } net;
-               int cap;
-               int ipc_id;
-       } u;
-};
-
-#define v4info fam.v4
-#define v6info fam.v6
-
-/* Initialize an AVC audit data structure. */
-#define AVC_AUDIT_DATA_INIT(_d,_t) \
-       { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; }
-
 /*
  * AVC statistics
  */
@@ -98,7 +57,9 @@ void __init avc_init(void);
 
 void avc_audit(u32 ssid, u32 tsid,
               u16 tclass, u32 requested,
-              struct av_decision *avd, int result, struct avc_audit_data *auditdata);
+              struct av_decision *avd,
+              int result,
+              struct common_audit_data *a);
 
 #define AVC_STRICT 1 /* Ignore permissive mode. */
 int avc_has_perm_noaudit(u32 ssid, u32 tsid,
@@ -108,7 +69,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
 
 int avc_has_perm(u32 ssid, u32 tsid,
                 u16 tclass, u32 requested,
-                struct avc_audit_data *auditdata);
+                struct common_audit_data *auditdata);
 
 u32 avc_policy_seqno(void);
 
@@ -127,13 +88,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 21ec786611d411ea1bfd52c9a0add689c0951237..7ab9299bfb6bb3b18c6d941effcd88e6a0d5524d 100644 (file)
@@ -77,3 +77,4 @@
     S_(NULL)
     S_(NULL)
     S_("kernel_service")
+    S_("tun_socket")
index 882f27d66facdbc780cb7ad6468af5d6b0796b78..f248500a1e3c3c197efa6eb5dfa6e6b0567f7960 100644 (file)
@@ -53,6 +53,7 @@
 #define SECCLASS_PEER                                    68
 #define SECCLASS_CAPABILITY2                             69
 #define SECCLASS_KERNEL_SERVICE                          74
+#define SECCLASS_TUN_SOCKET                              75
 
 /*
  * Security identifier indices for initial entities
index b4b5b9b2f0be1758babefede244375e604b08ccb..8d7384280a7a2cb39840fc3347ebde30b9352aef 100644 (file)
@@ -59,7 +59,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family);
 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
                                struct sk_buff *skb,
                                u16 family,
-                               struct avc_audit_data *ad);
+                               struct common_audit_data *ad);
 int selinux_netlbl_socket_setsockopt(struct socket *sock,
                                     int level,
                                     int optname);
@@ -129,7 +129,7 @@ static inline int selinux_netlbl_socket_post_create(struct sock *sk,
 static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
                                              struct sk_buff *skb,
                                              u16 family,
-                                             struct avc_audit_data *ad)
+                                             struct common_audit_data *ad)
 {
        return 0;
 }
index 289e24b39e3ea0a79fb8ade6ba586734b59c2c5c..13128f9a3e5aef56b7453af34ce86aa0e99f0513 100644 (file)
@@ -41,9 +41,9 @@ static inline int selinux_xfrm_enabled(void)
 }
 
 int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,
-                       struct avc_audit_data *ad);
+                       struct common_audit_data *ad);
 int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
-                       struct avc_audit_data *ad, u8 proto);
+                       struct common_audit_data *ad, u8 proto);
 int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);
 
 static inline void selinux_xfrm_notify_policyload(void)
@@ -57,13 +57,13 @@ static inline int selinux_xfrm_enabled(void)
 }
 
 static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
-                       struct avc_audit_data *ad)
+                       struct common_audit_data *ad)
 {
        return 0;
 }
 
 static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
-                       struct avc_audit_data *ad, u8 proto)
+                       struct common_audit_data *ad, u8 proto)
 {
        return 0;
 }
index 2e984413c7b2daaa5313e7bf8fa1b3b193064252..e68823741ad5836a54f38f34e98a86193dbc70eb 100644 (file)
@@ -342,7 +342,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
 int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
                                struct sk_buff *skb,
                                u16 family,
-                               struct avc_audit_data *ad)
+                               struct common_audit_data *ad)
 {
        int rc;
        u32 nlbl_sid;
index 500e6f78e1159e1d568355ce74a113b4b49859c1..ff17820d35ec73bedfab174d3adfb7c87b762420 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
@@ -278,6 +283,95 @@ mls_ops:
        return s[0];
 }
 
+/*
+ * 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 72b18452e1a12035f20e4269e0ed6d4474e135f2..f3cb9ed731a9d927319c37bfc3a2e0d63f330db9 100644 (file)
@@ -401,7 +401,7 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
  * gone thru the IPSec process.
  */
 int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
-                               struct avc_audit_data *ad)
+                               struct common_audit_data *ad)
 {
        int i, rc = 0;
        struct sec_path *sp;
@@ -442,7 +442,7 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
  * checked in the selinux_xfrm_state_pol_flow_match hook above.
  */
 int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
-                                       struct avc_audit_data *ad, u8 proto)
+                                       struct common_audit_data *ad, u8 proto)
 {
        struct dst_entry *dst;
        int rc = 0;
index 243bec175be050f930189a25d4a4bb6d5dc85ef3..c6e9acae72e4b74b9e75f037845e54b61fce6163 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 513dc1aa16dd1ff5594745b463dd67118648705a..0f9ac81469001d30d91a05af27974b116823d330 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 0023182078c726797de5ccab784a1922eba17859..acae7ef4092dd02872b54d7861ad233f8a74978e 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;
 
@@ -1079,6 +1079,22 @@ static int smack_file_receive(struct file *file)
  * Task hooks
  */
 
+/**
+ * smack_cred_alloc_blank - "allocate" blank task-level security credentials
+ * @new: the new credentials
+ * @gfp: the atomicity of any memory allocations
+ *
+ * Prepare a blank set of credentials for modification.  This must allocate all
+ * the memory the LSM module might require such that cred_transfer() can
+ * complete without error.
+ */
+static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
+{
+       cred->security = NULL;
+       return 0;
+}
+
+
 /**
  * smack_cred_free - "free" task-level security credentials
  * @cred: the credentials in question
@@ -1116,6 +1132,18 @@ static void smack_cred_commit(struct cred *new, const struct cred *old)
 {
 }
 
+/**
+ * smack_cred_transfer - Transfer the old credentials to the new credentials
+ * @new: the new credentials
+ * @old: the original credentials
+ *
+ * Fill in a set of blank credentials from another set of credentials.
+ */
+static void smack_cred_transfer(struct cred *new, const struct cred *old)
+{
+       new->security = old->security;
+}
+
 /**
  * smack_kernel_act_as - Set the subjective context in a set of credentials
  * @new: points to the set of credentials to be modified.
@@ -1638,6 +1666,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
 
        if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
                nsp->smk_inode = sp;
+               nsp->smk_flags |= SMK_INODE_INSTANT;
                return 0;
        }
        /*
@@ -2464,7 +2493,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);
@@ -3029,10 +3058,31 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 {
 }
 
+static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+       return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx, ctxlen, 0);
+}
+
+static int smack_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+       return __vfs_setxattr_noperm(dentry, XATTR_NAME_SMACK, ctx, ctxlen, 0);
+}
+
+static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+       int len = 0;
+       len = smack_inode_getsecurity(inode, XATTR_SMACK_SUFFIX, ctx, true);
+
+       if (len < 0)
+               return len;
+       *ctxlen = len;
+       return 0;
+}
+
 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,
 
@@ -3073,9 +3123,11 @@ struct security_operations smack_ops = {
        .file_send_sigiotask =          smack_file_send_sigiotask,
        .file_receive =                 smack_file_receive,
 
+       .cred_alloc_blank =             smack_cred_alloc_blank,
        .cred_free =                    smack_cred_free,
        .cred_prepare =                 smack_cred_prepare,
        .cred_commit =                  smack_cred_commit,
+       .cred_transfer =                smack_cred_transfer,
        .kernel_act_as =                smack_kernel_act_as,
        .kernel_create_files_as =       smack_kernel_create_files_as,
        .task_setpgid =                 smack_task_setpgid,
@@ -3155,6 +3207,9 @@ struct security_operations smack_ops = {
        .secid_to_secctx =              smack_secid_to_secctx,
        .secctx_to_secid =              smack_secctx_to_secid,
        .release_secctx =               smack_release_secctx,
+       .inode_notifysecctx =           smack_inode_notifysecctx,
+       .inode_setsecctx =              smack_inode_setsecctx,
+       .inode_getsecctx =              smack_inode_getsecctx,
 };
 
 
index fdd1f4b8c448e4c1fa6611bb9456f5e9c9d30070..3c8bd8ee0b95e70e17e801913eb7481030ebcfae 100644 (file)
@@ -1284,6 +1284,36 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
        return true;
 }
 
+/**
+ * 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.
  *
index 6d6ba09af4576b27d6aba92edad7d3c7b03515b3..31df541911f76f3d5cc39c92508eb37a25fb8545 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 1d8b16960576891615d7d523626d527030cf31bc..fcf52accce2b107798b7be675337eb53f9279a38 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 3194d09fe0f4ccd5311b819e526a1b696a8ecc33..9548a0984cc43674c8b5470ef5931bf71ac9cb1e 100644 (file)
 #include "tomoyo.h"
 #include "realpath.h"
 
+static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp)
+{
+       new->security = NULL;
+       return 0;
+}
+
 static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
                               gfp_t gfp)
 {
@@ -25,6 +31,15 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
        return 0;
 }
 
+static void tomoyo_cred_transfer(struct cred *new, const struct cred *old)
+{
+       /*
+        * Since "struct tomoyo_domain_info *" is a sharable pointer,
+        * we don't need to duplicate.
+        */
+       new->security = old->security;
+}
+
 static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
 {
        int rc;
@@ -61,14 +76,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).
@@ -268,7 +277,9 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
  */
 static struct security_operations tomoyo_security_ops = {
        .name                = "tomoyo",
+       .cred_alloc_blank    = tomoyo_cred_alloc_blank,
        .cred_prepare        = tomoyo_cred_prepare,
+       .cred_transfer       = tomoyo_cred_transfer,
        .bprm_set_creds      = tomoyo_bprm_set_creds,
        .bprm_check_security = tomoyo_bprm_check_security,
 #ifdef CONFIG_SYSCTL
index 0fd588a629cf915ca6be0a47dbc300292d908570..cd6ba0bf7069a98128bdac2d562c9746decdcc6f 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. */