diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-11 11:55:49 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-11 11:55:49 -0400 |
| commit | f6f79190866d5b2d06a2114d673f91f54e7c7ce4 (patch) | |
| tree | 025bc2ff00351c71a719cb5bc2aa3f59133400f6 | |
| parent | 0d03d59d9b31cd1e33b7e46a80b6fef66244b1f2 (diff) | |
| parent | a3c8b97396ef42edfb845788ba6f53b2a93ce980 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* '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, 2231 insertions, 595 deletions
diff --git a/Documentation/keys.txt b/Documentation/keys.txt index b56aacc1fff8..e4dbbdb1bd96 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt | |||
| @@ -26,7 +26,7 @@ This document has the following sections: | |||
| 26 | - Notes on accessing payload contents | 26 | - Notes on accessing payload contents |
| 27 | - Defining a key type | 27 | - Defining a key type |
| 28 | - Request-key callback service | 28 | - Request-key callback service |
| 29 | - Key access filesystem | 29 | - Garbage collection |
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | ============ | 32 | ============ |
| @@ -113,6 +113,9 @@ Each key has a number of attributes: | |||
| 113 | 113 | ||
| 114 | (*) Dead. The key's type was unregistered, and so the key is now useless. | 114 | (*) Dead. The key's type was unregistered, and so the key is now useless. |
| 115 | 115 | ||
| 116 | Keys in the last three states are subject to garbage collection. See the | ||
| 117 | section on "Garbage collection". | ||
| 118 | |||
| 116 | 119 | ||
| 117 | ==================== | 120 | ==================== |
| 118 | KEY SERVICE OVERVIEW | 121 | KEY SERVICE OVERVIEW |
| @@ -754,6 +757,26 @@ The keyctl syscall functions are: | |||
| 754 | successful. | 757 | successful. |
| 755 | 758 | ||
| 756 | 759 | ||
| 760 | (*) Install the calling process's session keyring on its parent. | ||
| 761 | |||
| 762 | long keyctl(KEYCTL_SESSION_TO_PARENT); | ||
| 763 | |||
| 764 | This functions attempts to install the calling process's session keyring | ||
| 765 | on to the calling process's parent, replacing the parent's current session | ||
| 766 | keyring. | ||
| 767 | |||
| 768 | The calling process must have the same ownership as its parent, the | ||
| 769 | keyring must have the same ownership as the calling process, the calling | ||
| 770 | process must have LINK permission on the keyring and the active LSM module | ||
| 771 | mustn't deny permission, otherwise error EPERM will be returned. | ||
| 772 | |||
| 773 | Error ENOMEM will be returned if there was insufficient memory to complete | ||
| 774 | the operation, otherwise 0 will be returned to indicate success. | ||
| 775 | |||
| 776 | The keyring will be replaced next time the parent process leaves the | ||
| 777 | kernel and resumes executing userspace. | ||
| 778 | |||
| 779 | |||
| 757 | =============== | 780 | =============== |
| 758 | KERNEL SERVICES | 781 | KERNEL SERVICES |
| 759 | =============== | 782 | =============== |
| @@ -1231,3 +1254,17 @@ by executing: | |||
| 1231 | 1254 | ||
| 1232 | In this case, the program isn't required to actually attach the key to a ring; | 1255 | In this case, the program isn't required to actually attach the key to a ring; |
| 1233 | the rings are provided for reference. | 1256 | the rings are provided for reference. |
| 1257 | |||
| 1258 | |||
| 1259 | ================== | ||
| 1260 | GARBAGE COLLECTION | ||
| 1261 | ================== | ||
| 1262 | |||
| 1263 | Dead keys (for which the type has been removed) will be automatically unlinked | ||
| 1264 | from those keyrings that point to them and deleted as soon as possible by a | ||
| 1265 | background garbage collector. | ||
| 1266 | |||
| 1267 | Similarly, revoked and expired keys will be garbage collected, but only after a | ||
| 1268 | certain amount of time has passed. This time is set as a number of seconds in: | ||
| 1269 | |||
| 1270 | /proc/sys/kernel/keys/gc_delay | ||
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h index 60c83abfde70..5076a8860b18 100644 --- a/arch/alpha/include/asm/thread_info.h +++ b/arch/alpha/include/asm/thread_info.h | |||
| @@ -75,6 +75,7 @@ register struct thread_info *__current_thread_info __asm__("$8"); | |||
| 75 | #define TIF_UAC_SIGBUS 7 | 75 | #define TIF_UAC_SIGBUS 7 |
| 76 | #define TIF_MEMDIE 8 | 76 | #define TIF_MEMDIE 8 |
| 77 | #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal */ | 77 | #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal */ |
| 78 | #define TIF_NOTIFY_RESUME 10 /* callback before returning to user */ | ||
| 78 | #define TIF_FREEZE 16 /* is freezing for suspend */ | 79 | #define TIF_FREEZE 16 /* is freezing for suspend */ |
| 79 | 80 | ||
| 80 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) | 81 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) |
| @@ -82,10 +83,12 @@ register struct thread_info *__current_thread_info __asm__("$8"); | |||
| 82 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) | 83 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) |
| 83 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | 84 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) |
| 84 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) | 85 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) |
| 86 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) | ||
| 85 | #define _TIF_FREEZE (1<<TIF_FREEZE) | 87 | #define _TIF_FREEZE (1<<TIF_FREEZE) |
| 86 | 88 | ||
| 87 | /* Work to do on interrupt/exception return. */ | 89 | /* Work to do on interrupt/exception return. */ |
| 88 | #define _TIF_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED) | 90 | #define _TIF_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ |
| 91 | _TIF_NOTIFY_RESUME) | ||
| 89 | 92 | ||
| 90 | /* Work to do on any return to userspace. */ | 93 | /* Work to do on any return to userspace. */ |
| 91 | #define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \ | 94 | #define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \ |
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index df65eaa84c4c..0932dbb1ef8e 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/binfmts.h> | 20 | #include <linux/binfmts.h> |
| 21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
| 22 | #include <linux/syscalls.h> | 22 | #include <linux/syscalls.h> |
| 23 | #include <linux/tracehook.h> | ||
| 23 | 24 | ||
| 24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
| 25 | #include <asm/sigcontext.h> | 26 | #include <asm/sigcontext.h> |
| @@ -683,4 +684,11 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw, | |||
| 683 | { | 684 | { |
| 684 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) | 685 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) |
| 685 | do_signal(regs, sw, r0, r19); | 686 | do_signal(regs, sw, r0, r19); |
| 687 | |||
| 688 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||
| 689 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
| 690 | tracehook_notify_resume(regs); | ||
| 691 | if (current->replacement_session_keyring) | ||
| 692 | key_replace_session_keyring(); | ||
| 693 | } | ||
| 686 | } | 694 | } |
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 73394e50cbca..d3a39b1e6c0f 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h | |||
| @@ -130,11 +130,13 @@ extern void vfp_sync_state(struct thread_info *thread); | |||
| 130 | * TIF_SYSCALL_TRACE - syscall trace active | 130 | * TIF_SYSCALL_TRACE - syscall trace active |
| 131 | * TIF_SIGPENDING - signal pending | 131 | * TIF_SIGPENDING - signal pending |
| 132 | * TIF_NEED_RESCHED - rescheduling necessary | 132 | * TIF_NEED_RESCHED - rescheduling necessary |
| 133 | * TIF_NOTIFY_RESUME - callback before returning to user | ||
| 133 | * TIF_USEDFPU - FPU was used by this task this quantum (SMP) | 134 | * TIF_USEDFPU - FPU was used by this task this quantum (SMP) |
| 134 | * TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED | 135 | * TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED |
| 135 | */ | 136 | */ |
| 136 | #define TIF_SIGPENDING 0 | 137 | #define TIF_SIGPENDING 0 |
| 137 | #define TIF_NEED_RESCHED 1 | 138 | #define TIF_NEED_RESCHED 1 |
| 139 | #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ | ||
| 138 | #define TIF_SYSCALL_TRACE 8 | 140 | #define TIF_SYSCALL_TRACE 8 |
| 139 | #define TIF_POLLING_NRFLAG 16 | 141 | #define TIF_POLLING_NRFLAG 16 |
| 140 | #define TIF_USING_IWMMXT 17 | 142 | #define TIF_USING_IWMMXT 17 |
| @@ -143,6 +145,7 @@ extern void vfp_sync_state(struct thread_info *thread); | |||
| 143 | 145 | ||
| 144 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) | 146 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) |
| 145 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | 147 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) |
| 148 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) | ||
| 146 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) | 149 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) |
| 147 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) | 150 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) |
| 148 | #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) | 151 | #define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT) |
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 8c3de1a350b5..7813ab782fda 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
| @@ -51,7 +51,7 @@ fast_work_pending: | |||
| 51 | work_pending: | 51 | work_pending: |
| 52 | tst r1, #_TIF_NEED_RESCHED | 52 | tst r1, #_TIF_NEED_RESCHED |
| 53 | bne work_resched | 53 | bne work_resched |
| 54 | tst r1, #_TIF_SIGPENDING | 54 | tst r1, #_TIF_SIGPENDING|_TIF_NOTIFY_RESUME |
| 55 | beq no_work_pending | 55 | beq no_work_pending |
| 56 | mov r0, sp @ 'regs' | 56 | mov r0, sp @ 'regs' |
| 57 | mov r2, why @ 'syscall' | 57 | mov r2, why @ 'syscall' |
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index f6bc5d442782..b76fe06d92e7 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <linux/personality.h> | 12 | #include <linux/personality.h> |
| 13 | #include <linux/freezer.h> | 13 | #include <linux/freezer.h> |
| 14 | #include <linux/uaccess.h> | 14 | #include <linux/uaccess.h> |
| 15 | #include <linux/tracehook.h> | ||
| 15 | 16 | ||
| 16 | #include <asm/elf.h> | 17 | #include <asm/elf.h> |
| 17 | #include <asm/cacheflush.h> | 18 | #include <asm/cacheflush.h> |
| @@ -707,4 +708,11 @@ do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) | |||
| 707 | { | 708 | { |
| 708 | if (thread_flags & _TIF_SIGPENDING) | 709 | if (thread_flags & _TIF_SIGPENDING) |
| 709 | do_signal(¤t->blocked, regs, syscall); | 710 | do_signal(¤t->blocked, regs, syscall); |
| 711 | |||
| 712 | if (thread_flags & _TIF_NOTIFY_RESUME) { | ||
| 713 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
| 714 | tracehook_notify_resume(regs); | ||
| 715 | if (current->replacement_session_keyring) | ||
| 716 | key_replace_session_keyring(); | ||
| 717 | } | ||
| 710 | } | 718 | } |
diff --git a/arch/avr32/include/asm/thread_info.h b/arch/avr32/include/asm/thread_info.h index fc42de5ca209..fd0c5d7e9337 100644 --- a/arch/avr32/include/asm/thread_info.h +++ b/arch/avr32/include/asm/thread_info.h | |||
| @@ -84,6 +84,7 @@ static inline struct thread_info *current_thread_info(void) | |||
| 84 | #define TIF_MEMDIE 6 | 84 | #define TIF_MEMDIE 6 |
| 85 | #define TIF_RESTORE_SIGMASK 7 /* restore signal mask in do_signal */ | 85 | #define TIF_RESTORE_SIGMASK 7 /* restore signal mask in do_signal */ |
| 86 | #define TIF_CPU_GOING_TO_SLEEP 8 /* CPU is entering sleep 0 mode */ | 86 | #define TIF_CPU_GOING_TO_SLEEP 8 /* CPU is entering sleep 0 mode */ |
| 87 | #define TIF_NOTIFY_RESUME 9 /* callback before returning to user */ | ||
| 87 | #define TIF_FREEZE 29 | 88 | #define TIF_FREEZE 29 |
| 88 | #define TIF_DEBUG 30 /* debugging enabled */ | 89 | #define TIF_DEBUG 30 /* debugging enabled */ |
| 89 | #define TIF_USERSPACE 31 /* true if FS sets userspace */ | 90 | #define TIF_USERSPACE 31 /* true if FS sets userspace */ |
| @@ -96,6 +97,7 @@ static inline struct thread_info *current_thread_info(void) | |||
| 96 | #define _TIF_MEMDIE (1 << TIF_MEMDIE) | 97 | #define _TIF_MEMDIE (1 << TIF_MEMDIE) |
| 97 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) | 98 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) |
| 98 | #define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP) | 99 | #define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP) |
| 100 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) | ||
| 99 | #define _TIF_FREEZE (1 << TIF_FREEZE) | 101 | #define _TIF_FREEZE (1 << TIF_FREEZE) |
| 100 | 102 | ||
| 101 | /* Note: The masks below must never span more than 16 bits! */ | 103 | /* Note: The masks below must never span more than 16 bits! */ |
| @@ -103,13 +105,15 @@ static inline struct thread_info *current_thread_info(void) | |||
| 103 | /* work to do on interrupt/exception return */ | 105 | /* work to do on interrupt/exception return */ |
| 104 | #define _TIF_WORK_MASK \ | 106 | #define _TIF_WORK_MASK \ |
| 105 | ((1 << TIF_SIGPENDING) \ | 107 | ((1 << TIF_SIGPENDING) \ |
| 108 | | _TIF_NOTIFY_RESUME \ | ||
| 106 | | (1 << TIF_NEED_RESCHED) \ | 109 | | (1 << TIF_NEED_RESCHED) \ |
| 107 | | (1 << TIF_POLLING_NRFLAG) \ | 110 | | (1 << TIF_POLLING_NRFLAG) \ |
| 108 | | (1 << TIF_BREAKPOINT) \ | 111 | | (1 << TIF_BREAKPOINT) \ |
| 109 | | (1 << TIF_RESTORE_SIGMASK)) | 112 | | (1 << TIF_RESTORE_SIGMASK)) |
| 110 | 113 | ||
| 111 | /* work to do on any return to userspace */ | 114 | /* work to do on any return to userspace */ |
| 112 | #define _TIF_ALLWORK_MASK (_TIF_WORK_MASK | (1 << TIF_SYSCALL_TRACE)) | 115 | #define _TIF_ALLWORK_MASK (_TIF_WORK_MASK | (1 << TIF_SYSCALL_TRACE) | \ |
| 116 | _TIF_NOTIFY_RESUME) | ||
| 113 | /* work to do on return from debug mode */ | 117 | /* work to do on return from debug mode */ |
| 114 | #define _TIF_DBGWORK_MASK (_TIF_WORK_MASK & ~(1 << TIF_BREAKPOINT)) | 118 | #define _TIF_DBGWORK_MASK (_TIF_WORK_MASK & ~(1 << TIF_BREAKPOINT)) |
| 115 | 119 | ||
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index 009a80155d67..169268c40ae2 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S | |||
| @@ -281,7 +281,7 @@ syscall_exit_work: | |||
| 281 | ld.w r1, r0[TI_flags] | 281 | ld.w r1, r0[TI_flags] |
| 282 | rjmp 1b | 282 | rjmp 1b |
| 283 | 283 | ||
| 284 | 2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | 284 | 2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NOTIFY_RESUME |
| 285 | tst r1, r2 | 285 | tst r1, r2 |
| 286 | breq 3f | 286 | breq 3f |
| 287 | unmask_interrupts | 287 | unmask_interrupts |
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 27227561bad6..64f886fac2ef 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/ptrace.h> | 16 | #include <linux/ptrace.h> |
| 17 | #include <linux/unistd.h> | 17 | #include <linux/unistd.h> |
| 18 | #include <linux/freezer.h> | 18 | #include <linux/freezer.h> |
| 19 | #include <linux/tracehook.h> | ||
| 19 | 20 | ||
| 20 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
| 21 | #include <asm/ucontext.h> | 22 | #include <asm/ucontext.h> |
| @@ -322,4 +323,11 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) | |||
| 322 | 323 | ||
| 323 | if (ti->flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) | 324 | if (ti->flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) |
| 324 | do_signal(regs, ¤t->blocked, syscall); | 325 | do_signal(regs, ¤t->blocked, syscall); |
| 326 | |||
| 327 | if (ti->flags & _TIF_NOTIFY_RESUME) { | ||
| 328 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
| 329 | tracehook_notify_resume(regs); | ||
| 330 | if (current->replacement_session_keyring) | ||
| 331 | key_replace_session_keyring(); | ||
| 332 | } | ||
| 325 | } | 333 | } |
diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c index b326023baab2..48b0f3912632 100644 --- a/arch/cris/kernel/ptrace.c +++ b/arch/cris/kernel/ptrace.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
| 17 | #include <linux/ptrace.h> | 17 | #include <linux/ptrace.h> |
| 18 | #include <linux/user.h> | 18 | #include <linux/user.h> |
| 19 | #include <linux/tracehook.h> | ||
| 19 | 20 | ||
| 20 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
| 21 | #include <asm/page.h> | 22 | #include <asm/page.h> |
| @@ -36,4 +37,11 @@ void do_notify_resume(int canrestart, struct pt_regs *regs, | |||
| 36 | /* deal with pending signal delivery */ | 37 | /* deal with pending signal delivery */ |
| 37 | if (thread_info_flags & _TIF_SIGPENDING) | 38 | if (thread_info_flags & _TIF_SIGPENDING) |
| 38 | do_signal(canrestart,regs); | 39 | do_signal(canrestart,regs); |
| 40 | |||
| 41 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||
| 42 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
| 43 | tracehook_notify_resume(regs); | ||
| 44 | if (current->replacement_session_keyring) | ||
| 45 | key_replace_session_keyring(); | ||
| 46 | } | ||
| 39 | } | 47 | } |
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 4a7a62c6e783..6b0a2b6fed6a 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c | |||
| @@ -572,6 +572,8 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags) | |||
| 572 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 572 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 573 | clear_thread_flag(TIF_NOTIFY_RESUME); | 573 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 574 | tracehook_notify_resume(__frame); | 574 | tracehook_notify_resume(__frame); |
| 575 | if (current->replacement_session_keyring) | ||
| 576 | key_replace_session_keyring(); | ||
| 575 | } | 577 | } |
| 576 | 578 | ||
| 577 | } /* end do_notify_resume() */ | 579 | } /* end do_notify_resume() */ |
diff --git a/arch/h8300/include/asm/thread_info.h b/arch/h8300/include/asm/thread_info.h index 8bbc8b0ee45d..70e67e47d020 100644 --- a/arch/h8300/include/asm/thread_info.h +++ b/arch/h8300/include/asm/thread_info.h | |||
| @@ -89,6 +89,7 @@ static inline struct thread_info *current_thread_info(void) | |||
| 89 | TIF_NEED_RESCHED */ | 89 | TIF_NEED_RESCHED */ |
| 90 | #define TIF_MEMDIE 4 | 90 | #define TIF_MEMDIE 4 |
| 91 | #define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */ | 91 | #define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */ |
| 92 | #define TIF_NOTIFY_RESUME 6 /* callback before returning to user */ | ||
| 92 | #define TIF_FREEZE 16 /* is freezing for suspend */ | 93 | #define TIF_FREEZE 16 /* is freezing for suspend */ |
| 93 | 94 | ||
| 94 | /* as above, but as bit values */ | 95 | /* as above, but as bit values */ |
| @@ -97,6 +98,7 @@ static inline struct thread_info *current_thread_info(void) | |||
| 97 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) | 98 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) |
| 98 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | 99 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) |
| 99 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) | 100 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) |
| 101 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) | ||
| 100 | #define _TIF_FREEZE (1<<TIF_FREEZE) | 102 | #define _TIF_FREEZE (1<<TIF_FREEZE) |
| 101 | 103 | ||
| 102 | #define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */ | 104 | #define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */ |
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index cf3472f7389b..af842c369d24 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #include <linux/tty.h> | 39 | #include <linux/tty.h> |
| 40 | #include <linux/binfmts.h> | 40 | #include <linux/binfmts.h> |
| 41 | #include <linux/freezer.h> | 41 | #include <linux/freezer.h> |
| 42 | #include <linux/tracehook.h> | ||
| 42 | 43 | ||
| 43 | #include <asm/setup.h> | 44 | #include <asm/setup.h> |
| 44 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
| @@ -552,4 +553,11 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) | |||
| 552 | { | 553 | { |
| 553 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) | 554 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) |
| 554 | do_signal(regs, NULL); | 555 | do_signal(regs, NULL); |
| 556 | |||
| 557 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||
| 558 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
| 559 | tracehook_notify_resume(regs); | ||
| 560 | if (current->replacement_session_keyring) | ||
| 561 | key_replace_session_keyring(); | ||
| 562 | } | ||
| 555 | } | 563 | } |
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 5d7c0e5b9e76..89969e950045 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c | |||
| @@ -192,6 +192,8 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall) | |||
| 192 | if (test_thread_flag(TIF_NOTIFY_RESUME)) { | 192 | if (test_thread_flag(TIF_NOTIFY_RESUME)) { |
| 193 | clear_thread_flag(TIF_NOTIFY_RESUME); | 193 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 194 | tracehook_notify_resume(&scr->pt); | 194 | tracehook_notify_resume(&scr->pt); |
| 195 | if (current->replacement_session_keyring) | ||
| 196 | key_replace_session_keyring(); | ||
| 195 | } | 197 | } |
| 196 | 198 | ||
| 197 | /* copy user rbs to kernel rbs */ | 199 | /* copy user rbs to kernel rbs */ |
diff --git a/arch/m32r/include/asm/thread_info.h b/arch/m32r/include/asm/thread_info.h index 07bb5bd00e2a..71578151a403 100644 --- a/arch/m32r/include/asm/thread_info.h +++ b/arch/m32r/include/asm/thread_info.h | |||
| @@ -149,6 +149,7 @@ static inline unsigned int get_thread_fault_code(void) | |||
| 149 | #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ | 149 | #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ |
| 150 | #define TIF_SINGLESTEP 3 /* restore singlestep on return to user mode */ | 150 | #define TIF_SINGLESTEP 3 /* restore singlestep on return to user mode */ |
| 151 | #define TIF_IRET 4 /* return with iret */ | 151 | #define TIF_IRET 4 /* return with iret */ |
| 152 | #define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ | ||
| 152 | #define TIF_RESTORE_SIGMASK 8 /* restore signal mask in do_signal() */ | 153 | #define TIF_RESTORE_SIGMASK 8 /* restore signal mask in do_signal() */ |
| 153 | #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ | 154 | #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ |
| 154 | #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ | 155 | #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) | |||
| 160 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) | 161 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) |
| 161 | #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) | 162 | #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) |
| 162 | #define _TIF_IRET (1<<TIF_IRET) | 163 | #define _TIF_IRET (1<<TIF_IRET) |
| 164 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) | ||
| 163 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) | 165 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) |
| 164 | #define _TIF_USEDFPU (1<<TIF_USEDFPU) | 166 | #define _TIF_USEDFPU (1<<TIF_USEDFPU) |
| 165 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | 167 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) |
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index 18124542a6eb..144b0f124fc7 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/stddef.h> | 21 | #include <linux/stddef.h> |
| 22 | #include <linux/personality.h> | 22 | #include <linux/personality.h> |
| 23 | #include <linux/freezer.h> | 23 | #include <linux/freezer.h> |
| 24 | #include <linux/tracehook.h> | ||
| 24 | #include <asm/cacheflush.h> | 25 | #include <asm/cacheflush.h> |
| 25 | #include <asm/ucontext.h> | 26 | #include <asm/ucontext.h> |
| 26 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
| @@ -408,5 +409,12 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, | |||
| 408 | if (thread_info_flags & _TIF_SIGPENDING) | 409 | if (thread_info_flags & _TIF_SIGPENDING) |
| 409 | do_signal(regs,oldset); | 410 | do_signal(regs,oldset); |
| 410 | 411 | ||
| 412 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||
| 413 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
| 414 | tracehook_notify_resume(regs); | ||
| 415 | if (current->replacement_session_keyring) | ||
| 416 | key_replace_session_keyring(); | ||
| 417 | } | ||
| 418 | |||
| 411 | clear_thread_flag(TIF_IRET); | 419 | clear_thread_flag(TIF_IRET); |
| 412 | } | 420 | } |
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index f9df720d2e40..01cc1630b66c 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h | |||
| @@ -115,6 +115,7 @@ register struct thread_info *__current_thread_info __asm__("$28"); | |||
| 115 | #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ | 115 | #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ |
| 116 | #define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */ | 116 | #define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */ |
| 117 | #define TIF_SECCOMP 4 /* secure computing */ | 117 | #define TIF_SECCOMP 4 /* secure computing */ |
| 118 | #define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ | ||
| 118 | #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ | 119 | #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ |
| 119 | #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ | 120 | #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ |
| 120 | #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ | 121 | #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"); | |||
| 139 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) | 140 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) |
| 140 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) | 141 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) |
| 141 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) | 142 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) |
| 143 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) | ||
| 142 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) | 144 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) |
| 143 | #define _TIF_USEDFPU (1<<TIF_USEDFPU) | 145 | #define _TIF_USEDFPU (1<<TIF_USEDFPU) |
| 144 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | 146 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) |
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 830c5ef9932b..6254041b942f 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/compiler.h> | 21 | #include <linux/compiler.h> |
| 22 | #include <linux/syscalls.h> | 22 | #include <linux/syscalls.h> |
| 23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
| 24 | #include <linux/tracehook.h> | ||
| 24 | 25 | ||
| 25 | #include <asm/abi.h> | 26 | #include <asm/abi.h> |
| 26 | #include <asm/asm.h> | 27 | #include <asm/asm.h> |
| @@ -700,4 +701,11 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, | |||
| 700 | /* deal with pending signal delivery */ | 701 | /* deal with pending signal delivery */ |
| 701 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) | 702 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) |
| 702 | do_signal(regs); | 703 | do_signal(regs); |
| 704 | |||
| 705 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | ||
| 706 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
| 707 | tracehook_notify_resume(regs); | ||
| 708 | if (current->replacement_session_keyring) | ||
| 709 | key_replace_session_keyring(); | ||
| 710 | } | ||
| 703 | } | 711 | } |
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c index feb2f2e810db..a21f43bc68e2 100644 --- a/arch/mn10300/kernel/signal.c +++ b/arch/mn10300/kernel/signal.c | |||
| @@ -568,5 +568,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) | |||
| 568 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 568 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 569 | clear_thread_flag(TIF_NOTIFY_RESUME); | 569 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 570 | tracehook_notify_resume(__frame); | 570 | tracehook_notify_resume(__frame); |
| 571 | if (current->replacement_session_keyring) | ||
| 572 | key_replace_session_keyring(); | ||
| 571 | } | 573 | } |
| 572 | } | 574 | } |
diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h index 4ce0edfbe969..ac775a76bff7 100644 --- a/arch/parisc/include/asm/thread_info.h +++ b/arch/parisc/include/asm/thread_info.h | |||
| @@ -59,6 +59,7 @@ struct thread_info { | |||
| 59 | #define TIF_MEMDIE 5 | 59 | #define TIF_MEMDIE 5 |
| 60 | #define TIF_RESTORE_SIGMASK 6 /* restore saved signal mask */ | 60 | #define TIF_RESTORE_SIGMASK 6 /* restore saved signal mask */ |
| 61 | #define TIF_FREEZE 7 /* is freezing for suspend */ | 61 | #define TIF_FREEZE 7 /* is freezing for suspend */ |
| 62 | #define TIF_NOTIFY_RESUME 8 /* callback before returning to user */ | ||
| 62 | 63 | ||
| 63 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) | 64 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) |
| 64 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) | 65 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) |
| @@ -67,8 +68,9 @@ struct thread_info { | |||
| 67 | #define _TIF_32BIT (1 << TIF_32BIT) | 68 | #define _TIF_32BIT (1 << TIF_32BIT) |
| 68 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) | 69 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) |
| 69 | #define _TIF_FREEZE (1 << TIF_FREEZE) | 70 | #define _TIF_FREEZE (1 << TIF_FREEZE) |
| 71 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) | ||
| 70 | 72 | ||
| 71 | #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | \ | 73 | #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | \ |
| 72 | _TIF_NEED_RESCHED | _TIF_RESTORE_SIGMASK) | 74 | _TIF_NEED_RESCHED | _TIF_RESTORE_SIGMASK) |
| 73 | 75 | ||
| 74 | #endif /* __KERNEL__ */ | 76 | #endif /* __KERNEL__ */ |
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index e552e547cb93..8c4712b74dc1 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S | |||
| @@ -948,7 +948,7 @@ intr_check_sig: | |||
| 948 | /* As above */ | 948 | /* As above */ |
| 949 | mfctl %cr30,%r1 | 949 | mfctl %cr30,%r1 |
| 950 | LDREG TI_FLAGS(%r1),%r19 | 950 | LDREG TI_FLAGS(%r1),%r19 |
| 951 | ldi (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %r20 | 951 | ldi (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NOTIFY_RESUME), %r20 |
| 952 | and,COND(<>) %r19, %r20, %r0 | 952 | and,COND(<>) %r19, %r20, %r0 |
| 953 | b,n intr_restore /* skip past if we've nothing to do */ | 953 | b,n intr_restore /* skip past if we've nothing to do */ |
| 954 | 954 | ||
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index f82544225e8e..8eb3c63c407a 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/stddef.h> | 25 | #include <linux/stddef.h> |
| 26 | #include <linux/compat.h> | 26 | #include <linux/compat.h> |
| 27 | #include <linux/elf.h> | 27 | #include <linux/elf.h> |
| 28 | #include <linux/tracehook.h> | ||
| 28 | #include <asm/ucontext.h> | 29 | #include <asm/ucontext.h> |
| 29 | #include <asm/rt_sigframe.h> | 30 | #include <asm/rt_sigframe.h> |
| 30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
| @@ -645,4 +646,11 @@ void do_notify_resume(struct pt_regs *regs, long in_syscall) | |||
| 645 | if (test_thread_flag(TIF_SIGPENDING) || | 646 | if (test_thread_flag(TIF_SIGPENDING) || |
| 646 | test_thread_flag(TIF_RESTORE_SIGMASK)) | 647 | test_thread_flag(TIF_RESTORE_SIGMASK)) |
| 647 | do_signal(regs, in_syscall); | 648 | do_signal(regs, in_syscall); |
| 649 | |||
| 650 | if (test_thread_flag(TIF_NOTIFY_RESUME)) { | ||
| 651 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
| 652 | tracehook_notify_resume(regs); | ||
| 653 | if (current->replacement_session_keyring) | ||
| 654 | key_replace_session_keyring(); | ||
| 655 | } | ||
| 648 | } | 656 | } |
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 062bd64e65fa..6b4fef877f9d 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c | |||
| @@ -536,4 +536,6 @@ void do_notify_resume(struct pt_regs *regs) | |||
| 536 | { | 536 | { |
| 537 | clear_thread_flag(TIF_NOTIFY_RESUME); | 537 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 538 | tracehook_notify_resume(regs); | 538 | tracehook_notify_resume(regs); |
| 539 | if (current->replacement_session_keyring) | ||
| 540 | key_replace_session_keyring(); | ||
| 539 | } | 541 | } |
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index b5afbec1db59..04a21883f327 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c | |||
| @@ -640,5 +640,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, | |||
| 640 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 640 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 641 | clear_thread_flag(TIF_NOTIFY_RESUME); | 641 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 642 | tracehook_notify_resume(regs); | 642 | tracehook_notify_resume(regs); |
| 643 | if (current->replacement_session_keyring) | ||
| 644 | key_replace_session_keyring(); | ||
| 643 | } | 645 | } |
| 644 | } | 646 | } |
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 0663a0ee6021..9e5c9b1d7e98 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c | |||
| @@ -772,5 +772,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info | |||
| 772 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 772 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 773 | clear_thread_flag(TIF_NOTIFY_RESUME); | 773 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 774 | tracehook_notify_resume(regs); | 774 | tracehook_notify_resume(regs); |
| 775 | if (current->replacement_session_keyring) | ||
| 776 | key_replace_session_keyring(); | ||
| 775 | } | 777 | } |
| 776 | } | 778 | } |
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 181d069a2d44..7ce1a1005b1d 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c | |||
| @@ -590,6 +590,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, | |||
| 590 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 590 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 591 | clear_thread_flag(TIF_NOTIFY_RESUME); | 591 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 592 | tracehook_notify_resume(regs); | 592 | tracehook_notify_resume(regs); |
| 593 | if (current->replacement_session_keyring) | ||
| 594 | key_replace_session_keyring(); | ||
| 593 | } | 595 | } |
| 594 | } | 596 | } |
| 595 | 597 | ||
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index ec82d76dc6f2..647afbda7ae1 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c | |||
| @@ -613,5 +613,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long | |||
| 613 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 613 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 614 | clear_thread_flag(TIF_NOTIFY_RESUME); | 614 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 615 | tracehook_notify_resume(regs); | 615 | tracehook_notify_resume(regs); |
| 616 | if (current->replacement_session_keyring) | ||
| 617 | key_replace_session_keyring(); | ||
| 616 | } | 618 | } |
| 617 | } | 619 | } |
| 620 | |||
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 4c578751e94e..81e58238c4ce 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
| @@ -869,6 +869,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) | |||
| 869 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { | 869 | if (thread_info_flags & _TIF_NOTIFY_RESUME) { |
| 870 | clear_thread_flag(TIF_NOTIFY_RESUME); | 870 | clear_thread_flag(TIF_NOTIFY_RESUME); |
| 871 | tracehook_notify_resume(regs); | 871 | tracehook_notify_resume(regs); |
| 872 | if (current->replacement_session_keyring) | ||
| 873 | key_replace_session_keyring(); | ||
| 872 | } | 874 | } |
| 873 | 875 | ||
| 874 | #ifdef CONFIG_X86_32 | 876 | #ifdef CONFIG_X86_32 |
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index aec1931608aa..0b73e4ec1add 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
| @@ -450,6 +450,12 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
| 450 | goto out_err; | 450 | goto out_err; |
| 451 | } | 451 | } |
| 452 | 452 | ||
| 453 | /* Default timeouts */ | ||
| 454 | chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
| 455 | chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); | ||
| 456 | chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
| 457 | chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
| 458 | |||
| 453 | if (request_locality(chip, 0) != 0) { | 459 | if (request_locality(chip, 0) != 0) { |
| 454 | rc = -ENODEV; | 460 | rc = -ENODEV; |
| 455 | goto out_err; | 461 | goto out_err; |
| @@ -457,12 +463,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
| 457 | 463 | ||
| 458 | vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); | 464 | vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); |
| 459 | 465 | ||
| 460 | /* Default timeouts */ | ||
| 461 | chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
| 462 | chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); | ||
| 463 | chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
| 464 | chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
| 465 | |||
| 466 | dev_info(dev, | 466 | dev_info(dev, |
| 467 | "1.2 TPM (device-id 0x%X, rev-id %d)\n", | 467 | "1.2 TPM (device-id 0x%X, rev-id %d)\n", |
| 468 | vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); | 468 | vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); |
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 42b6c6319bc2..87214a257d2a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
| @@ -130,17 +130,10 @@ static inline struct tun_sock *tun_sk(struct sock *sk) | |||
| 130 | static int tun_attach(struct tun_struct *tun, struct file *file) | 130 | static int tun_attach(struct tun_struct *tun, struct file *file) |
| 131 | { | 131 | { |
| 132 | struct tun_file *tfile = file->private_data; | 132 | struct tun_file *tfile = file->private_data; |
| 133 | const struct cred *cred = current_cred(); | ||
| 134 | int err; | 133 | int err; |
| 135 | 134 | ||
| 136 | ASSERT_RTNL(); | 135 | ASSERT_RTNL(); |
| 137 | 136 | ||
| 138 | /* Check permissions */ | ||
| 139 | if (((tun->owner != -1 && cred->euid != tun->owner) || | ||
| 140 | (tun->group != -1 && !in_egroup_p(tun->group))) && | ||
| 141 | !capable(CAP_NET_ADMIN)) | ||
| 142 | return -EPERM; | ||
| 143 | |||
| 144 | netif_tx_lock_bh(tun->dev); | 137 | netif_tx_lock_bh(tun->dev); |
| 145 | 138 | ||
| 146 | err = -EINVAL; | 139 | err = -EINVAL; |
| @@ -926,6 +919,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
| 926 | 919 | ||
| 927 | dev = __dev_get_by_name(net, ifr->ifr_name); | 920 | dev = __dev_get_by_name(net, ifr->ifr_name); |
| 928 | if (dev) { | 921 | if (dev) { |
| 922 | const struct cred *cred = current_cred(); | ||
| 923 | |||
| 929 | if (ifr->ifr_flags & IFF_TUN_EXCL) | 924 | if (ifr->ifr_flags & IFF_TUN_EXCL) |
| 930 | return -EBUSY; | 925 | return -EBUSY; |
| 931 | if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops) | 926 | 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) | |||
| 935 | else | 930 | else |
| 936 | return -EINVAL; | 931 | return -EINVAL; |
| 937 | 932 | ||
| 933 | if (((tun->owner != -1 && cred->euid != tun->owner) || | ||
| 934 | (tun->group != -1 && !in_egroup_p(tun->group))) && | ||
| 935 | !capable(CAP_NET_ADMIN)) | ||
| 936 | return -EPERM; | ||
| 937 | err = security_tun_dev_attach(tun->sk); | ||
| 938 | if (err < 0) | ||
| 939 | return err; | ||
| 940 | |||
| 938 | err = tun_attach(tun, file); | 941 | err = tun_attach(tun, file); |
| 939 | if (err < 0) | 942 | if (err < 0) |
| 940 | return err; | 943 | return err; |
| @@ -947,6 +950,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
| 947 | 950 | ||
| 948 | if (!capable(CAP_NET_ADMIN)) | 951 | if (!capable(CAP_NET_ADMIN)) |
| 949 | return -EPERM; | 952 | return -EPERM; |
| 953 | err = security_tun_dev_create(); | ||
| 954 | if (err < 0) | ||
| 955 | return err; | ||
| 950 | 956 | ||
| 951 | /* Set dev type */ | 957 | /* Set dev type */ |
| 952 | if (ifr->ifr_flags & IFF_TUN) { | 958 | if (ifr->ifr_flags & IFF_TUN) { |
| @@ -989,6 +995,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
| 989 | tun->sk = sk; | 995 | tun->sk = sk; |
| 990 | container_of(sk, struct tun_sock, sk)->tun = tun; | 996 | container_of(sk, struct tun_sock, sk)->tun = tun; |
| 991 | 997 | ||
| 998 | security_tun_dev_post_create(sk); | ||
| 999 | |||
| 992 | tun_net_init(dev); | 1000 | tun_net_init(dev); |
| 993 | 1001 | ||
| 994 | if (strchr(dev->name, '%')) { | 1002 | if (strchr(dev->name, '%')) { |
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 9d7c99394ec6..640f65c6ef84 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c | |||
| @@ -1752,12 +1752,12 @@ static int comedi_open(struct inode *inode, struct file *file) | |||
| 1752 | mutex_lock(&dev->mutex); | 1752 | mutex_lock(&dev->mutex); |
| 1753 | if (dev->attached) | 1753 | if (dev->attached) |
| 1754 | goto ok; | 1754 | goto ok; |
| 1755 | if (!capable(CAP_SYS_MODULE) && dev->in_request_module) { | 1755 | if (!capable(CAP_NET_ADMIN) && dev->in_request_module) { |
| 1756 | DPRINTK("in request module\n"); | 1756 | DPRINTK("in request module\n"); |
| 1757 | mutex_unlock(&dev->mutex); | 1757 | mutex_unlock(&dev->mutex); |
| 1758 | return -ENODEV; | 1758 | return -ENODEV; |
| 1759 | } | 1759 | } |
| 1760 | if (capable(CAP_SYS_MODULE) && dev->in_request_module) | 1760 | if (capable(CAP_NET_ADMIN) && dev->in_request_module) |
| 1761 | goto ok; | 1761 | goto ok; |
| 1762 | 1762 | ||
| 1763 | dev->in_request_module = 1; | 1763 | dev->in_request_module = 1; |
| @@ -1770,8 +1770,8 @@ static int comedi_open(struct inode *inode, struct file *file) | |||
| 1770 | 1770 | ||
| 1771 | dev->in_request_module = 0; | 1771 | dev->in_request_module = 0; |
| 1772 | 1772 | ||
| 1773 | if (!dev->attached && !capable(CAP_SYS_MODULE)) { | 1773 | if (!dev->attached && !capable(CAP_NET_ADMIN)) { |
| 1774 | DPRINTK("not attached and not CAP_SYS_MODULE\n"); | 1774 | DPRINTK("not attached and not CAP_NET_ADMIN\n"); |
| 1775 | mutex_unlock(&dev->mutex); | 1775 | mutex_unlock(&dev->mutex); |
| 1776 | return -ENODEV; | 1776 | return -ENODEV; |
| 1777 | } | 1777 | } |
diff --git a/fs/locks.c b/fs/locks.c index b6440f52178f..52366e877d76 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -1591,7 +1591,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) | |||
| 1591 | if (can_sleep) | 1591 | if (can_sleep) |
| 1592 | lock->fl_flags |= FL_SLEEP; | 1592 | lock->fl_flags |= FL_SLEEP; |
| 1593 | 1593 | ||
| 1594 | error = security_file_lock(filp, cmd); | 1594 | error = security_file_lock(filp, lock->fl_type); |
| 1595 | if (error) | 1595 | if (error) |
| 1596 | goto out_free; | 1596 | goto out_free; |
| 1597 | 1597 | ||
diff --git a/fs/namei.c b/fs/namei.c index ed27bb205b7e..d11f404667e9 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -1533,9 +1533,11 @@ int may_open(struct path *path, int acc_mode, int flag) | |||
| 1533 | if (error) | 1533 | if (error) |
| 1534 | return error; | 1534 | return error; |
| 1535 | 1535 | ||
| 1536 | error = ima_path_check(path, | 1536 | error = ima_path_check(path, acc_mode ? |
| 1537 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC), | 1537 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) : |
| 1538 | ACC_MODE(flag) & (MAY_READ | MAY_WRITE), | ||
| 1538 | IMA_COUNT_UPDATE); | 1539 | IMA_COUNT_UPDATE); |
| 1540 | |||
| 1539 | if (error) | 1541 | if (error) |
| 1540 | return error; | 1542 | return error; |
| 1541 | /* | 1543 | /* |
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 5573508f707f..36fcabbf5186 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
| @@ -34,6 +34,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |||
| 34 | int flags = nfsexp_flags(rqstp, exp); | 34 | int flags = nfsexp_flags(rqstp, exp); |
| 35 | int ret; | 35 | int ret; |
| 36 | 36 | ||
| 37 | validate_process_creds(); | ||
| 38 | |||
| 37 | /* discard any old override before preparing the new set */ | 39 | /* discard any old override before preparing the new set */ |
| 38 | revert_creds(get_cred(current->real_cred)); | 40 | revert_creds(get_cred(current->real_cred)); |
| 39 | new = prepare_creds(); | 41 | new = prepare_creds(); |
| @@ -86,8 +88,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |||
| 86 | else | 88 | else |
| 87 | new->cap_effective = cap_raise_nfsd_set(new->cap_effective, | 89 | new->cap_effective = cap_raise_nfsd_set(new->cap_effective, |
| 88 | new->cap_permitted); | 90 | new->cap_permitted); |
| 91 | validate_process_creds(); | ||
| 89 | put_cred(override_creds(new)); | 92 | put_cred(override_creds(new)); |
| 90 | put_cred(new); | 93 | put_cred(new); |
| 94 | validate_process_creds(); | ||
| 91 | return 0; | 95 | return 0; |
| 92 | 96 | ||
| 93 | oom: | 97 | oom: |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 492c79b7800b..24d58adfe5fd 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
| @@ -496,7 +496,9 @@ nfsd(void *vrqstp) | |||
| 496 | /* Lock the export hash tables for reading. */ | 496 | /* Lock the export hash tables for reading. */ |
| 497 | exp_readlock(); | 497 | exp_readlock(); |
| 498 | 498 | ||
| 499 | validate_process_creds(); | ||
| 499 | svc_process(rqstp); | 500 | svc_process(rqstp); |
| 501 | validate_process_creds(); | ||
| 500 | 502 | ||
| 501 | /* Unlock export hash tables */ | 503 | /* Unlock export hash tables */ |
| 502 | exp_readunlock(); | 504 | exp_readunlock(); |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 23341c1063bc..8fa09bfbcba7 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -684,6 +684,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 684 | __be32 err; | 684 | __be32 err; |
| 685 | int host_err; | 685 | int host_err; |
| 686 | 686 | ||
| 687 | validate_process_creds(); | ||
| 688 | |||
| 687 | /* | 689 | /* |
| 688 | * If we get here, then the client has already done an "open", | 690 | * If we get here, then the client has already done an "open", |
| 689 | * and (hopefully) checked permission - so allow OWNER_OVERRIDE | 691 | * and (hopefully) checked permission - so allow OWNER_OVERRIDE |
| @@ -740,6 +742,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 740 | out_nfserr: | 742 | out_nfserr: |
| 741 | err = nfserrno(host_err); | 743 | err = nfserrno(host_err); |
| 742 | out: | 744 | out: |
| 745 | validate_process_creds(); | ||
| 743 | return err; | 746 | return err; |
| 744 | } | 747 | } |
| 745 | 748 | ||
| @@ -199,7 +199,7 @@ out: | |||
| 199 | int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, | 199 | int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, |
| 200 | struct file *filp) | 200 | struct file *filp) |
| 201 | { | 201 | { |
| 202 | int err; | 202 | int ret; |
| 203 | struct iattr newattrs; | 203 | struct iattr newattrs; |
| 204 | 204 | ||
| 205 | /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ | 205 | /* 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, | |||
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | /* Remove suid/sgid on truncate too */ | 216 | /* Remove suid/sgid on truncate too */ |
| 217 | newattrs.ia_valid |= should_remove_suid(dentry); | 217 | ret = should_remove_suid(dentry); |
| 218 | if (ret) | ||
| 219 | newattrs.ia_valid |= ret | ATTR_FORCE; | ||
| 218 | 220 | ||
| 219 | mutex_lock(&dentry->d_inode->i_mutex); | 221 | mutex_lock(&dentry->d_inode->i_mutex); |
| 220 | err = notify_change(dentry, &newattrs); | 222 | ret = notify_change(dentry, &newattrs); |
| 221 | mutex_unlock(&dentry->d_inode->i_mutex); | 223 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 222 | return err; | 224 | return ret; |
| 223 | } | 225 | } |
| 224 | 226 | ||
| 225 | static long do_sys_truncate(const char __user *pathname, loff_t length) | 227 | 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, | |||
| 957 | int error; | 959 | int error; |
| 958 | struct file *f; | 960 | struct file *f; |
| 959 | 961 | ||
| 962 | validate_creds(cred); | ||
| 963 | |||
| 960 | /* | 964 | /* |
| 961 | * We must always pass in a valid mount pointer. Historically | 965 | * We must always pass in a valid mount pointer. Historically |
| 962 | * callers got away with not passing it, but we must enforce this at | 966 | * callers got away with not passing it, but we must enforce this at |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 14f2d71ea3ce..0050fc40e8c9 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
| @@ -760,6 +760,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 760 | const struct inode_operations sysfs_dir_inode_operations = { | 760 | const struct inode_operations sysfs_dir_inode_operations = { |
| 761 | .lookup = sysfs_lookup, | 761 | .lookup = sysfs_lookup, |
| 762 | .setattr = sysfs_setattr, | 762 | .setattr = sysfs_setattr, |
| 763 | .setxattr = sysfs_setxattr, | ||
| 763 | }; | 764 | }; |
| 764 | 765 | ||
| 765 | static void remove_dir(struct sysfs_dirent *sd) | 766 | static void remove_dir(struct sysfs_dirent *sd) |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 555f0ff988df..2b6a8d9de73d 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
| @@ -18,6 +18,8 @@ | |||
| 18 | #include <linux/capability.h> | 18 | #include <linux/capability.h> |
| 19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
| 20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
| 21 | #include <linux/xattr.h> | ||
| 22 | #include <linux/security.h> | ||
| 21 | #include "sysfs.h" | 23 | #include "sysfs.h" |
| 22 | 24 | ||
| 23 | extern struct super_block * sysfs_sb; | 25 | extern struct super_block * sysfs_sb; |
| @@ -35,6 +37,7 @@ static struct backing_dev_info sysfs_backing_dev_info = { | |||
| 35 | 37 | ||
| 36 | static const struct inode_operations sysfs_inode_operations ={ | 38 | static const struct inode_operations sysfs_inode_operations ={ |
| 37 | .setattr = sysfs_setattr, | 39 | .setattr = sysfs_setattr, |
| 40 | .setxattr = sysfs_setxattr, | ||
| 38 | }; | 41 | }; |
| 39 | 42 | ||
| 40 | int __init sysfs_inode_init(void) | 43 | int __init sysfs_inode_init(void) |
| @@ -42,18 +45,37 @@ int __init sysfs_inode_init(void) | |||
| 42 | return bdi_init(&sysfs_backing_dev_info); | 45 | return bdi_init(&sysfs_backing_dev_info); |
| 43 | } | 46 | } |
| 44 | 47 | ||
| 48 | struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | ||
| 49 | { | ||
| 50 | struct sysfs_inode_attrs *attrs; | ||
| 51 | struct iattr *iattrs; | ||
| 52 | |||
| 53 | attrs = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL); | ||
| 54 | if (!attrs) | ||
| 55 | return NULL; | ||
| 56 | iattrs = &attrs->ia_iattr; | ||
| 57 | |||
| 58 | /* assign default attributes */ | ||
| 59 | iattrs->ia_mode = sd->s_mode; | ||
| 60 | iattrs->ia_uid = 0; | ||
| 61 | iattrs->ia_gid = 0; | ||
| 62 | iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; | ||
| 63 | |||
| 64 | return attrs; | ||
| 65 | } | ||
| 45 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | 66 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) |
| 46 | { | 67 | { |
| 47 | struct inode * inode = dentry->d_inode; | 68 | struct inode * inode = dentry->d_inode; |
| 48 | struct sysfs_dirent * sd = dentry->d_fsdata; | 69 | struct sysfs_dirent * sd = dentry->d_fsdata; |
| 49 | struct iattr * sd_iattr; | 70 | struct sysfs_inode_attrs *sd_attrs; |
| 71 | struct iattr *iattrs; | ||
| 50 | unsigned int ia_valid = iattr->ia_valid; | 72 | unsigned int ia_valid = iattr->ia_valid; |
| 51 | int error; | 73 | int error; |
| 52 | 74 | ||
| 53 | if (!sd) | 75 | if (!sd) |
| 54 | return -EINVAL; | 76 | return -EINVAL; |
| 55 | 77 | ||
| 56 | sd_iattr = sd->s_iattr; | 78 | sd_attrs = sd->s_iattr; |
| 57 | 79 | ||
| 58 | error = inode_change_ok(inode, iattr); | 80 | error = inode_change_ok(inode, iattr); |
| 59 | if (error) | 81 | if (error) |
| @@ -65,42 +87,77 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | |||
| 65 | if (error) | 87 | if (error) |
| 66 | return error; | 88 | return error; |
| 67 | 89 | ||
| 68 | if (!sd_iattr) { | 90 | if (!sd_attrs) { |
| 69 | /* setting attributes for the first time, allocate now */ | 91 | /* setting attributes for the first time, allocate now */ |
| 70 | sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); | 92 | sd_attrs = sysfs_init_inode_attrs(sd); |
| 71 | if (!sd_iattr) | 93 | if (!sd_attrs) |
| 72 | return -ENOMEM; | 94 | return -ENOMEM; |
| 73 | /* assign default attributes */ | 95 | sd->s_iattr = sd_attrs; |
| 74 | sd_iattr->ia_mode = sd->s_mode; | 96 | } else { |
| 75 | sd_iattr->ia_uid = 0; | 97 | /* attributes were changed at least once in past */ |
| 76 | sd_iattr->ia_gid = 0; | 98 | iattrs = &sd_attrs->ia_iattr; |
| 77 | sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME; | 99 | |
| 78 | sd->s_iattr = sd_iattr; | 100 | if (ia_valid & ATTR_UID) |
| 101 | iattrs->ia_uid = iattr->ia_uid; | ||
| 102 | if (ia_valid & ATTR_GID) | ||
| 103 | iattrs->ia_gid = iattr->ia_gid; | ||
| 104 | if (ia_valid & ATTR_ATIME) | ||
| 105 | iattrs->ia_atime = timespec_trunc(iattr->ia_atime, | ||
| 106 | inode->i_sb->s_time_gran); | ||
| 107 | if (ia_valid & ATTR_MTIME) | ||
| 108 | iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime, | ||
| 109 | inode->i_sb->s_time_gran); | ||
| 110 | if (ia_valid & ATTR_CTIME) | ||
| 111 | iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime, | ||
| 112 | inode->i_sb->s_time_gran); | ||
| 113 | if (ia_valid & ATTR_MODE) { | ||
| 114 | umode_t mode = iattr->ia_mode; | ||
| 115 | |||
| 116 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
| 117 | mode &= ~S_ISGID; | ||
| 118 | iattrs->ia_mode = sd->s_mode = mode; | ||
| 119 | } | ||
| 79 | } | 120 | } |
| 121 | return error; | ||
| 122 | } | ||
| 80 | 123 | ||
| 81 | /* attributes were changed atleast once in past */ | 124 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
| 82 | 125 | size_t size, int flags) | |
| 83 | if (ia_valid & ATTR_UID) | 126 | { |
| 84 | sd_iattr->ia_uid = iattr->ia_uid; | 127 | struct sysfs_dirent *sd = dentry->d_fsdata; |
| 85 | if (ia_valid & ATTR_GID) | 128 | struct sysfs_inode_attrs *iattrs; |
| 86 | sd_iattr->ia_gid = iattr->ia_gid; | 129 | void *secdata; |
| 87 | if (ia_valid & ATTR_ATIME) | 130 | int error; |
| 88 | sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime, | 131 | u32 secdata_len = 0; |
| 89 | inode->i_sb->s_time_gran); | 132 | |
| 90 | if (ia_valid & ATTR_MTIME) | 133 | if (!sd) |
| 91 | sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime, | 134 | return -EINVAL; |
| 92 | inode->i_sb->s_time_gran); | 135 | if (!sd->s_iattr) |
| 93 | if (ia_valid & ATTR_CTIME) | 136 | sd->s_iattr = sysfs_init_inode_attrs(sd); |
| 94 | sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime, | 137 | if (!sd->s_iattr) |
| 95 | inode->i_sb->s_time_gran); | 138 | return -ENOMEM; |
| 96 | if (ia_valid & ATTR_MODE) { | 139 | |
| 97 | umode_t mode = iattr->ia_mode; | 140 | iattrs = sd->s_iattr; |
| 98 | 141 | ||
| 99 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | 142 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { |
| 100 | mode &= ~S_ISGID; | 143 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; |
| 101 | sd_iattr->ia_mode = sd->s_mode = mode; | 144 | error = security_inode_setsecurity(dentry->d_inode, suffix, |
| 102 | } | 145 | value, size, flags); |
| 146 | if (error) | ||
| 147 | goto out; | ||
| 148 | error = security_inode_getsecctx(dentry->d_inode, | ||
| 149 | &secdata, &secdata_len); | ||
| 150 | if (error) | ||
| 151 | goto out; | ||
| 152 | if (iattrs->ia_secdata) | ||
| 153 | security_release_secctx(iattrs->ia_secdata, | ||
| 154 | iattrs->ia_secdata_len); | ||
| 155 | iattrs->ia_secdata = secdata; | ||
| 156 | iattrs->ia_secdata_len = secdata_len; | ||
| 103 | 157 | ||
| 158 | } else | ||
| 159 | return -EINVAL; | ||
| 160 | out: | ||
| 104 | return error; | 161 | return error; |
| 105 | } | 162 | } |
| 106 | 163 | ||
| @@ -146,6 +203,7 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) | |||
| 146 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | 203 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
| 147 | { | 204 | { |
| 148 | struct bin_attribute *bin_attr; | 205 | struct bin_attribute *bin_attr; |
| 206 | struct sysfs_inode_attrs *iattrs; | ||
| 149 | 207 | ||
| 150 | inode->i_private = sysfs_get(sd); | 208 | inode->i_private = sysfs_get(sd); |
| 151 | inode->i_mapping->a_ops = &sysfs_aops; | 209 | inode->i_mapping->a_ops = &sysfs_aops; |
| @@ -154,16 +212,20 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | |||
| 154 | inode->i_ino = sd->s_ino; | 212 | inode->i_ino = sd->s_ino; |
| 155 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); | 213 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); |
| 156 | 214 | ||
| 157 | if (sd->s_iattr) { | 215 | iattrs = sd->s_iattr; |
| 216 | if (iattrs) { | ||
| 158 | /* sysfs_dirent has non-default attributes | 217 | /* sysfs_dirent has non-default attributes |
| 159 | * get them for the new inode from persistent copy | 218 | * get them for the new inode from persistent copy |
| 160 | * in sysfs_dirent | 219 | * in sysfs_dirent |
| 161 | */ | 220 | */ |
| 162 | set_inode_attr(inode, sd->s_iattr); | 221 | set_inode_attr(inode, &iattrs->ia_iattr); |
| 222 | if (iattrs->ia_secdata) | ||
| 223 | security_inode_notifysecctx(inode, | ||
| 224 | iattrs->ia_secdata, | ||
| 225 | iattrs->ia_secdata_len); | ||
| 163 | } else | 226 | } else |
| 164 | set_default_inode_attr(inode, sd->s_mode); | 227 | set_default_inode_attr(inode, sd->s_mode); |
| 165 | 228 | ||
| 166 | |||
| 167 | /* initialize inode according to type */ | 229 | /* initialize inode according to type */ |
| 168 | switch (sysfs_type(sd)) { | 230 | switch (sysfs_type(sd)) { |
| 169 | case SYSFS_DIR: | 231 | case SYSFS_DIR: |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 1d897ad808e0..c5081ad77026 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/kobject.h> | 16 | #include <linux/kobject.h> |
| 17 | #include <linux/namei.h> | 17 | #include <linux/namei.h> |
| 18 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
| 19 | #include <linux/security.h> | ||
| 19 | 20 | ||
| 20 | #include "sysfs.h" | 21 | #include "sysfs.h" |
| 21 | 22 | ||
| @@ -209,6 +210,7 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co | |||
| 209 | } | 210 | } |
| 210 | 211 | ||
| 211 | const struct inode_operations sysfs_symlink_inode_operations = { | 212 | const struct inode_operations sysfs_symlink_inode_operations = { |
| 213 | .setxattr = sysfs_setxattr, | ||
| 212 | .readlink = generic_readlink, | 214 | .readlink = generic_readlink, |
| 213 | .follow_link = sysfs_follow_link, | 215 | .follow_link = sysfs_follow_link, |
| 214 | .put_link = sysfs_put_link, | 216 | .put_link = sysfs_put_link, |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3fa0d98481e2..af4c4e7482ac 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
| @@ -8,6 +8,8 @@ | |||
| 8 | * This file is released under the GPLv2. | 8 | * This file is released under the GPLv2. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/fs.h> | ||
| 12 | |||
| 11 | struct sysfs_open_dirent; | 13 | struct sysfs_open_dirent; |
| 12 | 14 | ||
| 13 | /* type-specific structures for sysfs_dirent->s_* union members */ | 15 | /* type-specific structures for sysfs_dirent->s_* union members */ |
| @@ -31,6 +33,12 @@ struct sysfs_elem_bin_attr { | |||
| 31 | struct hlist_head buffers; | 33 | struct hlist_head buffers; |
| 32 | }; | 34 | }; |
| 33 | 35 | ||
| 36 | struct sysfs_inode_attrs { | ||
| 37 | struct iattr ia_iattr; | ||
| 38 | void *ia_secdata; | ||
| 39 | u32 ia_secdata_len; | ||
| 40 | }; | ||
| 41 | |||
| 34 | /* | 42 | /* |
| 35 | * sysfs_dirent - the building block of sysfs hierarchy. Each and | 43 | * sysfs_dirent - the building block of sysfs hierarchy. Each and |
| 36 | * every sysfs node is represented by single sysfs_dirent. | 44 | * every sysfs node is represented by single sysfs_dirent. |
| @@ -56,7 +64,7 @@ struct sysfs_dirent { | |||
| 56 | unsigned int s_flags; | 64 | unsigned int s_flags; |
| 57 | ino_t s_ino; | 65 | ino_t s_ino; |
| 58 | umode_t s_mode; | 66 | umode_t s_mode; |
| 59 | struct iattr *s_iattr; | 67 | struct sysfs_inode_attrs *s_iattr; |
| 60 | }; | 68 | }; |
| 61 | 69 | ||
| 62 | #define SD_DEACTIVATED_BIAS INT_MIN | 70 | #define SD_DEACTIVATED_BIAS INT_MIN |
| @@ -148,6 +156,8 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) | |||
| 148 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); | 156 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); |
| 149 | void sysfs_delete_inode(struct inode *inode); | 157 | void sysfs_delete_inode(struct inode *inode); |
| 150 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | 158 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); |
| 159 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | ||
| 160 | size_t size, int flags); | ||
| 151 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); | 161 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); |
| 152 | int sysfs_inode_init(void); | 162 | int sysfs_inode_init(void); |
| 153 | 163 | ||
diff --git a/fs/xattr.c b/fs/xattr.c index 1c3d0af59ddf..6d4f6d3449fb 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
| @@ -66,22 +66,28 @@ xattr_permission(struct inode *inode, const char *name, int mask) | |||
| 66 | return inode_permission(inode, mask); | 66 | return inode_permission(inode, mask); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | int | 69 | /** |
| 70 | vfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 70 | * __vfs_setxattr_noperm - perform setxattr operation without performing |
| 71 | size_t size, int flags) | 71 | * permission checks. |
| 72 | * | ||
| 73 | * @dentry - object to perform setxattr on | ||
| 74 | * @name - xattr name to set | ||
| 75 | * @value - value to set @name to | ||
| 76 | * @size - size of @value | ||
| 77 | * @flags - flags to pass into filesystem operations | ||
| 78 | * | ||
| 79 | * returns the result of the internal setxattr or setsecurity operations. | ||
| 80 | * | ||
| 81 | * This function requires the caller to lock the inode's i_mutex before it | ||
| 82 | * is executed. It also assumes that the caller will make the appropriate | ||
| 83 | * permission checks. | ||
| 84 | */ | ||
| 85 | int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, | ||
| 86 | const void *value, size_t size, int flags) | ||
| 72 | { | 87 | { |
| 73 | struct inode *inode = dentry->d_inode; | 88 | struct inode *inode = dentry->d_inode; |
| 74 | int error; | 89 | int error = -EOPNOTSUPP; |
| 75 | |||
| 76 | error = xattr_permission(inode, name, MAY_WRITE); | ||
| 77 | if (error) | ||
| 78 | return error; | ||
| 79 | 90 | ||
| 80 | mutex_lock(&inode->i_mutex); | ||
| 81 | error = security_inode_setxattr(dentry, name, value, size, flags); | ||
| 82 | if (error) | ||
| 83 | goto out; | ||
| 84 | error = -EOPNOTSUPP; | ||
| 85 | if (inode->i_op->setxattr) { | 91 | if (inode->i_op->setxattr) { |
| 86 | error = inode->i_op->setxattr(dentry, name, value, size, flags); | 92 | error = inode->i_op->setxattr(dentry, name, value, size, flags); |
| 87 | if (!error) { | 93 | if (!error) { |
| @@ -97,6 +103,29 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value, | |||
| 97 | if (!error) | 103 | if (!error) |
| 98 | fsnotify_xattr(dentry); | 104 | fsnotify_xattr(dentry); |
| 99 | } | 105 | } |
| 106 | |||
| 107 | return error; | ||
| 108 | } | ||
| 109 | |||
| 110 | |||
| 111 | int | ||
| 112 | vfs_setxattr(struct dentry *dentry, const char *name, const void *value, | ||
| 113 | size_t size, int flags) | ||
| 114 | { | ||
| 115 | struct inode *inode = dentry->d_inode; | ||
| 116 | int error; | ||
| 117 | |||
| 118 | error = xattr_permission(inode, name, MAY_WRITE); | ||
| 119 | if (error) | ||
| 120 | return error; | ||
| 121 | |||
| 122 | mutex_lock(&inode->i_mutex); | ||
| 123 | error = security_inode_setxattr(dentry, name, value, size, flags); | ||
| 124 | if (error) | ||
| 125 | goto out; | ||
| 126 | |||
| 127 | error = __vfs_setxattr_noperm(dentry, name, value, size, flags); | ||
| 128 | |||
| 100 | out: | 129 | out: |
| 101 | mutex_unlock(&inode->i_mutex); | 130 | mutex_unlock(&inode->i_mutex); |
| 102 | return error; | 131 | return error; |
diff --git a/include/linux/cred.h b/include/linux/cred.h index 4fa999696310..24520a539c6f 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h | |||
| @@ -114,6 +114,13 @@ struct thread_group_cred { | |||
| 114 | */ | 114 | */ |
| 115 | struct cred { | 115 | struct cred { |
| 116 | atomic_t usage; | 116 | atomic_t usage; |
| 117 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 118 | atomic_t subscribers; /* number of processes subscribed */ | ||
| 119 | void *put_addr; | ||
| 120 | unsigned magic; | ||
| 121 | #define CRED_MAGIC 0x43736564 | ||
| 122 | #define CRED_MAGIC_DEAD 0x44656144 | ||
| 123 | #endif | ||
| 117 | uid_t uid; /* real UID of the task */ | 124 | uid_t uid; /* real UID of the task */ |
| 118 | gid_t gid; /* real GID of the task */ | 125 | gid_t gid; /* real GID of the task */ |
| 119 | uid_t suid; /* saved UID of the task */ | 126 | uid_t suid; /* saved UID of the task */ |
| @@ -143,7 +150,9 @@ struct cred { | |||
| 143 | }; | 150 | }; |
| 144 | 151 | ||
| 145 | extern void __put_cred(struct cred *); | 152 | extern void __put_cred(struct cred *); |
| 153 | extern void exit_creds(struct task_struct *); | ||
| 146 | extern int copy_creds(struct task_struct *, unsigned long); | 154 | extern int copy_creds(struct task_struct *, unsigned long); |
| 155 | extern struct cred *cred_alloc_blank(void); | ||
| 147 | extern struct cred *prepare_creds(void); | 156 | extern struct cred *prepare_creds(void); |
| 148 | extern struct cred *prepare_exec_creds(void); | 157 | extern struct cred *prepare_exec_creds(void); |
| 149 | extern struct cred *prepare_usermodehelper_creds(void); | 158 | extern struct cred *prepare_usermodehelper_creds(void); |
| @@ -158,6 +167,60 @@ extern int set_security_override_from_ctx(struct cred *, const char *); | |||
| 158 | extern int set_create_files_as(struct cred *, struct inode *); | 167 | extern int set_create_files_as(struct cred *, struct inode *); |
| 159 | extern void __init cred_init(void); | 168 | extern void __init cred_init(void); |
| 160 | 169 | ||
| 170 | /* | ||
| 171 | * check for validity of credentials | ||
| 172 | */ | ||
| 173 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 174 | extern void __invalid_creds(const struct cred *, const char *, unsigned); | ||
| 175 | extern void __validate_process_creds(struct task_struct *, | ||
| 176 | const char *, unsigned); | ||
| 177 | |||
| 178 | static inline bool creds_are_invalid(const struct cred *cred) | ||
| 179 | { | ||
| 180 | if (cred->magic != CRED_MAGIC) | ||
| 181 | return true; | ||
| 182 | if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers)) | ||
| 183 | return true; | ||
| 184 | #ifdef CONFIG_SECURITY_SELINUX | ||
| 185 | if ((unsigned long) cred->security < PAGE_SIZE) | ||
| 186 | return true; | ||
| 187 | if ((*(u32*)cred->security & 0xffffff00) == | ||
| 188 | (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)) | ||
| 189 | return true; | ||
| 190 | #endif | ||
| 191 | return false; | ||
| 192 | } | ||
| 193 | |||
| 194 | static inline void __validate_creds(const struct cred *cred, | ||
| 195 | const char *file, unsigned line) | ||
| 196 | { | ||
| 197 | if (unlikely(creds_are_invalid(cred))) | ||
| 198 | __invalid_creds(cred, file, line); | ||
| 199 | } | ||
| 200 | |||
| 201 | #define validate_creds(cred) \ | ||
| 202 | do { \ | ||
| 203 | __validate_creds((cred), __FILE__, __LINE__); \ | ||
| 204 | } while(0) | ||
| 205 | |||
| 206 | #define validate_process_creds() \ | ||
| 207 | do { \ | ||
| 208 | __validate_process_creds(current, __FILE__, __LINE__); \ | ||
| 209 | } while(0) | ||
| 210 | |||
| 211 | extern void validate_creds_for_do_exit(struct task_struct *); | ||
| 212 | #else | ||
| 213 | static inline void validate_creds(const struct cred *cred) | ||
| 214 | { | ||
| 215 | } | ||
| 216 | static inline void validate_creds_for_do_exit(struct task_struct *tsk) | ||
| 217 | { | ||
| 218 | } | ||
| 219 | static inline void validate_process_creds(void) | ||
| 220 | { | ||
| 221 | } | ||
| 222 | #endif | ||
| 223 | |||
| 161 | /** | 224 | /** |
| 162 | * get_new_cred - Get a reference on a new set of credentials | 225 | * get_new_cred - Get a reference on a new set of credentials |
| 163 | * @cred: The new credentials to reference | 226 | * @cred: The new credentials to reference |
| @@ -186,7 +249,9 @@ static inline struct cred *get_new_cred(struct cred *cred) | |||
| 186 | */ | 249 | */ |
| 187 | static inline const struct cred *get_cred(const struct cred *cred) | 250 | static inline const struct cred *get_cred(const struct cred *cred) |
| 188 | { | 251 | { |
| 189 | return get_new_cred((struct cred *) cred); | 252 | struct cred *nonconst_cred = (struct cred *) cred; |
| 253 | validate_creds(cred); | ||
| 254 | return get_new_cred(nonconst_cred); | ||
| 190 | } | 255 | } |
| 191 | 256 | ||
| 192 | /** | 257 | /** |
| @@ -204,7 +269,7 @@ static inline void put_cred(const struct cred *_cred) | |||
| 204 | { | 269 | { |
| 205 | struct cred *cred = (struct cred *) _cred; | 270 | struct cred *cred = (struct cred *) _cred; |
| 206 | 271 | ||
| 207 | BUG_ON(atomic_read(&(cred)->usage) <= 0); | 272 | validate_creds(cred); |
| 208 | if (atomic_dec_and_test(&(cred)->usage)) | 273 | if (atomic_dec_and_test(&(cred)->usage)) |
| 209 | __put_cred(cred); | 274 | __put_cred(cred); |
| 210 | } | 275 | } |
diff --git a/include/linux/key.h b/include/linux/key.h index e544f466d69a..cd50dfa1d4c2 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
| @@ -129,7 +129,10 @@ struct key { | |||
| 129 | struct rw_semaphore sem; /* change vs change sem */ | 129 | struct rw_semaphore sem; /* change vs change sem */ |
| 130 | struct key_user *user; /* owner of this key */ | 130 | struct key_user *user; /* owner of this key */ |
| 131 | void *security; /* security data for this key */ | 131 | void *security; /* security data for this key */ |
| 132 | time_t expiry; /* time at which key expires (or 0) */ | 132 | union { |
| 133 | time_t expiry; /* time at which key expires (or 0) */ | ||
| 134 | time_t revoked_at; /* time at which key was revoked */ | ||
| 135 | }; | ||
| 133 | uid_t uid; | 136 | uid_t uid; |
| 134 | gid_t gid; | 137 | gid_t gid; |
| 135 | key_perm_t perm; /* access permissions */ | 138 | key_perm_t perm; /* access permissions */ |
| @@ -275,6 +278,8 @@ static inline key_serial_t key_serial(struct key *key) | |||
| 275 | extern ctl_table key_sysctls[]; | 278 | extern ctl_table key_sysctls[]; |
| 276 | #endif | 279 | #endif |
| 277 | 280 | ||
| 281 | extern void key_replace_session_keyring(void); | ||
| 282 | |||
| 278 | /* | 283 | /* |
| 279 | * the userspace interface | 284 | * the userspace interface |
| 280 | */ | 285 | */ |
| @@ -297,6 +302,7 @@ extern void key_init(void); | |||
| 297 | #define key_fsuid_changed(t) do { } while(0) | 302 | #define key_fsuid_changed(t) do { } while(0) |
| 298 | #define key_fsgid_changed(t) do { } while(0) | 303 | #define key_fsgid_changed(t) do { } while(0) |
| 299 | #define key_init() do { } while(0) | 304 | #define key_init() do { } while(0) |
| 305 | #define key_replace_session_keyring() do { } while(0) | ||
| 300 | 306 | ||
| 301 | #endif /* CONFIG_KEYS */ | 307 | #endif /* CONFIG_KEYS */ |
| 302 | #endif /* __KERNEL__ */ | 308 | #endif /* __KERNEL__ */ |
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h index c0688eb72093..bd383f1944fb 100644 --- a/include/linux/keyctl.h +++ b/include/linux/keyctl.h | |||
| @@ -52,5 +52,6 @@ | |||
| 52 | #define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ | 52 | #define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ |
| 53 | #define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ | 53 | #define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ |
| 54 | #define KEYCTL_GET_SECURITY 17 /* get key security label */ | 54 | #define KEYCTL_GET_SECURITY 17 /* get key security label */ |
| 55 | #define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ | ||
| 55 | 56 | ||
| 56 | #endif /* _LINUX_KEYCTL_H */ | 57 | #endif /* _LINUX_KEYCTL_H */ |
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index e461b2c3d711..190c37854870 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h | |||
| @@ -33,6 +33,7 @@ struct common_audit_data { | |||
| 33 | #define LSM_AUDIT_DATA_IPC 4 | 33 | #define LSM_AUDIT_DATA_IPC 4 |
| 34 | #define LSM_AUDIT_DATA_TASK 5 | 34 | #define LSM_AUDIT_DATA_TASK 5 |
| 35 | #define LSM_AUDIT_DATA_KEY 6 | 35 | #define LSM_AUDIT_DATA_KEY 6 |
| 36 | #define LSM_AUDIT_NO_AUDIT 7 | ||
| 36 | struct task_struct *tsk; | 37 | struct task_struct *tsk; |
| 37 | union { | 38 | union { |
| 38 | struct { | 39 | struct { |
| @@ -66,16 +67,19 @@ struct common_audit_data { | |||
| 66 | } key_struct; | 67 | } key_struct; |
| 67 | #endif | 68 | #endif |
| 68 | } u; | 69 | } u; |
| 69 | const char *function; | ||
| 70 | /* this union contains LSM specific data */ | 70 | /* this union contains LSM specific data */ |
| 71 | union { | 71 | union { |
| 72 | #ifdef CONFIG_SECURITY_SMACK | ||
| 72 | /* SMACK data */ | 73 | /* SMACK data */ |
| 73 | struct smack_audit_data { | 74 | struct smack_audit_data { |
| 75 | const char *function; | ||
| 74 | char *subject; | 76 | char *subject; |
| 75 | char *object; | 77 | char *object; |
| 76 | char *request; | 78 | char *request; |
| 77 | int result; | 79 | int result; |
| 78 | } smack_audit_data; | 80 | } smack_audit_data; |
| 81 | #endif | ||
| 82 | #ifdef CONFIG_SECURITY_SELINUX | ||
| 79 | /* SELinux data */ | 83 | /* SELinux data */ |
| 80 | struct { | 84 | struct { |
| 81 | u32 ssid; | 85 | u32 ssid; |
| @@ -83,10 +87,12 @@ struct common_audit_data { | |||
| 83 | u16 tclass; | 87 | u16 tclass; |
| 84 | u32 requested; | 88 | u32 requested; |
| 85 | u32 audited; | 89 | u32 audited; |
| 90 | u32 denied; | ||
| 86 | struct av_decision *avd; | 91 | struct av_decision *avd; |
| 87 | int result; | 92 | int result; |
| 88 | } selinux_audit_data; | 93 | } selinux_audit_data; |
| 89 | } lsm_priv; | 94 | #endif |
| 95 | }; | ||
| 90 | /* these callback will be implemented by a specific LSM */ | 96 | /* these callback will be implemented by a specific LSM */ |
| 91 | void (*lsm_pre_audit)(struct audit_buffer *, void *); | 97 | void (*lsm_pre_audit)(struct audit_buffer *, void *); |
| 92 | void (*lsm_post_audit)(struct audit_buffer *, void *); | 98 | void (*lsm_post_audit)(struct audit_buffer *, void *); |
| @@ -104,7 +110,7 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb, | |||
| 104 | /* Initialize an LSM audit data structure. */ | 110 | /* Initialize an LSM audit data structure. */ |
| 105 | #define COMMON_AUDIT_DATA_INIT(_d, _t) \ | 111 | #define COMMON_AUDIT_DATA_INIT(_d, _t) \ |
| 106 | { memset((_d), 0, sizeof(struct common_audit_data)); \ | 112 | { memset((_d), 0, sizeof(struct common_audit_data)); \ |
| 107 | (_d)->type = LSM_AUDIT_DATA_##_t; (_d)->function = __func__; } | 113 | (_d)->type = LSM_AUDIT_DATA_##_t; } |
| 108 | 114 | ||
| 109 | void common_lsm_audit(struct common_audit_data *a); | 115 | void common_lsm_audit(struct common_audit_data *a); |
| 110 | 116 | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index 0f1ea4a66957..9304027673b0 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -1292,6 +1292,7 @@ struct task_struct { | |||
| 1292 | struct mutex cred_guard_mutex; /* guard against foreign influences on | 1292 | struct mutex cred_guard_mutex; /* guard against foreign influences on |
| 1293 | * credential calculations | 1293 | * credential calculations |
| 1294 | * (notably. ptrace) */ | 1294 | * (notably. ptrace) */ |
| 1295 | struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */ | ||
| 1295 | 1296 | ||
| 1296 | char comm[TASK_COMM_LEN]; /* executable name excluding path | 1297 | char comm[TASK_COMM_LEN]; /* executable name excluding path |
| 1297 | - access with [gs]et_task_comm (which lock | 1298 | - access with [gs]et_task_comm (which lock |
| @@ -2077,7 +2078,7 @@ static inline unsigned long wait_task_inactive(struct task_struct *p, | |||
| 2077 | #define for_each_process(p) \ | 2078 | #define for_each_process(p) \ |
| 2078 | for (p = &init_task ; (p = next_task(p)) != &init_task ; ) | 2079 | for (p = &init_task ; (p = next_task(p)) != &init_task ; ) |
| 2079 | 2080 | ||
| 2080 | extern bool is_single_threaded(struct task_struct *); | 2081 | extern bool current_is_single_threaded(void); |
| 2081 | 2082 | ||
| 2082 | /* | 2083 | /* |
| 2083 | * Careful: do_each_thread/while_each_thread is a double loop so | 2084 | * Careful: do_each_thread/while_each_thread is a double loop so |
diff --git a/include/linux/security.h b/include/linux/security.h index 1f16eea2017b..d050b66ab9ef 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
| @@ -53,7 +53,7 @@ struct audit_krule; | |||
| 53 | extern int cap_capable(struct task_struct *tsk, const struct cred *cred, | 53 | extern int cap_capable(struct task_struct *tsk, const struct cred *cred, |
| 54 | int cap, int audit); | 54 | int cap, int audit); |
| 55 | extern int cap_settime(struct timespec *ts, struct timezone *tz); | 55 | extern int cap_settime(struct timespec *ts, struct timezone *tz); |
| 56 | extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode); | 56 | extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode); |
| 57 | extern int cap_ptrace_traceme(struct task_struct *parent); | 57 | extern int cap_ptrace_traceme(struct task_struct *parent); |
| 58 | extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); | 58 | extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); |
| 59 | extern int cap_capset(struct cred *new, const struct cred *old, | 59 | 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) | |||
| 653 | * manual page for definitions of the @clone_flags. | 653 | * manual page for definitions of the @clone_flags. |
| 654 | * @clone_flags contains the flags indicating what should be shared. | 654 | * @clone_flags contains the flags indicating what should be shared. |
| 655 | * Return 0 if permission is granted. | 655 | * Return 0 if permission is granted. |
| 656 | * @cred_alloc_blank: | ||
| 657 | * @cred points to the credentials. | ||
| 658 | * @gfp indicates the atomicity of any memory allocations. | ||
| 659 | * Only allocate sufficient memory and attach to @cred such that | ||
| 660 | * cred_transfer() will not get ENOMEM. | ||
| 656 | * @cred_free: | 661 | * @cred_free: |
| 657 | * @cred points to the credentials. | 662 | * @cred points to the credentials. |
| 658 | * Deallocate and clear the cred->security field in a set of credentials. | 663 | * 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) | |||
| 665 | * @new points to the new credentials. | 670 | * @new points to the new credentials. |
| 666 | * @old points to the original credentials. | 671 | * @old points to the original credentials. |
| 667 | * Install a new set of credentials. | 672 | * Install a new set of credentials. |
| 673 | * @cred_transfer: | ||
| 674 | * @new points to the new credentials. | ||
| 675 | * @old points to the original credentials. | ||
| 676 | * Transfer data from original creds to new creds | ||
| 668 | * @kernel_act_as: | 677 | * @kernel_act_as: |
| 669 | * Set the credentials for a kernel service to act as (subjective context). | 678 | * Set the credentials for a kernel service to act as (subjective context). |
| 670 | * @new points to the credentials to be modified. | 679 | * @new points to the credentials to be modified. |
| @@ -678,6 +687,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
| 678 | * @inode points to the inode to use as a reference. | 687 | * @inode points to the inode to use as a reference. |
| 679 | * The current task must be the one that nominated @inode. | 688 | * The current task must be the one that nominated @inode. |
| 680 | * Return 0 if successful. | 689 | * Return 0 if successful. |
| 690 | * @kernel_module_request: | ||
| 691 | * Ability to trigger the kernel to automatically upcall to userspace for | ||
| 692 | * userspace to load a kernel module with the given name. | ||
| 693 | * Return 0 if successful. | ||
| 681 | * @task_setuid: | 694 | * @task_setuid: |
| 682 | * Check permission before setting one or more of the user identity | 695 | * Check permission before setting one or more of the user identity |
| 683 | * attributes of the current process. The @flags parameter indicates | 696 | * 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) | |||
| 994 | * Sets the connection's peersid to the secmark on skb. | 1007 | * Sets the connection's peersid to the secmark on skb. |
| 995 | * @req_classify_flow: | 1008 | * @req_classify_flow: |
| 996 | * Sets the flow's sid to the openreq sid. | 1009 | * Sets the flow's sid to the openreq sid. |
| 1010 | * @tun_dev_create: | ||
| 1011 | * Check permissions prior to creating a new TUN device. | ||
| 1012 | * @tun_dev_post_create: | ||
| 1013 | * This hook allows a module to update or allocate a per-socket security | ||
| 1014 | * structure. | ||
| 1015 | * @sk contains the newly created sock structure. | ||
| 1016 | * @tun_dev_attach: | ||
| 1017 | * Check permissions prior to attaching to a persistent TUN device. This | ||
| 1018 | * hook can also be used by the module to update any security state | ||
| 1019 | * associated with the TUN device's sock structure. | ||
| 1020 | * @sk contains the existing sock structure. | ||
| 997 | * | 1021 | * |
| 998 | * Security hooks for XFRM operations. | 1022 | * Security hooks for XFRM operations. |
| 999 | * | 1023 | * |
| @@ -1088,6 +1112,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
| 1088 | * Return the length of the string (including terminating NUL) or -ve if | 1112 | * Return the length of the string (including terminating NUL) or -ve if |
| 1089 | * an error. | 1113 | * an error. |
| 1090 | * May also return 0 (and a NULL buffer pointer) if there is no label. | 1114 | * May also return 0 (and a NULL buffer pointer) if there is no label. |
| 1115 | * @key_session_to_parent: | ||
| 1116 | * Forcibly assign the session keyring from a process to its parent | ||
| 1117 | * process. | ||
| 1118 | * @cred: Pointer to process's credentials | ||
| 1119 | * @parent_cred: Pointer to parent process's credentials | ||
| 1120 | * @keyring: Proposed new session keyring | ||
| 1121 | * Return 0 if permission is granted, -ve error otherwise. | ||
| 1091 | * | 1122 | * |
| 1092 | * Security hooks affecting all System V IPC operations. | 1123 | * Security hooks affecting all System V IPC operations. |
| 1093 | * | 1124 | * |
| @@ -1229,7 +1260,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
| 1229 | * @alter contains the flag indicating whether changes are to be made. | 1260 | * @alter contains the flag indicating whether changes are to be made. |
| 1230 | * Return 0 if permission is granted. | 1261 | * Return 0 if permission is granted. |
| 1231 | * | 1262 | * |
| 1232 | * @ptrace_may_access: | 1263 | * @ptrace_access_check: |
| 1233 | * Check permission before allowing the current process to trace the | 1264 | * Check permission before allowing the current process to trace the |
| 1234 | * @child process. | 1265 | * @child process. |
| 1235 | * Security modules may also want to perform a process tracing check | 1266 | * 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) | |||
| 1244 | * Check that the @parent process has sufficient permission to trace the | 1275 | * Check that the @parent process has sufficient permission to trace the |
| 1245 | * current process before allowing the current process to present itself | 1276 | * current process before allowing the current process to present itself |
| 1246 | * to the @parent process for tracing. | 1277 | * to the @parent process for tracing. |
| 1247 | * The parent process will still have to undergo the ptrace_may_access | 1278 | * The parent process will still have to undergo the ptrace_access_check |
| 1248 | * checks before it is allowed to trace this one. | 1279 | * checks before it is allowed to trace this one. |
| 1249 | * @parent contains the task_struct structure for debugger process. | 1280 | * @parent contains the task_struct structure for debugger process. |
| 1250 | * Return 0 if permission is granted. | 1281 | * Return 0 if permission is granted. |
| @@ -1351,12 +1382,47 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
| 1351 | * audit_rule_init. | 1382 | * audit_rule_init. |
| 1352 | * @rule contains the allocated rule | 1383 | * @rule contains the allocated rule |
| 1353 | * | 1384 | * |
| 1385 | * @inode_notifysecctx: | ||
| 1386 | * Notify the security module of what the security context of an inode | ||
| 1387 | * should be. Initializes the incore security context managed by the | ||
| 1388 | * security module for this inode. Example usage: NFS client invokes | ||
| 1389 | * this hook to initialize the security context in its incore inode to the | ||
| 1390 | * value provided by the server for the file when the server returned the | ||
| 1391 | * file's attributes to the client. | ||
| 1392 | * | ||
| 1393 | * Must be called with inode->i_mutex locked. | ||
| 1394 | * | ||
| 1395 | * @inode we wish to set the security context of. | ||
| 1396 | * @ctx contains the string which we wish to set in the inode. | ||
| 1397 | * @ctxlen contains the length of @ctx. | ||
| 1398 | * | ||
| 1399 | * @inode_setsecctx: | ||
| 1400 | * Change the security context of an inode. Updates the | ||
| 1401 | * incore security context managed by the security module and invokes the | ||
| 1402 | * fs code as needed (via __vfs_setxattr_noperm) to update any backing | ||
| 1403 | * xattrs that represent the context. Example usage: NFS server invokes | ||
| 1404 | * this hook to change the security context in its incore inode and on the | ||
| 1405 | * backing filesystem to a value provided by the client on a SETATTR | ||
| 1406 | * operation. | ||
| 1407 | * | ||
| 1408 | * Must be called with inode->i_mutex locked. | ||
| 1409 | * | ||
| 1410 | * @dentry contains the inode we wish to set the security context of. | ||
| 1411 | * @ctx contains the string which we wish to set in the inode. | ||
| 1412 | * @ctxlen contains the length of @ctx. | ||
| 1413 | * | ||
| 1414 | * @inode_getsecctx: | ||
| 1415 | * Returns a string containing all relavent security context information | ||
| 1416 | * | ||
| 1417 | * @inode we wish to set the security context of. | ||
| 1418 | * @ctx is a pointer in which to place the allocated security context. | ||
| 1419 | * @ctxlen points to the place to put the length of @ctx. | ||
| 1354 | * This is the main security structure. | 1420 | * This is the main security structure. |
| 1355 | */ | 1421 | */ |
| 1356 | struct security_operations { | 1422 | struct security_operations { |
| 1357 | char name[SECURITY_NAME_MAX + 1]; | 1423 | char name[SECURITY_NAME_MAX + 1]; |
| 1358 | 1424 | ||
| 1359 | int (*ptrace_may_access) (struct task_struct *child, unsigned int mode); | 1425 | int (*ptrace_access_check) (struct task_struct *child, unsigned int mode); |
| 1360 | int (*ptrace_traceme) (struct task_struct *parent); | 1426 | int (*ptrace_traceme) (struct task_struct *parent); |
| 1361 | int (*capget) (struct task_struct *target, | 1427 | int (*capget) (struct task_struct *target, |
| 1362 | kernel_cap_t *effective, | 1428 | kernel_cap_t *effective, |
| @@ -1483,12 +1549,15 @@ struct security_operations { | |||
| 1483 | int (*dentry_open) (struct file *file, const struct cred *cred); | 1549 | int (*dentry_open) (struct file *file, const struct cred *cred); |
| 1484 | 1550 | ||
| 1485 | int (*task_create) (unsigned long clone_flags); | 1551 | int (*task_create) (unsigned long clone_flags); |
| 1552 | int (*cred_alloc_blank) (struct cred *cred, gfp_t gfp); | ||
| 1486 | void (*cred_free) (struct cred *cred); | 1553 | void (*cred_free) (struct cred *cred); |
| 1487 | int (*cred_prepare)(struct cred *new, const struct cred *old, | 1554 | int (*cred_prepare)(struct cred *new, const struct cred *old, |
| 1488 | gfp_t gfp); | 1555 | gfp_t gfp); |
| 1489 | void (*cred_commit)(struct cred *new, const struct cred *old); | 1556 | void (*cred_commit)(struct cred *new, const struct cred *old); |
| 1557 | void (*cred_transfer)(struct cred *new, const struct cred *old); | ||
| 1490 | int (*kernel_act_as)(struct cred *new, u32 secid); | 1558 | int (*kernel_act_as)(struct cred *new, u32 secid); |
| 1491 | int (*kernel_create_files_as)(struct cred *new, struct inode *inode); | 1559 | int (*kernel_create_files_as)(struct cred *new, struct inode *inode); |
| 1560 | int (*kernel_module_request)(void); | ||
| 1492 | int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags); | 1561 | int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags); |
| 1493 | int (*task_fix_setuid) (struct cred *new, const struct cred *old, | 1562 | int (*task_fix_setuid) (struct cred *new, const struct cred *old, |
| 1494 | int flags); | 1563 | int flags); |
| @@ -1556,6 +1625,10 @@ struct security_operations { | |||
| 1556 | int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid); | 1625 | int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid); |
| 1557 | void (*release_secctx) (char *secdata, u32 seclen); | 1626 | void (*release_secctx) (char *secdata, u32 seclen); |
| 1558 | 1627 | ||
| 1628 | int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen); | ||
| 1629 | int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen); | ||
| 1630 | int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen); | ||
| 1631 | |||
| 1559 | #ifdef CONFIG_SECURITY_NETWORK | 1632 | #ifdef CONFIG_SECURITY_NETWORK |
| 1560 | int (*unix_stream_connect) (struct socket *sock, | 1633 | int (*unix_stream_connect) (struct socket *sock, |
| 1561 | struct socket *other, struct sock *newsk); | 1634 | struct socket *other, struct sock *newsk); |
| @@ -1592,6 +1665,9 @@ struct security_operations { | |||
| 1592 | void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req); | 1665 | void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req); |
| 1593 | void (*inet_conn_established) (struct sock *sk, struct sk_buff *skb); | 1666 | void (*inet_conn_established) (struct sock *sk, struct sk_buff *skb); |
| 1594 | void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl); | 1667 | void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl); |
| 1668 | int (*tun_dev_create)(void); | ||
| 1669 | void (*tun_dev_post_create)(struct sock *sk); | ||
| 1670 | int (*tun_dev_attach)(struct sock *sk); | ||
| 1595 | #endif /* CONFIG_SECURITY_NETWORK */ | 1671 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 1596 | 1672 | ||
| 1597 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1673 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| @@ -1620,6 +1696,9 @@ struct security_operations { | |||
| 1620 | const struct cred *cred, | 1696 | const struct cred *cred, |
| 1621 | key_perm_t perm); | 1697 | key_perm_t perm); |
| 1622 | int (*key_getsecurity)(struct key *key, char **_buffer); | 1698 | int (*key_getsecurity)(struct key *key, char **_buffer); |
| 1699 | int (*key_session_to_parent)(const struct cred *cred, | ||
| 1700 | const struct cred *parent_cred, | ||
| 1701 | struct key *key); | ||
| 1623 | #endif /* CONFIG_KEYS */ | 1702 | #endif /* CONFIG_KEYS */ |
| 1624 | 1703 | ||
| 1625 | #ifdef CONFIG_AUDIT | 1704 | #ifdef CONFIG_AUDIT |
| @@ -1637,7 +1716,7 @@ extern int security_module_enable(struct security_operations *ops); | |||
| 1637 | extern int register_security(struct security_operations *ops); | 1716 | extern int register_security(struct security_operations *ops); |
| 1638 | 1717 | ||
| 1639 | /* Security operations */ | 1718 | /* Security operations */ |
| 1640 | int security_ptrace_may_access(struct task_struct *child, unsigned int mode); | 1719 | int security_ptrace_access_check(struct task_struct *child, unsigned int mode); |
| 1641 | int security_ptrace_traceme(struct task_struct *parent); | 1720 | int security_ptrace_traceme(struct task_struct *parent); |
| 1642 | int security_capget(struct task_struct *target, | 1721 | int security_capget(struct task_struct *target, |
| 1643 | kernel_cap_t *effective, | 1722 | kernel_cap_t *effective, |
| @@ -1736,11 +1815,14 @@ int security_file_send_sigiotask(struct task_struct *tsk, | |||
| 1736 | int security_file_receive(struct file *file); | 1815 | int security_file_receive(struct file *file); |
| 1737 | int security_dentry_open(struct file *file, const struct cred *cred); | 1816 | int security_dentry_open(struct file *file, const struct cred *cred); |
| 1738 | int security_task_create(unsigned long clone_flags); | 1817 | int security_task_create(unsigned long clone_flags); |
| 1818 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); | ||
| 1739 | void security_cred_free(struct cred *cred); | 1819 | void security_cred_free(struct cred *cred); |
| 1740 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); | 1820 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); |
| 1741 | void security_commit_creds(struct cred *new, const struct cred *old); | 1821 | void security_commit_creds(struct cred *new, const struct cred *old); |
| 1822 | void security_transfer_creds(struct cred *new, const struct cred *old); | ||
| 1742 | int security_kernel_act_as(struct cred *new, u32 secid); | 1823 | int security_kernel_act_as(struct cred *new, u32 secid); |
| 1743 | int security_kernel_create_files_as(struct cred *new, struct inode *inode); | 1824 | int security_kernel_create_files_as(struct cred *new, struct inode *inode); |
| 1825 | int security_kernel_module_request(void); | ||
| 1744 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags); | 1826 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags); |
| 1745 | int security_task_fix_setuid(struct cred *new, const struct cred *old, | 1827 | int security_task_fix_setuid(struct cred *new, const struct cred *old, |
| 1746 | int flags); | 1828 | int flags); |
| @@ -1796,6 +1878,9 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); | |||
| 1796 | int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); | 1878 | int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); |
| 1797 | void security_release_secctx(char *secdata, u32 seclen); | 1879 | void security_release_secctx(char *secdata, u32 seclen); |
| 1798 | 1880 | ||
| 1881 | int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); | ||
| 1882 | int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); | ||
| 1883 | int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); | ||
| 1799 | #else /* CONFIG_SECURITY */ | 1884 | #else /* CONFIG_SECURITY */ |
| 1800 | struct security_mnt_opts { | 1885 | struct security_mnt_opts { |
| 1801 | }; | 1886 | }; |
| @@ -1818,10 +1903,10 @@ static inline int security_init(void) | |||
| 1818 | return 0; | 1903 | return 0; |
| 1819 | } | 1904 | } |
| 1820 | 1905 | ||
| 1821 | static inline int security_ptrace_may_access(struct task_struct *child, | 1906 | static inline int security_ptrace_access_check(struct task_struct *child, |
| 1822 | unsigned int mode) | 1907 | unsigned int mode) |
| 1823 | { | 1908 | { |
| 1824 | return cap_ptrace_may_access(child, mode); | 1909 | return cap_ptrace_access_check(child, mode); |
| 1825 | } | 1910 | } |
| 1826 | 1911 | ||
| 1827 | static inline int security_ptrace_traceme(struct task_struct *parent) | 1912 | static inline int security_ptrace_traceme(struct task_struct *parent) |
| @@ -2266,6 +2351,11 @@ static inline int security_task_create(unsigned long clone_flags) | |||
| 2266 | return 0; | 2351 | return 0; |
| 2267 | } | 2352 | } |
| 2268 | 2353 | ||
| 2354 | static inline int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 2355 | { | ||
| 2356 | return 0; | ||
| 2357 | } | ||
| 2358 | |||
| 2269 | static inline void security_cred_free(struct cred *cred) | 2359 | static inline void security_cred_free(struct cred *cred) |
| 2270 | { } | 2360 | { } |
| 2271 | 2361 | ||
| @@ -2281,6 +2371,11 @@ static inline void security_commit_creds(struct cred *new, | |||
| 2281 | { | 2371 | { |
| 2282 | } | 2372 | } |
| 2283 | 2373 | ||
| 2374 | static inline void security_transfer_creds(struct cred *new, | ||
| 2375 | const struct cred *old) | ||
| 2376 | { | ||
| 2377 | } | ||
| 2378 | |||
| 2284 | static inline int security_kernel_act_as(struct cred *cred, u32 secid) | 2379 | static inline int security_kernel_act_as(struct cred *cred, u32 secid) |
| 2285 | { | 2380 | { |
| 2286 | return 0; | 2381 | return 0; |
| @@ -2292,6 +2387,11 @@ static inline int security_kernel_create_files_as(struct cred *cred, | |||
| 2292 | return 0; | 2387 | return 0; |
| 2293 | } | 2388 | } |
| 2294 | 2389 | ||
| 2390 | static inline int security_kernel_module_request(void) | ||
| 2391 | { | ||
| 2392 | return 0; | ||
| 2393 | } | ||
| 2394 | |||
| 2295 | static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, | 2395 | static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, |
| 2296 | int flags) | 2396 | int flags) |
| 2297 | { | 2397 | { |
| @@ -2537,6 +2637,19 @@ static inline int security_secctx_to_secid(const char *secdata, | |||
| 2537 | static inline void security_release_secctx(char *secdata, u32 seclen) | 2637 | static inline void security_release_secctx(char *secdata, u32 seclen) |
| 2538 | { | 2638 | { |
| 2539 | } | 2639 | } |
| 2640 | |||
| 2641 | static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) | ||
| 2642 | { | ||
| 2643 | return -EOPNOTSUPP; | ||
| 2644 | } | ||
| 2645 | static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) | ||
| 2646 | { | ||
| 2647 | return -EOPNOTSUPP; | ||
| 2648 | } | ||
| 2649 | static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | ||
| 2650 | { | ||
| 2651 | return -EOPNOTSUPP; | ||
| 2652 | } | ||
| 2540 | #endif /* CONFIG_SECURITY */ | 2653 | #endif /* CONFIG_SECURITY */ |
| 2541 | 2654 | ||
| 2542 | #ifdef CONFIG_SECURITY_NETWORK | 2655 | #ifdef CONFIG_SECURITY_NETWORK |
| @@ -2575,6 +2688,9 @@ void security_inet_csk_clone(struct sock *newsk, | |||
| 2575 | const struct request_sock *req); | 2688 | const struct request_sock *req); |
| 2576 | void security_inet_conn_established(struct sock *sk, | 2689 | void security_inet_conn_established(struct sock *sk, |
| 2577 | struct sk_buff *skb); | 2690 | struct sk_buff *skb); |
| 2691 | int security_tun_dev_create(void); | ||
| 2692 | void security_tun_dev_post_create(struct sock *sk); | ||
| 2693 | int security_tun_dev_attach(struct sock *sk); | ||
| 2578 | 2694 | ||
| 2579 | #else /* CONFIG_SECURITY_NETWORK */ | 2695 | #else /* CONFIG_SECURITY_NETWORK */ |
| 2580 | static inline int security_unix_stream_connect(struct socket *sock, | 2696 | static inline int security_unix_stream_connect(struct socket *sock, |
| @@ -2725,6 +2841,20 @@ static inline void security_inet_conn_established(struct sock *sk, | |||
| 2725 | struct sk_buff *skb) | 2841 | struct sk_buff *skb) |
| 2726 | { | 2842 | { |
| 2727 | } | 2843 | } |
| 2844 | |||
| 2845 | static inline int security_tun_dev_create(void) | ||
| 2846 | { | ||
| 2847 | return 0; | ||
| 2848 | } | ||
| 2849 | |||
| 2850 | static inline void security_tun_dev_post_create(struct sock *sk) | ||
| 2851 | { | ||
| 2852 | } | ||
| 2853 | |||
| 2854 | static inline int security_tun_dev_attach(struct sock *sk) | ||
| 2855 | { | ||
| 2856 | return 0; | ||
| 2857 | } | ||
| 2728 | #endif /* CONFIG_SECURITY_NETWORK */ | 2858 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 2729 | 2859 | ||
| 2730 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 2860 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| @@ -2881,6 +3011,9 @@ void security_key_free(struct key *key); | |||
| 2881 | int security_key_permission(key_ref_t key_ref, | 3011 | int security_key_permission(key_ref_t key_ref, |
| 2882 | const struct cred *cred, key_perm_t perm); | 3012 | const struct cred *cred, key_perm_t perm); |
| 2883 | int security_key_getsecurity(struct key *key, char **_buffer); | 3013 | int security_key_getsecurity(struct key *key, char **_buffer); |
| 3014 | int security_key_session_to_parent(const struct cred *cred, | ||
| 3015 | const struct cred *parent_cred, | ||
| 3016 | struct key *key); | ||
| 2884 | 3017 | ||
| 2885 | #else | 3018 | #else |
| 2886 | 3019 | ||
| @@ -2908,6 +3041,13 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer) | |||
| 2908 | return 0; | 3041 | return 0; |
| 2909 | } | 3042 | } |
| 2910 | 3043 | ||
| 3044 | static inline int security_key_session_to_parent(const struct cred *cred, | ||
| 3045 | const struct cred *parent_cred, | ||
| 3046 | struct key *key) | ||
| 3047 | { | ||
| 3048 | return 0; | ||
| 3049 | } | ||
| 3050 | |||
| 2911 | #endif | 3051 | #endif |
| 2912 | #endif /* CONFIG_KEYS */ | 3052 | #endif /* CONFIG_KEYS */ |
| 2913 | 3053 | ||
diff --git a/include/linux/xattr.h b/include/linux/xattr.h index d131e352cfe1..5c84af8c5f6f 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h | |||
| @@ -49,6 +49,7 @@ struct xattr_handler { | |||
| 49 | ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t); | 49 | ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t); |
| 50 | ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t); | 50 | ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t); |
| 51 | ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size); | 51 | ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size); |
| 52 | int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int); | ||
| 52 | int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int); | 53 | int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int); |
| 53 | int vfs_removexattr(struct dentry *, const char *); | 54 | int vfs_removexattr(struct dentry *, const char *); |
| 54 | 55 | ||
diff --git a/kernel/acct.c b/kernel/acct.c index 9f3391090b3e..9a4715a2f6bf 100644 --- a/kernel/acct.c +++ b/kernel/acct.c | |||
| @@ -491,13 +491,17 @@ static void do_acct_process(struct bsd_acct_struct *acct, | |||
| 491 | u64 run_time; | 491 | u64 run_time; |
| 492 | struct timespec uptime; | 492 | struct timespec uptime; |
| 493 | struct tty_struct *tty; | 493 | struct tty_struct *tty; |
| 494 | const struct cred *orig_cred; | ||
| 495 | |||
| 496 | /* Perform file operations on behalf of whoever enabled accounting */ | ||
| 497 | orig_cred = override_creds(file->f_cred); | ||
| 494 | 498 | ||
| 495 | /* | 499 | /* |
| 496 | * First check to see if there is enough free_space to continue | 500 | * First check to see if there is enough free_space to continue |
| 497 | * the process accounting system. | 501 | * the process accounting system. |
| 498 | */ | 502 | */ |
| 499 | if (!check_free_space(acct, file)) | 503 | if (!check_free_space(acct, file)) |
| 500 | return; | 504 | goto out; |
| 501 | 505 | ||
| 502 | /* | 506 | /* |
| 503 | * Fill the accounting struct with the needed info as recorded | 507 | * Fill the accounting struct with the needed info as recorded |
| @@ -578,6 +582,8 @@ static void do_acct_process(struct bsd_acct_struct *acct, | |||
| 578 | sizeof(acct_t), &file->f_pos); | 582 | sizeof(acct_t), &file->f_pos); |
| 579 | current->signal->rlim[RLIMIT_FSIZE].rlim_cur = flim; | 583 | current->signal->rlim[RLIMIT_FSIZE].rlim_cur = flim; |
| 580 | set_fs(fs); | 584 | set_fs(fs); |
| 585 | out: | ||
| 586 | revert_creds(orig_cred); | ||
| 581 | } | 587 | } |
| 582 | 588 | ||
| 583 | /** | 589 | /** |
diff --git a/kernel/cred.c b/kernel/cred.c index 1bb4d7e5d616..006fcab009d5 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
| @@ -18,6 +18,18 @@ | |||
| 18 | #include <linux/cn_proc.h> | 18 | #include <linux/cn_proc.h> |
| 19 | #include "cred-internals.h" | 19 | #include "cred-internals.h" |
| 20 | 20 | ||
| 21 | #if 0 | ||
| 22 | #define kdebug(FMT, ...) \ | ||
| 23 | printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__) | ||
| 24 | #else | ||
| 25 | static inline __attribute__((format(printf, 1, 2))) | ||
| 26 | void no_printk(const char *fmt, ...) | ||
| 27 | { | ||
| 28 | } | ||
| 29 | #define kdebug(FMT, ...) \ | ||
| 30 | no_printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__) | ||
| 31 | #endif | ||
| 32 | |||
| 21 | static struct kmem_cache *cred_jar; | 33 | static struct kmem_cache *cred_jar; |
| 22 | 34 | ||
| 23 | /* | 35 | /* |
| @@ -36,6 +48,10 @@ static struct thread_group_cred init_tgcred = { | |||
| 36 | */ | 48 | */ |
| 37 | struct cred init_cred = { | 49 | struct cred init_cred = { |
| 38 | .usage = ATOMIC_INIT(4), | 50 | .usage = ATOMIC_INIT(4), |
| 51 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 52 | .subscribers = ATOMIC_INIT(2), | ||
| 53 | .magic = CRED_MAGIC, | ||
| 54 | #endif | ||
| 39 | .securebits = SECUREBITS_DEFAULT, | 55 | .securebits = SECUREBITS_DEFAULT, |
| 40 | .cap_inheritable = CAP_INIT_INH_SET, | 56 | .cap_inheritable = CAP_INIT_INH_SET, |
| 41 | .cap_permitted = CAP_FULL_SET, | 57 | .cap_permitted = CAP_FULL_SET, |
| @@ -48,6 +64,31 @@ struct cred init_cred = { | |||
| 48 | #endif | 64 | #endif |
| 49 | }; | 65 | }; |
| 50 | 66 | ||
| 67 | static inline void set_cred_subscribers(struct cred *cred, int n) | ||
| 68 | { | ||
| 69 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 70 | atomic_set(&cred->subscribers, n); | ||
| 71 | #endif | ||
| 72 | } | ||
| 73 | |||
| 74 | static inline int read_cred_subscribers(const struct cred *cred) | ||
| 75 | { | ||
| 76 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 77 | return atomic_read(&cred->subscribers); | ||
| 78 | #else | ||
| 79 | return 0; | ||
| 80 | #endif | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline void alter_cred_subscribers(const struct cred *_cred, int n) | ||
| 84 | { | ||
| 85 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 86 | struct cred *cred = (struct cred *) _cred; | ||
| 87 | |||
| 88 | atomic_add(n, &cred->subscribers); | ||
| 89 | #endif | ||
| 90 | } | ||
| 91 | |||
| 51 | /* | 92 | /* |
| 52 | * Dispose of the shared task group credentials | 93 | * Dispose of the shared task group credentials |
| 53 | */ | 94 | */ |
| @@ -85,9 +126,22 @@ static void put_cred_rcu(struct rcu_head *rcu) | |||
| 85 | { | 126 | { |
| 86 | struct cred *cred = container_of(rcu, struct cred, rcu); | 127 | struct cred *cred = container_of(rcu, struct cred, rcu); |
| 87 | 128 | ||
| 129 | kdebug("put_cred_rcu(%p)", cred); | ||
| 130 | |||
| 131 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 132 | if (cred->magic != CRED_MAGIC_DEAD || | ||
| 133 | atomic_read(&cred->usage) != 0 || | ||
| 134 | read_cred_subscribers(cred) != 0) | ||
| 135 | panic("CRED: put_cred_rcu() sees %p with" | ||
| 136 | " mag %x, put %p, usage %d, subscr %d\n", | ||
| 137 | cred, cred->magic, cred->put_addr, | ||
| 138 | atomic_read(&cred->usage), | ||
| 139 | read_cred_subscribers(cred)); | ||
| 140 | #else | ||
| 88 | if (atomic_read(&cred->usage) != 0) | 141 | if (atomic_read(&cred->usage) != 0) |
| 89 | panic("CRED: put_cred_rcu() sees %p with usage %d\n", | 142 | panic("CRED: put_cred_rcu() sees %p with usage %d\n", |
| 90 | cred, atomic_read(&cred->usage)); | 143 | cred, atomic_read(&cred->usage)); |
| 144 | #endif | ||
| 91 | 145 | ||
| 92 | security_cred_free(cred); | 146 | security_cred_free(cred); |
| 93 | key_put(cred->thread_keyring); | 147 | key_put(cred->thread_keyring); |
| @@ -106,12 +160,90 @@ static void put_cred_rcu(struct rcu_head *rcu) | |||
| 106 | */ | 160 | */ |
| 107 | void __put_cred(struct cred *cred) | 161 | void __put_cred(struct cred *cred) |
| 108 | { | 162 | { |
| 163 | kdebug("__put_cred(%p{%d,%d})", cred, | ||
| 164 | atomic_read(&cred->usage), | ||
| 165 | read_cred_subscribers(cred)); | ||
| 166 | |||
| 109 | BUG_ON(atomic_read(&cred->usage) != 0); | 167 | BUG_ON(atomic_read(&cred->usage) != 0); |
| 168 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 169 | BUG_ON(read_cred_subscribers(cred) != 0); | ||
| 170 | cred->magic = CRED_MAGIC_DEAD; | ||
| 171 | cred->put_addr = __builtin_return_address(0); | ||
| 172 | #endif | ||
| 173 | BUG_ON(cred == current->cred); | ||
| 174 | BUG_ON(cred == current->real_cred); | ||
| 110 | 175 | ||
| 111 | call_rcu(&cred->rcu, put_cred_rcu); | 176 | call_rcu(&cred->rcu, put_cred_rcu); |
| 112 | } | 177 | } |
| 113 | EXPORT_SYMBOL(__put_cred); | 178 | EXPORT_SYMBOL(__put_cred); |
| 114 | 179 | ||
| 180 | /* | ||
| 181 | * Clean up a task's credentials when it exits | ||
| 182 | */ | ||
| 183 | void exit_creds(struct task_struct *tsk) | ||
| 184 | { | ||
| 185 | struct cred *cred; | ||
| 186 | |||
| 187 | kdebug("exit_creds(%u,%p,%p,{%d,%d})", tsk->pid, tsk->real_cred, tsk->cred, | ||
| 188 | atomic_read(&tsk->cred->usage), | ||
| 189 | read_cred_subscribers(tsk->cred)); | ||
| 190 | |||
| 191 | cred = (struct cred *) tsk->real_cred; | ||
| 192 | tsk->real_cred = NULL; | ||
| 193 | validate_creds(cred); | ||
| 194 | alter_cred_subscribers(cred, -1); | ||
| 195 | put_cred(cred); | ||
| 196 | |||
| 197 | cred = (struct cred *) tsk->cred; | ||
| 198 | tsk->cred = NULL; | ||
| 199 | validate_creds(cred); | ||
| 200 | alter_cred_subscribers(cred, -1); | ||
| 201 | put_cred(cred); | ||
| 202 | |||
| 203 | cred = (struct cred *) tsk->replacement_session_keyring; | ||
| 204 | if (cred) { | ||
| 205 | tsk->replacement_session_keyring = NULL; | ||
| 206 | validate_creds(cred); | ||
| 207 | put_cred(cred); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | /* | ||
| 212 | * Allocate blank credentials, such that the credentials can be filled in at a | ||
| 213 | * later date without risk of ENOMEM. | ||
| 214 | */ | ||
| 215 | struct cred *cred_alloc_blank(void) | ||
| 216 | { | ||
| 217 | struct cred *new; | ||
| 218 | |||
| 219 | new = kmem_cache_zalloc(cred_jar, GFP_KERNEL); | ||
| 220 | if (!new) | ||
| 221 | return NULL; | ||
| 222 | |||
| 223 | #ifdef CONFIG_KEYS | ||
| 224 | new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL); | ||
| 225 | if (!new->tgcred) { | ||
| 226 | kfree(new); | ||
| 227 | return NULL; | ||
| 228 | } | ||
| 229 | atomic_set(&new->tgcred->usage, 1); | ||
| 230 | #endif | ||
| 231 | |||
| 232 | atomic_set(&new->usage, 1); | ||
| 233 | |||
| 234 | if (security_cred_alloc_blank(new, GFP_KERNEL) < 0) | ||
| 235 | goto error; | ||
| 236 | |||
| 237 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 238 | new->magic = CRED_MAGIC; | ||
| 239 | #endif | ||
| 240 | return new; | ||
| 241 | |||
| 242 | error: | ||
| 243 | abort_creds(new); | ||
| 244 | return NULL; | ||
| 245 | } | ||
| 246 | |||
| 115 | /** | 247 | /** |
| 116 | * prepare_creds - Prepare a new set of credentials for modification | 248 | * prepare_creds - Prepare a new set of credentials for modification |
| 117 | * | 249 | * |
| @@ -132,16 +264,19 @@ struct cred *prepare_creds(void) | |||
| 132 | const struct cred *old; | 264 | const struct cred *old; |
| 133 | struct cred *new; | 265 | struct cred *new; |
| 134 | 266 | ||
| 135 | BUG_ON(atomic_read(&task->real_cred->usage) < 1); | 267 | validate_process_creds(); |
| 136 | 268 | ||
| 137 | new = kmem_cache_alloc(cred_jar, GFP_KERNEL); | 269 | new = kmem_cache_alloc(cred_jar, GFP_KERNEL); |
| 138 | if (!new) | 270 | if (!new) |
| 139 | return NULL; | 271 | return NULL; |
| 140 | 272 | ||
| 273 | kdebug("prepare_creds() alloc %p", new); | ||
| 274 | |||
| 141 | old = task->cred; | 275 | old = task->cred; |
| 142 | memcpy(new, old, sizeof(struct cred)); | 276 | memcpy(new, old, sizeof(struct cred)); |
| 143 | 277 | ||
| 144 | atomic_set(&new->usage, 1); | 278 | atomic_set(&new->usage, 1); |
| 279 | set_cred_subscribers(new, 0); | ||
| 145 | get_group_info(new->group_info); | 280 | get_group_info(new->group_info); |
| 146 | get_uid(new->user); | 281 | get_uid(new->user); |
| 147 | 282 | ||
| @@ -157,6 +292,7 @@ struct cred *prepare_creds(void) | |||
| 157 | 292 | ||
| 158 | if (security_prepare_creds(new, old, GFP_KERNEL) < 0) | 293 | if (security_prepare_creds(new, old, GFP_KERNEL) < 0) |
| 159 | goto error; | 294 | goto error; |
| 295 | validate_creds(new); | ||
| 160 | return new; | 296 | return new; |
| 161 | 297 | ||
| 162 | error: | 298 | error: |
| @@ -229,9 +365,12 @@ struct cred *prepare_usermodehelper_creds(void) | |||
| 229 | if (!new) | 365 | if (!new) |
| 230 | return NULL; | 366 | return NULL; |
| 231 | 367 | ||
| 368 | kdebug("prepare_usermodehelper_creds() alloc %p", new); | ||
| 369 | |||
| 232 | memcpy(new, &init_cred, sizeof(struct cred)); | 370 | memcpy(new, &init_cred, sizeof(struct cred)); |
| 233 | 371 | ||
| 234 | atomic_set(&new->usage, 1); | 372 | atomic_set(&new->usage, 1); |
| 373 | set_cred_subscribers(new, 0); | ||
| 235 | get_group_info(new->group_info); | 374 | get_group_info(new->group_info); |
| 236 | get_uid(new->user); | 375 | get_uid(new->user); |
| 237 | 376 | ||
| @@ -250,6 +389,7 @@ struct cred *prepare_usermodehelper_creds(void) | |||
| 250 | #endif | 389 | #endif |
| 251 | if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0) | 390 | if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0) |
| 252 | goto error; | 391 | goto error; |
| 392 | validate_creds(new); | ||
| 253 | 393 | ||
| 254 | BUG_ON(atomic_read(&new->usage) != 1); | 394 | BUG_ON(atomic_read(&new->usage) != 1); |
| 255 | return new; | 395 | return new; |
| @@ -286,6 +426,10 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
| 286 | ) { | 426 | ) { |
| 287 | p->real_cred = get_cred(p->cred); | 427 | p->real_cred = get_cred(p->cred); |
| 288 | get_cred(p->cred); | 428 | get_cred(p->cred); |
| 429 | alter_cred_subscribers(p->cred, 2); | ||
| 430 | kdebug("share_creds(%p{%d,%d})", | ||
| 431 | p->cred, atomic_read(&p->cred->usage), | ||
| 432 | read_cred_subscribers(p->cred)); | ||
| 289 | atomic_inc(&p->cred->user->processes); | 433 | atomic_inc(&p->cred->user->processes); |
| 290 | return 0; | 434 | return 0; |
| 291 | } | 435 | } |
| @@ -331,6 +475,8 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
| 331 | 475 | ||
| 332 | atomic_inc(&new->user->processes); | 476 | atomic_inc(&new->user->processes); |
| 333 | p->cred = p->real_cred = get_cred(new); | 477 | p->cred = p->real_cred = get_cred(new); |
| 478 | alter_cred_subscribers(new, 2); | ||
| 479 | validate_creds(new); | ||
| 334 | return 0; | 480 | return 0; |
| 335 | 481 | ||
| 336 | error_put: | 482 | error_put: |
| @@ -355,13 +501,20 @@ error_put: | |||
| 355 | int commit_creds(struct cred *new) | 501 | int commit_creds(struct cred *new) |
| 356 | { | 502 | { |
| 357 | struct task_struct *task = current; | 503 | struct task_struct *task = current; |
| 358 | const struct cred *old; | 504 | const struct cred *old = task->real_cred; |
| 359 | 505 | ||
| 360 | BUG_ON(task->cred != task->real_cred); | 506 | kdebug("commit_creds(%p{%d,%d})", new, |
| 361 | BUG_ON(atomic_read(&task->real_cred->usage) < 2); | 507 | atomic_read(&new->usage), |
| 508 | read_cred_subscribers(new)); | ||
| 509 | |||
| 510 | BUG_ON(task->cred != old); | ||
| 511 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 512 | BUG_ON(read_cred_subscribers(old) < 2); | ||
| 513 | validate_creds(old); | ||
| 514 | validate_creds(new); | ||
| 515 | #endif | ||
| 362 | BUG_ON(atomic_read(&new->usage) < 1); | 516 | BUG_ON(atomic_read(&new->usage) < 1); |
| 363 | 517 | ||
| 364 | old = task->real_cred; | ||
| 365 | security_commit_creds(new, old); | 518 | security_commit_creds(new, old); |
| 366 | 519 | ||
| 367 | get_cred(new); /* we will require a ref for the subj creds too */ | 520 | get_cred(new); /* we will require a ref for the subj creds too */ |
| @@ -390,12 +543,14 @@ int commit_creds(struct cred *new) | |||
| 390 | * cheaply with the new uid cache, so if it matters | 543 | * cheaply with the new uid cache, so if it matters |
| 391 | * we should be checking for it. -DaveM | 544 | * we should be checking for it. -DaveM |
| 392 | */ | 545 | */ |
| 546 | alter_cred_subscribers(new, 2); | ||
| 393 | if (new->user != old->user) | 547 | if (new->user != old->user) |
| 394 | atomic_inc(&new->user->processes); | 548 | atomic_inc(&new->user->processes); |
| 395 | rcu_assign_pointer(task->real_cred, new); | 549 | rcu_assign_pointer(task->real_cred, new); |
| 396 | rcu_assign_pointer(task->cred, new); | 550 | rcu_assign_pointer(task->cred, new); |
| 397 | if (new->user != old->user) | 551 | if (new->user != old->user) |
| 398 | atomic_dec(&old->user->processes); | 552 | atomic_dec(&old->user->processes); |
| 553 | alter_cred_subscribers(old, -2); | ||
| 399 | 554 | ||
| 400 | sched_switch_user(task); | 555 | sched_switch_user(task); |
| 401 | 556 | ||
| @@ -428,6 +583,13 @@ EXPORT_SYMBOL(commit_creds); | |||
| 428 | */ | 583 | */ |
| 429 | void abort_creds(struct cred *new) | 584 | void abort_creds(struct cred *new) |
| 430 | { | 585 | { |
| 586 | kdebug("abort_creds(%p{%d,%d})", new, | ||
| 587 | atomic_read(&new->usage), | ||
| 588 | read_cred_subscribers(new)); | ||
| 589 | |||
| 590 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 591 | BUG_ON(read_cred_subscribers(new) != 0); | ||
| 592 | #endif | ||
| 431 | BUG_ON(atomic_read(&new->usage) < 1); | 593 | BUG_ON(atomic_read(&new->usage) < 1); |
| 432 | put_cred(new); | 594 | put_cred(new); |
| 433 | } | 595 | } |
| @@ -444,7 +606,20 @@ const struct cred *override_creds(const struct cred *new) | |||
| 444 | { | 606 | { |
| 445 | const struct cred *old = current->cred; | 607 | const struct cred *old = current->cred; |
| 446 | 608 | ||
| 447 | rcu_assign_pointer(current->cred, get_cred(new)); | 609 | kdebug("override_creds(%p{%d,%d})", new, |
| 610 | atomic_read(&new->usage), | ||
| 611 | read_cred_subscribers(new)); | ||
| 612 | |||
| 613 | validate_creds(old); | ||
| 614 | validate_creds(new); | ||
| 615 | get_cred(new); | ||
| 616 | alter_cred_subscribers(new, 1); | ||
| 617 | rcu_assign_pointer(current->cred, new); | ||
| 618 | alter_cred_subscribers(old, -1); | ||
| 619 | |||
| 620 | kdebug("override_creds() = %p{%d,%d}", old, | ||
| 621 | atomic_read(&old->usage), | ||
| 622 | read_cred_subscribers(old)); | ||
| 448 | return old; | 623 | return old; |
| 449 | } | 624 | } |
| 450 | EXPORT_SYMBOL(override_creds); | 625 | EXPORT_SYMBOL(override_creds); |
| @@ -460,7 +635,15 @@ void revert_creds(const struct cred *old) | |||
| 460 | { | 635 | { |
| 461 | const struct cred *override = current->cred; | 636 | const struct cred *override = current->cred; |
| 462 | 637 | ||
| 638 | kdebug("revert_creds(%p{%d,%d})", old, | ||
| 639 | atomic_read(&old->usage), | ||
| 640 | read_cred_subscribers(old)); | ||
| 641 | |||
| 642 | validate_creds(old); | ||
| 643 | validate_creds(override); | ||
| 644 | alter_cred_subscribers(old, 1); | ||
| 463 | rcu_assign_pointer(current->cred, old); | 645 | rcu_assign_pointer(current->cred, old); |
| 646 | alter_cred_subscribers(override, -1); | ||
| 464 | put_cred(override); | 647 | put_cred(override); |
| 465 | } | 648 | } |
| 466 | EXPORT_SYMBOL(revert_creds); | 649 | EXPORT_SYMBOL(revert_creds); |
| @@ -502,11 +685,15 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) | |||
| 502 | if (!new) | 685 | if (!new) |
| 503 | return NULL; | 686 | return NULL; |
| 504 | 687 | ||
| 688 | kdebug("prepare_kernel_cred() alloc %p", new); | ||
| 689 | |||
| 505 | if (daemon) | 690 | if (daemon) |
| 506 | old = get_task_cred(daemon); | 691 | old = get_task_cred(daemon); |
| 507 | else | 692 | else |
| 508 | old = get_cred(&init_cred); | 693 | old = get_cred(&init_cred); |
| 509 | 694 | ||
| 695 | validate_creds(old); | ||
| 696 | |||
| 510 | *new = *old; | 697 | *new = *old; |
| 511 | get_uid(new->user); | 698 | get_uid(new->user); |
| 512 | get_group_info(new->group_info); | 699 | get_group_info(new->group_info); |
| @@ -526,7 +713,9 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) | |||
| 526 | goto error; | 713 | goto error; |
| 527 | 714 | ||
| 528 | atomic_set(&new->usage, 1); | 715 | atomic_set(&new->usage, 1); |
| 716 | set_cred_subscribers(new, 0); | ||
| 529 | put_cred(old); | 717 | put_cred(old); |
| 718 | validate_creds(new); | ||
| 530 | return new; | 719 | return new; |
| 531 | 720 | ||
| 532 | error: | 721 | error: |
| @@ -589,3 +778,95 @@ int set_create_files_as(struct cred *new, struct inode *inode) | |||
| 589 | return security_kernel_create_files_as(new, inode); | 778 | return security_kernel_create_files_as(new, inode); |
| 590 | } | 779 | } |
| 591 | EXPORT_SYMBOL(set_create_files_as); | 780 | EXPORT_SYMBOL(set_create_files_as); |
| 781 | |||
| 782 | #ifdef CONFIG_DEBUG_CREDENTIALS | ||
| 783 | |||
| 784 | /* | ||
| 785 | * dump invalid credentials | ||
| 786 | */ | ||
| 787 | static void dump_invalid_creds(const struct cred *cred, const char *label, | ||
| 788 | const struct task_struct *tsk) | ||
| 789 | { | ||
| 790 | printk(KERN_ERR "CRED: %s credentials: %p %s%s%s\n", | ||
| 791 | label, cred, | ||
| 792 | cred == &init_cred ? "[init]" : "", | ||
| 793 | cred == tsk->real_cred ? "[real]" : "", | ||
| 794 | cred == tsk->cred ? "[eff]" : ""); | ||
| 795 | printk(KERN_ERR "CRED: ->magic=%x, put_addr=%p\n", | ||
| 796 | cred->magic, cred->put_addr); | ||
| 797 | printk(KERN_ERR "CRED: ->usage=%d, subscr=%d\n", | ||
| 798 | atomic_read(&cred->usage), | ||
| 799 | read_cred_subscribers(cred)); | ||
| 800 | printk(KERN_ERR "CRED: ->*uid = { %d,%d,%d,%d }\n", | ||
| 801 | cred->uid, cred->euid, cred->suid, cred->fsuid); | ||
| 802 | printk(KERN_ERR "CRED: ->*gid = { %d,%d,%d,%d }\n", | ||
| 803 | cred->gid, cred->egid, cred->sgid, cred->fsgid); | ||
| 804 | #ifdef CONFIG_SECURITY | ||
| 805 | printk(KERN_ERR "CRED: ->security is %p\n", cred->security); | ||
| 806 | if ((unsigned long) cred->security >= PAGE_SIZE && | ||
| 807 | (((unsigned long) cred->security & 0xffffff00) != | ||
| 808 | (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))) | ||
| 809 | printk(KERN_ERR "CRED: ->security {%x, %x}\n", | ||
| 810 | ((u32*)cred->security)[0], | ||
| 811 | ((u32*)cred->security)[1]); | ||
| 812 | #endif | ||
| 813 | } | ||
| 814 | |||
| 815 | /* | ||
| 816 | * report use of invalid credentials | ||
| 817 | */ | ||
| 818 | void __invalid_creds(const struct cred *cred, const char *file, unsigned line) | ||
| 819 | { | ||
| 820 | printk(KERN_ERR "CRED: Invalid credentials\n"); | ||
| 821 | printk(KERN_ERR "CRED: At %s:%u\n", file, line); | ||
| 822 | dump_invalid_creds(cred, "Specified", current); | ||
| 823 | BUG(); | ||
| 824 | } | ||
| 825 | EXPORT_SYMBOL(__invalid_creds); | ||
| 826 | |||
| 827 | /* | ||
| 828 | * check the credentials on a process | ||
| 829 | */ | ||
| 830 | void __validate_process_creds(struct task_struct *tsk, | ||
| 831 | const char *file, unsigned line) | ||
| 832 | { | ||
| 833 | if (tsk->cred == tsk->real_cred) { | ||
| 834 | if (unlikely(read_cred_subscribers(tsk->cred) < 2 || | ||
| 835 | creds_are_invalid(tsk->cred))) | ||
| 836 | goto invalid_creds; | ||
| 837 | } else { | ||
| 838 | if (unlikely(read_cred_subscribers(tsk->real_cred) < 1 || | ||
| 839 | read_cred_subscribers(tsk->cred) < 1 || | ||
| 840 | creds_are_invalid(tsk->real_cred) || | ||
| 841 | creds_are_invalid(tsk->cred))) | ||
| 842 | goto invalid_creds; | ||
| 843 | } | ||
| 844 | return; | ||
| 845 | |||
| 846 | invalid_creds: | ||
| 847 | printk(KERN_ERR "CRED: Invalid process credentials\n"); | ||
| 848 | printk(KERN_ERR "CRED: At %s:%u\n", file, line); | ||
| 849 | |||
| 850 | dump_invalid_creds(tsk->real_cred, "Real", tsk); | ||
| 851 | if (tsk->cred != tsk->real_cred) | ||
| 852 | dump_invalid_creds(tsk->cred, "Effective", tsk); | ||
| 853 | else | ||
| 854 | printk(KERN_ERR "CRED: Effective creds == Real creds\n"); | ||
| 855 | BUG(); | ||
| 856 | } | ||
| 857 | EXPORT_SYMBOL(__validate_process_creds); | ||
| 858 | |||
| 859 | /* | ||
| 860 | * check creds for do_exit() | ||
| 861 | */ | ||
| 862 | void validate_creds_for_do_exit(struct task_struct *tsk) | ||
| 863 | { | ||
| 864 | kdebug("validate_creds_for_do_exit(%p,%p{%d,%d})", | ||
| 865 | tsk->real_cred, tsk->cred, | ||
| 866 | atomic_read(&tsk->cred->usage), | ||
| 867 | read_cred_subscribers(tsk->cred)); | ||
| 868 | |||
| 869 | __validate_process_creds(tsk, __FILE__, __LINE__); | ||
| 870 | } | ||
| 871 | |||
| 872 | #endif /* CONFIG_DEBUG_CREDENTIALS */ | ||
diff --git a/kernel/exit.c b/kernel/exit.c index 869dc221733e..c98ff7a8025f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -901,6 +901,8 @@ NORET_TYPE void do_exit(long code) | |||
| 901 | 901 | ||
| 902 | tracehook_report_exit(&code); | 902 | tracehook_report_exit(&code); |
| 903 | 903 | ||
| 904 | validate_creds_for_do_exit(tsk); | ||
| 905 | |||
| 904 | /* | 906 | /* |
| 905 | * We're taking recursive faults here in do_exit. Safest is to just | 907 | * We're taking recursive faults here in do_exit. Safest is to just |
| 906 | * leave this task alone and wait for reboot. | 908 | * leave this task alone and wait for reboot. |
| @@ -1009,6 +1011,8 @@ NORET_TYPE void do_exit(long code) | |||
| 1009 | if (tsk->splice_pipe) | 1011 | if (tsk->splice_pipe) |
| 1010 | __free_pipe_info(tsk->splice_pipe); | 1012 | __free_pipe_info(tsk->splice_pipe); |
| 1011 | 1013 | ||
| 1014 | validate_creds_for_do_exit(tsk); | ||
| 1015 | |||
| 1012 | preempt_disable(); | 1016 | preempt_disable(); |
| 1013 | /* causes final put_task_struct in finish_task_switch(). */ | 1017 | /* causes final put_task_struct in finish_task_switch(). */ |
| 1014 | tsk->state = TASK_DEAD; | 1018 | tsk->state = TASK_DEAD; |
diff --git a/kernel/fork.c b/kernel/fork.c index e6c04d462ab2..aab8579c6093 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -152,8 +152,7 @@ void __put_task_struct(struct task_struct *tsk) | |||
| 152 | WARN_ON(atomic_read(&tsk->usage)); | 152 | WARN_ON(atomic_read(&tsk->usage)); |
| 153 | WARN_ON(tsk == current); | 153 | WARN_ON(tsk == current); |
| 154 | 154 | ||
| 155 | put_cred(tsk->real_cred); | 155 | exit_creds(tsk); |
| 156 | put_cred(tsk->cred); | ||
| 157 | delayacct_tsk_free(tsk); | 156 | delayacct_tsk_free(tsk); |
| 158 | 157 | ||
| 159 | if (!profile_handoff_task(tsk)) | 158 | if (!profile_handoff_task(tsk)) |
| @@ -1297,8 +1296,7 @@ bad_fork_cleanup_put_domain: | |||
| 1297 | module_put(task_thread_info(p)->exec_domain->module); | 1296 | module_put(task_thread_info(p)->exec_domain->module); |
| 1298 | bad_fork_cleanup_count: | 1297 | bad_fork_cleanup_count: |
| 1299 | atomic_dec(&p->cred->user->processes); | 1298 | atomic_dec(&p->cred->user->processes); |
| 1300 | put_cred(p->real_cred); | 1299 | exit_creds(p); |
| 1301 | put_cred(p->cred); | ||
| 1302 | bad_fork_free: | 1300 | bad_fork_free: |
| 1303 | free_task(p); | 1301 | free_task(p); |
| 1304 | fork_out: | 1302 | fork_out: |
diff --git a/kernel/kmod.c b/kernel/kmod.c index 385c31a1bdbf..4e8cae2e9148 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
| @@ -78,6 +78,10 @@ int __request_module(bool wait, const char *fmt, ...) | |||
| 78 | #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ | 78 | #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ |
| 79 | static int kmod_loop_msg; | 79 | static int kmod_loop_msg; |
| 80 | 80 | ||
| 81 | ret = security_kernel_module_request(); | ||
| 82 | if (ret) | ||
| 83 | return ret; | ||
| 84 | |||
| 81 | va_start(args, fmt); | 85 | va_start(args, fmt); |
| 82 | ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); | 86 | ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); |
| 83 | va_end(args); | 87 | va_end(args); |
| @@ -462,6 +466,7 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, | |||
| 462 | int retval = 0; | 466 | int retval = 0; |
| 463 | 467 | ||
| 464 | BUG_ON(atomic_read(&sub_info->cred->usage) != 1); | 468 | BUG_ON(atomic_read(&sub_info->cred->usage) != 1); |
| 469 | validate_creds(sub_info->cred); | ||
| 465 | 470 | ||
| 466 | helper_lock(); | 471 | helper_lock(); |
| 467 | if (sub_info->path[0] == '\0') | 472 | if (sub_info->path[0] == '\0') |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 082c320e4dbf..307c285af59e 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -152,7 +152,7 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) | |||
| 152 | if (!dumpable && !capable(CAP_SYS_PTRACE)) | 152 | if (!dumpable && !capable(CAP_SYS_PTRACE)) |
| 153 | return -EPERM; | 153 | return -EPERM; |
| 154 | 154 | ||
| 155 | return security_ptrace_may_access(task, mode); | 155 | return security_ptrace_access_check(task, mode); |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | bool ptrace_may_access(struct task_struct *task, unsigned int mode) | 158 | bool ptrace_may_access(struct task_struct *task, unsigned int mode) |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 58be76017fd0..71d8dc7f9920 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -49,7 +49,6 @@ | |||
| 49 | #include <linux/acpi.h> | 49 | #include <linux/acpi.h> |
| 50 | #include <linux/reboot.h> | 50 | #include <linux/reboot.h> |
| 51 | #include <linux/ftrace.h> | 51 | #include <linux/ftrace.h> |
| 52 | #include <linux/security.h> | ||
| 53 | #include <linux/slow-work.h> | 52 | #include <linux/slow-work.h> |
| 54 | #include <linux/perf_counter.h> | 53 | #include <linux/perf_counter.h> |
| 55 | 54 | ||
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 12327b2bb785..fbb87cf138c5 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
| @@ -653,6 +653,21 @@ config DEBUG_NOTIFIERS | |||
| 653 | This is a relatively cheap check but if you care about maximum | 653 | This is a relatively cheap check but if you care about maximum |
| 654 | performance, say N. | 654 | performance, say N. |
| 655 | 655 | ||
| 656 | config DEBUG_CREDENTIALS | ||
| 657 | bool "Debug credential management" | ||
| 658 | depends on DEBUG_KERNEL | ||
| 659 | help | ||
| 660 | Enable this to turn on some debug checking for credential | ||
| 661 | management. The additional code keeps track of the number of | ||
| 662 | pointers from task_structs to any given cred struct, and checks to | ||
| 663 | see that this number never exceeds the usage count of the cred | ||
| 664 | struct. | ||
| 665 | |||
| 666 | Furthermore, if SELinux is enabled, this also checks that the | ||
| 667 | security pointer in the cred struct is never seen to be invalid. | ||
| 668 | |||
| 669 | If unsure, say N. | ||
| 670 | |||
| 656 | # | 671 | # |
| 657 | # Select this config option from the architecture Kconfig, if it | 672 | # Select this config option from the architecture Kconfig, if it |
| 658 | # it is preferred to always offer frame pointers as a config | 673 | # it is preferred to always offer frame pointers as a config |
diff --git a/lib/is_single_threaded.c b/lib/is_single_threaded.c index f1ed2fe76c65..bd2bea963364 100644 --- a/lib/is_single_threaded.c +++ b/lib/is_single_threaded.c | |||
| @@ -12,34 +12,47 @@ | |||
| 12 | 12 | ||
| 13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
| 14 | 14 | ||
| 15 | /** | 15 | /* |
| 16 | * is_single_threaded - Determine if a thread group is single-threaded or not | 16 | * Returns true if the task does not share ->mm with another thread/process. |
| 17 | * @p: A task in the thread group in question | ||
| 18 | * | ||
| 19 | * This returns true if the thread group to which a task belongs is single | ||
| 20 | * threaded, false if it is not. | ||
| 21 | */ | 17 | */ |
| 22 | bool is_single_threaded(struct task_struct *p) | 18 | bool current_is_single_threaded(void) |
| 23 | { | 19 | { |
| 24 | struct task_struct *g, *t; | 20 | struct task_struct *task = current; |
| 25 | struct mm_struct *mm = p->mm; | 21 | struct mm_struct *mm = task->mm; |
| 22 | struct task_struct *p, *t; | ||
| 23 | bool ret; | ||
| 26 | 24 | ||
| 27 | if (atomic_read(&p->signal->count) != 1) | 25 | if (atomic_read(&task->signal->live) != 1) |
| 28 | goto no; | 26 | return false; |
| 29 | 27 | ||
| 30 | if (atomic_read(&p->mm->mm_users) != 1) { | 28 | if (atomic_read(&mm->mm_users) == 1) |
| 31 | read_lock(&tasklist_lock); | 29 | return true; |
| 32 | do_each_thread(g, t) { | ||
| 33 | if (t->mm == mm && t != p) | ||
| 34 | goto no_unlock; | ||
| 35 | } while_each_thread(g, t); | ||
| 36 | read_unlock(&tasklist_lock); | ||
| 37 | } | ||
| 38 | 30 | ||
| 39 | return true; | 31 | ret = false; |
| 32 | rcu_read_lock(); | ||
| 33 | for_each_process(p) { | ||
| 34 | if (unlikely(p->flags & PF_KTHREAD)) | ||
| 35 | continue; | ||
| 36 | if (unlikely(p == task->group_leader)) | ||
| 37 | continue; | ||
| 38 | |||
| 39 | t = p; | ||
| 40 | do { | ||
| 41 | if (unlikely(t->mm == mm)) | ||
| 42 | goto found; | ||
| 43 | if (likely(t->mm)) | ||
| 44 | break; | ||
| 45 | /* | ||
| 46 | * t->mm == NULL. Make sure next_thread/next_task | ||
| 47 | * will see other CLONE_VM tasks which might be | ||
| 48 | * forked before exiting. | ||
| 49 | */ | ||
| 50 | smp_rmb(); | ||
| 51 | } while_each_thread(p, t); | ||
| 52 | } | ||
| 53 | ret = true; | ||
| 54 | found: | ||
| 55 | rcu_read_unlock(); | ||
| 40 | 56 | ||
| 41 | no_unlock: | 57 | return ret; |
| 42 | read_unlock(&tasklist_lock); | ||
| 43 | no: | ||
| 44 | return false; | ||
| 45 | } | 58 | } |
diff --git a/net/core/dev.c b/net/core/dev.c index 6a94475aee85..278d489aad3b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -1031,7 +1031,7 @@ void dev_load(struct net *net, const char *name) | |||
| 1031 | dev = __dev_get_by_name(net, name); | 1031 | dev = __dev_get_by_name(net, name); |
| 1032 | read_unlock(&dev_base_lock); | 1032 | read_unlock(&dev_base_lock); |
| 1033 | 1033 | ||
| 1034 | if (!dev && capable(CAP_SYS_MODULE)) | 1034 | if (!dev && capable(CAP_NET_ADMIN)) |
| 1035 | request_module("%s", name); | 1035 | request_module("%s", name); |
| 1036 | } | 1036 | } |
| 1037 | 1037 | ||
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index e92beb9e55e0..6428b342b164 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c | |||
| @@ -116,7 +116,7 @@ int tcp_set_default_congestion_control(const char *name) | |||
| 116 | spin_lock(&tcp_cong_list_lock); | 116 | spin_lock(&tcp_cong_list_lock); |
| 117 | ca = tcp_ca_find(name); | 117 | ca = tcp_ca_find(name); |
| 118 | #ifdef CONFIG_MODULES | 118 | #ifdef CONFIG_MODULES |
| 119 | if (!ca && capable(CAP_SYS_MODULE)) { | 119 | if (!ca && capable(CAP_NET_ADMIN)) { |
| 120 | spin_unlock(&tcp_cong_list_lock); | 120 | spin_unlock(&tcp_cong_list_lock); |
| 121 | 121 | ||
| 122 | request_module("tcp_%s", name); | 122 | request_module("tcp_%s", name); |
| @@ -246,7 +246,7 @@ int tcp_set_congestion_control(struct sock *sk, const char *name) | |||
| 246 | 246 | ||
| 247 | #ifdef CONFIG_MODULES | 247 | #ifdef CONFIG_MODULES |
| 248 | /* not found attempt to autoload module */ | 248 | /* not found attempt to autoload module */ |
| 249 | if (!ca && capable(CAP_SYS_MODULE)) { | 249 | if (!ca && capable(CAP_NET_ADMIN)) { |
| 250 | rcu_read_unlock(); | 250 | rcu_read_unlock(); |
| 251 | request_module("tcp_%s", name); | 251 | request_module("tcp_%s", name); |
| 252 | rcu_read_lock(); | 252 | rcu_read_lock(); |
diff --git a/security/Makefile b/security/Makefile index b56e7f9ecbc2..95ecc06392d7 100644 --- a/security/Makefile +++ b/security/Makefile | |||
| @@ -16,9 +16,7 @@ obj-$(CONFIG_SECURITYFS) += inode.o | |||
| 16 | # Must precede capability.o in order to stack properly. | 16 | # Must precede capability.o in order to stack properly. |
| 17 | obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o | 17 | obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o |
| 18 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o | 18 | obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o |
| 19 | ifeq ($(CONFIG_AUDIT),y) | 19 | obj-$(CONFIG_AUDIT) += lsm_audit.o |
| 20 | obj-$(CONFIG_SECURITY_SMACK) += lsm_audit.o | ||
| 21 | endif | ||
| 22 | obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o | 20 | obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o |
| 23 | obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o | 21 | obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o |
| 24 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o | 22 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o |
diff --git a/security/capability.c b/security/capability.c index 88f752e8152c..fce07a7bc825 100644 --- a/security/capability.c +++ b/security/capability.c | |||
| @@ -373,6 +373,11 @@ static int cap_task_create(unsigned long clone_flags) | |||
| 373 | return 0; | 373 | return 0; |
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 377 | { | ||
| 378 | return 0; | ||
| 379 | } | ||
| 380 | |||
| 376 | static void cap_cred_free(struct cred *cred) | 381 | static void cap_cred_free(struct cred *cred) |
| 377 | { | 382 | { |
| 378 | } | 383 | } |
| @@ -386,6 +391,10 @@ static void cap_cred_commit(struct cred *new, const struct cred *old) | |||
| 386 | { | 391 | { |
| 387 | } | 392 | } |
| 388 | 393 | ||
| 394 | static void cap_cred_transfer(struct cred *new, const struct cred *old) | ||
| 395 | { | ||
| 396 | } | ||
| 397 | |||
| 389 | static int cap_kernel_act_as(struct cred *new, u32 secid) | 398 | static int cap_kernel_act_as(struct cred *new, u32 secid) |
| 390 | { | 399 | { |
| 391 | return 0; | 400 | return 0; |
| @@ -396,6 +405,11 @@ static int cap_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
| 396 | return 0; | 405 | return 0; |
| 397 | } | 406 | } |
| 398 | 407 | ||
| 408 | static int cap_kernel_module_request(void) | ||
| 409 | { | ||
| 410 | return 0; | ||
| 411 | } | ||
| 412 | |||
| 399 | static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | 413 | static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) |
| 400 | { | 414 | { |
| 401 | return 0; | 415 | return 0; |
| @@ -701,10 +715,26 @@ static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb) | |||
| 701 | { | 715 | { |
| 702 | } | 716 | } |
| 703 | 717 | ||
| 718 | |||
| 719 | |||
| 704 | static void cap_req_classify_flow(const struct request_sock *req, | 720 | static void cap_req_classify_flow(const struct request_sock *req, |
| 705 | struct flowi *fl) | 721 | struct flowi *fl) |
| 706 | { | 722 | { |
| 707 | } | 723 | } |
| 724 | |||
| 725 | static int cap_tun_dev_create(void) | ||
| 726 | { | ||
| 727 | return 0; | ||
| 728 | } | ||
| 729 | |||
| 730 | static void cap_tun_dev_post_create(struct sock *sk) | ||
| 731 | { | ||
| 732 | } | ||
| 733 | |||
| 734 | static int cap_tun_dev_attach(struct sock *sk) | ||
| 735 | { | ||
| 736 | return 0; | ||
| 737 | } | ||
| 708 | #endif /* CONFIG_SECURITY_NETWORK */ | 738 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 709 | 739 | ||
| 710 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 740 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| @@ -792,6 +822,20 @@ static void cap_release_secctx(char *secdata, u32 seclen) | |||
| 792 | { | 822 | { |
| 793 | } | 823 | } |
| 794 | 824 | ||
| 825 | static int cap_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) | ||
| 826 | { | ||
| 827 | return 0; | ||
| 828 | } | ||
| 829 | |||
| 830 | static int cap_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) | ||
| 831 | { | ||
| 832 | return 0; | ||
| 833 | } | ||
| 834 | |||
| 835 | static int cap_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | ||
| 836 | { | ||
| 837 | return 0; | ||
| 838 | } | ||
| 795 | #ifdef CONFIG_KEYS | 839 | #ifdef CONFIG_KEYS |
| 796 | static int cap_key_alloc(struct key *key, const struct cred *cred, | 840 | static int cap_key_alloc(struct key *key, const struct cred *cred, |
| 797 | unsigned long flags) | 841 | unsigned long flags) |
| @@ -815,6 +859,13 @@ static int cap_key_getsecurity(struct key *key, char **_buffer) | |||
| 815 | return 0; | 859 | return 0; |
| 816 | } | 860 | } |
| 817 | 861 | ||
| 862 | static int cap_key_session_to_parent(const struct cred *cred, | ||
| 863 | const struct cred *parent_cred, | ||
| 864 | struct key *key) | ||
| 865 | { | ||
| 866 | return 0; | ||
| 867 | } | ||
| 868 | |||
| 818 | #endif /* CONFIG_KEYS */ | 869 | #endif /* CONFIG_KEYS */ |
| 819 | 870 | ||
| 820 | #ifdef CONFIG_AUDIT | 871 | #ifdef CONFIG_AUDIT |
| @@ -854,7 +905,7 @@ struct security_operations default_security_ops = { | |||
| 854 | 905 | ||
| 855 | void security_fixup_ops(struct security_operations *ops) | 906 | void security_fixup_ops(struct security_operations *ops) |
| 856 | { | 907 | { |
| 857 | set_to_cap_if_null(ops, ptrace_may_access); | 908 | set_to_cap_if_null(ops, ptrace_access_check); |
| 858 | set_to_cap_if_null(ops, ptrace_traceme); | 909 | set_to_cap_if_null(ops, ptrace_traceme); |
| 859 | set_to_cap_if_null(ops, capget); | 910 | set_to_cap_if_null(ops, capget); |
| 860 | set_to_cap_if_null(ops, capset); | 911 | set_to_cap_if_null(ops, capset); |
| @@ -940,11 +991,14 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 940 | set_to_cap_if_null(ops, file_receive); | 991 | set_to_cap_if_null(ops, file_receive); |
| 941 | set_to_cap_if_null(ops, dentry_open); | 992 | set_to_cap_if_null(ops, dentry_open); |
| 942 | set_to_cap_if_null(ops, task_create); | 993 | set_to_cap_if_null(ops, task_create); |
| 994 | set_to_cap_if_null(ops, cred_alloc_blank); | ||
| 943 | set_to_cap_if_null(ops, cred_free); | 995 | set_to_cap_if_null(ops, cred_free); |
| 944 | set_to_cap_if_null(ops, cred_prepare); | 996 | set_to_cap_if_null(ops, cred_prepare); |
| 945 | set_to_cap_if_null(ops, cred_commit); | 997 | set_to_cap_if_null(ops, cred_commit); |
| 998 | set_to_cap_if_null(ops, cred_transfer); | ||
| 946 | set_to_cap_if_null(ops, kernel_act_as); | 999 | set_to_cap_if_null(ops, kernel_act_as); |
| 947 | set_to_cap_if_null(ops, kernel_create_files_as); | 1000 | set_to_cap_if_null(ops, kernel_create_files_as); |
| 1001 | set_to_cap_if_null(ops, kernel_module_request); | ||
| 948 | set_to_cap_if_null(ops, task_setuid); | 1002 | set_to_cap_if_null(ops, task_setuid); |
| 949 | set_to_cap_if_null(ops, task_fix_setuid); | 1003 | set_to_cap_if_null(ops, task_fix_setuid); |
| 950 | set_to_cap_if_null(ops, task_setgid); | 1004 | set_to_cap_if_null(ops, task_setgid); |
| @@ -992,6 +1046,9 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 992 | set_to_cap_if_null(ops, secid_to_secctx); | 1046 | set_to_cap_if_null(ops, secid_to_secctx); |
| 993 | set_to_cap_if_null(ops, secctx_to_secid); | 1047 | set_to_cap_if_null(ops, secctx_to_secid); |
| 994 | set_to_cap_if_null(ops, release_secctx); | 1048 | set_to_cap_if_null(ops, release_secctx); |
| 1049 | set_to_cap_if_null(ops, inode_notifysecctx); | ||
| 1050 | set_to_cap_if_null(ops, inode_setsecctx); | ||
| 1051 | set_to_cap_if_null(ops, inode_getsecctx); | ||
| 995 | #ifdef CONFIG_SECURITY_NETWORK | 1052 | #ifdef CONFIG_SECURITY_NETWORK |
| 996 | set_to_cap_if_null(ops, unix_stream_connect); | 1053 | set_to_cap_if_null(ops, unix_stream_connect); |
| 997 | set_to_cap_if_null(ops, unix_may_send); | 1054 | set_to_cap_if_null(ops, unix_may_send); |
| @@ -1020,6 +1077,9 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 1020 | set_to_cap_if_null(ops, inet_csk_clone); | 1077 | set_to_cap_if_null(ops, inet_csk_clone); |
| 1021 | set_to_cap_if_null(ops, inet_conn_established); | 1078 | set_to_cap_if_null(ops, inet_conn_established); |
| 1022 | set_to_cap_if_null(ops, req_classify_flow); | 1079 | set_to_cap_if_null(ops, req_classify_flow); |
| 1080 | set_to_cap_if_null(ops, tun_dev_create); | ||
| 1081 | set_to_cap_if_null(ops, tun_dev_post_create); | ||
| 1082 | set_to_cap_if_null(ops, tun_dev_attach); | ||
| 1023 | #endif /* CONFIG_SECURITY_NETWORK */ | 1083 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 1024 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1084 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| 1025 | set_to_cap_if_null(ops, xfrm_policy_alloc_security); | 1085 | set_to_cap_if_null(ops, xfrm_policy_alloc_security); |
| @@ -1038,6 +1098,7 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 1038 | set_to_cap_if_null(ops, key_free); | 1098 | set_to_cap_if_null(ops, key_free); |
| 1039 | set_to_cap_if_null(ops, key_permission); | 1099 | set_to_cap_if_null(ops, key_permission); |
| 1040 | set_to_cap_if_null(ops, key_getsecurity); | 1100 | set_to_cap_if_null(ops, key_getsecurity); |
| 1101 | set_to_cap_if_null(ops, key_session_to_parent); | ||
| 1041 | #endif /* CONFIG_KEYS */ | 1102 | #endif /* CONFIG_KEYS */ |
| 1042 | #ifdef CONFIG_AUDIT | 1103 | #ifdef CONFIG_AUDIT |
| 1043 | set_to_cap_if_null(ops, audit_rule_init); | 1104 | set_to_cap_if_null(ops, audit_rule_init); |
diff --git a/security/commoncap.c b/security/commoncap.c index e3097c0a1311..fe30751a6cd9 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
| @@ -101,7 +101,7 @@ int cap_settime(struct timespec *ts, struct timezone *tz) | |||
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /** | 103 | /** |
| 104 | * cap_ptrace_may_access - Determine whether the current process may access | 104 | * cap_ptrace_access_check - Determine whether the current process may access |
| 105 | * another | 105 | * another |
| 106 | * @child: The process to be accessed | 106 | * @child: The process to be accessed |
| 107 | * @mode: The mode of attachment. | 107 | * @mode: The mode of attachment. |
| @@ -109,7 +109,7 @@ int cap_settime(struct timespec *ts, struct timezone *tz) | |||
| 109 | * Determine whether a process may access another, returning 0 if permission | 109 | * Determine whether a process may access another, returning 0 if permission |
| 110 | * granted, -ve if denied. | 110 | * granted, -ve if denied. |
| 111 | */ | 111 | */ |
| 112 | int cap_ptrace_may_access(struct task_struct *child, unsigned int mode) | 112 | int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) |
| 113 | { | 113 | { |
| 114 | int ret = 0; | 114 | int ret = 0; |
| 115 | 115 | ||
diff --git a/security/keys/Makefile b/security/keys/Makefile index 747a464943af..74d5447d7df7 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y := \ | 5 | obj-y := \ |
| 6 | gc.o \ | ||
| 6 | key.o \ | 7 | key.o \ |
| 7 | keyring.o \ | 8 | keyring.o \ |
| 8 | keyctl.o \ | 9 | keyctl.o \ |
diff --git a/security/keys/compat.c b/security/keys/compat.c index c766c68a63bc..792c0a611a6d 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
| @@ -82,6 +82,9 @@ asmlinkage long compat_sys_keyctl(u32 option, | |||
| 82 | case KEYCTL_GET_SECURITY: | 82 | case KEYCTL_GET_SECURITY: |
| 83 | return keyctl_get_security(arg2, compat_ptr(arg3), arg4); | 83 | return keyctl_get_security(arg2, compat_ptr(arg3), arg4); |
| 84 | 84 | ||
| 85 | case KEYCTL_SESSION_TO_PARENT: | ||
| 86 | return keyctl_session_to_parent(); | ||
| 87 | |||
| 85 | default: | 88 | default: |
| 86 | return -EOPNOTSUPP; | 89 | return -EOPNOTSUPP; |
| 87 | } | 90 | } |
diff --git a/security/keys/gc.c b/security/keys/gc.c new file mode 100644 index 000000000000..1e616aef55fd --- /dev/null +++ b/security/keys/gc.c | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | /* Key garbage collector | ||
| 2 | * | ||
| 3 | * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public Licence | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the Licence, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <keys/keyring-type.h> | ||
| 14 | #include "internal.h" | ||
| 15 | |||
| 16 | /* | ||
| 17 | * Delay between key revocation/expiry in seconds | ||
| 18 | */ | ||
| 19 | unsigned key_gc_delay = 5 * 60; | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Reaper | ||
| 23 | */ | ||
| 24 | static void key_gc_timer_func(unsigned long); | ||
| 25 | static void key_garbage_collector(struct work_struct *); | ||
| 26 | static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0); | ||
| 27 | static DECLARE_WORK(key_gc_work, key_garbage_collector); | ||
| 28 | static key_serial_t key_gc_cursor; /* the last key the gc considered */ | ||
| 29 | static unsigned long key_gc_executing; | ||
| 30 | static time_t key_gc_next_run = LONG_MAX; | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Schedule a garbage collection run | ||
| 34 | * - precision isn't particularly important | ||
| 35 | */ | ||
| 36 | void key_schedule_gc(time_t gc_at) | ||
| 37 | { | ||
| 38 | unsigned long expires; | ||
| 39 | time_t now = current_kernel_time().tv_sec; | ||
| 40 | |||
| 41 | kenter("%ld", gc_at - now); | ||
| 42 | |||
| 43 | gc_at += key_gc_delay; | ||
| 44 | |||
| 45 | if (now >= gc_at) { | ||
| 46 | schedule_work(&key_gc_work); | ||
| 47 | } else if (gc_at < key_gc_next_run) { | ||
| 48 | expires = jiffies + (gc_at - now) * HZ; | ||
| 49 | mod_timer(&key_gc_timer, expires); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | /* | ||
| 54 | * The garbage collector timer kicked off | ||
| 55 | */ | ||
| 56 | static void key_gc_timer_func(unsigned long data) | ||
| 57 | { | ||
| 58 | kenter(""); | ||
| 59 | key_gc_next_run = LONG_MAX; | ||
| 60 | schedule_work(&key_gc_work); | ||
| 61 | } | ||
| 62 | |||
| 63 | /* | ||
| 64 | * Garbage collect pointers from a keyring | ||
| 65 | * - return true if we altered the keyring | ||
| 66 | */ | ||
| 67 | static bool key_gc_keyring(struct key *keyring, time_t limit) | ||
| 68 | __releases(key_serial_lock) | ||
| 69 | { | ||
| 70 | struct keyring_list *klist; | ||
| 71 | struct key *key; | ||
| 72 | int loop; | ||
| 73 | |||
| 74 | kenter("%x", key_serial(keyring)); | ||
| 75 | |||
| 76 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | ||
| 77 | goto dont_gc; | ||
| 78 | |||
| 79 | /* scan the keyring looking for dead keys */ | ||
| 80 | klist = rcu_dereference(keyring->payload.subscriptions); | ||
| 81 | if (!klist) | ||
| 82 | goto dont_gc; | ||
| 83 | |||
| 84 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | ||
| 85 | key = klist->keys[loop]; | ||
| 86 | if (test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
| 87 | (key->expiry > 0 && key->expiry <= limit)) | ||
| 88 | goto do_gc; | ||
| 89 | } | ||
| 90 | |||
| 91 | dont_gc: | ||
| 92 | kleave(" = false"); | ||
| 93 | return false; | ||
| 94 | |||
| 95 | do_gc: | ||
| 96 | key_gc_cursor = keyring->serial; | ||
| 97 | key_get(keyring); | ||
| 98 | spin_unlock(&key_serial_lock); | ||
| 99 | keyring_gc(keyring, limit); | ||
| 100 | key_put(keyring); | ||
| 101 | kleave(" = true"); | ||
| 102 | return true; | ||
| 103 | } | ||
| 104 | |||
| 105 | /* | ||
| 106 | * Garbage collector for keys | ||
| 107 | * - this involves scanning the keyrings for dead, expired and revoked keys | ||
| 108 | * that have overstayed their welcome | ||
| 109 | */ | ||
| 110 | static void key_garbage_collector(struct work_struct *work) | ||
| 111 | { | ||
| 112 | struct rb_node *rb; | ||
| 113 | key_serial_t cursor; | ||
| 114 | struct key *key, *xkey; | ||
| 115 | time_t new_timer = LONG_MAX, limit; | ||
| 116 | |||
| 117 | kenter(""); | ||
| 118 | |||
| 119 | if (test_and_set_bit(0, &key_gc_executing)) { | ||
| 120 | key_schedule_gc(current_kernel_time().tv_sec); | ||
| 121 | return; | ||
| 122 | } | ||
| 123 | |||
| 124 | limit = current_kernel_time().tv_sec; | ||
| 125 | if (limit > key_gc_delay) | ||
| 126 | limit -= key_gc_delay; | ||
| 127 | else | ||
| 128 | limit = key_gc_delay; | ||
| 129 | |||
| 130 | spin_lock(&key_serial_lock); | ||
| 131 | |||
| 132 | if (RB_EMPTY_ROOT(&key_serial_tree)) | ||
| 133 | goto reached_the_end; | ||
| 134 | |||
| 135 | cursor = key_gc_cursor; | ||
| 136 | if (cursor < 0) | ||
| 137 | cursor = 0; | ||
| 138 | |||
| 139 | /* find the first key above the cursor */ | ||
| 140 | key = NULL; | ||
| 141 | rb = key_serial_tree.rb_node; | ||
| 142 | while (rb) { | ||
| 143 | xkey = rb_entry(rb, struct key, serial_node); | ||
| 144 | if (cursor < xkey->serial) { | ||
| 145 | key = xkey; | ||
| 146 | rb = rb->rb_left; | ||
| 147 | } else if (cursor > xkey->serial) { | ||
| 148 | rb = rb->rb_right; | ||
| 149 | } else { | ||
| 150 | rb = rb_next(rb); | ||
| 151 | if (!rb) | ||
| 152 | goto reached_the_end; | ||
| 153 | key = rb_entry(rb, struct key, serial_node); | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | if (!key) | ||
| 159 | goto reached_the_end; | ||
| 160 | |||
| 161 | /* trawl through the keys looking for keyrings */ | ||
| 162 | for (;;) { | ||
| 163 | if (key->expiry > 0 && key->expiry < new_timer) | ||
| 164 | new_timer = key->expiry; | ||
| 165 | |||
| 166 | if (key->type == &key_type_keyring && | ||
| 167 | key_gc_keyring(key, limit)) { | ||
| 168 | /* the gc ate our lock */ | ||
| 169 | schedule_work(&key_gc_work); | ||
| 170 | goto no_unlock; | ||
| 171 | } | ||
| 172 | |||
| 173 | rb = rb_next(&key->serial_node); | ||
| 174 | if (!rb) { | ||
| 175 | key_gc_cursor = 0; | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | key = rb_entry(rb, struct key, serial_node); | ||
| 179 | } | ||
| 180 | |||
| 181 | out: | ||
| 182 | spin_unlock(&key_serial_lock); | ||
| 183 | no_unlock: | ||
| 184 | clear_bit(0, &key_gc_executing); | ||
| 185 | if (new_timer < LONG_MAX) | ||
| 186 | key_schedule_gc(new_timer); | ||
| 187 | |||
| 188 | kleave(""); | ||
| 189 | return; | ||
| 190 | |||
| 191 | reached_the_end: | ||
| 192 | key_gc_cursor = 0; | ||
| 193 | goto out; | ||
| 194 | } | ||
diff --git a/security/keys/internal.h b/security/keys/internal.h index 9fb679c66b8a..24ba0307b7ad 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -124,11 +124,18 @@ extern struct key *request_key_and_link(struct key_type *type, | |||
| 124 | struct key *dest_keyring, | 124 | struct key *dest_keyring, |
| 125 | unsigned long flags); | 125 | unsigned long flags); |
| 126 | 126 | ||
| 127 | extern key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | 127 | extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, |
| 128 | key_perm_t perm); | 128 | key_perm_t perm); |
| 129 | #define KEY_LOOKUP_CREATE 0x01 | ||
| 130 | #define KEY_LOOKUP_PARTIAL 0x02 | ||
| 131 | #define KEY_LOOKUP_FOR_UNLINK 0x04 | ||
| 129 | 132 | ||
| 130 | extern long join_session_keyring(const char *name); | 133 | extern long join_session_keyring(const char *name); |
| 131 | 134 | ||
| 135 | extern unsigned key_gc_delay; | ||
| 136 | extern void keyring_gc(struct key *keyring, time_t limit); | ||
| 137 | extern void key_schedule_gc(time_t expiry_at); | ||
| 138 | |||
| 132 | /* | 139 | /* |
| 133 | * check to see whether permission is granted to use a key in the desired way | 140 | * check to see whether permission is granted to use a key in the desired way |
| 134 | */ | 141 | */ |
| @@ -194,6 +201,7 @@ extern long keyctl_set_timeout(key_serial_t, unsigned); | |||
| 194 | extern long keyctl_assume_authority(key_serial_t); | 201 | extern long keyctl_assume_authority(key_serial_t); |
| 195 | extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, | 202 | extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, |
| 196 | size_t buflen); | 203 | size_t buflen); |
| 204 | extern long keyctl_session_to_parent(void); | ||
| 197 | 205 | ||
| 198 | /* | 206 | /* |
| 199 | * debugging key validation | 207 | * debugging key validation |
diff --git a/security/keys/key.c b/security/keys/key.c index 4a1297d1ada4..08531ad0f252 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -500,6 +500,7 @@ int key_negate_and_link(struct key *key, | |||
| 500 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | 500 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); |
| 501 | now = current_kernel_time(); | 501 | now = current_kernel_time(); |
| 502 | key->expiry = now.tv_sec + timeout; | 502 | key->expiry = now.tv_sec + timeout; |
| 503 | key_schedule_gc(key->expiry); | ||
| 503 | 504 | ||
| 504 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) | 505 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
| 505 | awaken = 1; | 506 | awaken = 1; |
| @@ -642,10 +643,8 @@ struct key *key_lookup(key_serial_t id) | |||
| 642 | goto error; | 643 | goto error; |
| 643 | 644 | ||
| 644 | found: | 645 | found: |
| 645 | /* pretend it doesn't exist if it's dead */ | 646 | /* pretend it doesn't exist if it is awaiting deletion */ |
| 646 | if (atomic_read(&key->usage) == 0 || | 647 | if (atomic_read(&key->usage) == 0) |
| 647 | test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
| 648 | key->type == &key_type_dead) | ||
| 649 | goto not_found; | 648 | goto not_found; |
| 650 | 649 | ||
| 651 | /* this races with key_put(), but that doesn't matter since key_put() | 650 | /* this races with key_put(), but that doesn't matter since key_put() |
| @@ -890,6 +889,9 @@ EXPORT_SYMBOL(key_update); | |||
| 890 | */ | 889 | */ |
| 891 | void key_revoke(struct key *key) | 890 | void key_revoke(struct key *key) |
| 892 | { | 891 | { |
| 892 | struct timespec now; | ||
| 893 | time_t time; | ||
| 894 | |||
| 893 | key_check(key); | 895 | key_check(key); |
| 894 | 896 | ||
| 895 | /* make sure no one's trying to change or use the key when we mark it | 897 | /* 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) | |||
| 902 | key->type->revoke) | 904 | key->type->revoke) |
| 903 | key->type->revoke(key); | 905 | key->type->revoke(key); |
| 904 | 906 | ||
| 907 | /* set the death time to no more than the expiry time */ | ||
| 908 | now = current_kernel_time(); | ||
| 909 | time = now.tv_sec; | ||
| 910 | if (key->revoked_at == 0 || key->revoked_at > time) { | ||
| 911 | key->revoked_at = time; | ||
| 912 | key_schedule_gc(key->revoked_at); | ||
| 913 | } | ||
| 914 | |||
| 905 | up_write(&key->sem); | 915 | up_write(&key->sem); |
| 906 | 916 | ||
| 907 | } /* end key_revoke() */ | 917 | } /* end key_revoke() */ |
| @@ -958,8 +968,10 @@ void unregister_key_type(struct key_type *ktype) | |||
| 958 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { | 968 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { |
| 959 | key = rb_entry(_n, struct key, serial_node); | 969 | key = rb_entry(_n, struct key, serial_node); |
| 960 | 970 | ||
| 961 | if (key->type == ktype) | 971 | if (key->type == ktype) { |
| 962 | key->type = &key_type_dead; | 972 | key->type = &key_type_dead; |
| 973 | set_bit(KEY_FLAG_DEAD, &key->flags); | ||
| 974 | } | ||
| 963 | } | 975 | } |
| 964 | 976 | ||
| 965 | spin_unlock(&key_serial_lock); | 977 | spin_unlock(&key_serial_lock); |
| @@ -984,6 +996,8 @@ void unregister_key_type(struct key_type *ktype) | |||
| 984 | spin_unlock(&key_serial_lock); | 996 | spin_unlock(&key_serial_lock); |
| 985 | up_write(&key_types_sem); | 997 | up_write(&key_types_sem); |
| 986 | 998 | ||
| 999 | key_schedule_gc(0); | ||
| 1000 | |||
| 987 | } /* end unregister_key_type() */ | 1001 | } /* end unregister_key_type() */ |
| 988 | 1002 | ||
| 989 | EXPORT_SYMBOL(unregister_key_type); | 1003 | EXPORT_SYMBOL(unregister_key_type); |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 7f09fb897d2b..74c968524592 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -103,7 +103,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | /* find the target keyring (which must be writable) */ | 105 | /* find the target keyring (which must be writable) */ |
| 106 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 106 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
| 107 | if (IS_ERR(keyring_ref)) { | 107 | if (IS_ERR(keyring_ref)) { |
| 108 | ret = PTR_ERR(keyring_ref); | 108 | ret = PTR_ERR(keyring_ref); |
| 109 | goto error3; | 109 | goto error3; |
| @@ -185,7 +185,8 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
| 185 | /* get the destination keyring if specified */ | 185 | /* get the destination keyring if specified */ |
| 186 | dest_ref = NULL; | 186 | dest_ref = NULL; |
| 187 | if (destringid) { | 187 | if (destringid) { |
| 188 | dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE); | 188 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, |
| 189 | KEY_WRITE); | ||
| 189 | if (IS_ERR(dest_ref)) { | 190 | if (IS_ERR(dest_ref)) { |
| 190 | ret = PTR_ERR(dest_ref); | 191 | ret = PTR_ERR(dest_ref); |
| 191 | goto error3; | 192 | goto error3; |
| @@ -233,9 +234,11 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
| 233 | long keyctl_get_keyring_ID(key_serial_t id, int create) | 234 | long keyctl_get_keyring_ID(key_serial_t id, int create) |
| 234 | { | 235 | { |
| 235 | key_ref_t key_ref; | 236 | key_ref_t key_ref; |
| 237 | unsigned long lflags; | ||
| 236 | long ret; | 238 | long ret; |
| 237 | 239 | ||
| 238 | key_ref = lookup_user_key(id, create, 0, KEY_SEARCH); | 240 | lflags = create ? KEY_LOOKUP_CREATE : 0; |
| 241 | key_ref = lookup_user_key(id, lflags, KEY_SEARCH); | ||
| 239 | if (IS_ERR(key_ref)) { | 242 | if (IS_ERR(key_ref)) { |
| 240 | ret = PTR_ERR(key_ref); | 243 | ret = PTR_ERR(key_ref); |
| 241 | goto error; | 244 | goto error; |
| @@ -309,7 +312,7 @@ long keyctl_update_key(key_serial_t id, | |||
| 309 | } | 312 | } |
| 310 | 313 | ||
| 311 | /* find the target key (which must be writable) */ | 314 | /* find the target key (which must be writable) */ |
| 312 | key_ref = lookup_user_key(id, 0, 0, KEY_WRITE); | 315 | key_ref = lookup_user_key(id, 0, KEY_WRITE); |
| 313 | if (IS_ERR(key_ref)) { | 316 | if (IS_ERR(key_ref)) { |
| 314 | ret = PTR_ERR(key_ref); | 317 | ret = PTR_ERR(key_ref); |
| 315 | goto error2; | 318 | goto error2; |
| @@ -337,10 +340,16 @@ long keyctl_revoke_key(key_serial_t id) | |||
| 337 | key_ref_t key_ref; | 340 | key_ref_t key_ref; |
| 338 | long ret; | 341 | long ret; |
| 339 | 342 | ||
| 340 | key_ref = lookup_user_key(id, 0, 0, KEY_WRITE); | 343 | key_ref = lookup_user_key(id, 0, KEY_WRITE); |
| 341 | if (IS_ERR(key_ref)) { | 344 | if (IS_ERR(key_ref)) { |
| 342 | ret = PTR_ERR(key_ref); | 345 | ret = PTR_ERR(key_ref); |
| 343 | goto error; | 346 | if (ret != -EACCES) |
| 347 | goto error; | ||
| 348 | key_ref = lookup_user_key(id, 0, KEY_SETATTR); | ||
| 349 | if (IS_ERR(key_ref)) { | ||
| 350 | ret = PTR_ERR(key_ref); | ||
| 351 | goto error; | ||
| 352 | } | ||
| 344 | } | 353 | } |
| 345 | 354 | ||
| 346 | key_revoke(key_ref_to_ptr(key_ref)); | 355 | key_revoke(key_ref_to_ptr(key_ref)); |
| @@ -363,7 +372,7 @@ long keyctl_keyring_clear(key_serial_t ringid) | |||
| 363 | key_ref_t keyring_ref; | 372 | key_ref_t keyring_ref; |
| 364 | long ret; | 373 | long ret; |
| 365 | 374 | ||
| 366 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 375 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
| 367 | if (IS_ERR(keyring_ref)) { | 376 | if (IS_ERR(keyring_ref)) { |
| 368 | ret = PTR_ERR(keyring_ref); | 377 | ret = PTR_ERR(keyring_ref); |
| 369 | goto error; | 378 | goto error; |
| @@ -389,13 +398,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) | |||
| 389 | key_ref_t keyring_ref, key_ref; | 398 | key_ref_t keyring_ref, key_ref; |
| 390 | long ret; | 399 | long ret; |
| 391 | 400 | ||
| 392 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 401 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
| 393 | if (IS_ERR(keyring_ref)) { | 402 | if (IS_ERR(keyring_ref)) { |
| 394 | ret = PTR_ERR(keyring_ref); | 403 | ret = PTR_ERR(keyring_ref); |
| 395 | goto error; | 404 | goto error; |
| 396 | } | 405 | } |
| 397 | 406 | ||
| 398 | key_ref = lookup_user_key(id, 1, 0, KEY_LINK); | 407 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK); |
| 399 | if (IS_ERR(key_ref)) { | 408 | if (IS_ERR(key_ref)) { |
| 400 | ret = PTR_ERR(key_ref); | 409 | ret = PTR_ERR(key_ref); |
| 401 | goto error2; | 410 | goto error2; |
| @@ -423,13 +432,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) | |||
| 423 | key_ref_t keyring_ref, key_ref; | 432 | key_ref_t keyring_ref, key_ref; |
| 424 | long ret; | 433 | long ret; |
| 425 | 434 | ||
| 426 | keyring_ref = lookup_user_key(ringid, 0, 0, KEY_WRITE); | 435 | keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE); |
| 427 | if (IS_ERR(keyring_ref)) { | 436 | if (IS_ERR(keyring_ref)) { |
| 428 | ret = PTR_ERR(keyring_ref); | 437 | ret = PTR_ERR(keyring_ref); |
| 429 | goto error; | 438 | goto error; |
| 430 | } | 439 | } |
| 431 | 440 | ||
| 432 | key_ref = lookup_user_key(id, 0, 0, 0); | 441 | key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0); |
| 433 | if (IS_ERR(key_ref)) { | 442 | if (IS_ERR(key_ref)) { |
| 434 | ret = PTR_ERR(key_ref); | 443 | ret = PTR_ERR(key_ref); |
| 435 | goto error2; | 444 | goto error2; |
| @@ -465,7 +474,7 @@ long keyctl_describe_key(key_serial_t keyid, | |||
| 465 | char *tmpbuf; | 474 | char *tmpbuf; |
| 466 | long ret; | 475 | long ret; |
| 467 | 476 | ||
| 468 | key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW); | 477 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); |
| 469 | if (IS_ERR(key_ref)) { | 478 | if (IS_ERR(key_ref)) { |
| 470 | /* viewing a key under construction is permitted if we have the | 479 | /* viewing a key under construction is permitted if we have the |
| 471 | * authorisation token handy */ | 480 | * authorisation token handy */ |
| @@ -474,7 +483,8 @@ long keyctl_describe_key(key_serial_t keyid, | |||
| 474 | if (!IS_ERR(instkey)) { | 483 | if (!IS_ERR(instkey)) { |
| 475 | key_put(instkey); | 484 | key_put(instkey); |
| 476 | key_ref = lookup_user_key(keyid, | 485 | key_ref = lookup_user_key(keyid, |
| 477 | 0, 1, 0); | 486 | KEY_LOOKUP_PARTIAL, |
| 487 | 0); | ||
| 478 | if (!IS_ERR(key_ref)) | 488 | if (!IS_ERR(key_ref)) |
| 479 | goto okay; | 489 | goto okay; |
| 480 | } | 490 | } |
| @@ -558,7 +568,7 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
| 558 | } | 568 | } |
| 559 | 569 | ||
| 560 | /* get the keyring at which to begin the search */ | 570 | /* get the keyring at which to begin the search */ |
| 561 | keyring_ref = lookup_user_key(ringid, 0, 0, KEY_SEARCH); | 571 | keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH); |
| 562 | if (IS_ERR(keyring_ref)) { | 572 | if (IS_ERR(keyring_ref)) { |
| 563 | ret = PTR_ERR(keyring_ref); | 573 | ret = PTR_ERR(keyring_ref); |
| 564 | goto error2; | 574 | goto error2; |
| @@ -567,7 +577,8 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
| 567 | /* get the destination keyring if specified */ | 577 | /* get the destination keyring if specified */ |
| 568 | dest_ref = NULL; | 578 | dest_ref = NULL; |
| 569 | if (destringid) { | 579 | if (destringid) { |
| 570 | dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE); | 580 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, |
| 581 | KEY_WRITE); | ||
| 571 | if (IS_ERR(dest_ref)) { | 582 | if (IS_ERR(dest_ref)) { |
| 572 | ret = PTR_ERR(dest_ref); | 583 | ret = PTR_ERR(dest_ref); |
| 573 | goto error3; | 584 | goto error3; |
| @@ -637,7 +648,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) | |||
| 637 | long ret; | 648 | long ret; |
| 638 | 649 | ||
| 639 | /* find the key first */ | 650 | /* find the key first */ |
| 640 | key_ref = lookup_user_key(keyid, 0, 0, 0); | 651 | key_ref = lookup_user_key(keyid, 0, 0); |
| 641 | if (IS_ERR(key_ref)) { | 652 | if (IS_ERR(key_ref)) { |
| 642 | ret = -ENOKEY; | 653 | ret = -ENOKEY; |
| 643 | goto error; | 654 | goto error; |
| @@ -700,7 +711,8 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
| 700 | if (uid == (uid_t) -1 && gid == (gid_t) -1) | 711 | if (uid == (uid_t) -1 && gid == (gid_t) -1) |
| 701 | goto error; | 712 | goto error; |
| 702 | 713 | ||
| 703 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 714 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
| 715 | KEY_SETATTR); | ||
| 704 | if (IS_ERR(key_ref)) { | 716 | if (IS_ERR(key_ref)) { |
| 705 | ret = PTR_ERR(key_ref); | 717 | ret = PTR_ERR(key_ref); |
| 706 | goto error; | 718 | goto error; |
| @@ -805,7 +817,8 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) | |||
| 805 | if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) | 817 | if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) |
| 806 | goto error; | 818 | goto error; |
| 807 | 819 | ||
| 808 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 820 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
| 821 | KEY_SETATTR); | ||
| 809 | if (IS_ERR(key_ref)) { | 822 | if (IS_ERR(key_ref)) { |
| 810 | ret = PTR_ERR(key_ref); | 823 | ret = PTR_ERR(key_ref); |
| 811 | goto error; | 824 | goto error; |
| @@ -847,7 +860,7 @@ static long get_instantiation_keyring(key_serial_t ringid, | |||
| 847 | 860 | ||
| 848 | /* if a specific keyring is nominated by ID, then use that */ | 861 | /* if a specific keyring is nominated by ID, then use that */ |
| 849 | if (ringid > 0) { | 862 | if (ringid > 0) { |
| 850 | dkref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 863 | dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
| 851 | if (IS_ERR(dkref)) | 864 | if (IS_ERR(dkref)) |
| 852 | return PTR_ERR(dkref); | 865 | return PTR_ERR(dkref); |
| 853 | *_dest_keyring = key_ref_to_ptr(dkref); | 866 | *_dest_keyring = key_ref_to_ptr(dkref); |
| @@ -1083,7 +1096,8 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) | |||
| 1083 | time_t expiry; | 1096 | time_t expiry; |
| 1084 | long ret; | 1097 | long ret; |
| 1085 | 1098 | ||
| 1086 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 1099 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
| 1100 | KEY_SETATTR); | ||
| 1087 | if (IS_ERR(key_ref)) { | 1101 | if (IS_ERR(key_ref)) { |
| 1088 | ret = PTR_ERR(key_ref); | 1102 | ret = PTR_ERR(key_ref); |
| 1089 | goto error; | 1103 | goto error; |
| @@ -1101,6 +1115,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) | |||
| 1101 | } | 1115 | } |
| 1102 | 1116 | ||
| 1103 | key->expiry = expiry; | 1117 | key->expiry = expiry; |
| 1118 | key_schedule_gc(key->expiry); | ||
| 1104 | 1119 | ||
| 1105 | up_write(&key->sem); | 1120 | up_write(&key->sem); |
| 1106 | key_put(key); | 1121 | key_put(key); |
| @@ -1170,7 +1185,7 @@ long keyctl_get_security(key_serial_t keyid, | |||
| 1170 | char *context; | 1185 | char *context; |
| 1171 | long ret; | 1186 | long ret; |
| 1172 | 1187 | ||
| 1173 | key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW); | 1188 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); |
| 1174 | if (IS_ERR(key_ref)) { | 1189 | if (IS_ERR(key_ref)) { |
| 1175 | if (PTR_ERR(key_ref) != -EACCES) | 1190 | if (PTR_ERR(key_ref) != -EACCES) |
| 1176 | return PTR_ERR(key_ref); | 1191 | return PTR_ERR(key_ref); |
| @@ -1182,7 +1197,7 @@ long keyctl_get_security(key_serial_t keyid, | |||
| 1182 | return PTR_ERR(key_ref); | 1197 | return PTR_ERR(key_ref); |
| 1183 | key_put(instkey); | 1198 | key_put(instkey); |
| 1184 | 1199 | ||
| 1185 | key_ref = lookup_user_key(keyid, 0, 1, 0); | 1200 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0); |
| 1186 | if (IS_ERR(key_ref)) | 1201 | if (IS_ERR(key_ref)) |
| 1187 | return PTR_ERR(key_ref); | 1202 | return PTR_ERR(key_ref); |
| 1188 | } | 1203 | } |
| @@ -1213,6 +1228,105 @@ long keyctl_get_security(key_serial_t keyid, | |||
| 1213 | return ret; | 1228 | return ret; |
| 1214 | } | 1229 | } |
| 1215 | 1230 | ||
| 1231 | /* | ||
| 1232 | * attempt to install the calling process's session keyring on the process's | ||
| 1233 | * parent process | ||
| 1234 | * - the keyring must exist and must grant us LINK permission | ||
| 1235 | * - implements keyctl(KEYCTL_SESSION_TO_PARENT) | ||
| 1236 | */ | ||
| 1237 | long keyctl_session_to_parent(void) | ||
| 1238 | { | ||
| 1239 | struct task_struct *me, *parent; | ||
| 1240 | const struct cred *mycred, *pcred; | ||
| 1241 | struct cred *cred, *oldcred; | ||
| 1242 | key_ref_t keyring_r; | ||
| 1243 | int ret; | ||
| 1244 | |||
| 1245 | keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); | ||
| 1246 | if (IS_ERR(keyring_r)) | ||
| 1247 | return PTR_ERR(keyring_r); | ||
| 1248 | |||
| 1249 | /* our parent is going to need a new cred struct, a new tgcred struct | ||
| 1250 | * and new security data, so we allocate them here to prevent ENOMEM in | ||
| 1251 | * our parent */ | ||
| 1252 | ret = -ENOMEM; | ||
| 1253 | cred = cred_alloc_blank(); | ||
| 1254 | if (!cred) | ||
| 1255 | goto error_keyring; | ||
| 1256 | |||
| 1257 | cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); | ||
| 1258 | keyring_r = NULL; | ||
| 1259 | |||
| 1260 | me = current; | ||
| 1261 | write_lock_irq(&tasklist_lock); | ||
| 1262 | |||
| 1263 | parent = me->real_parent; | ||
| 1264 | ret = -EPERM; | ||
| 1265 | |||
| 1266 | /* the parent mustn't be init and mustn't be a kernel thread */ | ||
| 1267 | if (parent->pid <= 1 || !parent->mm) | ||
| 1268 | goto not_permitted; | ||
| 1269 | |||
| 1270 | /* the parent must be single threaded */ | ||
| 1271 | if (atomic_read(&parent->signal->count) != 1) | ||
| 1272 | goto not_permitted; | ||
| 1273 | |||
| 1274 | /* the parent and the child must have different session keyrings or | ||
| 1275 | * there's no point */ | ||
| 1276 | mycred = current_cred(); | ||
| 1277 | pcred = __task_cred(parent); | ||
| 1278 | if (mycred == pcred || | ||
| 1279 | mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) | ||
| 1280 | goto already_same; | ||
| 1281 | |||
| 1282 | /* the parent must have the same effective ownership and mustn't be | ||
| 1283 | * SUID/SGID */ | ||
| 1284 | if (pcred-> uid != mycred->euid || | ||
| 1285 | pcred->euid != mycred->euid || | ||
| 1286 | pcred->suid != mycred->euid || | ||
| 1287 | pcred-> gid != mycred->egid || | ||
| 1288 | pcred->egid != mycred->egid || | ||
| 1289 | pcred->sgid != mycred->egid) | ||
| 1290 | goto not_permitted; | ||
| 1291 | |||
| 1292 | /* the keyrings must have the same UID */ | ||
| 1293 | if (pcred ->tgcred->session_keyring->uid != mycred->euid || | ||
| 1294 | mycred->tgcred->session_keyring->uid != mycred->euid) | ||
| 1295 | goto not_permitted; | ||
| 1296 | |||
| 1297 | /* the LSM must permit the replacement of the parent's keyring with the | ||
| 1298 | * keyring from this process */ | ||
| 1299 | ret = security_key_session_to_parent(mycred, pcred, | ||
| 1300 | key_ref_to_ptr(keyring_r)); | ||
| 1301 | if (ret < 0) | ||
| 1302 | goto not_permitted; | ||
| 1303 | |||
| 1304 | /* if there's an already pending keyring replacement, then we replace | ||
| 1305 | * that */ | ||
| 1306 | oldcred = parent->replacement_session_keyring; | ||
| 1307 | |||
| 1308 | /* the replacement session keyring is applied just prior to userspace | ||
| 1309 | * restarting */ | ||
| 1310 | parent->replacement_session_keyring = cred; | ||
| 1311 | cred = NULL; | ||
| 1312 | set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); | ||
| 1313 | |||
| 1314 | write_unlock_irq(&tasklist_lock); | ||
| 1315 | if (oldcred) | ||
| 1316 | put_cred(oldcred); | ||
| 1317 | return 0; | ||
| 1318 | |||
| 1319 | already_same: | ||
| 1320 | ret = 0; | ||
| 1321 | not_permitted: | ||
| 1322 | put_cred(cred); | ||
| 1323 | return ret; | ||
| 1324 | |||
| 1325 | error_keyring: | ||
| 1326 | key_ref_put(keyring_r); | ||
| 1327 | return ret; | ||
| 1328 | } | ||
| 1329 | |||
| 1216 | /*****************************************************************************/ | 1330 | /*****************************************************************************/ |
| 1217 | /* | 1331 | /* |
| 1218 | * the key control system call | 1332 | * the key control system call |
| @@ -1298,6 +1412,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
| 1298 | (char __user *) arg3, | 1412 | (char __user *) arg3, |
| 1299 | (size_t) arg4); | 1413 | (size_t) arg4); |
| 1300 | 1414 | ||
| 1415 | case KEYCTL_SESSION_TO_PARENT: | ||
| 1416 | return keyctl_session_to_parent(); | ||
| 1417 | |||
| 1301 | default: | 1418 | default: |
| 1302 | return -EOPNOTSUPP; | 1419 | return -EOPNOTSUPP; |
| 1303 | } | 1420 | } |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 3dba81c2eba3..ac977f661a79 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -1000,3 +1000,88 @@ static void keyring_revoke(struct key *keyring) | |||
| 1000 | } | 1000 | } |
| 1001 | 1001 | ||
| 1002 | } /* end keyring_revoke() */ | 1002 | } /* end keyring_revoke() */ |
| 1003 | |||
| 1004 | /* | ||
| 1005 | * Determine whether a key is dead | ||
| 1006 | */ | ||
| 1007 | static bool key_is_dead(struct key *key, time_t limit) | ||
| 1008 | { | ||
| 1009 | return test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
| 1010 | (key->expiry > 0 && key->expiry <= limit); | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | /* | ||
| 1014 | * Collect garbage from the contents of a keyring | ||
| 1015 | */ | ||
| 1016 | void keyring_gc(struct key *keyring, time_t limit) | ||
| 1017 | { | ||
| 1018 | struct keyring_list *klist, *new; | ||
| 1019 | struct key *key; | ||
| 1020 | int loop, keep, max; | ||
| 1021 | |||
| 1022 | kenter("%x", key_serial(keyring)); | ||
| 1023 | |||
| 1024 | down_write(&keyring->sem); | ||
| 1025 | |||
| 1026 | klist = keyring->payload.subscriptions; | ||
| 1027 | if (!klist) | ||
| 1028 | goto just_return; | ||
| 1029 | |||
| 1030 | /* work out how many subscriptions we're keeping */ | ||
| 1031 | keep = 0; | ||
| 1032 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | ||
| 1033 | if (!key_is_dead(klist->keys[loop], limit)); | ||
| 1034 | keep++; | ||
| 1035 | |||
| 1036 | if (keep == klist->nkeys) | ||
| 1037 | goto just_return; | ||
| 1038 | |||
| 1039 | /* allocate a new keyring payload */ | ||
| 1040 | max = roundup(keep, 4); | ||
| 1041 | new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *), | ||
| 1042 | GFP_KERNEL); | ||
| 1043 | if (!new) | ||
| 1044 | goto just_return; | ||
| 1045 | new->maxkeys = max; | ||
| 1046 | new->nkeys = 0; | ||
| 1047 | new->delkey = 0; | ||
| 1048 | |||
| 1049 | /* install the live keys | ||
| 1050 | * - must take care as expired keys may be updated back to life | ||
| 1051 | */ | ||
| 1052 | keep = 0; | ||
| 1053 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | ||
| 1054 | key = klist->keys[loop]; | ||
| 1055 | if (!key_is_dead(key, limit)) { | ||
| 1056 | if (keep >= max) | ||
| 1057 | goto discard_new; | ||
| 1058 | new->keys[keep++] = key_get(key); | ||
| 1059 | } | ||
| 1060 | } | ||
| 1061 | new->nkeys = keep; | ||
| 1062 | |||
| 1063 | /* adjust the quota */ | ||
| 1064 | key_payload_reserve(keyring, | ||
| 1065 | sizeof(struct keyring_list) + | ||
| 1066 | KEYQUOTA_LINK_BYTES * keep); | ||
| 1067 | |||
| 1068 | if (keep == 0) { | ||
| 1069 | rcu_assign_pointer(keyring->payload.subscriptions, NULL); | ||
| 1070 | kfree(new); | ||
| 1071 | } else { | ||
| 1072 | rcu_assign_pointer(keyring->payload.subscriptions, new); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | up_write(&keyring->sem); | ||
| 1076 | |||
| 1077 | call_rcu(&klist->rcu, keyring_clear_rcu_disposal); | ||
| 1078 | kleave(" [yes]"); | ||
| 1079 | return; | ||
| 1080 | |||
| 1081 | discard_new: | ||
| 1082 | new->nkeys = keep; | ||
| 1083 | keyring_clear_rcu_disposal(&new->rcu); | ||
| 1084 | just_return: | ||
| 1085 | up_write(&keyring->sem); | ||
| 1086 | kleave(" [no]"); | ||
| 1087 | } | ||
diff --git a/security/keys/proc.c b/security/keys/proc.c index 769f9bdfd2b3..9d01021ca0c8 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
| @@ -91,59 +91,94 @@ __initcall(key_proc_init); | |||
| 91 | */ | 91 | */ |
| 92 | #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS | 92 | #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS |
| 93 | 93 | ||
| 94 | static struct rb_node *__key_serial_next(struct rb_node *n) | 94 | static struct rb_node *key_serial_next(struct rb_node *n) |
| 95 | { | 95 | { |
| 96 | struct user_namespace *user_ns = current_user_ns(); | ||
| 97 | |||
| 98 | n = rb_next(n); | ||
| 96 | while (n) { | 99 | while (n) { |
| 97 | struct key *key = rb_entry(n, struct key, serial_node); | 100 | struct key *key = rb_entry(n, struct key, serial_node); |
| 98 | if (key->user->user_ns == current_user_ns()) | 101 | if (key->user->user_ns == user_ns) |
| 99 | break; | 102 | break; |
| 100 | n = rb_next(n); | 103 | n = rb_next(n); |
| 101 | } | 104 | } |
| 102 | return n; | 105 | return n; |
| 103 | } | 106 | } |
| 104 | 107 | ||
| 105 | static struct rb_node *key_serial_next(struct rb_node *n) | 108 | static int proc_keys_open(struct inode *inode, struct file *file) |
| 106 | { | 109 | { |
| 107 | return __key_serial_next(rb_next(n)); | 110 | return seq_open(file, &proc_keys_ops); |
| 108 | } | 111 | } |
| 109 | 112 | ||
| 110 | static struct rb_node *key_serial_first(struct rb_root *r) | 113 | static struct key *find_ge_key(key_serial_t id) |
| 111 | { | 114 | { |
| 112 | struct rb_node *n = rb_first(r); | 115 | struct user_namespace *user_ns = current_user_ns(); |
| 113 | return __key_serial_next(n); | 116 | struct rb_node *n = key_serial_tree.rb_node; |
| 114 | } | 117 | struct key *minkey = NULL; |
| 115 | 118 | ||
| 116 | static int proc_keys_open(struct inode *inode, struct file *file) | 119 | while (n) { |
| 117 | { | 120 | struct key *key = rb_entry(n, struct key, serial_node); |
| 118 | return seq_open(file, &proc_keys_ops); | 121 | if (id < key->serial) { |
| 122 | if (!minkey || minkey->serial > key->serial) | ||
| 123 | minkey = key; | ||
| 124 | n = n->rb_left; | ||
| 125 | } else if (id > key->serial) { | ||
| 126 | n = n->rb_right; | ||
| 127 | } else { | ||
| 128 | minkey = key; | ||
| 129 | break; | ||
| 130 | } | ||
| 131 | key = NULL; | ||
| 132 | } | ||
| 119 | 133 | ||
| 134 | if (!minkey) | ||
| 135 | return NULL; | ||
| 136 | |||
| 137 | for (;;) { | ||
| 138 | if (minkey->user->user_ns == user_ns) | ||
| 139 | return minkey; | ||
| 140 | n = rb_next(&minkey->serial_node); | ||
| 141 | if (!n) | ||
| 142 | return NULL; | ||
| 143 | minkey = rb_entry(n, struct key, serial_node); | ||
| 144 | } | ||
| 120 | } | 145 | } |
| 121 | 146 | ||
| 122 | static void *proc_keys_start(struct seq_file *p, loff_t *_pos) | 147 | static void *proc_keys_start(struct seq_file *p, loff_t *_pos) |
| 148 | __acquires(key_serial_lock) | ||
| 123 | { | 149 | { |
| 124 | struct rb_node *_p; | 150 | key_serial_t pos = *_pos; |
| 125 | loff_t pos = *_pos; | 151 | struct key *key; |
| 126 | 152 | ||
| 127 | spin_lock(&key_serial_lock); | 153 | spin_lock(&key_serial_lock); |
| 128 | 154 | ||
| 129 | _p = key_serial_first(&key_serial_tree); | 155 | if (*_pos > INT_MAX) |
| 130 | while (pos > 0 && _p) { | 156 | return NULL; |
| 131 | pos--; | 157 | key = find_ge_key(pos); |
| 132 | _p = key_serial_next(_p); | 158 | if (!key) |
| 133 | } | 159 | return NULL; |
| 134 | 160 | *_pos = key->serial; | |
| 135 | return _p; | 161 | return &key->serial_node; |
| 162 | } | ||
| 136 | 163 | ||
| 164 | static inline key_serial_t key_node_serial(struct rb_node *n) | ||
| 165 | { | ||
| 166 | struct key *key = rb_entry(n, struct key, serial_node); | ||
| 167 | return key->serial; | ||
| 137 | } | 168 | } |
| 138 | 169 | ||
| 139 | static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) | 170 | static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) |
| 140 | { | 171 | { |
| 141 | (*_pos)++; | 172 | struct rb_node *n; |
| 142 | return key_serial_next((struct rb_node *) v); | ||
| 143 | 173 | ||
| 174 | n = key_serial_next(v); | ||
| 175 | if (n) | ||
| 176 | *_pos = key_node_serial(n); | ||
| 177 | return n; | ||
| 144 | } | 178 | } |
| 145 | 179 | ||
| 146 | static void proc_keys_stop(struct seq_file *p, void *v) | 180 | static void proc_keys_stop(struct seq_file *p, void *v) |
| 181 | __releases(key_serial_lock) | ||
| 147 | { | 182 | { |
| 148 | spin_unlock(&key_serial_lock); | 183 | spin_unlock(&key_serial_lock); |
| 149 | } | 184 | } |
| @@ -174,11 +209,9 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
| 174 | /* come up with a suitable timeout value */ | 209 | /* come up with a suitable timeout value */ |
| 175 | if (key->expiry == 0) { | 210 | if (key->expiry == 0) { |
| 176 | memcpy(xbuf, "perm", 5); | 211 | memcpy(xbuf, "perm", 5); |
| 177 | } | 212 | } else if (now.tv_sec >= key->expiry) { |
| 178 | else if (now.tv_sec >= key->expiry) { | ||
| 179 | memcpy(xbuf, "expd", 5); | 213 | memcpy(xbuf, "expd", 5); |
| 180 | } | 214 | } else { |
| 181 | else { | ||
| 182 | timo = key->expiry - now.tv_sec; | 215 | timo = key->expiry - now.tv_sec; |
| 183 | 216 | ||
| 184 | if (timo < 60) | 217 | if (timo < 60) |
| @@ -218,9 +251,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
| 218 | seq_putc(m, '\n'); | 251 | seq_putc(m, '\n'); |
| 219 | 252 | ||
| 220 | rcu_read_unlock(); | 253 | rcu_read_unlock(); |
| 221 | |||
| 222 | return 0; | 254 | return 0; |
| 223 | |||
| 224 | } | 255 | } |
| 225 | 256 | ||
| 226 | #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ | 257 | #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ |
| @@ -246,6 +277,7 @@ static struct rb_node *key_user_first(struct rb_root *r) | |||
| 246 | struct rb_node *n = rb_first(r); | 277 | struct rb_node *n = rb_first(r); |
| 247 | return __key_user_next(n); | 278 | return __key_user_next(n); |
| 248 | } | 279 | } |
| 280 | |||
| 249 | /*****************************************************************************/ | 281 | /*****************************************************************************/ |
| 250 | /* | 282 | /* |
| 251 | * implement "/proc/key-users" to provides a list of the key users | 283 | * 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) | |||
| 253 | static int proc_key_users_open(struct inode *inode, struct file *file) | 285 | static int proc_key_users_open(struct inode *inode, struct file *file) |
| 254 | { | 286 | { |
| 255 | return seq_open(file, &proc_key_users_ops); | 287 | return seq_open(file, &proc_key_users_ops); |
| 256 | |||
| 257 | } | 288 | } |
| 258 | 289 | ||
| 259 | static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) | 290 | static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) |
| 291 | __acquires(key_user_lock) | ||
| 260 | { | 292 | { |
| 261 | struct rb_node *_p; | 293 | struct rb_node *_p; |
| 262 | loff_t pos = *_pos; | 294 | loff_t pos = *_pos; |
| @@ -270,17 +302,16 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) | |||
| 270 | } | 302 | } |
| 271 | 303 | ||
| 272 | return _p; | 304 | return _p; |
| 273 | |||
| 274 | } | 305 | } |
| 275 | 306 | ||
| 276 | static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) | 307 | static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) |
| 277 | { | 308 | { |
| 278 | (*_pos)++; | 309 | (*_pos)++; |
| 279 | return key_user_next((struct rb_node *) v); | 310 | return key_user_next((struct rb_node *) v); |
| 280 | |||
| 281 | } | 311 | } |
| 282 | 312 | ||
| 283 | static void proc_key_users_stop(struct seq_file *p, void *v) | 313 | static void proc_key_users_stop(struct seq_file *p, void *v) |
| 314 | __releases(key_user_lock) | ||
| 284 | { | 315 | { |
| 285 | spin_unlock(&key_user_lock); | 316 | spin_unlock(&key_user_lock); |
| 286 | } | 317 | } |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 276d27882ce8..5c23afb31ece 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
| 18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
| 19 | #include <linux/mutex.h> | 19 | #include <linux/mutex.h> |
| 20 | #include <linux/security.h> | ||
| 20 | #include <linux/user_namespace.h> | 21 | #include <linux/user_namespace.h> |
| 21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
| 22 | #include "internal.h" | 23 | #include "internal.h" |
| @@ -487,7 +488,7 @@ static int lookup_user_key_possessed(const struct key *key, const void *target) | |||
| 487 | * - don't create special keyrings unless so requested | 488 | * - don't create special keyrings unless so requested |
| 488 | * - partially constructed keys aren't found unless requested | 489 | * - partially constructed keys aren't found unless requested |
| 489 | */ | 490 | */ |
| 490 | key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | 491 | key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, |
| 491 | key_perm_t perm) | 492 | key_perm_t perm) |
| 492 | { | 493 | { |
| 493 | struct request_key_auth *rka; | 494 | struct request_key_auth *rka; |
| @@ -503,7 +504,7 @@ try_again: | |||
| 503 | switch (id) { | 504 | switch (id) { |
| 504 | case KEY_SPEC_THREAD_KEYRING: | 505 | case KEY_SPEC_THREAD_KEYRING: |
| 505 | if (!cred->thread_keyring) { | 506 | if (!cred->thread_keyring) { |
| 506 | if (!create) | 507 | if (!(lflags & KEY_LOOKUP_CREATE)) |
| 507 | goto error; | 508 | goto error; |
| 508 | 509 | ||
| 509 | ret = install_thread_keyring(); | 510 | ret = install_thread_keyring(); |
| @@ -521,7 +522,7 @@ try_again: | |||
| 521 | 522 | ||
| 522 | case KEY_SPEC_PROCESS_KEYRING: | 523 | case KEY_SPEC_PROCESS_KEYRING: |
| 523 | if (!cred->tgcred->process_keyring) { | 524 | if (!cred->tgcred->process_keyring) { |
| 524 | if (!create) | 525 | if (!(lflags & KEY_LOOKUP_CREATE)) |
| 525 | goto error; | 526 | goto error; |
| 526 | 527 | ||
| 527 | ret = install_process_keyring(); | 528 | ret = install_process_keyring(); |
| @@ -642,7 +643,14 @@ try_again: | |||
| 642 | break; | 643 | break; |
| 643 | } | 644 | } |
| 644 | 645 | ||
| 645 | if (!partial) { | 646 | /* unlink does not use the nominated key in any way, so can skip all |
| 647 | * the permission checks as it is only concerned with the keyring */ | ||
| 648 | if (lflags & KEY_LOOKUP_FOR_UNLINK) { | ||
| 649 | ret = 0; | ||
| 650 | goto error; | ||
| 651 | } | ||
| 652 | |||
| 653 | if (!(lflags & KEY_LOOKUP_PARTIAL)) { | ||
| 646 | ret = wait_for_key_construction(key, true); | 654 | ret = wait_for_key_construction(key, true); |
| 647 | switch (ret) { | 655 | switch (ret) { |
| 648 | case -ERESTARTSYS: | 656 | case -ERESTARTSYS: |
| @@ -660,7 +668,8 @@ try_again: | |||
| 660 | } | 668 | } |
| 661 | 669 | ||
| 662 | ret = -EIO; | 670 | ret = -EIO; |
| 663 | if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 671 | if (!(lflags & KEY_LOOKUP_PARTIAL) && |
| 672 | !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | ||
| 664 | goto invalid_key; | 673 | goto invalid_key; |
| 665 | 674 | ||
| 666 | /* check the permissions */ | 675 | /* check the permissions */ |
| @@ -702,7 +711,7 @@ long join_session_keyring(const char *name) | |||
| 702 | /* only permit this if there's a single thread in the thread group - | 711 | /* only permit this if there's a single thread in the thread group - |
| 703 | * this avoids us having to adjust the creds on all threads and risking | 712 | * this avoids us having to adjust the creds on all threads and risking |
| 704 | * ENOMEM */ | 713 | * ENOMEM */ |
| 705 | if (!is_single_threaded(current)) | 714 | if (!current_is_single_threaded()) |
| 706 | return -EMLINK; | 715 | return -EMLINK; |
| 707 | 716 | ||
| 708 | new = prepare_creds(); | 717 | new = prepare_creds(); |
| @@ -760,3 +769,51 @@ error: | |||
| 760 | abort_creds(new); | 769 | abort_creds(new); |
| 761 | return ret; | 770 | return ret; |
| 762 | } | 771 | } |
| 772 | |||
| 773 | /* | ||
| 774 | * Replace a process's session keyring when that process resumes userspace on | ||
| 775 | * behalf of one of its children | ||
| 776 | */ | ||
| 777 | void key_replace_session_keyring(void) | ||
| 778 | { | ||
| 779 | const struct cred *old; | ||
| 780 | struct cred *new; | ||
| 781 | |||
| 782 | if (!current->replacement_session_keyring) | ||
| 783 | return; | ||
| 784 | |||
| 785 | write_lock_irq(&tasklist_lock); | ||
| 786 | new = current->replacement_session_keyring; | ||
| 787 | current->replacement_session_keyring = NULL; | ||
| 788 | write_unlock_irq(&tasklist_lock); | ||
| 789 | |||
| 790 | if (!new) | ||
| 791 | return; | ||
| 792 | |||
| 793 | old = current_cred(); | ||
| 794 | new-> uid = old-> uid; | ||
| 795 | new-> euid = old-> euid; | ||
| 796 | new-> suid = old-> suid; | ||
| 797 | new->fsuid = old->fsuid; | ||
| 798 | new-> gid = old-> gid; | ||
| 799 | new-> egid = old-> egid; | ||
| 800 | new-> sgid = old-> sgid; | ||
| 801 | new->fsgid = old->fsgid; | ||
| 802 | new->user = get_uid(old->user); | ||
| 803 | new->group_info = get_group_info(old->group_info); | ||
| 804 | |||
| 805 | new->securebits = old->securebits; | ||
| 806 | new->cap_inheritable = old->cap_inheritable; | ||
| 807 | new->cap_permitted = old->cap_permitted; | ||
| 808 | new->cap_effective = old->cap_effective; | ||
| 809 | new->cap_bset = old->cap_bset; | ||
| 810 | |||
| 811 | new->jit_keyring = old->jit_keyring; | ||
| 812 | new->thread_keyring = key_get(old->thread_keyring); | ||
| 813 | new->tgcred->tgid = old->tgcred->tgid; | ||
| 814 | new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); | ||
| 815 | |||
| 816 | security_transfer_creds(new, old); | ||
| 817 | |||
| 818 | commit_creds(new); | ||
| 819 | } | ||
diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c index b611d493c2d8..5e05dc09e2db 100644 --- a/security/keys/sysctl.c +++ b/security/keys/sysctl.c | |||
| @@ -13,6 +13,8 @@ | |||
| 13 | #include <linux/sysctl.h> | 13 | #include <linux/sysctl.h> |
| 14 | #include "internal.h" | 14 | #include "internal.h" |
| 15 | 15 | ||
| 16 | static const int zero, one = 1, max = INT_MAX; | ||
| 17 | |||
| 16 | ctl_table key_sysctls[] = { | 18 | ctl_table key_sysctls[] = { |
| 17 | { | 19 | { |
| 18 | .ctl_name = CTL_UNNUMBERED, | 20 | .ctl_name = CTL_UNNUMBERED, |
| @@ -20,7 +22,9 @@ ctl_table key_sysctls[] = { | |||
| 20 | .data = &key_quota_maxkeys, | 22 | .data = &key_quota_maxkeys, |
| 21 | .maxlen = sizeof(unsigned), | 23 | .maxlen = sizeof(unsigned), |
| 22 | .mode = 0644, | 24 | .mode = 0644, |
| 23 | .proc_handler = &proc_dointvec, | 25 | .proc_handler = &proc_dointvec_minmax, |
| 26 | .extra1 = (void *) &one, | ||
| 27 | .extra2 = (void *) &max, | ||
| 24 | }, | 28 | }, |
| 25 | { | 29 | { |
| 26 | .ctl_name = CTL_UNNUMBERED, | 30 | .ctl_name = CTL_UNNUMBERED, |
| @@ -28,7 +32,9 @@ ctl_table key_sysctls[] = { | |||
| 28 | .data = &key_quota_maxbytes, | 32 | .data = &key_quota_maxbytes, |
| 29 | .maxlen = sizeof(unsigned), | 33 | .maxlen = sizeof(unsigned), |
| 30 | .mode = 0644, | 34 | .mode = 0644, |
| 31 | .proc_handler = &proc_dointvec, | 35 | .proc_handler = &proc_dointvec_minmax, |
| 36 | .extra1 = (void *) &one, | ||
| 37 | .extra2 = (void *) &max, | ||
| 32 | }, | 38 | }, |
| 33 | { | 39 | { |
| 34 | .ctl_name = CTL_UNNUMBERED, | 40 | .ctl_name = CTL_UNNUMBERED, |
| @@ -36,7 +42,9 @@ ctl_table key_sysctls[] = { | |||
| 36 | .data = &key_quota_root_maxkeys, | 42 | .data = &key_quota_root_maxkeys, |
| 37 | .maxlen = sizeof(unsigned), | 43 | .maxlen = sizeof(unsigned), |
| 38 | .mode = 0644, | 44 | .mode = 0644, |
| 39 | .proc_handler = &proc_dointvec, | 45 | .proc_handler = &proc_dointvec_minmax, |
| 46 | .extra1 = (void *) &one, | ||
| 47 | .extra2 = (void *) &max, | ||
| 40 | }, | 48 | }, |
| 41 | { | 49 | { |
| 42 | .ctl_name = CTL_UNNUMBERED, | 50 | .ctl_name = CTL_UNNUMBERED, |
| @@ -44,7 +52,19 @@ ctl_table key_sysctls[] = { | |||
| 44 | .data = &key_quota_root_maxbytes, | 52 | .data = &key_quota_root_maxbytes, |
| 45 | .maxlen = sizeof(unsigned), | 53 | .maxlen = sizeof(unsigned), |
| 46 | .mode = 0644, | 54 | .mode = 0644, |
| 47 | .proc_handler = &proc_dointvec, | 55 | .proc_handler = &proc_dointvec_minmax, |
| 56 | .extra1 = (void *) &one, | ||
| 57 | .extra2 = (void *) &max, | ||
| 58 | }, | ||
| 59 | { | ||
| 60 | .ctl_name = CTL_UNNUMBERED, | ||
| 61 | .procname = "gc_delay", | ||
| 62 | .data = &key_gc_delay, | ||
| 63 | .maxlen = sizeof(unsigned), | ||
| 64 | .mode = 0644, | ||
| 65 | .proc_handler = &proc_dointvec_minmax, | ||
| 66 | .extra1 = (void *) &zero, | ||
| 67 | .extra2 = (void *) &max, | ||
| 48 | }, | 68 | }, |
| 49 | { .ctl_name = 0 } | 69 | { .ctl_name = 0 } |
| 50 | }; | 70 | }; |
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 94b868494b31..500aad0ebd6a 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c | |||
| @@ -220,6 +220,8 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | switch (a->type) { | 222 | switch (a->type) { |
| 223 | case LSM_AUDIT_NO_AUDIT: | ||
| 224 | return; | ||
| 223 | case LSM_AUDIT_DATA_IPC: | 225 | case LSM_AUDIT_DATA_IPC: |
| 224 | audit_log_format(ab, " key=%d ", a->u.ipc_id); | 226 | audit_log_format(ab, " key=%d ", a->u.ipc_id); |
| 225 | break; | 227 | break; |
diff --git a/security/security.c b/security/security.c index dc7674fbfc7a..c4c673240c1c 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -124,9 +124,9 @@ int register_security(struct security_operations *ops) | |||
| 124 | 124 | ||
| 125 | /* Security operations */ | 125 | /* Security operations */ |
| 126 | 126 | ||
| 127 | int security_ptrace_may_access(struct task_struct *child, unsigned int mode) | 127 | int security_ptrace_access_check(struct task_struct *child, unsigned int mode) |
| 128 | { | 128 | { |
| 129 | return security_ops->ptrace_may_access(child, mode); | 129 | return security_ops->ptrace_access_check(child, mode); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | int security_ptrace_traceme(struct task_struct *parent) | 132 | int security_ptrace_traceme(struct task_struct *parent) |
| @@ -684,6 +684,11 @@ int security_task_create(unsigned long clone_flags) | |||
| 684 | return security_ops->task_create(clone_flags); | 684 | return security_ops->task_create(clone_flags); |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 688 | { | ||
| 689 | return security_ops->cred_alloc_blank(cred, gfp); | ||
| 690 | } | ||
| 691 | |||
| 687 | void security_cred_free(struct cred *cred) | 692 | void security_cred_free(struct cred *cred) |
| 688 | { | 693 | { |
| 689 | security_ops->cred_free(cred); | 694 | security_ops->cred_free(cred); |
| @@ -699,6 +704,11 @@ void security_commit_creds(struct cred *new, const struct cred *old) | |||
| 699 | security_ops->cred_commit(new, old); | 704 | security_ops->cred_commit(new, old); |
| 700 | } | 705 | } |
| 701 | 706 | ||
| 707 | void security_transfer_creds(struct cred *new, const struct cred *old) | ||
| 708 | { | ||
| 709 | security_ops->cred_transfer(new, old); | ||
| 710 | } | ||
| 711 | |||
| 702 | int security_kernel_act_as(struct cred *new, u32 secid) | 712 | int security_kernel_act_as(struct cred *new, u32 secid) |
| 703 | { | 713 | { |
| 704 | return security_ops->kernel_act_as(new, secid); | 714 | return security_ops->kernel_act_as(new, secid); |
| @@ -709,6 +719,11 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
| 709 | return security_ops->kernel_create_files_as(new, inode); | 719 | return security_ops->kernel_create_files_as(new, inode); |
| 710 | } | 720 | } |
| 711 | 721 | ||
| 722 | int security_kernel_module_request(void) | ||
| 723 | { | ||
| 724 | return security_ops->kernel_module_request(); | ||
| 725 | } | ||
| 726 | |||
| 712 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | 727 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) |
| 713 | { | 728 | { |
| 714 | return security_ops->task_setuid(id0, id1, id2, flags); | 729 | return security_ops->task_setuid(id0, id1, id2, flags); |
| @@ -959,6 +974,24 @@ void security_release_secctx(char *secdata, u32 seclen) | |||
| 959 | } | 974 | } |
| 960 | EXPORT_SYMBOL(security_release_secctx); | 975 | EXPORT_SYMBOL(security_release_secctx); |
| 961 | 976 | ||
| 977 | int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) | ||
| 978 | { | ||
| 979 | return security_ops->inode_notifysecctx(inode, ctx, ctxlen); | ||
| 980 | } | ||
| 981 | EXPORT_SYMBOL(security_inode_notifysecctx); | ||
| 982 | |||
| 983 | int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) | ||
| 984 | { | ||
| 985 | return security_ops->inode_setsecctx(dentry, ctx, ctxlen); | ||
| 986 | } | ||
| 987 | EXPORT_SYMBOL(security_inode_setsecctx); | ||
| 988 | |||
| 989 | int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | ||
| 990 | { | ||
| 991 | return security_ops->inode_getsecctx(inode, ctx, ctxlen); | ||
| 992 | } | ||
| 993 | EXPORT_SYMBOL(security_inode_getsecctx); | ||
| 994 | |||
| 962 | #ifdef CONFIG_SECURITY_NETWORK | 995 | #ifdef CONFIG_SECURITY_NETWORK |
| 963 | 996 | ||
| 964 | int security_unix_stream_connect(struct socket *sock, struct socket *other, | 997 | int security_unix_stream_connect(struct socket *sock, struct socket *other, |
| @@ -1112,6 +1145,24 @@ void security_inet_conn_established(struct sock *sk, | |||
| 1112 | security_ops->inet_conn_established(sk, skb); | 1145 | security_ops->inet_conn_established(sk, skb); |
| 1113 | } | 1146 | } |
| 1114 | 1147 | ||
| 1148 | int security_tun_dev_create(void) | ||
| 1149 | { | ||
| 1150 | return security_ops->tun_dev_create(); | ||
| 1151 | } | ||
| 1152 | EXPORT_SYMBOL(security_tun_dev_create); | ||
| 1153 | |||
| 1154 | void security_tun_dev_post_create(struct sock *sk) | ||
| 1155 | { | ||
| 1156 | return security_ops->tun_dev_post_create(sk); | ||
| 1157 | } | ||
| 1158 | EXPORT_SYMBOL(security_tun_dev_post_create); | ||
| 1159 | |||
| 1160 | int security_tun_dev_attach(struct sock *sk) | ||
| 1161 | { | ||
| 1162 | return security_ops->tun_dev_attach(sk); | ||
| 1163 | } | ||
| 1164 | EXPORT_SYMBOL(security_tun_dev_attach); | ||
| 1165 | |||
| 1115 | #endif /* CONFIG_SECURITY_NETWORK */ | 1166 | #endif /* CONFIG_SECURITY_NETWORK */ |
| 1116 | 1167 | ||
| 1117 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 1168 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| @@ -1218,6 +1269,13 @@ int security_key_getsecurity(struct key *key, char **_buffer) | |||
| 1218 | return security_ops->key_getsecurity(key, _buffer); | 1269 | return security_ops->key_getsecurity(key, _buffer); |
| 1219 | } | 1270 | } |
| 1220 | 1271 | ||
| 1272 | int security_key_session_to_parent(const struct cred *cred, | ||
| 1273 | const struct cred *parent_cred, | ||
| 1274 | struct key *key) | ||
| 1275 | { | ||
| 1276 | return security_ops->key_session_to_parent(cred, parent_cred, key); | ||
| 1277 | } | ||
| 1278 | |||
| 1221 | #endif /* CONFIG_KEYS */ | 1279 | #endif /* CONFIG_KEYS */ |
| 1222 | 1280 | ||
| 1223 | #ifdef CONFIG_AUDIT | 1281 | #ifdef CONFIG_AUDIT |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index b2ab60859832..e3d19014259b 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
| @@ -137,7 +137,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) | |||
| 137 | * @tclass: target security class | 137 | * @tclass: target security class |
| 138 | * @av: access vector | 138 | * @av: access vector |
| 139 | */ | 139 | */ |
| 140 | void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) | 140 | static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) |
| 141 | { | 141 | { |
| 142 | const char **common_pts = NULL; | 142 | const char **common_pts = NULL; |
| 143 | u32 common_base = 0; | 143 | u32 common_base = 0; |
| @@ -492,23 +492,35 @@ out: | |||
| 492 | return node; | 492 | return node; |
| 493 | } | 493 | } |
| 494 | 494 | ||
| 495 | static inline void avc_print_ipv6_addr(struct audit_buffer *ab, | 495 | /** |
| 496 | struct in6_addr *addr, __be16 port, | 496 | * avc_audit_pre_callback - SELinux specific information |
| 497 | char *name1, char *name2) | 497 | * will be called by generic audit code |
| 498 | * @ab: the audit buffer | ||
| 499 | * @a: audit_data | ||
| 500 | */ | ||
| 501 | static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) | ||
| 498 | { | 502 | { |
| 499 | if (!ipv6_addr_any(addr)) | 503 | struct common_audit_data *ad = a; |
| 500 | audit_log_format(ab, " %s=%pI6", name1, addr); | 504 | audit_log_format(ab, "avc: %s ", |
| 501 | if (port) | 505 | ad->selinux_audit_data.denied ? "denied" : "granted"); |
| 502 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); | 506 | avc_dump_av(ab, ad->selinux_audit_data.tclass, |
| 507 | ad->selinux_audit_data.audited); | ||
| 508 | audit_log_format(ab, " for "); | ||
| 503 | } | 509 | } |
| 504 | 510 | ||
| 505 | static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, | 511 | /** |
| 506 | __be16 port, char *name1, char *name2) | 512 | * avc_audit_post_callback - SELinux specific information |
| 513 | * will be called by generic audit code | ||
| 514 | * @ab: the audit buffer | ||
| 515 | * @a: audit_data | ||
| 516 | */ | ||
| 517 | static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | ||
| 507 | { | 518 | { |
| 508 | if (addr) | 519 | struct common_audit_data *ad = a; |
| 509 | audit_log_format(ab, " %s=%pI4", name1, &addr); | 520 | audit_log_format(ab, " "); |
| 510 | if (port) | 521 | avc_dump_query(ab, ad->selinux_audit_data.ssid, |
| 511 | audit_log_format(ab, " %s=%d", name2, ntohs(port)); | 522 | ad->selinux_audit_data.tsid, |
| 523 | ad->selinux_audit_data.tclass); | ||
| 512 | } | 524 | } |
| 513 | 525 | ||
| 514 | /** | 526 | /** |
| @@ -532,13 +544,10 @@ static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, | |||
| 532 | */ | 544 | */ |
| 533 | void avc_audit(u32 ssid, u32 tsid, | 545 | void avc_audit(u32 ssid, u32 tsid, |
| 534 | u16 tclass, u32 requested, | 546 | u16 tclass, u32 requested, |
| 535 | struct av_decision *avd, int result, struct avc_audit_data *a) | 547 | struct av_decision *avd, int result, struct common_audit_data *a) |
| 536 | { | 548 | { |
| 537 | struct task_struct *tsk = current; | 549 | struct common_audit_data stack_data; |
| 538 | struct inode *inode = NULL; | ||
| 539 | u32 denied, audited; | 550 | u32 denied, audited; |
| 540 | struct audit_buffer *ab; | ||
| 541 | |||
| 542 | denied = requested & ~avd->allowed; | 551 | denied = requested & ~avd->allowed; |
| 543 | if (denied) { | 552 | if (denied) { |
| 544 | audited = denied; | 553 | audited = denied; |
| @@ -551,144 +560,20 @@ void avc_audit(u32 ssid, u32 tsid, | |||
| 551 | if (!(audited & avd->auditallow)) | 560 | if (!(audited & avd->auditallow)) |
| 552 | return; | 561 | return; |
| 553 | } | 562 | } |
| 554 | 563 | if (!a) { | |
| 555 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); | 564 | a = &stack_data; |
| 556 | if (!ab) | 565 | memset(a, 0, sizeof(*a)); |
| 557 | return; /* audit_panic has been called */ | 566 | a->type = LSM_AUDIT_NO_AUDIT; |
| 558 | audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); | ||
| 559 | avc_dump_av(ab, tclass, audited); | ||
| 560 | audit_log_format(ab, " for "); | ||
| 561 | if (a && a->tsk) | ||
| 562 | tsk = a->tsk; | ||
| 563 | if (tsk && tsk->pid) { | ||
| 564 | audit_log_format(ab, " pid=%d comm=", tsk->pid); | ||
| 565 | audit_log_untrustedstring(ab, tsk->comm); | ||
| 566 | } | 567 | } |
| 567 | if (a) { | 568 | a->selinux_audit_data.tclass = tclass; |
| 568 | switch (a->type) { | 569 | a->selinux_audit_data.requested = requested; |
| 569 | case AVC_AUDIT_DATA_IPC: | 570 | a->selinux_audit_data.ssid = ssid; |
| 570 | audit_log_format(ab, " key=%d", a->u.ipc_id); | 571 | a->selinux_audit_data.tsid = tsid; |
| 571 | break; | 572 | a->selinux_audit_data.audited = audited; |
| 572 | case AVC_AUDIT_DATA_CAP: | 573 | a->selinux_audit_data.denied = denied; |
| 573 | audit_log_format(ab, " capability=%d", a->u.cap); | 574 | a->lsm_pre_audit = avc_audit_pre_callback; |
| 574 | break; | 575 | a->lsm_post_audit = avc_audit_post_callback; |
| 575 | case AVC_AUDIT_DATA_FS: | 576 | common_lsm_audit(a); |
| 576 | if (a->u.fs.path.dentry) { | ||
| 577 | struct dentry *dentry = a->u.fs.path.dentry; | ||
| 578 | if (a->u.fs.path.mnt) { | ||
| 579 | audit_log_d_path(ab, "path=", | ||
| 580 | &a->u.fs.path); | ||
| 581 | } else { | ||
| 582 | audit_log_format(ab, " name="); | ||
| 583 | audit_log_untrustedstring(ab, dentry->d_name.name); | ||
| 584 | } | ||
| 585 | inode = dentry->d_inode; | ||
| 586 | } else if (a->u.fs.inode) { | ||
| 587 | struct dentry *dentry; | ||
| 588 | inode = a->u.fs.inode; | ||
| 589 | dentry = d_find_alias(inode); | ||
| 590 | if (dentry) { | ||
| 591 | audit_log_format(ab, " name="); | ||
| 592 | audit_log_untrustedstring(ab, dentry->d_name.name); | ||
| 593 | dput(dentry); | ||
| 594 | } | ||
| 595 | } | ||
| 596 | if (inode) | ||
| 597 | audit_log_format(ab, " dev=%s ino=%lu", | ||
| 598 | inode->i_sb->s_id, | ||
| 599 | inode->i_ino); | ||
| 600 | break; | ||
| 601 | case AVC_AUDIT_DATA_NET: | ||
| 602 | if (a->u.net.sk) { | ||
| 603 | struct sock *sk = a->u.net.sk; | ||
| 604 | struct unix_sock *u; | ||
| 605 | int len = 0; | ||
| 606 | char *p = NULL; | ||
| 607 | |||
| 608 | switch (sk->sk_family) { | ||
| 609 | case AF_INET: { | ||
| 610 | struct inet_sock *inet = inet_sk(sk); | ||
| 611 | |||
| 612 | avc_print_ipv4_addr(ab, inet->rcv_saddr, | ||
| 613 | inet->sport, | ||
| 614 | "laddr", "lport"); | ||
| 615 | avc_print_ipv4_addr(ab, inet->daddr, | ||
| 616 | inet->dport, | ||
| 617 | "faddr", "fport"); | ||
| 618 | break; | ||
| 619 | } | ||
| 620 | case AF_INET6: { | ||
| 621 | struct inet_sock *inet = inet_sk(sk); | ||
| 622 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | ||
| 623 | |||
| 624 | avc_print_ipv6_addr(ab, &inet6->rcv_saddr, | ||
| 625 | inet->sport, | ||
| 626 | "laddr", "lport"); | ||
| 627 | avc_print_ipv6_addr(ab, &inet6->daddr, | ||
| 628 | inet->dport, | ||
| 629 | "faddr", "fport"); | ||
| 630 | break; | ||
| 631 | } | ||
| 632 | case AF_UNIX: | ||
| 633 | u = unix_sk(sk); | ||
| 634 | if (u->dentry) { | ||
| 635 | struct path path = { | ||
| 636 | .dentry = u->dentry, | ||
| 637 | .mnt = u->mnt | ||
| 638 | }; | ||
| 639 | audit_log_d_path(ab, "path=", | ||
| 640 | &path); | ||
| 641 | break; | ||
| 642 | } | ||
| 643 | if (!u->addr) | ||
| 644 | break; | ||
| 645 | len = u->addr->len-sizeof(short); | ||
| 646 | p = &u->addr->name->sun_path[0]; | ||
| 647 | audit_log_format(ab, " path="); | ||
| 648 | if (*p) | ||
| 649 | audit_log_untrustedstring(ab, p); | ||
| 650 | else | ||
| 651 | audit_log_n_hex(ab, p, len); | ||
| 652 | break; | ||
| 653 | } | ||
| 654 | } | ||
| 655 | |||
| 656 | switch (a->u.net.family) { | ||
| 657 | case AF_INET: | ||
| 658 | avc_print_ipv4_addr(ab, a->u.net.v4info.saddr, | ||
| 659 | a->u.net.sport, | ||
| 660 | "saddr", "src"); | ||
| 661 | avc_print_ipv4_addr(ab, a->u.net.v4info.daddr, | ||
| 662 | a->u.net.dport, | ||
| 663 | "daddr", "dest"); | ||
| 664 | break; | ||
| 665 | case AF_INET6: | ||
| 666 | avc_print_ipv6_addr(ab, &a->u.net.v6info.saddr, | ||
| 667 | a->u.net.sport, | ||
| 668 | "saddr", "src"); | ||
| 669 | avc_print_ipv6_addr(ab, &a->u.net.v6info.daddr, | ||
| 670 | a->u.net.dport, | ||
| 671 | "daddr", "dest"); | ||
| 672 | break; | ||
| 673 | } | ||
| 674 | if (a->u.net.netif > 0) { | ||
| 675 | struct net_device *dev; | ||
| 676 | |||
| 677 | /* NOTE: we always use init's namespace */ | ||
| 678 | dev = dev_get_by_index(&init_net, | ||
| 679 | a->u.net.netif); | ||
| 680 | if (dev) { | ||
| 681 | audit_log_format(ab, " netif=%s", | ||
| 682 | dev->name); | ||
| 683 | dev_put(dev); | ||
| 684 | } | ||
| 685 | } | ||
| 686 | break; | ||
| 687 | } | ||
| 688 | } | ||
| 689 | audit_log_format(ab, " "); | ||
| 690 | avc_dump_query(ab, ssid, tsid, tclass); | ||
| 691 | audit_log_end(ab); | ||
| 692 | } | 577 | } |
| 693 | 578 | ||
| 694 | /** | 579 | /** |
| @@ -956,7 +841,7 @@ out: | |||
| 956 | * another -errno upon other errors. | 841 | * another -errno upon other errors. |
| 957 | */ | 842 | */ |
| 958 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, | 843 | int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, |
| 959 | u32 requested, struct avc_audit_data *auditdata) | 844 | u32 requested, struct common_audit_data *auditdata) |
| 960 | { | 845 | { |
| 961 | struct av_decision avd; | 846 | struct av_decision avd; |
| 962 | int rc; | 847 | int rc; |
| @@ -970,3 +855,9 @@ u32 avc_policy_seqno(void) | |||
| 970 | { | 855 | { |
| 971 | return avc_cache.latest_notif; | 856 | return avc_cache.latest_notif; |
| 972 | } | 857 | } |
| 858 | |||
| 859 | void avc_disable(void) | ||
| 860 | { | ||
| 861 | if (avc_node_cachep) | ||
| 862 | kmem_cache_destroy(avc_node_cachep); | ||
| 863 | } | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 8d8b69c5664e..417f7c994522 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -13,8 +13,8 @@ | |||
| 13 | * Eric Paris <eparis@redhat.com> | 13 | * Eric Paris <eparis@redhat.com> |
| 14 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. | 14 | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. |
| 15 | * <dgoeddel@trustedcs.com> | 15 | * <dgoeddel@trustedcs.com> |
| 16 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. | 16 | * Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P. |
| 17 | * Paul Moore <paul.moore@hp.com> | 17 | * Paul Moore <paul.moore@hp.com> |
| 18 | * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. | 18 | * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. |
| 19 | * Yuichi Nakamura <ynakam@hitachisoft.jp> | 19 | * Yuichi Nakamura <ynakam@hitachisoft.jp> |
| 20 | * | 20 | * |
| @@ -448,6 +448,10 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
| 448 | sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) | 448 | sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) |
| 449 | sbsec->flags &= ~SE_SBLABELSUPP; | 449 | sbsec->flags &= ~SE_SBLABELSUPP; |
| 450 | 450 | ||
| 451 | /* Special handling for sysfs. Is genfs but also has setxattr handler*/ | ||
| 452 | if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0) | ||
| 453 | sbsec->flags |= SE_SBLABELSUPP; | ||
| 454 | |||
| 451 | /* Initialize the root inode. */ | 455 | /* Initialize the root inode. */ |
| 452 | rc = inode_doinit_with_dentry(root_inode, root); | 456 | rc = inode_doinit_with_dentry(root_inode, root); |
| 453 | 457 | ||
| @@ -1479,14 +1483,14 @@ static int task_has_capability(struct task_struct *tsk, | |||
| 1479 | const struct cred *cred, | 1483 | const struct cred *cred, |
| 1480 | int cap, int audit) | 1484 | int cap, int audit) |
| 1481 | { | 1485 | { |
| 1482 | struct avc_audit_data ad; | 1486 | struct common_audit_data ad; |
| 1483 | struct av_decision avd; | 1487 | struct av_decision avd; |
| 1484 | u16 sclass; | 1488 | u16 sclass; |
| 1485 | u32 sid = cred_sid(cred); | 1489 | u32 sid = cred_sid(cred); |
| 1486 | u32 av = CAP_TO_MASK(cap); | 1490 | u32 av = CAP_TO_MASK(cap); |
| 1487 | int rc; | 1491 | int rc; |
| 1488 | 1492 | ||
| 1489 | AVC_AUDIT_DATA_INIT(&ad, CAP); | 1493 | COMMON_AUDIT_DATA_INIT(&ad, CAP); |
| 1490 | ad.tsk = tsk; | 1494 | ad.tsk = tsk; |
| 1491 | ad.u.cap = cap; | 1495 | ad.u.cap = cap; |
| 1492 | 1496 | ||
| @@ -1525,12 +1529,14 @@ static int task_has_system(struct task_struct *tsk, | |||
| 1525 | static int inode_has_perm(const struct cred *cred, | 1529 | static int inode_has_perm(const struct cred *cred, |
| 1526 | struct inode *inode, | 1530 | struct inode *inode, |
| 1527 | u32 perms, | 1531 | u32 perms, |
| 1528 | struct avc_audit_data *adp) | 1532 | struct common_audit_data *adp) |
| 1529 | { | 1533 | { |
| 1530 | struct inode_security_struct *isec; | 1534 | struct inode_security_struct *isec; |
| 1531 | struct avc_audit_data ad; | 1535 | struct common_audit_data ad; |
| 1532 | u32 sid; | 1536 | u32 sid; |
| 1533 | 1537 | ||
| 1538 | validate_creds(cred); | ||
| 1539 | |||
| 1534 | if (unlikely(IS_PRIVATE(inode))) | 1540 | if (unlikely(IS_PRIVATE(inode))) |
| 1535 | return 0; | 1541 | return 0; |
| 1536 | 1542 | ||
| @@ -1539,7 +1545,7 @@ static int inode_has_perm(const struct cred *cred, | |||
| 1539 | 1545 | ||
| 1540 | if (!adp) { | 1546 | if (!adp) { |
| 1541 | adp = &ad; | 1547 | adp = &ad; |
| 1542 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1548 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1543 | ad.u.fs.inode = inode; | 1549 | ad.u.fs.inode = inode; |
| 1544 | } | 1550 | } |
| 1545 | 1551 | ||
| @@ -1555,9 +1561,9 @@ static inline int dentry_has_perm(const struct cred *cred, | |||
| 1555 | u32 av) | 1561 | u32 av) |
| 1556 | { | 1562 | { |
| 1557 | struct inode *inode = dentry->d_inode; | 1563 | struct inode *inode = dentry->d_inode; |
| 1558 | struct avc_audit_data ad; | 1564 | struct common_audit_data ad; |
| 1559 | 1565 | ||
| 1560 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1566 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1561 | ad.u.fs.path.mnt = mnt; | 1567 | ad.u.fs.path.mnt = mnt; |
| 1562 | ad.u.fs.path.dentry = dentry; | 1568 | ad.u.fs.path.dentry = dentry; |
| 1563 | return inode_has_perm(cred, inode, av, &ad); | 1569 | return inode_has_perm(cred, inode, av, &ad); |
| @@ -1577,11 +1583,11 @@ static int file_has_perm(const struct cred *cred, | |||
| 1577 | { | 1583 | { |
| 1578 | struct file_security_struct *fsec = file->f_security; | 1584 | struct file_security_struct *fsec = file->f_security; |
| 1579 | struct inode *inode = file->f_path.dentry->d_inode; | 1585 | struct inode *inode = file->f_path.dentry->d_inode; |
| 1580 | struct avc_audit_data ad; | 1586 | struct common_audit_data ad; |
| 1581 | u32 sid = cred_sid(cred); | 1587 | u32 sid = cred_sid(cred); |
| 1582 | int rc; | 1588 | int rc; |
| 1583 | 1589 | ||
| 1584 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1590 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1585 | ad.u.fs.path = file->f_path; | 1591 | ad.u.fs.path = file->f_path; |
| 1586 | 1592 | ||
| 1587 | if (sid != fsec->sid) { | 1593 | if (sid != fsec->sid) { |
| @@ -1612,7 +1618,7 @@ static int may_create(struct inode *dir, | |||
| 1612 | struct inode_security_struct *dsec; | 1618 | struct inode_security_struct *dsec; |
| 1613 | struct superblock_security_struct *sbsec; | 1619 | struct superblock_security_struct *sbsec; |
| 1614 | u32 sid, newsid; | 1620 | u32 sid, newsid; |
| 1615 | struct avc_audit_data ad; | 1621 | struct common_audit_data ad; |
| 1616 | int rc; | 1622 | int rc; |
| 1617 | 1623 | ||
| 1618 | dsec = dir->i_security; | 1624 | dsec = dir->i_security; |
| @@ -1621,7 +1627,7 @@ static int may_create(struct inode *dir, | |||
| 1621 | sid = tsec->sid; | 1627 | sid = tsec->sid; |
| 1622 | newsid = tsec->create_sid; | 1628 | newsid = tsec->create_sid; |
| 1623 | 1629 | ||
| 1624 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1630 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1625 | ad.u.fs.path.dentry = dentry; | 1631 | ad.u.fs.path.dentry = dentry; |
| 1626 | 1632 | ||
| 1627 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, | 1633 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, |
| @@ -1665,7 +1671,7 @@ static int may_link(struct inode *dir, | |||
| 1665 | 1671 | ||
| 1666 | { | 1672 | { |
| 1667 | struct inode_security_struct *dsec, *isec; | 1673 | struct inode_security_struct *dsec, *isec; |
| 1668 | struct avc_audit_data ad; | 1674 | struct common_audit_data ad; |
| 1669 | u32 sid = current_sid(); | 1675 | u32 sid = current_sid(); |
| 1670 | u32 av; | 1676 | u32 av; |
| 1671 | int rc; | 1677 | int rc; |
| @@ -1673,7 +1679,7 @@ static int may_link(struct inode *dir, | |||
| 1673 | dsec = dir->i_security; | 1679 | dsec = dir->i_security; |
| 1674 | isec = dentry->d_inode->i_security; | 1680 | isec = dentry->d_inode->i_security; |
| 1675 | 1681 | ||
| 1676 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1682 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1677 | ad.u.fs.path.dentry = dentry; | 1683 | ad.u.fs.path.dentry = dentry; |
| 1678 | 1684 | ||
| 1679 | av = DIR__SEARCH; | 1685 | av = DIR__SEARCH; |
| @@ -1708,7 +1714,7 @@ static inline int may_rename(struct inode *old_dir, | |||
| 1708 | struct dentry *new_dentry) | 1714 | struct dentry *new_dentry) |
| 1709 | { | 1715 | { |
| 1710 | struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; | 1716 | struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; |
| 1711 | struct avc_audit_data ad; | 1717 | struct common_audit_data ad; |
| 1712 | u32 sid = current_sid(); | 1718 | u32 sid = current_sid(); |
| 1713 | u32 av; | 1719 | u32 av; |
| 1714 | int old_is_dir, new_is_dir; | 1720 | int old_is_dir, new_is_dir; |
| @@ -1719,7 +1725,7 @@ static inline int may_rename(struct inode *old_dir, | |||
| 1719 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); | 1725 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); |
| 1720 | new_dsec = new_dir->i_security; | 1726 | new_dsec = new_dir->i_security; |
| 1721 | 1727 | ||
| 1722 | AVC_AUDIT_DATA_INIT(&ad, FS); | 1728 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 1723 | 1729 | ||
| 1724 | ad.u.fs.path.dentry = old_dentry; | 1730 | ad.u.fs.path.dentry = old_dentry; |
| 1725 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, | 1731 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, |
| @@ -1761,7 +1767,7 @@ static inline int may_rename(struct inode *old_dir, | |||
| 1761 | static int superblock_has_perm(const struct cred *cred, | 1767 | static int superblock_has_perm(const struct cred *cred, |
| 1762 | struct super_block *sb, | 1768 | struct super_block *sb, |
| 1763 | u32 perms, | 1769 | u32 perms, |
| 1764 | struct avc_audit_data *ad) | 1770 | struct common_audit_data *ad) |
| 1765 | { | 1771 | { |
| 1766 | struct superblock_security_struct *sbsec; | 1772 | struct superblock_security_struct *sbsec; |
| 1767 | u32 sid = cred_sid(cred); | 1773 | u32 sid = cred_sid(cred); |
| @@ -1855,12 +1861,12 @@ static inline u32 open_file_to_av(struct file *file) | |||
| 1855 | 1861 | ||
| 1856 | /* Hook functions begin here. */ | 1862 | /* Hook functions begin here. */ |
| 1857 | 1863 | ||
| 1858 | static int selinux_ptrace_may_access(struct task_struct *child, | 1864 | static int selinux_ptrace_access_check(struct task_struct *child, |
| 1859 | unsigned int mode) | 1865 | unsigned int mode) |
| 1860 | { | 1866 | { |
| 1861 | int rc; | 1867 | int rc; |
| 1862 | 1868 | ||
| 1863 | rc = cap_ptrace_may_access(child, mode); | 1869 | rc = cap_ptrace_access_check(child, mode); |
| 1864 | if (rc) | 1870 | if (rc) |
| 1865 | return rc; | 1871 | return rc; |
| 1866 | 1872 | ||
| @@ -2101,7 +2107,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
| 2101 | const struct task_security_struct *old_tsec; | 2107 | const struct task_security_struct *old_tsec; |
| 2102 | struct task_security_struct *new_tsec; | 2108 | struct task_security_struct *new_tsec; |
| 2103 | struct inode_security_struct *isec; | 2109 | struct inode_security_struct *isec; |
| 2104 | struct avc_audit_data ad; | 2110 | struct common_audit_data ad; |
| 2105 | struct inode *inode = bprm->file->f_path.dentry->d_inode; | 2111 | struct inode *inode = bprm->file->f_path.dentry->d_inode; |
| 2106 | int rc; | 2112 | int rc; |
| 2107 | 2113 | ||
| @@ -2139,7 +2145,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
| 2139 | return rc; | 2145 | return rc; |
| 2140 | } | 2146 | } |
| 2141 | 2147 | ||
| 2142 | AVC_AUDIT_DATA_INIT(&ad, FS); | 2148 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 2143 | ad.u.fs.path = bprm->file->f_path; | 2149 | ad.u.fs.path = bprm->file->f_path; |
| 2144 | 2150 | ||
| 2145 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) | 2151 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) |
| @@ -2232,7 +2238,7 @@ extern struct dentry *selinux_null; | |||
| 2232 | static inline void flush_unauthorized_files(const struct cred *cred, | 2238 | static inline void flush_unauthorized_files(const struct cred *cred, |
| 2233 | struct files_struct *files) | 2239 | struct files_struct *files) |
| 2234 | { | 2240 | { |
| 2235 | struct avc_audit_data ad; | 2241 | struct common_audit_data ad; |
| 2236 | struct file *file, *devnull = NULL; | 2242 | struct file *file, *devnull = NULL; |
| 2237 | struct tty_struct *tty; | 2243 | struct tty_struct *tty; |
| 2238 | struct fdtable *fdt; | 2244 | struct fdtable *fdt; |
| @@ -2266,7 +2272,7 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
| 2266 | 2272 | ||
| 2267 | /* Revalidate access to inherited open files. */ | 2273 | /* Revalidate access to inherited open files. */ |
| 2268 | 2274 | ||
| 2269 | AVC_AUDIT_DATA_INIT(&ad, FS); | 2275 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 2270 | 2276 | ||
| 2271 | spin_lock(&files->file_lock); | 2277 | spin_lock(&files->file_lock); |
| 2272 | for (;;) { | 2278 | for (;;) { |
| @@ -2515,7 +2521,7 @@ out: | |||
| 2515 | static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | 2521 | static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) |
| 2516 | { | 2522 | { |
| 2517 | const struct cred *cred = current_cred(); | 2523 | const struct cred *cred = current_cred(); |
| 2518 | struct avc_audit_data ad; | 2524 | struct common_audit_data ad; |
| 2519 | int rc; | 2525 | int rc; |
| 2520 | 2526 | ||
| 2521 | rc = superblock_doinit(sb, data); | 2527 | rc = superblock_doinit(sb, data); |
| @@ -2526,7 +2532,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
| 2526 | if (flags & MS_KERNMOUNT) | 2532 | if (flags & MS_KERNMOUNT) |
| 2527 | return 0; | 2533 | return 0; |
| 2528 | 2534 | ||
| 2529 | AVC_AUDIT_DATA_INIT(&ad, FS); | 2535 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 2530 | ad.u.fs.path.dentry = sb->s_root; | 2536 | ad.u.fs.path.dentry = sb->s_root; |
| 2531 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); | 2537 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); |
| 2532 | } | 2538 | } |
| @@ -2534,9 +2540,9 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
| 2534 | static int selinux_sb_statfs(struct dentry *dentry) | 2540 | static int selinux_sb_statfs(struct dentry *dentry) |
| 2535 | { | 2541 | { |
| 2536 | const struct cred *cred = current_cred(); | 2542 | const struct cred *cred = current_cred(); |
| 2537 | struct avc_audit_data ad; | 2543 | struct common_audit_data ad; |
| 2538 | 2544 | ||
| 2539 | AVC_AUDIT_DATA_INIT(&ad, FS); | 2545 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 2540 | ad.u.fs.path.dentry = dentry->d_sb->s_root; | 2546 | ad.u.fs.path.dentry = dentry->d_sb->s_root; |
| 2541 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); | 2547 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); |
| 2542 | } | 2548 | } |
| @@ -2711,12 +2717,18 @@ static int selinux_inode_permission(struct inode *inode, int mask) | |||
| 2711 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 2717 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) |
| 2712 | { | 2718 | { |
| 2713 | const struct cred *cred = current_cred(); | 2719 | const struct cred *cred = current_cred(); |
| 2720 | unsigned int ia_valid = iattr->ia_valid; | ||
| 2721 | |||
| 2722 | /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ | ||
| 2723 | if (ia_valid & ATTR_FORCE) { | ||
| 2724 | ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE | | ||
| 2725 | ATTR_FORCE); | ||
| 2726 | if (!ia_valid) | ||
| 2727 | return 0; | ||
| 2728 | } | ||
| 2714 | 2729 | ||
| 2715 | if (iattr->ia_valid & ATTR_FORCE) | 2730 | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | |
| 2716 | return 0; | 2731 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) |
| 2717 | |||
| 2718 | if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | | ||
| 2719 | ATTR_ATIME_SET | ATTR_MTIME_SET)) | ||
| 2720 | return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); | 2732 | return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR); |
| 2721 | 2733 | ||
| 2722 | return dentry_has_perm(cred, NULL, dentry, FILE__WRITE); | 2734 | return dentry_has_perm(cred, NULL, dentry, FILE__WRITE); |
| @@ -2756,7 +2768,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
| 2756 | struct inode *inode = dentry->d_inode; | 2768 | struct inode *inode = dentry->d_inode; |
| 2757 | struct inode_security_struct *isec = inode->i_security; | 2769 | struct inode_security_struct *isec = inode->i_security; |
| 2758 | struct superblock_security_struct *sbsec; | 2770 | struct superblock_security_struct *sbsec; |
| 2759 | struct avc_audit_data ad; | 2771 | struct common_audit_data ad; |
| 2760 | u32 newsid, sid = current_sid(); | 2772 | u32 newsid, sid = current_sid(); |
| 2761 | int rc = 0; | 2773 | int rc = 0; |
| 2762 | 2774 | ||
| @@ -2770,7 +2782,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
| 2770 | if (!is_owner_or_cap(inode)) | 2782 | if (!is_owner_or_cap(inode)) |
| 2771 | return -EPERM; | 2783 | return -EPERM; |
| 2772 | 2784 | ||
| 2773 | AVC_AUDIT_DATA_INIT(&ad, FS); | 2785 | COMMON_AUDIT_DATA_INIT(&ad, FS); |
| 2774 | ad.u.fs.path.dentry = dentry; | 2786 | ad.u.fs.path.dentry = dentry; |
| 2775 | 2787 | ||
| 2776 | rc = avc_has_perm(sid, isec->sid, isec->sclass, | 2788 | rc = avc_has_perm(sid, isec->sid, isec->sclass, |
| @@ -2915,6 +2927,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, | |||
| 2915 | return rc; | 2927 | return rc; |
| 2916 | 2928 | ||
| 2917 | isec->sid = newsid; | 2929 | isec->sid = newsid; |
| 2930 | isec->initialized = 1; | ||
| 2918 | return 0; | 2931 | return 0; |
| 2919 | } | 2932 | } |
| 2920 | 2933 | ||
| @@ -2939,11 +2952,6 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) | |||
| 2939 | const struct cred *cred = current_cred(); | 2952 | const struct cred *cred = current_cred(); |
| 2940 | struct inode *inode = file->f_path.dentry->d_inode; | 2953 | struct inode *inode = file->f_path.dentry->d_inode; |
| 2941 | 2954 | ||
| 2942 | if (!mask) { | ||
| 2943 | /* No permission to check. Existence test. */ | ||
| 2944 | return 0; | ||
| 2945 | } | ||
| 2946 | |||
| 2947 | /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */ | 2955 | /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */ |
| 2948 | if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) | 2956 | if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) |
| 2949 | mask |= MAY_APPEND; | 2957 | mask |= MAY_APPEND; |
| @@ -2954,10 +2962,20 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) | |||
| 2954 | 2962 | ||
| 2955 | static int selinux_file_permission(struct file *file, int mask) | 2963 | static int selinux_file_permission(struct file *file, int mask) |
| 2956 | { | 2964 | { |
| 2965 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 2966 | struct file_security_struct *fsec = file->f_security; | ||
| 2967 | struct inode_security_struct *isec = inode->i_security; | ||
| 2968 | u32 sid = current_sid(); | ||
| 2969 | |||
| 2957 | if (!mask) | 2970 | if (!mask) |
| 2958 | /* No permission to check. Existence test. */ | 2971 | /* No permission to check. Existence test. */ |
| 2959 | return 0; | 2972 | return 0; |
| 2960 | 2973 | ||
| 2974 | if (sid == fsec->sid && fsec->isid == isec->sid && | ||
| 2975 | fsec->pseqno == avc_policy_seqno()) | ||
| 2976 | /* No change since dentry_open check. */ | ||
| 2977 | return 0; | ||
| 2978 | |||
| 2961 | return selinux_revalidate_file_permission(file, mask); | 2979 | return selinux_revalidate_file_permission(file, mask); |
| 2962 | } | 2980 | } |
| 2963 | 2981 | ||
| @@ -3220,12 +3238,29 @@ static int selinux_task_create(unsigned long clone_flags) | |||
| 3220 | } | 3238 | } |
| 3221 | 3239 | ||
| 3222 | /* | 3240 | /* |
| 3241 | * allocate the SELinux part of blank credentials | ||
| 3242 | */ | ||
| 3243 | static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 3244 | { | ||
| 3245 | struct task_security_struct *tsec; | ||
| 3246 | |||
| 3247 | tsec = kzalloc(sizeof(struct task_security_struct), gfp); | ||
| 3248 | if (!tsec) | ||
| 3249 | return -ENOMEM; | ||
| 3250 | |||
| 3251 | cred->security = tsec; | ||
| 3252 | return 0; | ||
| 3253 | } | ||
| 3254 | |||
| 3255 | /* | ||
| 3223 | * detach and free the LSM part of a set of credentials | 3256 | * detach and free the LSM part of a set of credentials |
| 3224 | */ | 3257 | */ |
| 3225 | static void selinux_cred_free(struct cred *cred) | 3258 | static void selinux_cred_free(struct cred *cred) |
| 3226 | { | 3259 | { |
| 3227 | struct task_security_struct *tsec = cred->security; | 3260 | struct task_security_struct *tsec = cred->security; |
| 3228 | cred->security = NULL; | 3261 | |
| 3262 | BUG_ON((unsigned long) cred->security < PAGE_SIZE); | ||
| 3263 | cred->security = (void *) 0x7UL; | ||
| 3229 | kfree(tsec); | 3264 | kfree(tsec); |
| 3230 | } | 3265 | } |
| 3231 | 3266 | ||
| @@ -3249,6 +3284,17 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old, | |||
| 3249 | } | 3284 | } |
| 3250 | 3285 | ||
| 3251 | /* | 3286 | /* |
| 3287 | * transfer the SELinux data to a blank set of creds | ||
| 3288 | */ | ||
| 3289 | static void selinux_cred_transfer(struct cred *new, const struct cred *old) | ||
| 3290 | { | ||
| 3291 | const struct task_security_struct *old_tsec = old->security; | ||
| 3292 | struct task_security_struct *tsec = new->security; | ||
| 3293 | |||
| 3294 | *tsec = *old_tsec; | ||
| 3295 | } | ||
| 3296 | |||
| 3297 | /* | ||
| 3252 | * set the security data for a kernel service | 3298 | * set the security data for a kernel service |
| 3253 | * - all the creation contexts are set to unlabelled | 3299 | * - all the creation contexts are set to unlabelled |
| 3254 | */ | 3300 | */ |
| @@ -3292,6 +3338,11 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
| 3292 | return 0; | 3338 | return 0; |
| 3293 | } | 3339 | } |
| 3294 | 3340 | ||
| 3341 | static int selinux_kernel_module_request(void) | ||
| 3342 | { | ||
| 3343 | return task_has_system(current, SYSTEM__MODULE_REQUEST); | ||
| 3344 | } | ||
| 3345 | |||
| 3295 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) | 3346 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) |
| 3296 | { | 3347 | { |
| 3297 | return current_has_perm(p, PROCESS__SETPGID); | 3348 | return current_has_perm(p, PROCESS__SETPGID); |
| @@ -3409,7 +3460,7 @@ static void selinux_task_to_inode(struct task_struct *p, | |||
| 3409 | 3460 | ||
| 3410 | /* Returns error only if unable to parse addresses */ | 3461 | /* Returns error only if unable to parse addresses */ |
| 3411 | static int selinux_parse_skb_ipv4(struct sk_buff *skb, | 3462 | static int selinux_parse_skb_ipv4(struct sk_buff *skb, |
| 3412 | struct avc_audit_data *ad, u8 *proto) | 3463 | struct common_audit_data *ad, u8 *proto) |
| 3413 | { | 3464 | { |
| 3414 | int offset, ihlen, ret = -EINVAL; | 3465 | int offset, ihlen, ret = -EINVAL; |
| 3415 | struct iphdr _iph, *ih; | 3466 | struct iphdr _iph, *ih; |
| @@ -3490,7 +3541,7 @@ out: | |||
| 3490 | 3541 | ||
| 3491 | /* Returns error only if unable to parse addresses */ | 3542 | /* Returns error only if unable to parse addresses */ |
| 3492 | static int selinux_parse_skb_ipv6(struct sk_buff *skb, | 3543 | static int selinux_parse_skb_ipv6(struct sk_buff *skb, |
| 3493 | struct avc_audit_data *ad, u8 *proto) | 3544 | struct common_audit_data *ad, u8 *proto) |
| 3494 | { | 3545 | { |
| 3495 | u8 nexthdr; | 3546 | u8 nexthdr; |
| 3496 | int ret = -EINVAL, offset; | 3547 | int ret = -EINVAL, offset; |
| @@ -3561,7 +3612,7 @@ out: | |||
| 3561 | 3612 | ||
| 3562 | #endif /* IPV6 */ | 3613 | #endif /* IPV6 */ |
| 3563 | 3614 | ||
| 3564 | static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | 3615 | static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad, |
| 3565 | char **_addrp, int src, u8 *proto) | 3616 | char **_addrp, int src, u8 *proto) |
| 3566 | { | 3617 | { |
| 3567 | char *addrp; | 3618 | char *addrp; |
| @@ -3643,7 +3694,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, | |||
| 3643 | u32 perms) | 3694 | u32 perms) |
| 3644 | { | 3695 | { |
| 3645 | struct inode_security_struct *isec; | 3696 | struct inode_security_struct *isec; |
| 3646 | struct avc_audit_data ad; | 3697 | struct common_audit_data ad; |
| 3647 | u32 sid; | 3698 | u32 sid; |
| 3648 | int err = 0; | 3699 | int err = 0; |
| 3649 | 3700 | ||
| @@ -3653,7 +3704,7 @@ static int socket_has_perm(struct task_struct *task, struct socket *sock, | |||
| 3653 | goto out; | 3704 | goto out; |
| 3654 | sid = task_sid(task); | 3705 | sid = task_sid(task); |
| 3655 | 3706 | ||
| 3656 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3707 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3657 | ad.u.net.sk = sock->sk; | 3708 | ad.u.net.sk = sock->sk; |
| 3658 | err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); | 3709 | err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); |
| 3659 | 3710 | ||
| @@ -3740,7 +3791,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
| 3740 | if (family == PF_INET || family == PF_INET6) { | 3791 | if (family == PF_INET || family == PF_INET6) { |
| 3741 | char *addrp; | 3792 | char *addrp; |
| 3742 | struct inode_security_struct *isec; | 3793 | struct inode_security_struct *isec; |
| 3743 | struct avc_audit_data ad; | 3794 | struct common_audit_data ad; |
| 3744 | struct sockaddr_in *addr4 = NULL; | 3795 | struct sockaddr_in *addr4 = NULL; |
| 3745 | struct sockaddr_in6 *addr6 = NULL; | 3796 | struct sockaddr_in6 *addr6 = NULL; |
| 3746 | unsigned short snum; | 3797 | unsigned short snum; |
| @@ -3769,7 +3820,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
| 3769 | snum, &sid); | 3820 | snum, &sid); |
| 3770 | if (err) | 3821 | if (err) |
| 3771 | goto out; | 3822 | goto out; |
| 3772 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3823 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3773 | ad.u.net.sport = htons(snum); | 3824 | ad.u.net.sport = htons(snum); |
| 3774 | ad.u.net.family = family; | 3825 | ad.u.net.family = family; |
| 3775 | err = avc_has_perm(isec->sid, sid, | 3826 | err = avc_has_perm(isec->sid, sid, |
| @@ -3802,7 +3853,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
| 3802 | if (err) | 3853 | if (err) |
| 3803 | goto out; | 3854 | goto out; |
| 3804 | 3855 | ||
| 3805 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3856 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3806 | ad.u.net.sport = htons(snum); | 3857 | ad.u.net.sport = htons(snum); |
| 3807 | ad.u.net.family = family; | 3858 | ad.u.net.family = family; |
| 3808 | 3859 | ||
| @@ -3836,7 +3887,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 3836 | isec = SOCK_INODE(sock)->i_security; | 3887 | isec = SOCK_INODE(sock)->i_security; |
| 3837 | if (isec->sclass == SECCLASS_TCP_SOCKET || | 3888 | if (isec->sclass == SECCLASS_TCP_SOCKET || |
| 3838 | isec->sclass == SECCLASS_DCCP_SOCKET) { | 3889 | isec->sclass == SECCLASS_DCCP_SOCKET) { |
| 3839 | struct avc_audit_data ad; | 3890 | struct common_audit_data ad; |
| 3840 | struct sockaddr_in *addr4 = NULL; | 3891 | struct sockaddr_in *addr4 = NULL; |
| 3841 | struct sockaddr_in6 *addr6 = NULL; | 3892 | struct sockaddr_in6 *addr6 = NULL; |
| 3842 | unsigned short snum; | 3893 | unsigned short snum; |
| @@ -3861,7 +3912,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
| 3861 | perm = (isec->sclass == SECCLASS_TCP_SOCKET) ? | 3912 | perm = (isec->sclass == SECCLASS_TCP_SOCKET) ? |
| 3862 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; | 3913 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; |
| 3863 | 3914 | ||
| 3864 | AVC_AUDIT_DATA_INIT(&ad, NET); | 3915 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3865 | ad.u.net.dport = htons(snum); | 3916 | ad.u.net.dport = htons(snum); |
| 3866 | ad.u.net.family = sk->sk_family; | 3917 | ad.u.net.family = sk->sk_family; |
| 3867 | err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad); | 3918 | 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, | |||
| 3951 | struct sk_security_struct *ssec; | 4002 | struct sk_security_struct *ssec; |
| 3952 | struct inode_security_struct *isec; | 4003 | struct inode_security_struct *isec; |
| 3953 | struct inode_security_struct *other_isec; | 4004 | struct inode_security_struct *other_isec; |
| 3954 | struct avc_audit_data ad; | 4005 | struct common_audit_data ad; |
| 3955 | int err; | 4006 | int err; |
| 3956 | 4007 | ||
| 3957 | isec = SOCK_INODE(sock)->i_security; | 4008 | isec = SOCK_INODE(sock)->i_security; |
| 3958 | other_isec = SOCK_INODE(other)->i_security; | 4009 | other_isec = SOCK_INODE(other)->i_security; |
| 3959 | 4010 | ||
| 3960 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4011 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3961 | ad.u.net.sk = other->sk; | 4012 | ad.u.net.sk = other->sk; |
| 3962 | 4013 | ||
| 3963 | err = avc_has_perm(isec->sid, other_isec->sid, | 4014 | err = avc_has_perm(isec->sid, other_isec->sid, |
| @@ -3983,13 +4034,13 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
| 3983 | { | 4034 | { |
| 3984 | struct inode_security_struct *isec; | 4035 | struct inode_security_struct *isec; |
| 3985 | struct inode_security_struct *other_isec; | 4036 | struct inode_security_struct *other_isec; |
| 3986 | struct avc_audit_data ad; | 4037 | struct common_audit_data ad; |
| 3987 | int err; | 4038 | int err; |
| 3988 | 4039 | ||
| 3989 | isec = SOCK_INODE(sock)->i_security; | 4040 | isec = SOCK_INODE(sock)->i_security; |
| 3990 | other_isec = SOCK_INODE(other)->i_security; | 4041 | other_isec = SOCK_INODE(other)->i_security; |
| 3991 | 4042 | ||
| 3992 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4043 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 3993 | ad.u.net.sk = other->sk; | 4044 | ad.u.net.sk = other->sk; |
| 3994 | 4045 | ||
| 3995 | err = avc_has_perm(isec->sid, other_isec->sid, | 4046 | err = avc_has_perm(isec->sid, other_isec->sid, |
| @@ -4002,7 +4053,7 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
| 4002 | 4053 | ||
| 4003 | static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, | 4054 | static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, |
| 4004 | u32 peer_sid, | 4055 | u32 peer_sid, |
| 4005 | struct avc_audit_data *ad) | 4056 | struct common_audit_data *ad) |
| 4006 | { | 4057 | { |
| 4007 | int err; | 4058 | int err; |
| 4008 | u32 if_sid; | 4059 | u32 if_sid; |
| @@ -4030,10 +4081,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
| 4030 | struct sk_security_struct *sksec = sk->sk_security; | 4081 | struct sk_security_struct *sksec = sk->sk_security; |
| 4031 | u32 peer_sid; | 4082 | u32 peer_sid; |
| 4032 | u32 sk_sid = sksec->sid; | 4083 | u32 sk_sid = sksec->sid; |
| 4033 | struct avc_audit_data ad; | 4084 | struct common_audit_data ad; |
| 4034 | char *addrp; | 4085 | char *addrp; |
| 4035 | 4086 | ||
| 4036 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4087 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 4037 | ad.u.net.netif = skb->iif; | 4088 | ad.u.net.netif = skb->iif; |
| 4038 | ad.u.net.family = family; | 4089 | ad.u.net.family = family; |
| 4039 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); | 4090 | 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) | |||
| 4071 | struct sk_security_struct *sksec = sk->sk_security; | 4122 | struct sk_security_struct *sksec = sk->sk_security; |
| 4072 | u16 family = sk->sk_family; | 4123 | u16 family = sk->sk_family; |
| 4073 | u32 sk_sid = sksec->sid; | 4124 | u32 sk_sid = sksec->sid; |
| 4074 | struct avc_audit_data ad; | 4125 | struct common_audit_data ad; |
| 4075 | char *addrp; | 4126 | char *addrp; |
| 4076 | u8 secmark_active; | 4127 | u8 secmark_active; |
| 4077 | u8 peerlbl_active; | 4128 | u8 peerlbl_active; |
| @@ -4095,7 +4146,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4095 | if (!secmark_active && !peerlbl_active) | 4146 | if (!secmark_active && !peerlbl_active) |
| 4096 | return 0; | 4147 | return 0; |
| 4097 | 4148 | ||
| 4098 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4149 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 4099 | ad.u.net.netif = skb->iif; | 4150 | ad.u.net.netif = skb->iif; |
| 4100 | ad.u.net.family = family; | 4151 | ad.u.net.family = family; |
| 4101 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); | 4152 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); |
| @@ -4309,6 +4360,59 @@ static void selinux_req_classify_flow(const struct request_sock *req, | |||
| 4309 | fl->secid = req->secid; | 4360 | fl->secid = req->secid; |
| 4310 | } | 4361 | } |
| 4311 | 4362 | ||
| 4363 | static int selinux_tun_dev_create(void) | ||
| 4364 | { | ||
| 4365 | u32 sid = current_sid(); | ||
| 4366 | |||
| 4367 | /* we aren't taking into account the "sockcreate" SID since the socket | ||
| 4368 | * that is being created here is not a socket in the traditional sense, | ||
| 4369 | * instead it is a private sock, accessible only to the kernel, and | ||
| 4370 | * representing a wide range of network traffic spanning multiple | ||
| 4371 | * connections unlike traditional sockets - check the TUN driver to | ||
| 4372 | * get a better understanding of why this socket is special */ | ||
| 4373 | |||
| 4374 | return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE, | ||
| 4375 | NULL); | ||
| 4376 | } | ||
| 4377 | |||
| 4378 | static void selinux_tun_dev_post_create(struct sock *sk) | ||
| 4379 | { | ||
| 4380 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 4381 | |||
| 4382 | /* we don't currently perform any NetLabel based labeling here and it | ||
| 4383 | * isn't clear that we would want to do so anyway; while we could apply | ||
| 4384 | * labeling without the support of the TUN user the resulting labeled | ||
| 4385 | * traffic from the other end of the connection would almost certainly | ||
| 4386 | * cause confusion to the TUN user that had no idea network labeling | ||
| 4387 | * protocols were being used */ | ||
| 4388 | |||
| 4389 | /* see the comments in selinux_tun_dev_create() about why we don't use | ||
| 4390 | * the sockcreate SID here */ | ||
| 4391 | |||
| 4392 | sksec->sid = current_sid(); | ||
| 4393 | sksec->sclass = SECCLASS_TUN_SOCKET; | ||
| 4394 | } | ||
| 4395 | |||
| 4396 | static int selinux_tun_dev_attach(struct sock *sk) | ||
| 4397 | { | ||
| 4398 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 4399 | u32 sid = current_sid(); | ||
| 4400 | int err; | ||
| 4401 | |||
| 4402 | err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET, | ||
| 4403 | TUN_SOCKET__RELABELFROM, NULL); | ||
| 4404 | if (err) | ||
| 4405 | return err; | ||
| 4406 | err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, | ||
| 4407 | TUN_SOCKET__RELABELTO, NULL); | ||
| 4408 | if (err) | ||
| 4409 | return err; | ||
| 4410 | |||
| 4411 | sksec->sid = sid; | ||
| 4412 | |||
| 4413 | return 0; | ||
| 4414 | } | ||
| 4415 | |||
| 4312 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) | 4416 | static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) |
| 4313 | { | 4417 | { |
| 4314 | int err = 0; | 4418 | int err = 0; |
| @@ -4353,7 +4457,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
| 4353 | int err; | 4457 | int err; |
| 4354 | char *addrp; | 4458 | char *addrp; |
| 4355 | u32 peer_sid; | 4459 | u32 peer_sid; |
| 4356 | struct avc_audit_data ad; | 4460 | struct common_audit_data ad; |
| 4357 | u8 secmark_active; | 4461 | u8 secmark_active; |
| 4358 | u8 netlbl_active; | 4462 | u8 netlbl_active; |
| 4359 | u8 peerlbl_active; | 4463 | u8 peerlbl_active; |
| @@ -4370,7 +4474,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
| 4370 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | 4474 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) |
| 4371 | return NF_DROP; | 4475 | return NF_DROP; |
| 4372 | 4476 | ||
| 4373 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4477 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 4374 | ad.u.net.netif = ifindex; | 4478 | ad.u.net.netif = ifindex; |
| 4375 | ad.u.net.family = family; | 4479 | ad.u.net.family = family; |
| 4376 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) | 4480 | 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, | |||
| 4458 | { | 4562 | { |
| 4459 | struct sock *sk = skb->sk; | 4563 | struct sock *sk = skb->sk; |
| 4460 | struct sk_security_struct *sksec; | 4564 | struct sk_security_struct *sksec; |
| 4461 | struct avc_audit_data ad; | 4565 | struct common_audit_data ad; |
| 4462 | char *addrp; | 4566 | char *addrp; |
| 4463 | u8 proto; | 4567 | u8 proto; |
| 4464 | 4568 | ||
| @@ -4466,7 +4570,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
| 4466 | return NF_ACCEPT; | 4570 | return NF_ACCEPT; |
| 4467 | sksec = sk->sk_security; | 4571 | sksec = sk->sk_security; |
| 4468 | 4572 | ||
| 4469 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4573 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 4470 | ad.u.net.netif = ifindex; | 4574 | ad.u.net.netif = ifindex; |
| 4471 | ad.u.net.family = family; | 4575 | ad.u.net.family = family; |
| 4472 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | 4576 | 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, | |||
| 4490 | u32 secmark_perm; | 4594 | u32 secmark_perm; |
| 4491 | u32 peer_sid; | 4595 | u32 peer_sid; |
| 4492 | struct sock *sk; | 4596 | struct sock *sk; |
| 4493 | struct avc_audit_data ad; | 4597 | struct common_audit_data ad; |
| 4494 | char *addrp; | 4598 | char *addrp; |
| 4495 | u8 secmark_active; | 4599 | u8 secmark_active; |
| 4496 | u8 peerlbl_active; | 4600 | u8 peerlbl_active; |
| @@ -4549,7 +4653,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4549 | secmark_perm = PACKET__SEND; | 4653 | secmark_perm = PACKET__SEND; |
| 4550 | } | 4654 | } |
| 4551 | 4655 | ||
| 4552 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4656 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
| 4553 | ad.u.net.netif = ifindex; | 4657 | ad.u.net.netif = ifindex; |
| 4554 | ad.u.net.family = family; | 4658 | ad.u.net.family = family; |
| 4555 | if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) | 4659 | 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) | |||
| 4619 | static int selinux_netlink_recv(struct sk_buff *skb, int capability) | 4723 | static int selinux_netlink_recv(struct sk_buff *skb, int capability) |
| 4620 | { | 4724 | { |
| 4621 | int err; | 4725 | int err; |
| 4622 | struct avc_audit_data ad; | 4726 | struct common_audit_data ad; |
| 4623 | 4727 | ||
| 4624 | err = cap_netlink_recv(skb, capability); | 4728 | err = cap_netlink_recv(skb, capability); |
| 4625 | if (err) | 4729 | if (err) |
| 4626 | return err; | 4730 | return err; |
| 4627 | 4731 | ||
| 4628 | AVC_AUDIT_DATA_INIT(&ad, CAP); | 4732 | COMMON_AUDIT_DATA_INIT(&ad, CAP); |
| 4629 | ad.u.cap = capability; | 4733 | ad.u.cap = capability; |
| 4630 | 4734 | ||
| 4631 | return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, | 4735 | 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, | |||
| 4684 | u32 perms) | 4788 | u32 perms) |
| 4685 | { | 4789 | { |
| 4686 | struct ipc_security_struct *isec; | 4790 | struct ipc_security_struct *isec; |
| 4687 | struct avc_audit_data ad; | 4791 | struct common_audit_data ad; |
| 4688 | u32 sid = current_sid(); | 4792 | u32 sid = current_sid(); |
| 4689 | 4793 | ||
| 4690 | isec = ipc_perms->security; | 4794 | isec = ipc_perms->security; |
| 4691 | 4795 | ||
| 4692 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4796 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4693 | ad.u.ipc_id = ipc_perms->key; | 4797 | ad.u.ipc_id = ipc_perms->key; |
| 4694 | 4798 | ||
| 4695 | return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); | 4799 | 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) | |||
| 4709 | static int selinux_msg_queue_alloc_security(struct msg_queue *msq) | 4813 | static int selinux_msg_queue_alloc_security(struct msg_queue *msq) |
| 4710 | { | 4814 | { |
| 4711 | struct ipc_security_struct *isec; | 4815 | struct ipc_security_struct *isec; |
| 4712 | struct avc_audit_data ad; | 4816 | struct common_audit_data ad; |
| 4713 | u32 sid = current_sid(); | 4817 | u32 sid = current_sid(); |
| 4714 | int rc; | 4818 | int rc; |
| 4715 | 4819 | ||
| @@ -4719,7 +4823,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) | |||
| 4719 | 4823 | ||
| 4720 | isec = msq->q_perm.security; | 4824 | isec = msq->q_perm.security; |
| 4721 | 4825 | ||
| 4722 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4826 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4723 | ad.u.ipc_id = msq->q_perm.key; | 4827 | ad.u.ipc_id = msq->q_perm.key; |
| 4724 | 4828 | ||
| 4725 | rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, | 4829 | rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, |
| @@ -4739,12 +4843,12 @@ static void selinux_msg_queue_free_security(struct msg_queue *msq) | |||
| 4739 | static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) | 4843 | static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) |
| 4740 | { | 4844 | { |
| 4741 | struct ipc_security_struct *isec; | 4845 | struct ipc_security_struct *isec; |
| 4742 | struct avc_audit_data ad; | 4846 | struct common_audit_data ad; |
| 4743 | u32 sid = current_sid(); | 4847 | u32 sid = current_sid(); |
| 4744 | 4848 | ||
| 4745 | isec = msq->q_perm.security; | 4849 | isec = msq->q_perm.security; |
| 4746 | 4850 | ||
| 4747 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4851 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4748 | ad.u.ipc_id = msq->q_perm.key; | 4852 | ad.u.ipc_id = msq->q_perm.key; |
| 4749 | 4853 | ||
| 4750 | return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, | 4854 | 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, | |||
| 4783 | { | 4887 | { |
| 4784 | struct ipc_security_struct *isec; | 4888 | struct ipc_security_struct *isec; |
| 4785 | struct msg_security_struct *msec; | 4889 | struct msg_security_struct *msec; |
| 4786 | struct avc_audit_data ad; | 4890 | struct common_audit_data ad; |
| 4787 | u32 sid = current_sid(); | 4891 | u32 sid = current_sid(); |
| 4788 | int rc; | 4892 | int rc; |
| 4789 | 4893 | ||
| @@ -4804,7 +4908,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | |||
| 4804 | return rc; | 4908 | return rc; |
| 4805 | } | 4909 | } |
| 4806 | 4910 | ||
| 4807 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4911 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4808 | ad.u.ipc_id = msq->q_perm.key; | 4912 | ad.u.ipc_id = msq->q_perm.key; |
| 4809 | 4913 | ||
| 4810 | /* Can this process write to the queue? */ | 4914 | /* 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, | |||
| 4828 | { | 4932 | { |
| 4829 | struct ipc_security_struct *isec; | 4933 | struct ipc_security_struct *isec; |
| 4830 | struct msg_security_struct *msec; | 4934 | struct msg_security_struct *msec; |
| 4831 | struct avc_audit_data ad; | 4935 | struct common_audit_data ad; |
| 4832 | u32 sid = task_sid(target); | 4936 | u32 sid = task_sid(target); |
| 4833 | int rc; | 4937 | int rc; |
| 4834 | 4938 | ||
| 4835 | isec = msq->q_perm.security; | 4939 | isec = msq->q_perm.security; |
| 4836 | msec = msg->security; | 4940 | msec = msg->security; |
| 4837 | 4941 | ||
| 4838 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4942 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4839 | ad.u.ipc_id = msq->q_perm.key; | 4943 | ad.u.ipc_id = msq->q_perm.key; |
| 4840 | 4944 | ||
| 4841 | rc = avc_has_perm(sid, isec->sid, | 4945 | 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, | |||
| 4850 | static int selinux_shm_alloc_security(struct shmid_kernel *shp) | 4954 | static int selinux_shm_alloc_security(struct shmid_kernel *shp) |
| 4851 | { | 4955 | { |
| 4852 | struct ipc_security_struct *isec; | 4956 | struct ipc_security_struct *isec; |
| 4853 | struct avc_audit_data ad; | 4957 | struct common_audit_data ad; |
| 4854 | u32 sid = current_sid(); | 4958 | u32 sid = current_sid(); |
| 4855 | int rc; | 4959 | int rc; |
| 4856 | 4960 | ||
| @@ -4860,7 +4964,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) | |||
| 4860 | 4964 | ||
| 4861 | isec = shp->shm_perm.security; | 4965 | isec = shp->shm_perm.security; |
| 4862 | 4966 | ||
| 4863 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4967 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4864 | ad.u.ipc_id = shp->shm_perm.key; | 4968 | ad.u.ipc_id = shp->shm_perm.key; |
| 4865 | 4969 | ||
| 4866 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, | 4970 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, |
| @@ -4880,12 +4984,12 @@ static void selinux_shm_free_security(struct shmid_kernel *shp) | |||
| 4880 | static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) | 4984 | static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) |
| 4881 | { | 4985 | { |
| 4882 | struct ipc_security_struct *isec; | 4986 | struct ipc_security_struct *isec; |
| 4883 | struct avc_audit_data ad; | 4987 | struct common_audit_data ad; |
| 4884 | u32 sid = current_sid(); | 4988 | u32 sid = current_sid(); |
| 4885 | 4989 | ||
| 4886 | isec = shp->shm_perm.security; | 4990 | isec = shp->shm_perm.security; |
| 4887 | 4991 | ||
| 4888 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 4992 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4889 | ad.u.ipc_id = shp->shm_perm.key; | 4993 | ad.u.ipc_id = shp->shm_perm.key; |
| 4890 | 4994 | ||
| 4891 | return avc_has_perm(sid, isec->sid, SECCLASS_SHM, | 4995 | return avc_has_perm(sid, isec->sid, SECCLASS_SHM, |
| @@ -4942,7 +5046,7 @@ static int selinux_shm_shmat(struct shmid_kernel *shp, | |||
| 4942 | static int selinux_sem_alloc_security(struct sem_array *sma) | 5046 | static int selinux_sem_alloc_security(struct sem_array *sma) |
| 4943 | { | 5047 | { |
| 4944 | struct ipc_security_struct *isec; | 5048 | struct ipc_security_struct *isec; |
| 4945 | struct avc_audit_data ad; | 5049 | struct common_audit_data ad; |
| 4946 | u32 sid = current_sid(); | 5050 | u32 sid = current_sid(); |
| 4947 | int rc; | 5051 | int rc; |
| 4948 | 5052 | ||
| @@ -4952,7 +5056,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) | |||
| 4952 | 5056 | ||
| 4953 | isec = sma->sem_perm.security; | 5057 | isec = sma->sem_perm.security; |
| 4954 | 5058 | ||
| 4955 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 5059 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4956 | ad.u.ipc_id = sma->sem_perm.key; | 5060 | ad.u.ipc_id = sma->sem_perm.key; |
| 4957 | 5061 | ||
| 4958 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, | 5062 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, |
| @@ -4972,12 +5076,12 @@ static void selinux_sem_free_security(struct sem_array *sma) | |||
| 4972 | static int selinux_sem_associate(struct sem_array *sma, int semflg) | 5076 | static int selinux_sem_associate(struct sem_array *sma, int semflg) |
| 4973 | { | 5077 | { |
| 4974 | struct ipc_security_struct *isec; | 5078 | struct ipc_security_struct *isec; |
| 4975 | struct avc_audit_data ad; | 5079 | struct common_audit_data ad; |
| 4976 | u32 sid = current_sid(); | 5080 | u32 sid = current_sid(); |
| 4977 | 5081 | ||
| 4978 | isec = sma->sem_perm.security; | 5082 | isec = sma->sem_perm.security; |
| 4979 | 5083 | ||
| 4980 | AVC_AUDIT_DATA_INIT(&ad, IPC); | 5084 | COMMON_AUDIT_DATA_INIT(&ad, IPC); |
| 4981 | ad.u.ipc_id = sma->sem_perm.key; | 5085 | ad.u.ipc_id = sma->sem_perm.key; |
| 4982 | 5086 | ||
| 4983 | return avc_has_perm(sid, isec->sid, SECCLASS_SEM, | 5087 | return avc_has_perm(sid, isec->sid, SECCLASS_SEM, |
| @@ -5195,7 +5299,7 @@ static int selinux_setprocattr(struct task_struct *p, | |||
| 5195 | 5299 | ||
| 5196 | /* Only allow single threaded processes to change context */ | 5300 | /* Only allow single threaded processes to change context */ |
| 5197 | error = -EPERM; | 5301 | error = -EPERM; |
| 5198 | if (!is_single_threaded(p)) { | 5302 | if (!current_is_single_threaded()) { |
| 5199 | error = security_bounded_transition(tsec->sid, sid); | 5303 | error = security_bounded_transition(tsec->sid, sid); |
| 5200 | if (error) | 5304 | if (error) |
| 5201 | goto abort_change; | 5305 | goto abort_change; |
| @@ -5252,6 +5356,32 @@ static void selinux_release_secctx(char *secdata, u32 seclen) | |||
| 5252 | kfree(secdata); | 5356 | kfree(secdata); |
| 5253 | } | 5357 | } |
| 5254 | 5358 | ||
| 5359 | /* | ||
| 5360 | * called with inode->i_mutex locked | ||
| 5361 | */ | ||
| 5362 | static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) | ||
| 5363 | { | ||
| 5364 | return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0); | ||
| 5365 | } | ||
| 5366 | |||
| 5367 | /* | ||
| 5368 | * called with inode->i_mutex locked | ||
| 5369 | */ | ||
| 5370 | static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) | ||
| 5371 | { | ||
| 5372 | return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0); | ||
| 5373 | } | ||
| 5374 | |||
| 5375 | static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | ||
| 5376 | { | ||
| 5377 | int len = 0; | ||
| 5378 | len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX, | ||
| 5379 | ctx, true); | ||
| 5380 | if (len < 0) | ||
| 5381 | return len; | ||
| 5382 | *ctxlen = len; | ||
| 5383 | return 0; | ||
| 5384 | } | ||
| 5255 | #ifdef CONFIG_KEYS | 5385 | #ifdef CONFIG_KEYS |
| 5256 | 5386 | ||
| 5257 | static int selinux_key_alloc(struct key *k, const struct cred *cred, | 5387 | 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) | |||
| 5323 | static struct security_operations selinux_ops = { | 5453 | static struct security_operations selinux_ops = { |
| 5324 | .name = "selinux", | 5454 | .name = "selinux", |
| 5325 | 5455 | ||
| 5326 | .ptrace_may_access = selinux_ptrace_may_access, | 5456 | .ptrace_access_check = selinux_ptrace_access_check, |
| 5327 | .ptrace_traceme = selinux_ptrace_traceme, | 5457 | .ptrace_traceme = selinux_ptrace_traceme, |
| 5328 | .capget = selinux_capget, | 5458 | .capget = selinux_capget, |
| 5329 | .capset = selinux_capset, | 5459 | .capset = selinux_capset, |
| @@ -5396,10 +5526,13 @@ static struct security_operations selinux_ops = { | |||
| 5396 | .dentry_open = selinux_dentry_open, | 5526 | .dentry_open = selinux_dentry_open, |
| 5397 | 5527 | ||
| 5398 | .task_create = selinux_task_create, | 5528 | .task_create = selinux_task_create, |
| 5529 | .cred_alloc_blank = selinux_cred_alloc_blank, | ||
| 5399 | .cred_free = selinux_cred_free, | 5530 | .cred_free = selinux_cred_free, |
| 5400 | .cred_prepare = selinux_cred_prepare, | 5531 | .cred_prepare = selinux_cred_prepare, |
| 5532 | .cred_transfer = selinux_cred_transfer, | ||
| 5401 | .kernel_act_as = selinux_kernel_act_as, | 5533 | .kernel_act_as = selinux_kernel_act_as, |
| 5402 | .kernel_create_files_as = selinux_kernel_create_files_as, | 5534 | .kernel_create_files_as = selinux_kernel_create_files_as, |
| 5535 | .kernel_module_request = selinux_kernel_module_request, | ||
| 5403 | .task_setpgid = selinux_task_setpgid, | 5536 | .task_setpgid = selinux_task_setpgid, |
| 5404 | .task_getpgid = selinux_task_getpgid, | 5537 | .task_getpgid = selinux_task_getpgid, |
| 5405 | .task_getsid = selinux_task_getsid, | 5538 | .task_getsid = selinux_task_getsid, |
| @@ -5448,6 +5581,9 @@ static struct security_operations selinux_ops = { | |||
| 5448 | .secid_to_secctx = selinux_secid_to_secctx, | 5581 | .secid_to_secctx = selinux_secid_to_secctx, |
| 5449 | .secctx_to_secid = selinux_secctx_to_secid, | 5582 | .secctx_to_secid = selinux_secctx_to_secid, |
| 5450 | .release_secctx = selinux_release_secctx, | 5583 | .release_secctx = selinux_release_secctx, |
| 5584 | .inode_notifysecctx = selinux_inode_notifysecctx, | ||
| 5585 | .inode_setsecctx = selinux_inode_setsecctx, | ||
| 5586 | .inode_getsecctx = selinux_inode_getsecctx, | ||
| 5451 | 5587 | ||
| 5452 | .unix_stream_connect = selinux_socket_unix_stream_connect, | 5588 | .unix_stream_connect = selinux_socket_unix_stream_connect, |
| 5453 | .unix_may_send = selinux_socket_unix_may_send, | 5589 | .unix_may_send = selinux_socket_unix_may_send, |
| @@ -5477,6 +5613,9 @@ static struct security_operations selinux_ops = { | |||
| 5477 | .inet_csk_clone = selinux_inet_csk_clone, | 5613 | .inet_csk_clone = selinux_inet_csk_clone, |
| 5478 | .inet_conn_established = selinux_inet_conn_established, | 5614 | .inet_conn_established = selinux_inet_conn_established, |
| 5479 | .req_classify_flow = selinux_req_classify_flow, | 5615 | .req_classify_flow = selinux_req_classify_flow, |
| 5616 | .tun_dev_create = selinux_tun_dev_create, | ||
| 5617 | .tun_dev_post_create = selinux_tun_dev_post_create, | ||
| 5618 | .tun_dev_attach = selinux_tun_dev_attach, | ||
| 5480 | 5619 | ||
| 5481 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 5620 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| 5482 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, | 5621 | .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, |
| @@ -5691,6 +5830,9 @@ int selinux_disable(void) | |||
| 5691 | selinux_disabled = 1; | 5830 | selinux_disabled = 1; |
| 5692 | selinux_enabled = 0; | 5831 | selinux_enabled = 0; |
| 5693 | 5832 | ||
| 5833 | /* Try to destroy the avc node cache */ | ||
| 5834 | avc_disable(); | ||
| 5835 | |||
| 5694 | /* Reset security_ops to the secondary module, dummy or capability. */ | 5836 | /* Reset security_ops to the secondary module, dummy or capability. */ |
| 5695 | security_ops = secondary_ops; | 5837 | security_ops = secondary_ops; |
| 5696 | 5838 | ||
diff --git a/security/selinux/include/av_inherit.h b/security/selinux/include/av_inherit.h index 8377a4ba3b95..abedcd704dae 100644 --- a/security/selinux/include/av_inherit.h +++ b/security/selinux/include/av_inherit.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | S_(SECCLASS_KEY_SOCKET, socket, 0x00400000UL) | 15 | S_(SECCLASS_KEY_SOCKET, socket, 0x00400000UL) |
| 16 | S_(SECCLASS_UNIX_STREAM_SOCKET, socket, 0x00400000UL) | 16 | S_(SECCLASS_UNIX_STREAM_SOCKET, socket, 0x00400000UL) |
| 17 | S_(SECCLASS_UNIX_DGRAM_SOCKET, socket, 0x00400000UL) | 17 | S_(SECCLASS_UNIX_DGRAM_SOCKET, socket, 0x00400000UL) |
| 18 | S_(SECCLASS_TUN_SOCKET, socket, 0x00400000UL) | ||
| 18 | S_(SECCLASS_IPC, ipc, 0x00000200UL) | 19 | S_(SECCLASS_IPC, ipc, 0x00000200UL) |
| 19 | S_(SECCLASS_SEM, ipc, 0x00000200UL) | 20 | S_(SECCLASS_SEM, ipc, 0x00000200UL) |
| 20 | S_(SECCLASS_MSGQ, ipc, 0x00000200UL) | 21 | S_(SECCLASS_MSGQ, ipc, 0x00000200UL) |
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index 31df1d7c1aee..2b683ad83d21 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h | |||
| @@ -107,6 +107,7 @@ | |||
| 107 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read") | 107 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read") |
| 108 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod") | 108 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod") |
| 109 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console") | 109 | S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console") |
| 110 | S_(SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, "module_request") | ||
| 110 | S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown") | 111 | S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown") |
| 111 | S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override") | 112 | S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override") |
| 112 | S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search") | 113 | S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search") |
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index d645192ee950..0546d616ccac 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h | |||
| @@ -423,6 +423,28 @@ | |||
| 423 | #define UNIX_DGRAM_SOCKET__RECV_MSG 0x00080000UL | 423 | #define UNIX_DGRAM_SOCKET__RECV_MSG 0x00080000UL |
| 424 | #define UNIX_DGRAM_SOCKET__SEND_MSG 0x00100000UL | 424 | #define UNIX_DGRAM_SOCKET__SEND_MSG 0x00100000UL |
| 425 | #define UNIX_DGRAM_SOCKET__NAME_BIND 0x00200000UL | 425 | #define UNIX_DGRAM_SOCKET__NAME_BIND 0x00200000UL |
| 426 | #define TUN_SOCKET__IOCTL 0x00000001UL | ||
| 427 | #define TUN_SOCKET__READ 0x00000002UL | ||
| 428 | #define TUN_SOCKET__WRITE 0x00000004UL | ||
| 429 | #define TUN_SOCKET__CREATE 0x00000008UL | ||
| 430 | #define TUN_SOCKET__GETATTR 0x00000010UL | ||
| 431 | #define TUN_SOCKET__SETATTR 0x00000020UL | ||
| 432 | #define TUN_SOCKET__LOCK 0x00000040UL | ||
| 433 | #define TUN_SOCKET__RELABELFROM 0x00000080UL | ||
| 434 | #define TUN_SOCKET__RELABELTO 0x00000100UL | ||
| 435 | #define TUN_SOCKET__APPEND 0x00000200UL | ||
| 436 | #define TUN_SOCKET__BIND 0x00000400UL | ||
| 437 | #define TUN_SOCKET__CONNECT 0x00000800UL | ||
| 438 | #define TUN_SOCKET__LISTEN 0x00001000UL | ||
| 439 | #define TUN_SOCKET__ACCEPT 0x00002000UL | ||
| 440 | #define TUN_SOCKET__GETOPT 0x00004000UL | ||
| 441 | #define TUN_SOCKET__SETOPT 0x00008000UL | ||
| 442 | #define TUN_SOCKET__SHUTDOWN 0x00010000UL | ||
| 443 | #define TUN_SOCKET__RECVFROM 0x00020000UL | ||
| 444 | #define TUN_SOCKET__SENDTO 0x00040000UL | ||
| 445 | #define TUN_SOCKET__RECV_MSG 0x00080000UL | ||
| 446 | #define TUN_SOCKET__SEND_MSG 0x00100000UL | ||
| 447 | #define TUN_SOCKET__NAME_BIND 0x00200000UL | ||
| 426 | #define PROCESS__FORK 0x00000001UL | 448 | #define PROCESS__FORK 0x00000001UL |
| 427 | #define PROCESS__TRANSITION 0x00000002UL | 449 | #define PROCESS__TRANSITION 0x00000002UL |
| 428 | #define PROCESS__SIGCHLD 0x00000004UL | 450 | #define PROCESS__SIGCHLD 0x00000004UL |
| @@ -508,6 +530,7 @@ | |||
| 508 | #define SYSTEM__SYSLOG_READ 0x00000002UL | 530 | #define SYSTEM__SYSLOG_READ 0x00000002UL |
| 509 | #define SYSTEM__SYSLOG_MOD 0x00000004UL | 531 | #define SYSTEM__SYSLOG_MOD 0x00000004UL |
| 510 | #define SYSTEM__SYSLOG_CONSOLE 0x00000008UL | 532 | #define SYSTEM__SYSLOG_CONSOLE 0x00000008UL |
| 533 | #define SYSTEM__MODULE_REQUEST 0x00000010UL | ||
| 511 | #define CAPABILITY__CHOWN 0x00000001UL | 534 | #define CAPABILITY__CHOWN 0x00000001UL |
| 512 | #define CAPABILITY__DAC_OVERRIDE 0x00000002UL | 535 | #define CAPABILITY__DAC_OVERRIDE 0x00000002UL |
| 513 | #define CAPABILITY__DAC_READ_SEARCH 0x00000004UL | 536 | #define CAPABILITY__DAC_READ_SEARCH 0x00000004UL |
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index d12ff1a9c0aa..e94e82f73818 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
| 14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 15 | #include <linux/audit.h> | 15 | #include <linux/audit.h> |
| 16 | #include <linux/lsm_audit.h> | ||
| 16 | #include <linux/in6.h> | 17 | #include <linux/in6.h> |
| 17 | #include <linux/path.h> | 18 | #include <linux/path.h> |
| 18 | #include <asm/system.h> | 19 | #include <asm/system.h> |
| @@ -36,48 +37,6 @@ struct inode; | |||
| 36 | struct sock; | 37 | struct sock; |
| 37 | struct sk_buff; | 38 | struct sk_buff; |
| 38 | 39 | ||
| 39 | /* Auxiliary data to use in generating the audit record. */ | ||
| 40 | struct avc_audit_data { | ||
| 41 | char type; | ||
| 42 | #define AVC_AUDIT_DATA_FS 1 | ||
| 43 | #define AVC_AUDIT_DATA_NET 2 | ||
| 44 | #define AVC_AUDIT_DATA_CAP 3 | ||
| 45 | #define AVC_AUDIT_DATA_IPC 4 | ||
| 46 | struct task_struct *tsk; | ||
| 47 | union { | ||
| 48 | struct { | ||
| 49 | struct path path; | ||
| 50 | struct inode *inode; | ||
| 51 | } fs; | ||
| 52 | struct { | ||
| 53 | int netif; | ||
| 54 | struct sock *sk; | ||
| 55 | u16 family; | ||
| 56 | __be16 dport; | ||
| 57 | __be16 sport; | ||
| 58 | union { | ||
| 59 | struct { | ||
| 60 | __be32 daddr; | ||
| 61 | __be32 saddr; | ||
| 62 | } v4; | ||
| 63 | struct { | ||
| 64 | struct in6_addr daddr; | ||
| 65 | struct in6_addr saddr; | ||
| 66 | } v6; | ||
| 67 | } fam; | ||
| 68 | } net; | ||
| 69 | int cap; | ||
| 70 | int ipc_id; | ||
| 71 | } u; | ||
| 72 | }; | ||
| 73 | |||
| 74 | #define v4info fam.v4 | ||
| 75 | #define v6info fam.v6 | ||
| 76 | |||
| 77 | /* Initialize an AVC audit data structure. */ | ||
| 78 | #define AVC_AUDIT_DATA_INIT(_d,_t) \ | ||
| 79 | { memset((_d), 0, sizeof(struct avc_audit_data)); (_d)->type = AVC_AUDIT_DATA_##_t; } | ||
| 80 | |||
| 81 | /* | 40 | /* |
| 82 | * AVC statistics | 41 | * AVC statistics |
| 83 | */ | 42 | */ |
| @@ -98,7 +57,9 @@ void __init avc_init(void); | |||
| 98 | 57 | ||
| 99 | void avc_audit(u32 ssid, u32 tsid, | 58 | void avc_audit(u32 ssid, u32 tsid, |
| 100 | u16 tclass, u32 requested, | 59 | u16 tclass, u32 requested, |
| 101 | struct av_decision *avd, int result, struct avc_audit_data *auditdata); | 60 | struct av_decision *avd, |
| 61 | int result, | ||
| 62 | struct common_audit_data *a); | ||
| 102 | 63 | ||
| 103 | #define AVC_STRICT 1 /* Ignore permissive mode. */ | 64 | #define AVC_STRICT 1 /* Ignore permissive mode. */ |
| 104 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 65 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
| @@ -108,7 +69,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
| 108 | 69 | ||
| 109 | int avc_has_perm(u32 ssid, u32 tsid, | 70 | int avc_has_perm(u32 ssid, u32 tsid, |
| 110 | u16 tclass, u32 requested, | 71 | u16 tclass, u32 requested, |
| 111 | struct avc_audit_data *auditdata); | 72 | struct common_audit_data *auditdata); |
| 112 | 73 | ||
| 113 | u32 avc_policy_seqno(void); | 74 | u32 avc_policy_seqno(void); |
| 114 | 75 | ||
| @@ -127,13 +88,13 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | |||
| 127 | u32 events, u32 ssid, u32 tsid, | 88 | u32 events, u32 ssid, u32 tsid, |
| 128 | u16 tclass, u32 perms); | 89 | u16 tclass, u32 perms); |
| 129 | 90 | ||
| 130 | /* Shows permission in human readable form */ | ||
| 131 | void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av); | ||
| 132 | |||
| 133 | /* Exported to selinuxfs */ | 91 | /* Exported to selinuxfs */ |
| 134 | int avc_get_hash_stats(char *page); | 92 | int avc_get_hash_stats(char *page); |
| 135 | extern unsigned int avc_cache_threshold; | 93 | extern unsigned int avc_cache_threshold; |
| 136 | 94 | ||
| 95 | /* Attempt to free avc node cache */ | ||
| 96 | void avc_disable(void); | ||
| 97 | |||
| 137 | #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS | 98 | #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS |
| 138 | DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats); | 99 | DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats); |
| 139 | #endif | 100 | #endif |
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h index 21ec786611d4..7ab9299bfb6b 100644 --- a/security/selinux/include/class_to_string.h +++ b/security/selinux/include/class_to_string.h | |||
| @@ -77,3 +77,4 @@ | |||
| 77 | S_(NULL) | 77 | S_(NULL) |
| 78 | S_(NULL) | 78 | S_(NULL) |
| 79 | S_("kernel_service") | 79 | S_("kernel_service") |
| 80 | S_("tun_socket") | ||
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h index 882f27d66fac..f248500a1e3c 100644 --- a/security/selinux/include/flask.h +++ b/security/selinux/include/flask.h | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #define SECCLASS_PEER 68 | 53 | #define SECCLASS_PEER 68 |
| 54 | #define SECCLASS_CAPABILITY2 69 | 54 | #define SECCLASS_CAPABILITY2 69 |
| 55 | #define SECCLASS_KERNEL_SERVICE 74 | 55 | #define SECCLASS_KERNEL_SERVICE 74 |
| 56 | #define SECCLASS_TUN_SOCKET 75 | ||
| 56 | 57 | ||
| 57 | /* | 58 | /* |
| 58 | * Security identifier indices for initial entities | 59 | * Security identifier indices for initial entities |
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index b4b5b9b2f0be..8d7384280a7a 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
| @@ -59,7 +59,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); | |||
| 59 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 59 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
| 60 | struct sk_buff *skb, | 60 | struct sk_buff *skb, |
| 61 | u16 family, | 61 | u16 family, |
| 62 | struct avc_audit_data *ad); | 62 | struct common_audit_data *ad); |
| 63 | int selinux_netlbl_socket_setsockopt(struct socket *sock, | 63 | int selinux_netlbl_socket_setsockopt(struct socket *sock, |
| 64 | int level, | 64 | int level, |
| 65 | int optname); | 65 | int optname); |
| @@ -129,7 +129,7 @@ static inline int selinux_netlbl_socket_post_create(struct sock *sk, | |||
| 129 | static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 129 | static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
| 130 | struct sk_buff *skb, | 130 | struct sk_buff *skb, |
| 131 | u16 family, | 131 | u16 family, |
| 132 | struct avc_audit_data *ad) | 132 | struct common_audit_data *ad) |
| 133 | { | 133 | { |
| 134 | return 0; | 134 | return 0; |
| 135 | } | 135 | } |
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 289e24b39e3e..13128f9a3e5a 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h | |||
| @@ -41,9 +41,9 @@ static inline int selinux_xfrm_enabled(void) | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, | 43 | int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, |
| 44 | struct avc_audit_data *ad); | 44 | struct common_audit_data *ad); |
| 45 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | 45 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
| 46 | struct avc_audit_data *ad, u8 proto); | 46 | struct common_audit_data *ad, u8 proto); |
| 47 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); | 47 | int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); |
| 48 | 48 | ||
| 49 | static inline void selinux_xfrm_notify_policyload(void) | 49 | static inline void selinux_xfrm_notify_policyload(void) |
| @@ -57,13 +57,13 @@ static inline int selinux_xfrm_enabled(void) | |||
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | 59 | static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, |
| 60 | struct avc_audit_data *ad) | 60 | struct common_audit_data *ad) |
| 61 | { | 61 | { |
| 62 | return 0; | 62 | return 0; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | 65 | static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
| 66 | struct avc_audit_data *ad, u8 proto) | 66 | struct common_audit_data *ad, u8 proto) |
| 67 | { | 67 | { |
| 68 | return 0; | 68 | return 0; |
| 69 | } | 69 | } |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 2e984413c7b2..e68823741ad5 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
| @@ -342,7 +342,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family) | |||
| 342 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, | 342 | int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, |
| 343 | struct sk_buff *skb, | 343 | struct sk_buff *skb, |
| 344 | u16 family, | 344 | u16 family, |
| 345 | struct avc_audit_data *ad) | 345 | struct common_audit_data *ad) |
| 346 | { | 346 | { |
| 347 | int rc; | 347 | int rc; |
| 348 | u32 nlbl_sid; | 348 | u32 nlbl_sid; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 500e6f78e115..ff17820d35ec 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -22,6 +22,11 @@ | |||
| 22 | * | 22 | * |
| 23 | * Added validation of kernel classes and permissions | 23 | * Added validation of kernel classes and permissions |
| 24 | * | 24 | * |
| 25 | * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com> | ||
| 26 | * | ||
| 27 | * Added support for bounds domain and audit messaged on masked permissions | ||
| 28 | * | ||
| 29 | * Copyright (C) 2008, 2009 NEC Corporation | ||
| 25 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. | 30 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. |
| 26 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. | 31 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. |
| 27 | * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC | 32 | * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC |
| @@ -279,6 +284,95 @@ mls_ops: | |||
| 279 | } | 284 | } |
| 280 | 285 | ||
| 281 | /* | 286 | /* |
| 287 | * security_dump_masked_av - dumps masked permissions during | ||
| 288 | * security_compute_av due to RBAC, MLS/Constraint and Type bounds. | ||
| 289 | */ | ||
| 290 | static int dump_masked_av_helper(void *k, void *d, void *args) | ||
| 291 | { | ||
| 292 | struct perm_datum *pdatum = d; | ||
| 293 | char **permission_names = args; | ||
| 294 | |||
| 295 | BUG_ON(pdatum->value < 1 || pdatum->value > 32); | ||
| 296 | |||
| 297 | permission_names[pdatum->value - 1] = (char *)k; | ||
| 298 | |||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | static void security_dump_masked_av(struct context *scontext, | ||
| 303 | struct context *tcontext, | ||
| 304 | u16 tclass, | ||
| 305 | u32 permissions, | ||
| 306 | const char *reason) | ||
| 307 | { | ||
| 308 | struct common_datum *common_dat; | ||
| 309 | struct class_datum *tclass_dat; | ||
| 310 | struct audit_buffer *ab; | ||
| 311 | char *tclass_name; | ||
| 312 | char *scontext_name = NULL; | ||
| 313 | char *tcontext_name = NULL; | ||
| 314 | char *permission_names[32]; | ||
| 315 | int index, length; | ||
| 316 | bool need_comma = false; | ||
| 317 | |||
| 318 | if (!permissions) | ||
| 319 | return; | ||
| 320 | |||
| 321 | tclass_name = policydb.p_class_val_to_name[tclass - 1]; | ||
| 322 | tclass_dat = policydb.class_val_to_struct[tclass - 1]; | ||
| 323 | common_dat = tclass_dat->comdatum; | ||
| 324 | |||
| 325 | /* init permission_names */ | ||
| 326 | if (common_dat && | ||
| 327 | hashtab_map(common_dat->permissions.table, | ||
| 328 | dump_masked_av_helper, permission_names) < 0) | ||
| 329 | goto out; | ||
| 330 | |||
| 331 | if (hashtab_map(tclass_dat->permissions.table, | ||
| 332 | dump_masked_av_helper, permission_names) < 0) | ||
| 333 | goto out; | ||
| 334 | |||
| 335 | /* get scontext/tcontext in text form */ | ||
| 336 | if (context_struct_to_string(scontext, | ||
| 337 | &scontext_name, &length) < 0) | ||
| 338 | goto out; | ||
| 339 | |||
| 340 | if (context_struct_to_string(tcontext, | ||
| 341 | &tcontext_name, &length) < 0) | ||
| 342 | goto out; | ||
| 343 | |||
| 344 | /* audit a message */ | ||
| 345 | ab = audit_log_start(current->audit_context, | ||
| 346 | GFP_ATOMIC, AUDIT_SELINUX_ERR); | ||
| 347 | if (!ab) | ||
| 348 | goto out; | ||
| 349 | |||
| 350 | audit_log_format(ab, "op=security_compute_av reason=%s " | ||
| 351 | "scontext=%s tcontext=%s tclass=%s perms=", | ||
| 352 | reason, scontext_name, tcontext_name, tclass_name); | ||
| 353 | |||
| 354 | for (index = 0; index < 32; index++) { | ||
| 355 | u32 mask = (1 << index); | ||
| 356 | |||
| 357 | if ((mask & permissions) == 0) | ||
| 358 | continue; | ||
| 359 | |||
| 360 | audit_log_format(ab, "%s%s", | ||
| 361 | need_comma ? "," : "", | ||
| 362 | permission_names[index] | ||
| 363 | ? permission_names[index] : "????"); | ||
| 364 | need_comma = true; | ||
| 365 | } | ||
| 366 | audit_log_end(ab); | ||
| 367 | out: | ||
| 368 | /* release scontext/tcontext */ | ||
| 369 | kfree(tcontext_name); | ||
| 370 | kfree(scontext_name); | ||
| 371 | |||
| 372 | return; | ||
| 373 | } | ||
| 374 | |||
| 375 | /* | ||
| 282 | * security_boundary_permission - drops violated permissions | 376 | * security_boundary_permission - drops violated permissions |
| 283 | * on boundary constraint. | 377 | * on boundary constraint. |
| 284 | */ | 378 | */ |
| @@ -347,28 +441,12 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 347 | } | 441 | } |
| 348 | 442 | ||
| 349 | if (masked) { | 443 | if (masked) { |
| 350 | struct audit_buffer *ab; | ||
| 351 | char *stype_name | ||
| 352 | = policydb.p_type_val_to_name[source->value - 1]; | ||
| 353 | char *ttype_name | ||
| 354 | = policydb.p_type_val_to_name[target->value - 1]; | ||
| 355 | char *tclass_name | ||
| 356 | = policydb.p_class_val_to_name[tclass - 1]; | ||
| 357 | |||
| 358 | /* mask violated permissions */ | 444 | /* mask violated permissions */ |
| 359 | avd->allowed &= ~masked; | 445 | avd->allowed &= ~masked; |
| 360 | 446 | ||
| 361 | /* notice to userspace via audit message */ | 447 | /* audit masked permissions */ |
| 362 | ab = audit_log_start(current->audit_context, | 448 | security_dump_masked_av(scontext, tcontext, |
| 363 | GFP_ATOMIC, AUDIT_SELINUX_ERR); | 449 | tclass, masked, "bounds"); |
| 364 | if (!ab) | ||
| 365 | return; | ||
| 366 | |||
| 367 | audit_log_format(ab, "av boundary violation: " | ||
| 368 | "source=%s target=%s tclass=%s", | ||
| 369 | stype_name, ttype_name, tclass_name); | ||
| 370 | avc_dump_av(ab, tclass, masked); | ||
| 371 | audit_log_end(ab); | ||
| 372 | } | 450 | } |
| 373 | } | 451 | } |
| 374 | 452 | ||
| @@ -480,7 +558,7 @@ static int context_struct_compute_av(struct context *scontext, | |||
| 480 | if ((constraint->permissions & (avd->allowed)) && | 558 | if ((constraint->permissions & (avd->allowed)) && |
| 481 | !constraint_expr_eval(scontext, tcontext, NULL, | 559 | !constraint_expr_eval(scontext, tcontext, NULL, |
| 482 | constraint->expr)) { | 560 | constraint->expr)) { |
| 483 | avd->allowed = (avd->allowed) & ~(constraint->permissions); | 561 | avd->allowed &= ~(constraint->permissions); |
| 484 | } | 562 | } |
| 485 | constraint = constraint->next; | 563 | constraint = constraint->next; |
| 486 | } | 564 | } |
| @@ -499,8 +577,8 @@ static int context_struct_compute_av(struct context *scontext, | |||
| 499 | break; | 577 | break; |
| 500 | } | 578 | } |
| 501 | if (!ra) | 579 | if (!ra) |
| 502 | avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION | | 580 | avd->allowed &= ~(PROCESS__TRANSITION | |
| 503 | PROCESS__DYNTRANSITION); | 581 | PROCESS__DYNTRANSITION); |
| 504 | } | 582 | } |
| 505 | 583 | ||
| 506 | /* | 584 | /* |
| @@ -687,6 +765,26 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) | |||
| 687 | } | 765 | } |
| 688 | index = type->bounds; | 766 | index = type->bounds; |
| 689 | } | 767 | } |
| 768 | |||
| 769 | if (rc) { | ||
| 770 | char *old_name = NULL; | ||
| 771 | char *new_name = NULL; | ||
| 772 | int length; | ||
| 773 | |||
| 774 | if (!context_struct_to_string(old_context, | ||
| 775 | &old_name, &length) && | ||
| 776 | !context_struct_to_string(new_context, | ||
| 777 | &new_name, &length)) { | ||
| 778 | audit_log(current->audit_context, | ||
| 779 | GFP_ATOMIC, AUDIT_SELINUX_ERR, | ||
| 780 | "op=security_bounded_transition " | ||
| 781 | "result=denied " | ||
| 782 | "oldcontext=%s newcontext=%s", | ||
| 783 | old_name, new_name); | ||
| 784 | } | ||
| 785 | kfree(new_name); | ||
| 786 | kfree(old_name); | ||
| 787 | } | ||
| 690 | out: | 788 | out: |
| 691 | read_unlock(&policy_rwlock); | 789 | read_unlock(&policy_rwlock); |
| 692 | 790 | ||
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 72b18452e1a1..f3cb9ed731a9 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
| @@ -401,7 +401,7 @@ int selinux_xfrm_state_delete(struct xfrm_state *x) | |||
| 401 | * gone thru the IPSec process. | 401 | * gone thru the IPSec process. |
| 402 | */ | 402 | */ |
| 403 | int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | 403 | int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, |
| 404 | struct avc_audit_data *ad) | 404 | struct common_audit_data *ad) |
| 405 | { | 405 | { |
| 406 | int i, rc = 0; | 406 | int i, rc = 0; |
| 407 | struct sec_path *sp; | 407 | struct sec_path *sp; |
| @@ -442,7 +442,7 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, | |||
| 442 | * checked in the selinux_xfrm_state_pol_flow_match hook above. | 442 | * checked in the selinux_xfrm_state_pol_flow_match hook above. |
| 443 | */ | 443 | */ |
| 444 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, | 444 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, |
| 445 | struct avc_audit_data *ad, u8 proto) | 445 | struct common_audit_data *ad, u8 proto) |
| 446 | { | 446 | { |
| 447 | struct dst_entry *dst; | 447 | struct dst_entry *dst; |
| 448 | int rc = 0; | 448 | int rc = 0; |
diff --git a/security/smack/smack.h b/security/smack/smack.h index 243bec175be0..c6e9acae72e4 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
| @@ -275,7 +275,7 @@ static inline void smk_ad_init(struct smk_audit_info *a, const char *func, | |||
| 275 | { | 275 | { |
| 276 | memset(a, 0, sizeof(*a)); | 276 | memset(a, 0, sizeof(*a)); |
| 277 | a->a.type = type; | 277 | a->a.type = type; |
| 278 | a->a.function = func; | 278 | a->a.smack_audit_data.function = func; |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, | 281 | static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a, |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 513dc1aa16dd..0f9ac8146900 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
| @@ -240,8 +240,9 @@ static inline void smack_str_from_perm(char *string, int access) | |||
| 240 | static void smack_log_callback(struct audit_buffer *ab, void *a) | 240 | static void smack_log_callback(struct audit_buffer *ab, void *a) |
| 241 | { | 241 | { |
| 242 | struct common_audit_data *ad = a; | 242 | struct common_audit_data *ad = a; |
| 243 | struct smack_audit_data *sad = &ad->lsm_priv.smack_audit_data; | 243 | struct smack_audit_data *sad = &ad->smack_audit_data; |
| 244 | audit_log_format(ab, "lsm=SMACK fn=%s action=%s", ad->function, | 244 | audit_log_format(ab, "lsm=SMACK fn=%s action=%s", |
| 245 | ad->smack_audit_data.function, | ||
| 245 | sad->result ? "denied" : "granted"); | 246 | sad->result ? "denied" : "granted"); |
| 246 | audit_log_format(ab, " subject="); | 247 | audit_log_format(ab, " subject="); |
| 247 | audit_log_untrustedstring(ab, sad->subject); | 248 | audit_log_untrustedstring(ab, sad->subject); |
| @@ -274,11 +275,11 @@ void smack_log(char *subject_label, char *object_label, int request, | |||
| 274 | if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) | 275 | if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) |
| 275 | return; | 276 | return; |
| 276 | 277 | ||
| 277 | if (a->function == NULL) | 278 | if (a->smack_audit_data.function == NULL) |
| 278 | a->function = "unknown"; | 279 | a->smack_audit_data.function = "unknown"; |
| 279 | 280 | ||
| 280 | /* end preparing the audit data */ | 281 | /* end preparing the audit data */ |
| 281 | sad = &a->lsm_priv.smack_audit_data; | 282 | sad = &a->smack_audit_data; |
| 282 | smack_str_from_perm(request_buffer, request); | 283 | smack_str_from_perm(request_buffer, request); |
| 283 | sad->subject = subject_label; | 284 | sad->subject = subject_label; |
| 284 | sad->object = object_label; | 285 | sad->object = object_label; |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 0023182078c7..acae7ef4092d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -91,7 +91,7 @@ struct inode_smack *new_inode_smack(char *smack) | |||
| 91 | */ | 91 | */ |
| 92 | 92 | ||
| 93 | /** | 93 | /** |
| 94 | * smack_ptrace_may_access - Smack approval on PTRACE_ATTACH | 94 | * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH |
| 95 | * @ctp: child task pointer | 95 | * @ctp: child task pointer |
| 96 | * @mode: ptrace attachment mode | 96 | * @mode: ptrace attachment mode |
| 97 | * | 97 | * |
| @@ -99,13 +99,13 @@ struct inode_smack *new_inode_smack(char *smack) | |||
| 99 | * | 99 | * |
| 100 | * Do the capability checks, and require read and write. | 100 | * Do the capability checks, and require read and write. |
| 101 | */ | 101 | */ |
| 102 | static int smack_ptrace_may_access(struct task_struct *ctp, unsigned int mode) | 102 | static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) |
| 103 | { | 103 | { |
| 104 | int rc; | 104 | int rc; |
| 105 | struct smk_audit_info ad; | 105 | struct smk_audit_info ad; |
| 106 | char *sp, *tsp; | 106 | char *sp, *tsp; |
| 107 | 107 | ||
| 108 | rc = cap_ptrace_may_access(ctp, mode); | 108 | rc = cap_ptrace_access_check(ctp, mode); |
| 109 | if (rc != 0) | 109 | if (rc != 0) |
| 110 | return rc; | 110 | return rc; |
| 111 | 111 | ||
| @@ -1080,6 +1080,22 @@ static int smack_file_receive(struct file *file) | |||
| 1080 | */ | 1080 | */ |
| 1081 | 1081 | ||
| 1082 | /** | 1082 | /** |
| 1083 | * smack_cred_alloc_blank - "allocate" blank task-level security credentials | ||
| 1084 | * @new: the new credentials | ||
| 1085 | * @gfp: the atomicity of any memory allocations | ||
| 1086 | * | ||
| 1087 | * Prepare a blank set of credentials for modification. This must allocate all | ||
| 1088 | * the memory the LSM module might require such that cred_transfer() can | ||
| 1089 | * complete without error. | ||
| 1090 | */ | ||
| 1091 | static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) | ||
| 1092 | { | ||
| 1093 | cred->security = NULL; | ||
| 1094 | return 0; | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | |||
| 1098 | /** | ||
| 1083 | * smack_cred_free - "free" task-level security credentials | 1099 | * smack_cred_free - "free" task-level security credentials |
| 1084 | * @cred: the credentials in question | 1100 | * @cred: the credentials in question |
| 1085 | * | 1101 | * |
| @@ -1117,6 +1133,18 @@ static void smack_cred_commit(struct cred *new, const struct cred *old) | |||
| 1117 | } | 1133 | } |
| 1118 | 1134 | ||
| 1119 | /** | 1135 | /** |
| 1136 | * smack_cred_transfer - Transfer the old credentials to the new credentials | ||
| 1137 | * @new: the new credentials | ||
| 1138 | * @old: the original credentials | ||
| 1139 | * | ||
| 1140 | * Fill in a set of blank credentials from another set of credentials. | ||
| 1141 | */ | ||
| 1142 | static void smack_cred_transfer(struct cred *new, const struct cred *old) | ||
| 1143 | { | ||
| 1144 | new->security = old->security; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | /** | ||
| 1120 | * smack_kernel_act_as - Set the subjective context in a set of credentials | 1148 | * smack_kernel_act_as - Set the subjective context in a set of credentials |
| 1121 | * @new: points to the set of credentials to be modified. | 1149 | * @new: points to the set of credentials to be modified. |
| 1122 | * @secid: specifies the security ID to be set | 1150 | * @secid: specifies the security ID to be set |
| @@ -1638,6 +1666,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
| 1638 | 1666 | ||
| 1639 | if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { | 1667 | if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { |
| 1640 | nsp->smk_inode = sp; | 1668 | nsp->smk_inode = sp; |
| 1669 | nsp->smk_flags |= SMK_INODE_INSTANT; | ||
| 1641 | return 0; | 1670 | return 0; |
| 1642 | } | 1671 | } |
| 1643 | /* | 1672 | /* |
| @@ -2464,7 +2493,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
| 2464 | /* | 2493 | /* |
| 2465 | * Perfectly reasonable for this to be NULL | 2494 | * Perfectly reasonable for this to be NULL |
| 2466 | */ | 2495 | */ |
| 2467 | if (sip == NULL || sip->sin_family != PF_INET) | 2496 | if (sip == NULL || sip->sin_family != AF_INET) |
| 2468 | return 0; | 2497 | return 0; |
| 2469 | 2498 | ||
| 2470 | return smack_netlabel_send(sock->sk, sip); | 2499 | return smack_netlabel_send(sock->sk, sip); |
| @@ -3029,10 +3058,31 @@ static void smack_release_secctx(char *secdata, u32 seclen) | |||
| 3029 | { | 3058 | { |
| 3030 | } | 3059 | } |
| 3031 | 3060 | ||
| 3061 | static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) | ||
| 3062 | { | ||
| 3063 | return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx, ctxlen, 0); | ||
| 3064 | } | ||
| 3065 | |||
| 3066 | static int smack_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) | ||
| 3067 | { | ||
| 3068 | return __vfs_setxattr_noperm(dentry, XATTR_NAME_SMACK, ctx, ctxlen, 0); | ||
| 3069 | } | ||
| 3070 | |||
| 3071 | static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | ||
| 3072 | { | ||
| 3073 | int len = 0; | ||
| 3074 | len = smack_inode_getsecurity(inode, XATTR_SMACK_SUFFIX, ctx, true); | ||
| 3075 | |||
| 3076 | if (len < 0) | ||
| 3077 | return len; | ||
| 3078 | *ctxlen = len; | ||
| 3079 | return 0; | ||
| 3080 | } | ||
| 3081 | |||
| 3032 | struct security_operations smack_ops = { | 3082 | struct security_operations smack_ops = { |
| 3033 | .name = "smack", | 3083 | .name = "smack", |
| 3034 | 3084 | ||
| 3035 | .ptrace_may_access = smack_ptrace_may_access, | 3085 | .ptrace_access_check = smack_ptrace_access_check, |
| 3036 | .ptrace_traceme = smack_ptrace_traceme, | 3086 | .ptrace_traceme = smack_ptrace_traceme, |
| 3037 | .syslog = smack_syslog, | 3087 | .syslog = smack_syslog, |
| 3038 | 3088 | ||
| @@ -3073,9 +3123,11 @@ struct security_operations smack_ops = { | |||
| 3073 | .file_send_sigiotask = smack_file_send_sigiotask, | 3123 | .file_send_sigiotask = smack_file_send_sigiotask, |
| 3074 | .file_receive = smack_file_receive, | 3124 | .file_receive = smack_file_receive, |
| 3075 | 3125 | ||
| 3126 | .cred_alloc_blank = smack_cred_alloc_blank, | ||
| 3076 | .cred_free = smack_cred_free, | 3127 | .cred_free = smack_cred_free, |
| 3077 | .cred_prepare = smack_cred_prepare, | 3128 | .cred_prepare = smack_cred_prepare, |
| 3078 | .cred_commit = smack_cred_commit, | 3129 | .cred_commit = smack_cred_commit, |
| 3130 | .cred_transfer = smack_cred_transfer, | ||
| 3079 | .kernel_act_as = smack_kernel_act_as, | 3131 | .kernel_act_as = smack_kernel_act_as, |
| 3080 | .kernel_create_files_as = smack_kernel_create_files_as, | 3132 | .kernel_create_files_as = smack_kernel_create_files_as, |
| 3081 | .task_setpgid = smack_task_setpgid, | 3133 | .task_setpgid = smack_task_setpgid, |
| @@ -3155,6 +3207,9 @@ struct security_operations smack_ops = { | |||
| 3155 | .secid_to_secctx = smack_secid_to_secctx, | 3207 | .secid_to_secctx = smack_secid_to_secctx, |
| 3156 | .secctx_to_secid = smack_secctx_to_secid, | 3208 | .secctx_to_secid = smack_secctx_to_secid, |
| 3157 | .release_secctx = smack_release_secctx, | 3209 | .release_secctx = smack_release_secctx, |
| 3210 | .inode_notifysecctx = smack_inode_notifysecctx, | ||
| 3211 | .inode_setsecctx = smack_inode_setsecctx, | ||
| 3212 | .inode_getsecctx = smack_inode_getsecctx, | ||
| 3158 | }; | 3213 | }; |
| 3159 | 3214 | ||
| 3160 | 3215 | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index fdd1f4b8c448..3c8bd8ee0b95 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
| @@ -1285,6 +1285,36 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | |||
| 1285 | } | 1285 | } |
| 1286 | 1286 | ||
| 1287 | /** | 1287 | /** |
| 1288 | * tomoyo_delete_domain - Delete a domain. | ||
| 1289 | * | ||
| 1290 | * @domainname: The name of domain. | ||
| 1291 | * | ||
| 1292 | * Returns 0. | ||
| 1293 | */ | ||
| 1294 | static int tomoyo_delete_domain(char *domainname) | ||
| 1295 | { | ||
| 1296 | struct tomoyo_domain_info *domain; | ||
| 1297 | struct tomoyo_path_info name; | ||
| 1298 | |||
| 1299 | name.name = domainname; | ||
| 1300 | tomoyo_fill_path_info(&name); | ||
| 1301 | down_write(&tomoyo_domain_list_lock); | ||
| 1302 | /* Is there an active domain? */ | ||
| 1303 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | ||
| 1304 | /* Never delete tomoyo_kernel_domain */ | ||
| 1305 | if (domain == &tomoyo_kernel_domain) | ||
| 1306 | continue; | ||
| 1307 | if (domain->is_deleted || | ||
| 1308 | tomoyo_pathcmp(domain->domainname, &name)) | ||
| 1309 | continue; | ||
| 1310 | domain->is_deleted = true; | ||
| 1311 | break; | ||
| 1312 | } | ||
| 1313 | up_write(&tomoyo_domain_list_lock); | ||
| 1314 | return 0; | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | /** | ||
| 1288 | * tomoyo_write_domain_policy - Write domain policy. | 1318 | * tomoyo_write_domain_policy - Write domain policy. |
| 1289 | * | 1319 | * |
| 1290 | * @head: Pointer to "struct tomoyo_io_buffer". | 1320 | * @head: Pointer to "struct tomoyo_io_buffer". |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 6d6ba09af457..31df541911f7 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
| @@ -339,8 +339,6 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); | |||
| 339 | const char *tomoyo_get_msg(const bool is_enforce); | 339 | const char *tomoyo_get_msg(const bool is_enforce); |
| 340 | /* Convert single path operation to operation name. */ | 340 | /* Convert single path operation to operation name. */ |
| 341 | const char *tomoyo_sp2keyword(const u8 operation); | 341 | const char *tomoyo_sp2keyword(const u8 operation); |
| 342 | /* Delete a domain. */ | ||
| 343 | int tomoyo_delete_domain(char *data); | ||
| 344 | /* Create "alias" entry in exception policy. */ | 342 | /* Create "alias" entry in exception policy. */ |
| 345 | int tomoyo_write_alias_policy(char *data, const bool is_delete); | 343 | int tomoyo_write_alias_policy(char *data, const bool is_delete); |
| 346 | /* | 344 | /* |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 1d8b16960576..fcf52accce2b 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
| @@ -717,38 +717,6 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete) | |||
| 717 | return tomoyo_update_alias_entry(data, cp, is_delete); | 717 | return tomoyo_update_alias_entry(data, cp, is_delete); |
| 718 | } | 718 | } |
| 719 | 719 | ||
| 720 | /* Domain create/delete handler. */ | ||
| 721 | |||
| 722 | /** | ||
| 723 | * tomoyo_delete_domain - Delete a domain. | ||
| 724 | * | ||
| 725 | * @domainname: The name of domain. | ||
| 726 | * | ||
| 727 | * Returns 0. | ||
| 728 | */ | ||
| 729 | int tomoyo_delete_domain(char *domainname) | ||
| 730 | { | ||
| 731 | struct tomoyo_domain_info *domain; | ||
| 732 | struct tomoyo_path_info name; | ||
| 733 | |||
| 734 | name.name = domainname; | ||
| 735 | tomoyo_fill_path_info(&name); | ||
| 736 | down_write(&tomoyo_domain_list_lock); | ||
| 737 | /* Is there an active domain? */ | ||
| 738 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | ||
| 739 | /* Never delete tomoyo_kernel_domain */ | ||
| 740 | if (domain == &tomoyo_kernel_domain) | ||
| 741 | continue; | ||
| 742 | if (domain->is_deleted || | ||
| 743 | tomoyo_pathcmp(domain->domainname, &name)) | ||
| 744 | continue; | ||
| 745 | domain->is_deleted = true; | ||
| 746 | break; | ||
| 747 | } | ||
| 748 | up_write(&tomoyo_domain_list_lock); | ||
| 749 | return 0; | ||
| 750 | } | ||
| 751 | |||
| 752 | /** | 720 | /** |
| 753 | * tomoyo_find_or_assign_new_domain - Create a domain. | 721 | * tomoyo_find_or_assign_new_domain - Create a domain. |
| 754 | * | 722 | * |
| @@ -818,13 +786,11 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
| 818 | /** | 786 | /** |
| 819 | * tomoyo_find_next_domain - Find a domain. | 787 | * tomoyo_find_next_domain - Find a domain. |
| 820 | * | 788 | * |
| 821 | * @bprm: Pointer to "struct linux_binprm". | 789 | * @bprm: Pointer to "struct linux_binprm". |
| 822 | * @next_domain: Pointer to pointer to "struct tomoyo_domain_info". | ||
| 823 | * | 790 | * |
| 824 | * Returns 0 on success, negative value otherwise. | 791 | * Returns 0 on success, negative value otherwise. |
| 825 | */ | 792 | */ |
| 826 | int tomoyo_find_next_domain(struct linux_binprm *bprm, | 793 | int tomoyo_find_next_domain(struct linux_binprm *bprm) |
| 827 | struct tomoyo_domain_info **next_domain) | ||
| 828 | { | 794 | { |
| 829 | /* | 795 | /* |
| 830 | * This function assumes that the size of buffer returned by | 796 | * This function assumes that the size of buffer returned by |
| @@ -946,9 +912,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm, | |||
| 946 | tomoyo_set_domain_flag(old_domain, false, | 912 | tomoyo_set_domain_flag(old_domain, false, |
| 947 | TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); | 913 | TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); |
| 948 | out: | 914 | out: |
| 915 | if (!domain) | ||
| 916 | domain = old_domain; | ||
| 917 | bprm->cred->security = domain; | ||
| 949 | tomoyo_free(real_program_name); | 918 | tomoyo_free(real_program_name); |
| 950 | tomoyo_free(symlink_program_name); | 919 | tomoyo_free(symlink_program_name); |
| 951 | *next_domain = domain ? domain : old_domain; | ||
| 952 | tomoyo_free(tmp); | 920 | tomoyo_free(tmp); |
| 953 | return retval; | 921 | return retval; |
| 954 | } | 922 | } |
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 3194d09fe0f4..9548a0984cc4 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
| @@ -14,6 +14,12 @@ | |||
| 14 | #include "tomoyo.h" | 14 | #include "tomoyo.h" |
| 15 | #include "realpath.h" | 15 | #include "realpath.h" |
| 16 | 16 | ||
| 17 | static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) | ||
| 18 | { | ||
| 19 | new->security = NULL; | ||
| 20 | return 0; | ||
| 21 | } | ||
| 22 | |||
| 17 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | 23 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, |
| 18 | gfp_t gfp) | 24 | gfp_t gfp) |
| 19 | { | 25 | { |
| @@ -25,6 +31,15 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | |||
| 25 | return 0; | 31 | return 0; |
| 26 | } | 32 | } |
| 27 | 33 | ||
| 34 | static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) | ||
| 35 | { | ||
| 36 | /* | ||
| 37 | * Since "struct tomoyo_domain_info *" is a sharable pointer, | ||
| 38 | * we don't need to duplicate. | ||
| 39 | */ | ||
| 40 | new->security = old->security; | ||
| 41 | } | ||
| 42 | |||
| 28 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | 43 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
| 29 | { | 44 | { |
| 30 | int rc; | 45 | int rc; |
| @@ -61,14 +76,8 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) | |||
| 61 | * Execute permission is checked against pathname passed to do_execve() | 76 | * Execute permission is checked against pathname passed to do_execve() |
| 62 | * using current domain. | 77 | * using current domain. |
| 63 | */ | 78 | */ |
| 64 | if (!domain) { | 79 | if (!domain) |
| 65 | struct tomoyo_domain_info *next_domain = NULL; | 80 | return tomoyo_find_next_domain(bprm); |
| 66 | int retval = tomoyo_find_next_domain(bprm, &next_domain); | ||
| 67 | |||
| 68 | if (!retval) | ||
| 69 | bprm->cred->security = next_domain; | ||
| 70 | return retval; | ||
| 71 | } | ||
| 72 | /* | 81 | /* |
| 73 | * Read permission is checked against interpreters using next domain. | 82 | * Read permission is checked against interpreters using next domain. |
| 74 | * '1' is the result of open_to_namei_flags(O_RDONLY). | 83 | * '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) | |||
| 268 | */ | 277 | */ |
| 269 | static struct security_operations tomoyo_security_ops = { | 278 | static struct security_operations tomoyo_security_ops = { |
| 270 | .name = "tomoyo", | 279 | .name = "tomoyo", |
| 280 | .cred_alloc_blank = tomoyo_cred_alloc_blank, | ||
| 271 | .cred_prepare = tomoyo_cred_prepare, | 281 | .cred_prepare = tomoyo_cred_prepare, |
| 282 | .cred_transfer = tomoyo_cred_transfer, | ||
| 272 | .bprm_set_creds = tomoyo_bprm_set_creds, | 283 | .bprm_set_creds = tomoyo_bprm_set_creds, |
| 273 | .bprm_check_security = tomoyo_bprm_check_security, | 284 | .bprm_check_security = tomoyo_bprm_check_security, |
| 274 | #ifdef CONFIG_SYSCTL | 285 | #ifdef CONFIG_SYSCTL |
diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h index 0fd588a629cf..cd6ba0bf7069 100644 --- a/security/tomoyo/tomoyo.h +++ b/security/tomoyo/tomoyo.h | |||
| @@ -31,8 +31,7 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain, | |||
| 31 | struct path *path2); | 31 | struct path *path2); |
| 32 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | 32 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, |
| 33 | struct file *filp); | 33 | struct file *filp); |
| 34 | int tomoyo_find_next_domain(struct linux_binprm *bprm, | 34 | int tomoyo_find_next_domain(struct linux_binprm *bprm); |
| 35 | struct tomoyo_domain_info **next_domain); | ||
| 36 | 35 | ||
| 37 | /* Index numbers for Access Controls. */ | 36 | /* Index numbers for Access Controls. */ |
| 38 | 37 | ||
