diff options
author | James Morris <jmorris@namei.org> | 2009-09-10 18:04:49 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-09-10 18:04:49 -0400 |
commit | a3c8b97396ef42edfb845788ba6f53b2a93ce980 (patch) | |
tree | 530c5bdbc534618311dab3e0af245835af56db0f | |
parent | 74fca6a42863ffacaf7ba6f1936a9f228950f657 (diff) | |
parent | 9f0ab4a3f0fdb1ff404d150618ace2fa069bb2e1 (diff) |
Merge branch 'next' into for-linus
97 files changed, 2245 insertions, 609 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/binfmt_elf.c b/fs/binfmt_elf.c index b7c1603cd4bd..7c1e65d54872 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -501,22 +501,22 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, | |||
501 | } | 501 | } |
502 | } | 502 | } |
503 | 503 | ||
504 | /* | 504 | if (last_bss > elf_bss) { |
505 | * Now fill out the bss section. First pad the last page up | 505 | /* |
506 | * to the page boundary, and then perform a mmap to make sure | 506 | * Now fill out the bss section. First pad the last page up |
507 | * that there are zero-mapped pages up to and including the | 507 | * to the page boundary, and then perform a mmap to make sure |
508 | * last bss page. | 508 | * that there are zero-mapped pages up to and including the |
509 | */ | 509 | * last bss page. |
510 | if (padzero(elf_bss)) { | 510 | */ |
511 | error = -EFAULT; | 511 | if (padzero(elf_bss)) { |
512 | goto out_close; | 512 | error = -EFAULT; |
513 | } | 513 | goto out_close; |
514 | } | ||
514 | 515 | ||
515 | /* What we have mapped so far */ | 516 | /* What we have mapped so far */ |
516 | elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); | 517 | elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); |
517 | 518 | ||
518 | /* Map the last of the bss segment */ | 519 | /* Map the last of the bss segment */ |
519 | if (last_bss > elf_bss) { | ||
520 | down_write(¤t->mm->mmap_sem); | 520 | down_write(¤t->mm->mmap_sem); |
521 | error = do_brk(elf_bss, last_bss - elf_bss); | 521 | error = do_brk(elf_bss, last_bss - elf_bss); |
522 | up_write(¤t->mm->mmap_sem); | 522 | up_write(¤t->mm->mmap_sem); |
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 1f13751693a5..fcfc5539252c 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 | ||