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