diff options
80 files changed, 4179 insertions, 3892 deletions
diff --git a/Documentation/ABI/obsolete/sysfs-selinux-checkreqprot b/Documentation/ABI/removed/sysfs-selinux-checkreqprot index ed6b52ca210f..f599a0a87e8b 100644 --- a/Documentation/ABI/obsolete/sysfs-selinux-checkreqprot +++ b/Documentation/ABI/removed/sysfs-selinux-checkreqprot @@ -4,6 +4,9 @@ KernelVersion: 2.6.12-rc2 (predates git) Contact: [email protected] Description: + REMOVAL UPDATE: The SELinux checkreqprot functionality was removed in + March 2023, the original deprecation notice is shown below. + The selinuxfs "checkreqprot" node allows SELinux to be configured to check the protection requested by userspace for mmap/mprotect calls instead of the actual protection applied by the kernel. diff --git a/Documentation/ABI/obsolete/sysfs-selinux-disable b/Documentation/ABI/removed/sysfs-selinux-disable index c340278e3cf8..cb783c64cab3 100644 --- a/Documentation/ABI/obsolete/sysfs-selinux-disable +++ b/Documentation/ABI/removed/sysfs-selinux-disable @@ -4,6 +4,9 @@ KernelVersion: 2.6.12-rc2 (predates git) Contact: [email protected] Description: + REMOVAL UPDATE: The SELinux runtime disable functionality was removed + in March 2023, the original deprecation notice is shown below. + The selinuxfs "disable" node allows SELinux to be disabled at runtime prior to a policy being loaded into the kernel. If disabled via this mechanism, SELinux will remain disabled until the system is rebooted. diff --git a/MAINTAINERS b/MAINTAINERS index c6545eb54104..456285afd716 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18822,8 +18822,8 @@ S: Supported W: https://selinuxproject.org W: https://github.com/SELinuxProject T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git -F: Documentation/ABI/obsolete/sysfs-selinux-checkreqprot -F: Documentation/ABI/obsolete/sysfs-selinux-disable +F: Documentation/ABI/removed/sysfs-selinux-checkreqprot +F: Documentation/ABI/removed/sysfs-selinux-disable F: Documentation/admin-guide/LSM/SELinux.rst F: include/trace/events/avc.h F: include/uapi/linux/selinux_netlink.h diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 2ef651a78fa2..726ecabcef09 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -107,7 +107,7 @@ ccflags-remove-$(CONFIG_FUNCTION_TRACER) += -pg asflags-y := -DZIMAGE # Supply kernel BSS size to the decompressor via a linker symbol. -KBSS_SZ = $(shell echo $$(($$($(NM) $(obj)/../../../../vmlinux | \ +KBSS_SZ = $(shell echo $$(($$($(NM) vmlinux | \ sed -n -e 's/^\([^ ]*\) [ABD] __bss_start$$/-0x\1/p' \ -e 's/^\([^ ]*\) [ABD] __bss_stop$$/+0x\1/p') )) ) LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ) diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 06b48ce23e1c..505a306e0271 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -244,19 +244,6 @@ THUMB( fpreg .req r7 ) .endm #endif - .macro local_bh_disable, ti, tmp - ldr \tmp, [\ti, #TI_PREEMPT] - add \tmp, \tmp, #SOFTIRQ_DISABLE_OFFSET - str \tmp, [\ti, #TI_PREEMPT] - .endm - - .macro local_bh_enable_ti, ti, tmp - get_thread_info \ti - ldr \tmp, [\ti, #TI_PREEMPT] - sub \tmp, \tmp, #SOFTIRQ_DISABLE_OFFSET - str \tmp, [\ti, #TI_PREEMPT] - .endm - #define USERL(l, x...) \ 9999: x; \ .pushsection __ex_table,"a"; \ diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index 9a89264cdcc0..7483ef8bccda 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -22,18 +22,7 @@ @ IRQs enabled. @ ENTRY(do_vfp) - local_bh_disable r10, r4 - ldr r4, .LCvfp - ldr r11, [r10, #TI_CPU] @ CPU number - add r10, r10, #TI_VFPSTATE @ r10 = workspace - ldr pc, [r4] @ call VFP entry point + mov r1, r10 + mov r3, r9 + b vfp_entry ENDPROC(do_vfp) - -ENTRY(vfp_null_entry) - local_bh_enable_ti r10, r4 - ret lr -ENDPROC(vfp_null_entry) - - .align 2 -.LCvfp: - .word vfp_vector diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 26c4f61ecfa3..4d8478264d82 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -6,9 +6,9 @@ * Written by Deep Blue Solutions Limited. * * This code is called from the kernel's undefined instruction trap. - * r9 holds the return address for successful handling. + * r1 holds the thread_info pointer + * r3 holds the return address for successful handling. * lr holds the return address for unrecognised instructions. - * r10 points at the start of the private FP workspace in the thread structure * sp points to a struct pt_regs (as defined in include/asm/proc/ptrace.h) */ #include <linux/init.h> @@ -69,13 +69,15 @@ @ VFP hardware support entry point. @ @ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) +@ r1 = thread_info pointer @ r2 = PC value to resume execution after successful emulation -@ r9 = normal "successful" return address -@ r10 = vfp_state union -@ r11 = CPU number +@ r3 = normal "successful" return address @ lr = unrecognised instruction return address @ IRQs enabled. ENTRY(vfp_support_entry) + ldr r11, [r1, #TI_CPU] @ CPU number + add r10, r1, #TI_VFPSTATE @ r10 = workspace + DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10 .fpu vfpv2 @@ -85,9 +87,9 @@ ENTRY(vfp_support_entry) bne look_for_VFP_exceptions @ VFP is already enabled DBGSTR1 "enable %x", r10 - ldr r3, vfp_current_hw_state_address + ldr r9, vfp_current_hw_state_address orr r1, r1, #FPEXC_EN @ user FPEXC has the enable bit set - ldr r4, [r3, r11, lsl #2] @ vfp_current_hw_state pointer + ldr r4, [r9, r11, lsl #2] @ vfp_current_hw_state pointer bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled cmp r4, r10 @ this thread owns the hw context? #ifndef CONFIG_SMP @@ -146,7 +148,7 @@ vfp_reload_hw: #endif DBGSTR1 "load state %p", r10 - str r10, [r3, r11, lsl #2] @ update the vfp_current_hw_state pointer + str r10, [r9, r11, lsl #2] @ update the vfp_current_hw_state pointer @ Load the saved state back into the VFP VFPFLDMIA r10, r5 @ reload the working registers while @ FPEXC is in a safe state @@ -175,9 +177,12 @@ vfp_hw_state_valid: @ else it's one 32-bit instruction, so @ always subtract 4 from the following @ instruction address. - local_bh_enable_ti r10, r4 - ret r9 @ we think we have handled things + mov lr, r3 @ we think we have handled things +local_bh_enable_and_ret: + adr r0, . + mov r1, #SOFTIRQ_DISABLE_OFFSET + b __local_bh_enable_ip @ tail call look_for_VFP_exceptions: @ Check for synchronous or asynchronous exception @@ -200,13 +205,12 @@ skip: @ not recognised by VFP DBGSTR "not VFP" - local_bh_enable_ti r10, r4 - ret lr + b local_bh_enable_and_ret process_exception: DBGSTR "bounce" mov r2, sp @ nothing stacked - regdump is at TOS - mov lr, r9 @ setup for a return to the user code. + mov lr, r3 @ setup for a return to the user code. @ Now call the C code to package up the bounce to the support code @ r0 holds the trigger instruction diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 01bc48d73847..349dcb944a93 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -32,10 +32,9 @@ /* * Our undef handlers (in entry.S) */ -asmlinkage void vfp_support_entry(void); -asmlinkage void vfp_null_entry(void); +asmlinkage void vfp_support_entry(u32, void *, u32, u32); -asmlinkage void (*vfp_vector)(void) = vfp_null_entry; +static bool have_vfp __ro_after_init; /* * Dual-use variable. @@ -645,6 +644,25 @@ static int vfp_starting_cpu(unsigned int unused) return 0; } +/* + * Entered with: + * + * r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) + * r1 = thread_info pointer + * r2 = PC value to resume execution after successful emulation + * r3 = normal "successful" return address + * lr = unrecognised instruction return address + */ +asmlinkage void vfp_entry(u32 trigger, struct thread_info *ti, u32 resume_pc, + u32 resume_return_address) +{ + if (unlikely(!have_vfp)) + return; + + local_bh_disable(); + vfp_support_entry(trigger, ti, resume_pc, resume_return_address); +} + #ifdef CONFIG_KERNEL_MODE_NEON static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr) @@ -798,7 +816,6 @@ static int __init vfp_init(void) vfpsid = fmrx(FPSID); barrier(); unregister_undef_hook(&vfp_detect_hook); - vfp_vector = vfp_null_entry; pr_info("VFP support v0.3: "); if (VFP_arch) { @@ -883,7 +900,7 @@ static int __init vfp_init(void) "arm/vfp:starting", vfp_starting_cpu, vfp_dying_cpu); - vfp_vector = vfp_support_entry; + have_vfp = true; thread_register_notifier(&vfp_notifier_block); vfp_pm_init(); diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index d13d71af5cf6..0a49a8de9f3c 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h @@ -18,32 +18,26 @@ /* Handles exceptions in both to and from, but doesn't do access_ok */ __must_check unsigned long -copy_user_enhanced_fast_string(void *to, const void *from, unsigned len); -__must_check unsigned long -copy_user_generic_string(void *to, const void *from, unsigned len); -__must_check unsigned long -copy_user_generic_unrolled(void *to, const void *from, unsigned len); +rep_movs_alternative(void *to, const void *from, unsigned len); static __always_inline __must_check unsigned long -copy_user_generic(void *to, const void *from, unsigned len) +copy_user_generic(void *to, const void *from, unsigned long len) { - unsigned ret; - + stac(); /* - * If CPU has ERMS feature, use copy_user_enhanced_fast_string. - * Otherwise, if CPU has rep_good feature, use copy_user_generic_string. - * Otherwise, use copy_user_generic_unrolled. + * If CPU has FSRM feature, use 'rep movs'. + * Otherwise, use rep_movs_alternative. */ - alternative_call_2(copy_user_generic_unrolled, - copy_user_generic_string, - X86_FEATURE_REP_GOOD, - copy_user_enhanced_fast_string, - X86_FEATURE_ERMS, - ASM_OUTPUT2("=a" (ret), "=D" (to), "=S" (from), - "=d" (len)), - "1" (to), "2" (from), "3" (len) - : "memory", "rcx", "r8", "r9", "r10", "r11"); - return ret; + asm volatile( + "1:\n\t" + ALTERNATIVE("rep movsb", + "call rep_movs_alternative", ALT_NOT(X86_FEATURE_FSRM)) + "2:\n" + _ASM_EXTABLE_UA(1b, 2b) + :"+c" (len), "+D" (to), "+S" (from), ASM_CALL_CONSTRAINT + : : "memory", "rax", "r8", "r9", "r10", "r11"); + clac(); + return len; } static __always_inline __must_check unsigned long @@ -58,9 +52,7 @@ raw_copy_to_user(void __user *dst, const void *src, unsigned long size) return copy_user_generic((__force void *)dst, src, size); } -extern long __copy_user_nocache(void *dst, const void __user *src, - unsigned size, int zerorest); - +extern long __copy_user_nocache(void *dst, const void __user *src, unsigned size); extern long __copy_user_flushcache(void *dst, const void __user *src, unsigned size); extern void memcpy_page_flushcache(char *to, struct page *page, size_t offset, size_t len); @@ -69,8 +61,12 @@ static inline int __copy_from_user_inatomic_nocache(void *dst, const void __user *src, unsigned size) { + long ret; kasan_check_write(dst, size); - return __copy_user_nocache(dst, src, size, 0); + stac(); + ret = __copy_user_nocache(dst, src, size); + clac(); + return ret; } static inline int @@ -85,11 +81,7 @@ __copy_from_user_flushcache(void *dst, const void __user *src, unsigned size) */ __must_check unsigned long -clear_user_original(void __user *addr, unsigned long len); -__must_check unsigned long -clear_user_rep_good(void __user *addr, unsigned long len); -__must_check unsigned long -clear_user_erms(void __user *addr, unsigned long len); +rep_stos_alternative(void __user *addr, unsigned long len); static __always_inline __must_check unsigned long __clear_user(void __user *addr, unsigned long size) { @@ -102,16 +94,12 @@ static __always_inline __must_check unsigned long __clear_user(void __user *addr */ asm volatile( "1:\n\t" - ALTERNATIVE_3("rep stosb", - "call clear_user_erms", ALT_NOT(X86_FEATURE_FSRM), - "call clear_user_rep_good", ALT_NOT(X86_FEATURE_ERMS), - "call clear_user_original", ALT_NOT(X86_FEATURE_REP_GOOD)) + ALTERNATIVE("rep stosb", + "call rep_stos_alternative", ALT_NOT(X86_FEATURE_FSRS)) "2:\n" _ASM_EXTABLE_UA(1b, 2b) : "+c" (size), "+D" (addr), ASM_CALL_CONSTRAINT - : "a" (0) - /* rep_good clobbers %rdx */ - : "rdx"); + : "a" (0)); clac(); diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 95cdd08c4cbb..1547781e505b 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -929,6 +929,10 @@ static void init_amd(struct cpuinfo_x86 *c) if (c->x86 >= 0x10) set_cpu_cap(c, X86_FEATURE_REP_GOOD); + /* AMD FSRM also implies FSRS */ + if (cpu_has(c, X86_FEATURE_FSRM)) + set_cpu_cap(c, X86_FEATURE_FSRS); + /* get apicid instead of initial apic id from cpuid */ c->apicid = hard_smp_processor_id(); diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 4f1a40a86534..01932af64193 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -71,6 +71,6 @@ ifneq ($(CONFIG_GENERIC_CSUM),y) endif lib-y += clear_page_64.o copy_page_64.o lib-y += memmove_64.o memset_64.o - lib-y += copy_user_64.o + lib-y += copy_user_64.o copy_user_uncached_64.o lib-y += cmpxchg16b_emu.o endif diff --git a/arch/x86/lib/clear_page_64.S b/arch/x86/lib/clear_page_64.S index ecbfb4dd3b01..f74a3e704a1c 100644 --- a/arch/x86/lib/clear_page_64.S +++ b/arch/x86/lib/clear_page_64.S @@ -57,134 +57,85 @@ EXPORT_SYMBOL_GPL(clear_page_erms) * Input: * rdi destination * rcx count + * rax is zero * * Output: * rcx: uncleared bytes or 0 if successful. */ -SYM_FUNC_START(clear_user_original) - /* - * Copy only the lower 32 bits of size as that is enough to handle the rest bytes, - * i.e., no need for a 'q' suffix and thus a REX prefix. - */ - mov %ecx,%eax - shr $3,%rcx - jz .Lrest_bytes +SYM_FUNC_START(rep_stos_alternative) + cmpq $64,%rcx + jae .Lunrolled - # do the qwords first - .p2align 4 -.Lqwords: - movq $0,(%rdi) - lea 8(%rdi),%rdi - dec %rcx - jnz .Lqwords + cmp $8,%ecx + jae .Lword -.Lrest_bytes: - and $7, %eax - jz .Lexit + testl %ecx,%ecx + je .Lexit - # now do the rest bytes -.Lbytes: - movb $0,(%rdi) +.Lclear_user_tail: +0: movb %al,(%rdi) inc %rdi - dec %eax - jnz .Lbytes - + dec %rcx + jnz .Lclear_user_tail .Lexit: - /* - * %rax still needs to be cleared in the exception case because this function is called - * from inline asm and the compiler expects %rax to be zero when exiting the inline asm, - * in case it might reuse it somewhere. - */ - xor %eax,%eax - RET - -.Lqwords_exception: - # convert remaining qwords back into bytes to return to caller - shl $3, %rcx - and $7, %eax - add %rax,%rcx - jmp .Lexit - -.Lbytes_exception: - mov %eax,%ecx - jmp .Lexit - - _ASM_EXTABLE_UA(.Lqwords, .Lqwords_exception) - _ASM_EXTABLE_UA(.Lbytes, .Lbytes_exception) -SYM_FUNC_END(clear_user_original) -EXPORT_SYMBOL(clear_user_original) - -/* - * Alternative clear user-space when CPU feature X86_FEATURE_REP_GOOD is - * present. - * Input: - * rdi destination - * rcx count - * - * Output: - * rcx: uncleared bytes or 0 if successful. - */ -SYM_FUNC_START(clear_user_rep_good) - # call the original thing for less than a cacheline - cmp $64, %rcx - jb clear_user_original - -.Lprep: - # copy lower 32-bits for rest bytes - mov %ecx, %edx - shr $3, %rcx - jz .Lrep_good_rest_bytes - -.Lrep_good_qwords: - rep stosq - -.Lrep_good_rest_bytes: - and $7, %edx - jz .Lrep_good_exit - -.Lrep_good_bytes: - mov %edx, %ecx - rep stosb - -.Lrep_good_exit: - # see .Lexit comment above - xor %eax, %eax RET -.Lrep_good_qwords_exception: - # convert remaining qwords back into bytes to return to caller - shl $3, %rcx - and $7, %edx - add %rdx, %rcx - jmp .Lrep_good_exit + _ASM_EXTABLE_UA( 0b, .Lexit) - _ASM_EXTABLE_UA(.Lrep_good_qwords, .Lrep_good_qwords_exception) - _ASM_EXTABLE_UA(.Lrep_good_bytes, .Lrep_good_exit) -SYM_FUNC_END(clear_user_rep_good) -EXPORT_SYMBOL(clear_user_rep_good) +.Lword: +1: movq %rax,(%rdi) + addq $8,%rdi + sub $8,%ecx + je .Lexit + cmp $8,%ecx + jae .Lword + jmp .Lclear_user_tail -/* - * Alternative clear user-space when CPU feature X86_FEATURE_ERMS is present. - * Input: - * rdi destination - * rcx count - * - * Output: - * rcx: uncleared bytes or 0 if successful. - * - */ -SYM_FUNC_START(clear_user_erms) - # call the original thing for less than a cacheline - cmp $64, %rcx - jb clear_user_original - -.Lerms_bytes: - rep stosb - -.Lerms_exit: - xorl %eax,%eax + .p2align 4 +.Lunrolled: +10: movq %rax,(%rdi) +11: movq %rax,8(%rdi) +12: movq %rax,16(%rdi) +13: movq %rax,24(%rdi) +14: movq %rax,32(%rdi) +15: movq %rax,40(%rdi) +16: movq %rax,48(%rdi) +17: movq %rax,56(%rdi) + addq $64,%rdi + subq $64,%rcx + cmpq $64,%rcx + jae .Lunrolled + cmpl $8,%ecx + jae .Lword + testl %ecx,%ecx + jne .Lclear_user_tail RET - _ASM_EXTABLE_UA(.Lerms_bytes, .Lerms_exit) -SYM_FUNC_END(clear_user_erms) -EXPORT_SYMBOL(clear_user_erms) + /* + * If we take an exception on any of the + * word stores, we know that %rcx isn't zero, + * so we can just go to the tail clearing to + * get the exact count. + * + * The unrolled case might end up clearing + * some bytes twice. Don't care. + * + * We could use the value in %rdi to avoid + * a second fault on the exact count case, + * but do we really care? No. + * + * Finally, we could try to align %rdi at the + * top of the unrolling. But unaligned stores + * just aren't that common or expensive. + */ + _ASM_EXTABLE_UA( 1b, .Lclear_user_tail) + _ASM_EXTABLE_UA(10b, .Lclear_user_tail) + _ASM_EXTABLE_UA(11b, .Lclear_user_tail) + _ASM_EXTABLE_UA(12b, .Lclear_user_tail) + _ASM_EXTABLE_UA(13b, .Lclear_user_tail) + _ASM_EXTABLE_UA(14b, .Lclear_user_tail) + _ASM_EXTABLE_UA(15b, .Lclear_user_tail) + _ASM_EXTABLE_UA(16b, .Lclear_user_tail) + _ASM_EXTABLE_UA(17b, .Lclear_user_tail) +SYM_FUNC_END(rep_stos_alternative) +EXPORT_SYMBOL(rep_stos_alternative) diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index 9dec1b38a98f..4fc5c2de2de4 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -7,404 +7,108 @@ */ #include <linux/linkage.h> -#include <asm/current.h> -#include <asm/asm-offsets.h> -#include <asm/thread_info.h> -#include <asm/cpufeatures.h> -#include <asm/alternative.h> #include <asm/asm.h> -#include <asm/smap.h> #include <asm/export.h> -#include <asm/trapnr.h> - -.macro ALIGN_DESTINATION - /* check for bad alignment of destination */ - movl %edi,%ecx - andl $7,%ecx - jz 102f /* already aligned */ - subl $8,%ecx - negl %ecx - subl %ecx,%edx -100: movb (%rsi),%al -101: movb %al,(%rdi) - incq %rsi - incq %rdi - decl %ecx - jnz 100b -102: - - _ASM_EXTABLE_CPY(100b, .Lcopy_user_handle_align) - _ASM_EXTABLE_CPY(101b, .Lcopy_user_handle_align) -.endm /* - * copy_user_generic_unrolled - memory copy with exception handling. - * This version is for CPUs like P4 that don't have efficient micro - * code for rep movsq - * - * Input: - * rdi destination - * rsi source - * rdx count - * - * Output: - * eax uncopied bytes or 0 if successful. - */ -SYM_FUNC_START(copy_user_generic_unrolled) - ASM_STAC - cmpl $8,%edx - jb .Lcopy_user_short_string_bytes - ALIGN_DESTINATION - movl %edx,%ecx - andl $63,%edx - shrl $6,%ecx - jz copy_user_short_string -1: movq (%rsi),%r8 -2: movq 1*8(%rsi),%r9 -3: movq 2*8(%rsi),%r10 -4: movq 3*8(%rsi),%r11 -5: movq %r8,(%rdi) -6: movq %r9,1*8(%rdi) -7: movq %r10,2*8(%rdi) -8: movq %r11,3*8(%rdi) -9: movq 4*8(%rsi),%r8 -10: movq 5*8(%rsi),%r9 -11: movq 6*8(%rsi),%r10 -12: movq 7*8(%rsi),%r11 -13: movq %r8,4*8(%rdi) -14: movq %r9,5*8(%rdi) -15: movq %r10,6*8(%rdi) -16: movq %r11,7*8(%rdi) - leaq 64(%rsi),%rsi - leaq 64(%rdi),%rdi - decl %ecx - jnz 1b - jmp copy_user_short_string - -30: shll $6,%ecx - addl %ecx,%edx - jmp .Lcopy_user_handle_tail - - _ASM_EXTABLE_CPY(1b, 30b) - _ASM_EXTABLE_CPY(2b, 30b) - _ASM_EXTABLE_CPY(3b, 30b) - _ASM_EXTABLE_CPY(4b, 30b) - _ASM_EXTABLE_CPY(5b, 30b) - _ASM_EXTABLE_CPY(6b, 30b) - _ASM_EXTABLE_CPY(7b, 30b) - _ASM_EXTABLE_CPY(8b, 30b) - _ASM_EXTABLE_CPY(9b, 30b) - _ASM_EXTABLE_CPY(10b, 30b) - _ASM_EXTABLE_CPY(11b, 30b) - _ASM_EXTABLE_CPY(12b, 30b) - _ASM_EXTABLE_CPY(13b, 30b) - _ASM_EXTABLE_CPY(14b, 30b) - _ASM_EXTABLE_CPY(15b, 30b) - _ASM_EXTABLE_CPY(16b, 30b) -SYM_FUNC_END(copy_user_generic_unrolled) -EXPORT_SYMBOL(copy_user_generic_unrolled) - -/* Some CPUs run faster using the string copy instructions. - * This is also a lot simpler. Use them when possible. - * - * Only 4GB of copy is supported. This shouldn't be a problem - * because the kernel normally only writes from/to page sized chunks - * even if user space passed a longer buffer. - * And more would be dangerous because both Intel and AMD have - * errata with rep movsq > 4GB. If someone feels the need to fix - * this please consider this. + * rep_movs_alternative - memory copy with exception handling. + * This version is for CPUs that don't have FSRM (Fast Short Rep Movs) * * Input: * rdi destination * rsi source - * rdx count + * rcx count * * Output: - * eax uncopied bytes or 0 if successful. - */ -SYM_FUNC_START(copy_user_generic_string) - ASM_STAC - cmpl $8,%edx - jb 2f /* less than 8 bytes, go to byte copy loop */ - ALIGN_DESTINATION - movl %edx,%ecx - shrl $3,%ecx - andl $7,%edx -1: rep movsq -2: movl %edx,%ecx -3: rep movsb - xorl %eax,%eax - ASM_CLAC - RET - -11: leal (%rdx,%rcx,8),%ecx -12: movl %ecx,%edx /* ecx is zerorest also */ - jmp .Lcopy_user_handle_tail - - _ASM_EXTABLE_CPY(1b, 11b) - _ASM_EXTABLE_CPY(3b, 12b) -SYM_FUNC_END(copy_user_generic_string) -EXPORT_SYMBOL(copy_user_generic_string) - -/* - * Some CPUs are adding enhanced REP MOVSB/STOSB instructions. - * It's recommended to use enhanced REP MOVSB/STOSB if it's enabled. - * - * Input: - * rdi destination - * rsi source - * rdx count + * rcx uncopied bytes or 0 if successful. * - * Output: - * eax uncopied bytes or 0 if successful. + * NOTE! The calling convention is very intentionally the same as + * for 'rep movs', so that we can rewrite the function call with + * just a plain 'rep movs' on machines that have FSRM. But to make + * it simpler for us, we can clobber rsi/rdi and rax/r8-r11 freely. */ -SYM_FUNC_START(copy_user_enhanced_fast_string) - ASM_STAC - /* CPUs without FSRM should avoid rep movsb for short copies */ - ALTERNATIVE "cmpl $64, %edx; jb copy_user_short_string", "", X86_FEATURE_FSRM - movl %edx,%ecx -1: rep movsb - xorl %eax,%eax - ASM_CLAC +SYM_FUNC_START(rep_movs_alternative) + cmpq $64,%rcx + jae .Lunrolled + + cmp $8,%ecx + jae .Lword + + testl %ecx,%ecx + je .Lexit + +.Lcopy_user_tail: +0: movb (%rsi),%al +1: movb %al,(%rdi) + inc %rdi + inc %rsi + dec %rcx + jne .Lcopy_user_tail +.Lexit: RET -12: movl %ecx,%edx /* ecx is zerorest also */ - jmp .Lcopy_user_handle_tail - - _ASM_EXTABLE_CPY(1b, 12b) -SYM_FUNC_END(copy_user_enhanced_fast_string) -EXPORT_SYMBOL(copy_user_enhanced_fast_string) - -/* - * Try to copy last bytes and clear the rest if needed. - * Since protection fault in copy_from/to_user is not a normal situation, - * it is not necessary to optimize tail handling. - * Don't try to copy the tail if machine check happened - * - * Input: - * eax trap number written by ex_handler_copy() - * rdi destination - * rsi source - * rdx count - * - * Output: - * eax uncopied bytes or 0 if successful. - */ -SYM_CODE_START_LOCAL(.Lcopy_user_handle_tail) - cmp $X86_TRAP_MC,%eax - je 3f - - movl %edx,%ecx -1: rep movsb -2: mov %ecx,%eax - ASM_CLAC + _ASM_EXTABLE_UA( 0b, .Lexit) + _ASM_EXTABLE_UA( 1b, .Lexit) + + .p2align 4 +.Lword: +2: movq (%rsi),%rax +3: movq %rax,(%rdi) + addq $8,%rsi + addq $8,%rdi + sub $8,%ecx + je .Lexit + cmp $8,%ecx + jae .Lword + jmp .Lcopy_user_tail + + _ASM_EXTABLE_UA( 2b, .Lcopy_user_tail) + _ASM_EXTABLE_UA( 3b, .Lcopy_user_tail) + + .p2align 4 +.Lunrolled: +10: movq (%rsi),%r8 +11: movq 8(%rsi),%r9 +12: movq 16(%rsi),%r10 +13: movq 24(%rsi),%r11 +14: movq %r8,(%rdi) +15: movq %r9,8(%rdi) +16: movq %r10,16(%rdi) +17: movq %r11,24(%rdi) +20: movq 32(%rsi),%r8 +21: movq 40(%rsi),%r9 +22: movq 48(%rsi),%r10 +23: movq 56(%rsi),%r11 +24: movq %r8,32(%rdi) +25: movq %r9,40(%rdi) +26: movq %r10,48(%rdi) +27: movq %r11,56(%rdi) + addq $64,%rsi + addq $64,%rdi + subq $64,%rcx + cmpq $64,%rcx + jae .Lunrolled + cmpl $8,%ecx + jae .Lword + testl %ecx,%ecx + jne .Lcopy_user_tail RET -3: - movl %edx,%eax - ASM_CLAC - RET - - _ASM_EXTABLE_CPY(1b, 2b) - -.Lcopy_user_handle_align: - addl %ecx,%edx /* ecx is zerorest also */ - jmp .Lcopy_user_handle_tail - -SYM_CODE_END(.Lcopy_user_handle_tail) - -/* - * Finish memcpy of less than 64 bytes. #AC should already be set. - * - * Input: - * rdi destination - * rsi source - * rdx count (< 64) - * - * Output: - * eax uncopied bytes or 0 if successful. - */ -SYM_CODE_START_LOCAL(copy_user_short_string) - movl %edx,%ecx - andl $7,%edx - shrl $3,%ecx - jz .Lcopy_user_short_string_bytes -18: movq (%rsi),%r8 -19: movq %r8,(%rdi) - leaq 8(%rsi),%rsi - leaq 8(%rdi),%rdi - decl %ecx - jnz 18b -.Lcopy_user_short_string_bytes: - andl %edx,%edx - jz 23f - movl %edx,%ecx -21: movb (%rsi),%al -22: movb %al,(%rdi) - incq %rsi - incq %rdi - decl %ecx - jnz 21b -23: xor %eax,%eax - ASM_CLAC - RET - -40: leal (%rdx,%rcx,8),%edx - jmp 60f -50: movl %ecx,%edx /* ecx is zerorest also */ -60: jmp .Lcopy_user_handle_tail - - _ASM_EXTABLE_CPY(18b, 40b) - _ASM_EXTABLE_CPY(19b, 40b) - _ASM_EXTABLE_CPY(21b, 50b) - _ASM_EXTABLE_CPY(22b, 50b) -SYM_CODE_END(copy_user_short_string) - -/* - * copy_user_nocache - Uncached memory copy with exception handling - * This will force destination out of cache for more performance. - * - * Note: Cached memory copy is used when destination or size is not - * naturally aligned. That is: - * - Require 8-byte alignment when size is 8 bytes or larger. - * - Require 4-byte alignment when size is 4 bytes. - */ -SYM_FUNC_START(__copy_user_nocache) - ASM_STAC - - /* If size is less than 8 bytes, go to 4-byte copy */ - cmpl $8,%edx - jb .L_4b_nocache_copy_entry - - /* If destination is not 8-byte aligned, "cache" copy to align it */ - ALIGN_DESTINATION - - /* Set 4x8-byte copy count and remainder */ - movl %edx,%ecx - andl $63,%edx - shrl $6,%ecx - jz .L_8b_nocache_copy_entry /* jump if count is 0 */ - - /* Perform 4x8-byte nocache loop-copy */ -.L_4x8b_nocache_copy_loop: -1: movq (%rsi),%r8 -2: movq 1*8(%rsi),%r9 -3: movq 2*8(%rsi),%r10 -4: movq 3*8(%rsi),%r11 -5: movnti %r8,(%rdi) -6: movnti %r9,1*8(%rdi) -7: movnti %r10,2*8(%rdi) -8: movnti %r11,3*8(%rdi) -9: movq 4*8(%rsi),%r8 -10: movq 5*8(%rsi),%r9 -11: movq 6*8(%rsi),%r10 -12: movq 7*8(%rsi),%r11 -13: movnti %r8,4*8(%rdi) -14: movnti %r9,5*8(%rdi) -15: movnti %r10,6*8(%rdi) -16: movnti %r11,7*8(%rdi) - leaq 64(%rsi),%rsi - leaq 64(%rdi),%rdi - decl %ecx - jnz .L_4x8b_nocache_copy_loop - - /* Set 8-byte copy count and remainder */ -.L_8b_nocache_copy_entry: - movl %edx,%ecx - andl $7,%edx - shrl $3,%ecx - jz .L_4b_nocache_copy_entry /* jump if count is 0 */ - - /* Perform 8-byte nocache loop-copy */ -.L_8b_nocache_copy_loop: -20: movq (%rsi),%r8 -21: movnti %r8,(%rdi) - leaq 8(%rsi),%rsi - leaq 8(%rdi),%rdi - decl %ecx - jnz .L_8b_nocache_copy_loop - - /* If no byte left, we're done */ -.L_4b_nocache_copy_entry: - andl %edx,%edx - jz .L_finish_copy - - /* If destination is not 4-byte aligned, go to byte copy: */ - movl %edi,%ecx - andl $3,%ecx - jnz .L_1b_cache_copy_entry - - /* Set 4-byte copy count (1 or 0) and remainder */ - movl %edx,%ecx - andl $3,%edx - shrl $2,%ecx - jz .L_1b_cache_copy_entry /* jump if count is 0 */ - - /* Perform 4-byte nocache copy: */ -30: movl (%rsi),%r8d -31: movnti %r8d,(%rdi) - leaq 4(%rsi),%rsi - leaq 4(%rdi),%rdi - - /* If no bytes left, we're done: */ - andl %edx,%edx - jz .L_finish_copy - - /* Perform byte "cache" loop-copy for the remainder */ -.L_1b_cache_copy_entry: - movl %edx,%ecx -.L_1b_cache_copy_loop: -40: movb (%rsi),%al -41: movb %al,(%rdi) - incq %rsi - incq %rdi - decl %ecx - jnz .L_1b_cache_copy_loop - - /* Finished copying; fence the prior stores */ -.L_finish_copy: - xorl %eax,%eax - ASM_CLAC - sfence - RET - -.L_fixup_4x8b_copy: - shll $6,%ecx - addl %ecx,%edx - jmp .L_fixup_handle_tail -.L_fixup_8b_copy: - lea (%rdx,%rcx,8),%rdx - jmp .L_fixup_handle_tail -.L_fixup_4b_copy: - lea (%rdx,%rcx,4),%rdx - jmp .L_fixup_handle_tail -.L_fixup_1b_copy: - movl %ecx,%edx -.L_fixup_handle_tail: - sfence - jmp .Lcopy_user_handle_tail - - _ASM_EXTABLE_CPY(1b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(2b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(3b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(4b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(5b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(6b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(7b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(8b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(9b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(10b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(11b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(12b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(13b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(14b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(15b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(16b, .L_fixup_4x8b_copy) - _ASM_EXTABLE_CPY(20b, .L_fixup_8b_copy) - _ASM_EXTABLE_CPY(21b, .L_fixup_8b_copy) - _ASM_EXTABLE_CPY(30b, .L_fixup_4b_copy) - _ASM_EXTABLE_CPY(31b, .L_fixup_4b_copy) - _ASM_EXTABLE_CPY(40b, .L_fixup_1b_copy) - _ASM_EXTABLE_CPY(41b, .L_fixup_1b_copy) -SYM_FUNC_END(__copy_user_nocache) -EXPORT_SYMBOL(__copy_user_nocache) + _ASM_EXTABLE_UA(10b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(11b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(12b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(13b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(14b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(15b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(16b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(17b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(20b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(21b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(22b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(23b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(24b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(25b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(26b, .Lcopy_user_tail) + _ASM_EXTABLE_UA(27b, .Lcopy_user_tail) +SYM_FUNC_END(rep_movs_alternative) +EXPORT_SYMBOL(rep_movs_alternative) diff --git a/arch/x86/lib/copy_user_uncached_64.S b/arch/x86/lib/copy_user_uncached_64.S new file mode 100644 index 000000000000..5c5f38d32672 --- /dev/null +++ b/arch/x86/lib/copy_user_uncached_64.S @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright 2023 Linus Torvalds <[email protected]> + */ + +#include <linux/linkage.h> +#include <asm/asm.h> +#include <asm/export.h> + +/* + * copy_user_nocache - Uncached memory copy with exception handling + * + * This copies from user space into kernel space, but the kernel + * space accesses can take a machine check exception, so they too + * need exception handling. + * + * Note: only 32-bit and 64-bit stores have non-temporal versions, + * and we only use aligned versions. Any unaligned parts at the + * start or end of the copy will be done using normal cached stores. + * + * Input: + * rdi destination + * rsi source + * edx count + * + * Output: + * rax uncopied bytes or 0 if successful. + */ +SYM_FUNC_START(__copy_user_nocache) + /* If destination is not 7-byte aligned, we'll have to align it */ + testb $7,%dil + jne .Lalign + +.Lis_aligned: + cmp $64,%edx + jb .Lquadwords + + .p2align 4,0x90 +.Lunrolled: +10: movq (%rsi),%r8 +11: movq 8(%rsi),%r9 +12: movq 16(%rsi),%r10 +13: movq 24(%rsi),%r11 +20: movnti %r8,(%rdi) +21: movnti %r9,8(%rdi) +22: movnti %r10,16(%rdi) +23: movnti %r11,24(%rdi) +30: movq 32(%rsi),%r8 +31: movq 40(%rsi),%r9 +32: movq 48(%rsi),%r10 +33: movq 56(%rsi),%r11 +40: movnti %r8,32(%rdi) +41: movnti %r9,40(%rdi) +42: movnti %r10,48(%rdi) +43: movnti %r11,56(%rdi) + + addq $64,%rsi + addq $64,%rdi + sub $64,%edx + cmp $64,%edx + jae .Lunrolled + +/* + * First set of user mode loads have been done + * without any stores, so if they fail, we can + * just try the non-unrolled loop. + */ +_ASM_EXTABLE_UA(10b, .Lquadwords) +_ASM_EXTABLE_UA(11b, .Lquadwords) +_ASM_EXTABLE_UA(12b, .Lquadwords) +_ASM_EXTABLE_UA(13b, .Lquadwords) + +/* + * The second set of user mode loads have been + * done with 32 bytes stored to the destination, + * so we need to take that into account before + * falling back to the unrolled loop. + */ +_ASM_EXTABLE_UA(30b, .Lfixup32) +_ASM_EXTABLE_UA(31b, .Lfixup32) +_ASM_EXTABLE_UA(32b, .Lfixup32) +_ASM_EXTABLE_UA(33b, .Lfixup32) + +/* + * An exception on a write means that we're + * done, but we need to update the count + * depending on where in the unrolled loop + * we were. + */ +_ASM_EXTABLE_UA(20b, .Ldone0) +_ASM_EXTABLE_UA(21b, .Ldone8) +_ASM_EXTABLE_UA(22b, .Ldone16) +_ASM_EXTABLE_UA(23b, .Ldone24) +_ASM_EXTABLE_UA(40b, .Ldone32) +_ASM_EXTABLE_UA(41b, .Ldone40) +_ASM_EXTABLE_UA(42b, .Ldone48) +_ASM_EXTABLE_UA(43b, .Ldone56) + +.Lquadwords: + cmp $8,%edx + jb .Llong +50: movq (%rsi),%rax +51: movnti %rax,(%rdi) + addq $8,%rsi + addq $8,%rdi + sub $8,%edx + jmp .Lquadwords + +/* + * If we fail on the last full quadword, we will + * not try to do any byte-wise cached accesses. + * We will try to do one more 4-byte uncached + * one, though. + */ +_ASM_EXTABLE_UA(50b, .Llast4) +_ASM_EXTABLE_UA(51b, .Ldone0) + +.Llong: + test $4,%dl + je .Lword +60: movl (%rsi),%eax +61: movnti %eax,(%rdi) + addq $4,%rsi + addq $4,%rdi + sub $4,%edx +.Lword: + sfence + test $2,%dl + je .Lbyte +70: movw (%rsi),%ax +71: movw %ax,(%rdi) + addq $2,%rsi + addq $2,%rdi + sub $2,%edx +.Lbyte: + test $1,%dl + je .Ldone +80: movb (%rsi),%al +81: movb %al,(%rdi) + dec %edx +.Ldone: + mov %edx,%eax + RET + +/* + * If we fail on the last four bytes, we won't + * bother with any fixups. It's dead, Jim. Note + * that there's no need for 'sfence' for any + * of this, since the exception will have been + * serializing. + */ +_ASM_EXTABLE_UA(60b, .Ldone) +_ASM_EXTABLE_UA(61b, .Ldone) +_ASM_EXTABLE_UA(70b, .Ldone) +_ASM_EXTABLE_UA(71b, .Ldone) +_ASM_EXTABLE_UA(80b, .Ldone) +_ASM_EXTABLE_UA(81b, .Ldone) + +/* + * This is the "head needs aliging" case when + * the destination isn't 8-byte aligned. The + * 4-byte case can be done uncached, but any + * smaller alignment is done with regular stores. + */ +.Lalign: + test $1,%dil + je .Lalign_word + test %edx,%edx + je .Ldone +90: movb (%rsi),%al +91: movb %al,(%rdi) + inc %rsi + inc %rdi + dec %edx +.Lalign_word: + test $2,%dil + je .Lalign_long + cmp $2,%edx + jb .Lbyte +92: movw (%rsi),%ax +93: movw %ax,(%rdi) + addq $2,%rsi + addq $2,%rdi + sub $2,%edx +.Lalign_long: + test $4,%dil + je .Lis_aligned + cmp $4,%edx + jb .Lword +94: movl (%rsi),%eax +95: movnti %eax,(%rdi) + addq $4,%rsi + addq $4,%rdi + sub $4,%edx + jmp .Lis_aligned + +/* + * If we fail on the initial alignment accesses, + * we're all done. Again, no point in trying to + * do byte-by-byte probing if the 4-byte load + * fails - we're not doing any uncached accesses + * any more. + */ +_ASM_EXTABLE_UA(90b, .Ldone) +_ASM_EXTABLE_UA(91b, .Ldone) +_ASM_EXTABLE_UA(92b, .Ldone) +_ASM_EXTABLE_UA(93b, .Ldone) +_ASM_EXTABLE_UA(94b, .Ldone) +_ASM_EXTABLE_UA(95b, .Ldone) + +/* + * Exception table fixups for faults in the middle + */ +.Ldone56: sub $8,%edx +.Ldone48: sub $8,%edx +.Ldone40: sub $8,%edx +.Ldone32: sub $8,%edx +.Ldone24: sub $8,%edx +.Ldone16: sub $8,%edx +.Ldone8: sub $8,%edx +.Ldone0: + mov %edx,%eax + RET + +.Lfixup32: + addq $32,%rsi + addq $32,%rdi + sub $32,%edx + jmp .Lquadwords + +.Llast4: +52: movl (%rsi),%eax +53: movnti %eax,(%rdi) + sfence + sub $4,%edx + mov %edx,%eax + RET +_ASM_EXTABLE_UA(52b, .Ldone0) +_ASM_EXTABLE_UA(53b, .Ldone0) + +SYM_FUNC_END(__copy_user_nocache) +EXPORT_SYMBOL(__copy_user_nocache) diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S index a64017602010..8f95fb267caa 100644 --- a/arch/x86/lib/memcpy_64.S +++ b/arch/x86/lib/memcpy_64.S @@ -11,13 +11,6 @@ .section .noinstr.text, "ax" /* - * We build a jump to memcpy_orig by default which gets NOPped out on - * the majority of x86 CPUs which set REP_GOOD. In addition, CPUs which - * have the enhanced REP MOVSB/STOSB feature (ERMS), change those NOPs - * to a jmp to memcpy_erms which does the REP; MOVSB mem copy. - */ - -/* * memcpy - Copy a memory block. * * Input: @@ -27,17 +20,21 @@ * * Output: * rax original destination + * + * The FSRM alternative should be done inline (avoiding the call and + * the disgusting return handling), but that would require some help + * from the compiler for better calling conventions. + * + * The 'rep movsb' itself is small enough to replace the call, but the + * two register moves blow up the code. And one of them is "needed" + * only for the return value that is the same as the source input, + * which the compiler could/should do much better anyway. */ SYM_TYPED_FUNC_START(__memcpy) - ALTERNATIVE_2 "jmp memcpy_orig", "", X86_FEATURE_REP_GOOD, \ - "jmp memcpy_erms", X86_FEATURE_ERMS + ALTERNATIVE "jmp memcpy_orig", "", X86_FEATURE_FSRM movq %rdi, %rax movq %rdx, %rcx - shrq $3, %rcx - andl $7, %edx - rep movsq - movl %edx, %ecx rep movsb RET SYM_FUNC_END(__memcpy) @@ -46,17 +43,6 @@ EXPORT_SYMBOL(__memcpy) SYM_FUNC_ALIAS(memcpy, __memcpy) EXPORT_SYMBOL(memcpy) -/* - * memcpy_erms() - enhanced fast string memcpy. This is faster and - * simpler than memcpy. Use memcpy_erms when possible. - */ -SYM_FUNC_START_LOCAL(memcpy_erms) - movq %rdi, %rax - movq %rdx, %rcx - rep movsb - RET -SYM_FUNC_END(memcpy_erms) - SYM_FUNC_START_LOCAL(memcpy_orig) movq %rdi, %rax diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S index 6143b1a6fa2c..7c59a704c458 100644 --- a/arch/x86/lib/memset_64.S +++ b/arch/x86/lib/memset_64.S @@ -18,27 +18,22 @@ * rdx count (bytes) * * rax original destination + * + * The FSRS alternative should be done inline (avoiding the call and + * the disgusting return handling), but that would require some help + * from the compiler for better calling conventions. + * + * The 'rep stosb' itself is small enough to replace the call, but all + * the register moves blow up the code. And two of them are "needed" + * only for the return value that is the same as the source input, + * which the compiler could/should do much better anyway. */ SYM_FUNC_START(__memset) - /* - * Some CPUs support enhanced REP MOVSB/STOSB feature. It is recommended - * to use it when possible. If not available, use fast string instructions. - * - * Otherwise, use original memset function. - */ - ALTERNATIVE_2 "jmp memset_orig", "", X86_FEATURE_REP_GOOD, \ - "jmp memset_erms", X86_FEATURE_ERMS + ALTERNATIVE "jmp memset_orig", "", X86_FEATURE_FSRS movq %rdi,%r9 + movb %sil,%al movq %rdx,%rcx - andl $7,%edx - shrq $3,%rcx - /* expand byte value */ - movzbl %sil,%esi - movabs $0x0101010101010101,%rax - imulq %rsi,%rax - rep stosq - movl %edx,%ecx rep stosb movq %r9,%rax RET @@ -48,26 +43,6 @@ EXPORT_SYMBOL(__memset) SYM_FUNC_ALIAS(memset, __memset) EXPORT_SYMBOL(memset) -/* - * ISO C memset - set a memory block to a byte value. This function uses - * enhanced rep stosb to override the fast string function. - * The code is simpler and shorter than the fast string function as well. - * - * rdi destination - * rsi value (char) - * rdx count (bytes) - * - * rax original destination - */ -SYM_FUNC_START_LOCAL(memset_erms) - movq %rdi,%r9 - movb %sil,%al - movq %rdx,%rcx - rep stosb - movq %r9,%rax - RET -SYM_FUNC_END(memset_erms) - SYM_FUNC_START_LOCAL(memset_orig) movq %rdi,%r10 diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index 6c1f8ac5e721..c3a5bbc0b41e 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c @@ -45,7 +45,11 @@ EXPORT_SYMBOL_GPL(arch_wb_cache_pmem); long __copy_user_flushcache(void *dst, const void __user *src, unsigned size) { unsigned long flushed, dest = (unsigned long) dst; - long rc = __copy_user_nocache(dst, src, size, 0); + long rc; + + stac(); + rc = __copy_user_nocache(dst, src, size); + clac(); /* * __copy_user_nocache() uses non-temporal stores for the bulk diff --git a/block/blk-map.c b/block/blk-map.c index 9137d16cecdc..04c55f1c492e 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -29,10 +29,11 @@ static struct bio_map_data *bio_alloc_map_data(struct iov_iter *data, bmd = kmalloc(struct_size(bmd, iov, data->nr_segs), gfp_mask); if (!bmd) return NULL; - memcpy(bmd->iov, data->iov, sizeof(struct iovec) * data->nr_segs); bmd->iter = *data; - if (iter_is_iovec(data)) - bmd->iter.iov = bmd->iov; + if (iter_is_iovec(data)) { + memcpy(bmd->iov, iter_iov(data), sizeof(struct iovec) * data->nr_segs); + bmd->iter.__iov = bmd->iov; + } return bmd; } diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index b1d6ca7e9708..f3d6ce45c397 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -267,6 +267,8 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from) if (!HFI1_CAP_IS_KSET(SDMA)) return -EINVAL; + if (!from->user_backed) + return -EINVAL; idx = srcu_read_lock(&fd->pq_srcu); pq = srcu_dereference(fd->pq, &fd->pq_srcu); if (!cq || !pq) { @@ -274,11 +276,6 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from) return -EIO; } - if (!iter_is_iovec(from) || !dim) { - srcu_read_unlock(&fd->pq_srcu, idx); - return -EINVAL; - } - trace_hfi1_sdma_request(fd->dd, fd->uctxt->ctxt, fd->subctxt, dim); if (atomic_read(&pq->n_reqs) == pq->n_max_reqs) { @@ -287,11 +284,12 @@ static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from) } while (dim) { + const struct iovec *iov = iter_iov(from); int ret; unsigned long count = 0; ret = hfi1_user_sdma_process_request( - fd, (struct iovec *)(from->iov + done), + fd, (struct iovec *)(iov + done), dim, &count); if (ret) { reqs = ret; diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 80fe92a21f96..815ea72ad473 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -2245,10 +2245,10 @@ static ssize_t qib_write_iter(struct kiocb *iocb, struct iov_iter *from) struct qib_ctxtdata *rcd = ctxt_fp(iocb->ki_filp); struct qib_user_sdma_queue *pq = fp->pq; - if (!iter_is_iovec(from) || !from->nr_segs || !pq) + if (!from->user_backed || !from->nr_segs || !pq) return -EINVAL; - return qib_user_sdma_writev(rcd, pq, from->iov, from->nr_segs); + return qib_user_sdma_writev(rcd, pq, iter_iov(from), from->nr_segs); } static struct class *qib_class; diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index 3acab569fbb9..9b4c0389d2c0 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -97,7 +97,7 @@ static void cacheless_memcpy(void *dst, void *src, size_t n) * there are no security issues. The extra fault recovery machinery * is not invoked. */ - __copy_user_nocache(dst, (void __user *)src, n, 0); + __copy_user_nocache(dst, (void __user *)src, n); } void rvt_wss_exit(struct rvt_dev_info *rdi) diff --git a/drivers/net/tun.c b/drivers/net/tun.c index ad653b32b2f0..5df1eba7b30a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1486,7 +1486,8 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile, skb->truesize += skb->data_len; for (i = 1; i < it->nr_segs; i++) { - size_t fragsz = it->iov[i].iov_len; + const struct iovec *iov = iter_iov(it); + size_t fragsz = iov->iov_len; struct page *page; void *frag; diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 32d0be968103..e68f7d226bc9 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -665,7 +665,7 @@ vhost_scsi_calc_sgls(struct iov_iter *iter, size_t bytes, int max_sgls) { int sgl_count = 0; - if (!iter || !iter->iov) { + if (!iter || !iter_iov(iter)) { pr_err("%s: iter->iov is NULL, but expected bytes: %zu" " present\n", __func__, bytes); return -EINVAL; diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 5cc5a1faaef5..f649647392e0 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -3730,10 +3730,15 @@ static int check_direct_read(struct btrfs_fs_info *fs_info, if (!iter_is_iovec(iter)) return 0; - for (seg = 0; seg < iter->nr_segs; seg++) - for (i = seg + 1; i < iter->nr_segs; i++) - if (iter->iov[seg].iov_base == iter->iov[i].iov_base) + for (seg = 0; seg < iter->nr_segs; seg++) { + for (i = seg + 1; i < iter->nr_segs; i++) { + const struct iovec *iov1 = iter_iov(iter) + seg; + const struct iovec *iov2 = iter_iov(iter) + i; + + if (iov1->iov_base == iov2->iov_base) return -EINVAL; + } + } return 0; } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index de37a3a06a71..89d97f6188e0 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1419,7 +1419,7 @@ out: static inline unsigned long fuse_get_user_addr(const struct iov_iter *ii) { - return (unsigned long)ii->iov->iov_base + ii->iov_offset; + return (unsigned long)iter_iov(ii)->iov_base + ii->iov_offset; } static inline size_t fuse_get_frag_size(const struct iov_iter *ii, diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 9175dbc47201..17c52225b87d 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -242,6 +242,7 @@ static int ocfs2_mknod(struct mnt_idmap *idmap, int want_meta = 0; int xattr_credits = 0; struct ocfs2_security_xattr_info si = { + .name = NULL, .enable = 1, }; int did_quota_inode = 0; @@ -1805,6 +1806,7 @@ static int ocfs2_symlink(struct mnt_idmap *idmap, int want_clusters = 0; int xattr_credits = 0; struct ocfs2_security_xattr_info si = { + .name = NULL, .enable = 1, }; int did_quota = 0, did_quota_inode = 0; diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 389308efe854..469ec45baee2 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -7259,9 +7259,21 @@ static int ocfs2_xattr_security_set(const struct xattr_handler *handler, static int ocfs2_initxattrs(struct inode *inode, const struct xattr *xattr_array, void *fs_info) { + struct ocfs2_security_xattr_info *si = fs_info; const struct xattr *xattr; int err = 0; + if (si) { + si->value = kmemdup(xattr_array->value, xattr_array->value_len, + GFP_KERNEL); + if (!si->value) + return -ENOMEM; + + si->name = xattr_array->name; + si->value_len = xattr_array->value_len; + return 0; + } + for (xattr = xattr_array; xattr->name != NULL; xattr++) { err = ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_SECURITY, xattr->name, xattr->value, @@ -7277,13 +7289,23 @@ int ocfs2_init_security_get(struct inode *inode, const struct qstr *qstr, struct ocfs2_security_xattr_info *si) { + int ret; + /* check whether ocfs2 support feature xattr */ if (!ocfs2_supports_xattr(OCFS2_SB(dir->i_sb))) return -EOPNOTSUPP; - if (si) - return security_old_inode_init_security(inode, dir, qstr, - &si->name, &si->value, - &si->value_len); + if (si) { + ret = security_inode_init_security(inode, dir, qstr, + &ocfs2_initxattrs, si); + /* + * security_inode_init_security() does not return -EOPNOTSUPP, + * we have to check the xattr ourselves. + */ + if (!ret && !si->name) + si->enable = 0; + + return ret; + } return security_inode_init_security(inode, dir, qstr, &ocfs2_initxattrs, NULL); diff --git a/fs/read_write.c b/fs/read_write.c index 7a2ff6157eda..a21ba3be7dbe 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -749,15 +749,14 @@ static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter, return -EOPNOTSUPP; while (iov_iter_count(iter)) { - struct iovec iovec = iov_iter_iovec(iter); ssize_t nr; if (type == READ) { - nr = filp->f_op->read(filp, iovec.iov_base, - iovec.iov_len, ppos); + nr = filp->f_op->read(filp, iter_iov_addr(iter), + iter_iov_len(iter), ppos); } else { - nr = filp->f_op->write(filp, iovec.iov_base, - iovec.iov_len, ppos); + nr = filp->f_op->write(filp, iter_iov_addr(iter), + iter_iov_len(iter), ppos); } if (nr < 0) { @@ -766,7 +765,7 @@ static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter, break; } ret += nr; - if (nr != iovec.iov_len) + if (nr != iter_iov_len(iter)) break; iov_iter_advance(iter, nr); } diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c index 41c0ea84fbff..6e0a099dd788 100644 --- a/fs/reiserfs/xattr_security.c +++ b/fs/reiserfs/xattr_security.c @@ -39,6 +39,22 @@ static bool security_list(struct dentry *dentry) return !IS_PRIVATE(d_inode(dentry)); } +static int +reiserfs_initxattrs(struct inode *inode, const struct xattr *xattr_array, + void *fs_info) +{ + struct reiserfs_security_handle *sec = fs_info; + + sec->value = kmemdup(xattr_array->value, xattr_array->value_len, + GFP_KERNEL); + if (!sec->value) + return -ENOMEM; + + sec->name = xattr_array->name; + sec->length = xattr_array->value_len; + return 0; +} + /* Initializes the security context for a new inode and returns the number * of blocks needed for the transaction. If successful, reiserfs_security * must be released using reiserfs_security_free when the caller is done. */ @@ -56,12 +72,9 @@ int reiserfs_security_init(struct inode *dir, struct inode *inode, if (IS_PRIVATE(dir)) return 0; - error = security_old_inode_init_security(inode, dir, qstr, &sec->name, - &sec->value, &sec->length); + error = security_inode_init_security(inode, dir, qstr, + &reiserfs_initxattrs, sec); if (error) { - if (error == -EOPNOTSUPP) - error = 0; - sec->name = NULL; sec->value = NULL; sec->length = 0; @@ -82,11 +95,15 @@ int reiserfs_security_write(struct reiserfs_transaction_handle *th, struct inode *inode, struct reiserfs_security_handle *sec) { + char xattr_name[XATTR_NAME_MAX + 1] = XATTR_SECURITY_PREFIX; int error; - if (strlen(sec->name) < sizeof(XATTR_SECURITY_PREFIX)) + + if (XATTR_SECURITY_PREFIX_LEN + strlen(sec->name) > XATTR_NAME_MAX) return -EINVAL; - error = reiserfs_xattr_set_handle(th, inode, sec->name, sec->value, + strlcat(xattr_name, sec->name, sizeof(xattr_name)); + + error = reiserfs_xattr_set_handle(th, inode, xattr_name, sec->value, sec->length, XATTR_CREATE); if (error == -ENODATA || error == -EOPNOTSUPP) error = 0; diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 094b76dc7164..6bb55e61e8e8 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -381,7 +381,7 @@ LSM_HOOK(int, 0, key_alloc, struct key *key, const struct cred *cred, LSM_HOOK(void, LSM_RET_VOID, key_free, struct key *key) LSM_HOOK(int, 0, key_permission, key_ref_t key_ref, const struct cred *cred, enum key_need_perm need_perm) -LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **_buffer) +LSM_HOOK(int, 0, key_getsecurity, struct key *key, char **buffer) #endif /* CONFIG_KEYS */ #ifdef CONFIG_AUDIT diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 6e156d2acffc..ab2b2fafa4a4 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -29,1630 +29,6 @@ #include <linux/init.h> #include <linux/rculist.h> -/** - * union security_list_options - Linux Security Module hook function list - * - * Security hooks for program execution operations. - * - * @bprm_creds_for_exec: - * If the setup in prepare_exec_creds did not setup @bprm->cred->security - * properly for executing @bprm->file, update the LSM's portion of - * @bprm->cred->security to be what commit_creds needs to install for the - * new program. This hook may also optionally check permissions - * (e.g. for transitions between security domains). - * The hook must set @bprm->secureexec to 1 if AT_SECURE should be set to - * request libc enable secure mode. - * @bprm contains the linux_binprm structure. - * Return 0 if the hook is successful and permission is granted. - * @bprm_creds_from_file: - * If @file is setpcap, suid, sgid or otherwise marked to change - * privilege upon exec, update @bprm->cred to reflect that change. - * This is called after finding the binary that will be executed. - * without an interpreter. This ensures that the credentials will not - * be derived from a script that the binary will need to reopen, which - * when reopend may end up being a completely different file. This - * hook may also optionally check permissions (e.g. for transitions - * between security domains). - * The hook must set @bprm->secureexec to 1 if AT_SECURE should be set to - * request libc enable secure mode. - * The hook must add to @bprm->per_clear any personality flags that - * should be cleared from current->personality. - * @bprm contains the linux_binprm structure. - * Return 0 if the hook is successful and permission is granted. - * @bprm_check_security: - * This hook mediates the point when a search for a binary handler will - * begin. It allows a check against the @bprm->cred->security value - * which was set in the preceding creds_for_exec call. The argv list and - * envp list are reliably available in @bprm. This hook may be called - * multiple times during a single execve. - * @bprm contains the linux_binprm structure. - * Return 0 if the hook is successful and permission is granted. - * @bprm_committing_creds: - * Prepare to install the new security attributes of a process being - * transformed by an execve operation, based on the old credentials - * pointed to by @current->cred and the information set in @bprm->cred by - * the bprm_creds_for_exec hook. @bprm points to the linux_binprm - * structure. This hook is a good place to perform state changes on the - * process such as closing open file descriptors to which access will no - * longer be granted when the attributes are changed. This is called - * immediately before commit_creds(). - * @bprm_committed_creds: - * Tidy up after the installation of the new security attributes of a - * process being transformed by an execve operation. The new credentials - * have, by this point, been set to @current->cred. @bprm points to the - * linux_binprm structure. This hook is a good place to perform state - * changes on the process such as clearing out non-inheritable signal - * state. This is called immediately after commit_creds(). - * - * Security hooks for mount using fs_context. - * [See also Documentation/filesystems/mount_api.rst] - * - * @fs_context_dup: - * Allocate and attach a security structure to sc->security. This pointer - * is initialised to NULL by the caller. - * @fc indicates the new filesystem context. - * @src_fc indicates the original filesystem context. - * Return 0 on success or a negative error code on failure. - * @fs_context_parse_param: - * Userspace provided a parameter to configure a superblock. The LSM may - * reject it with an error and may use it for itself, in which case it - * should return 0; otherwise it should return -ENOPARAM to pass it on to - * the filesystem. - * @fc indicates the filesystem context. - * @param The parameter. - * - * Security hooks for filesystem operations. - * - * @sb_alloc_security: - * Allocate and attach a security structure to the sb->s_security field. - * The s_security field is initialized to NULL when the structure is - * allocated. - * @sb contains the super_block structure to be modified. - * Return 0 if operation was successful. - * @sb_delete: - * Release objects tied to a superblock (e.g. inodes). - * @sb contains the super_block structure being released. - * @sb_free_security: - * Deallocate and clear the sb->s_security field. - * @sb contains the super_block structure to be modified. - * @sb_free_mnt_opts: - * Free memory associated with @mnt_ops. - * @sb_eat_lsm_opts: - * Eat (scan @orig options) and save them in @mnt_opts. - * Return 0 on success, negative values on failure. - * @sb_statfs: - * Check permission before obtaining filesystem statistics for the @mnt - * mountpoint. - * @dentry is a handle on the superblock for the filesystem. - * Return 0 if permission is granted. - * @sb_mount: - * Check permission before an object specified by @dev_name is mounted on - * the mount point named by @nd. For an ordinary mount, @dev_name - * identifies a device if the file system type requires a device. For a - * remount (@flags & MS_REMOUNT), @dev_name is irrelevant. For a - * loopback/bind mount (@flags & MS_BIND), @dev_name identifies the - * pathname of the object being mounted. - * @dev_name contains the name for object being mounted. - * @path contains the path for mount point object. - * @type contains the filesystem type. - * @flags contains the mount flags. - * @data contains the filesystem-specific data. - * Return 0 if permission is granted. - * @sb_mnt_opts_compat: - * Determine if the new mount options in @mnt_opts are allowed given - * the existing mounted filesystem at @sb. - * @sb superblock being compared. - * @mnt_opts new mount options. - * Return 0 if options are compatible. - * @sb_remount: - * Extracts security system specific mount options and verifies no changes - * are being made to those options. - * @sb superblock being remounted. - * @data contains the filesystem-specific data. - * Return 0 if permission is granted. - * @sb_kern_mount: - * Mount this @sb if allowed by permissions. - * Return 0 if permission is granted. - * @sb_show_options: - * Show (print on @m) mount options for this @sb. - * Return 0 on success, negative values on failure. - * @sb_umount: - * Check permission before the @mnt file system is unmounted. - * @mnt contains the mounted file system. - * @flags contains the unmount flags, e.g. MNT_FORCE. - * Return 0 if permission is granted. - * @sb_pivotroot: - * Check permission before pivoting the root filesystem. - * @old_path contains the path for the new location of the - * current root (put_old). - * @new_path contains the path for the new root (new_root). - * Return 0 if permission is granted. - * @sb_set_mnt_opts: - * Set the security relevant mount options used for a superblock - * @sb the superblock to set security mount options for. - * @opts binary data structure containing all lsm mount data. - * Return 0 on success, error on failure. - * @sb_clone_mnt_opts: - * Copy all security options from a given superblock to another - * @oldsb old superblock which contain information to clone. - * @newsb new superblock which needs filled in. - * Return 0 on success, error on failure. - * @move_mount: - * Check permission before a mount is moved. - * @from_path indicates the mount that is going to be moved. - * @to_path indicates the mountpoint that will be mounted upon. - * Return 0 if permission is granted. - * @dentry_init_security: - * Compute a context for a dentry as the inode is not yet available - * since NFSv4 has no label backed by an EA anyway. - * @dentry dentry to use in calculating the context. - * @mode mode used to determine resource type. - * @name name of the last path component used to create file. - * @xattr_name pointer to place the pointer to security xattr name. - * Caller does not have to free the resulting pointer. Its - * a pointer to static string. - * @ctx pointer to place the pointer to the resulting context in. - * @ctxlen point to place the length of the resulting context. - * Return 0 on success, negative values on failure. - * @dentry_create_files_as: - * Compute a context for a dentry as the inode is not yet available - * and set that context in passed in creds so that new files are - * created using that context. Context is calculated using the - * passed in creds and not the creds of the caller. - * @dentry dentry to use in calculating the context. - * @mode mode used to determine resource type. - * @name name of the last path component used to create file. - * @old creds which should be used for context calculation. - * @new creds to modify. - * Return 0 on success, error on failure. - * - * - * Security hooks for inode operations. - * - * @inode_alloc_security: - * Allocate and attach a security structure to @inode->i_security. The - * i_security field is initialized to NULL when the inode structure is - * allocated. - * @inode contains the inode structure. - * Return 0 if operation was successful. - * @inode_free_security: - * @inode contains the inode structure. - * Deallocate the inode security structure and set @inode->i_security to - * NULL. - * @inode_init_security: - * Obtain the security attribute name suffix and value to set on a newly - * created inode and set up the incore security field for the new inode. - * This hook is called by the fs code as part of the inode creation - * transaction and provides for atomic labeling of the inode, unlike - * the post_create/mkdir/... hooks called by the VFS. The hook function - * is expected to allocate the name and value via kmalloc, with the caller - * being responsible for calling kfree after using them. - * If the security module does not use security attributes or does - * not wish to put a security attribute on this particular inode, - * then it should return -EOPNOTSUPP to skip this processing. - * @inode contains the inode structure of the newly created inode. - * @dir contains the inode structure of the parent directory. - * @qstr contains the last path component of the new object. - * @name will be set to the allocated name suffix (e.g. selinux). - * @value will be set to the allocated attribute value. - * @len will be set to the length of the value. - * Returns 0 if @name and @value have been successfully set, - * -EOPNOTSUPP if no security attribute is needed, or - * -ENOMEM on memory allocation failure. - * @inode_init_security_anon: - * Set up the incore security field for the new anonymous inode - * and return whether the inode creation is permitted by the security - * module or not. - * @inode contains the inode structure. - * @name name of the anonymous inode class. - * @context_inode optional related inode. - * Returns 0 on success, -EACCES if the security module denies the - * creation of this inode, or another -errno upon other errors. - * @inode_create: - * Check permission to create a regular file. - * @dir contains inode structure of the parent of the new file. - * @dentry contains the dentry structure for the file to be created. - * @mode contains the file mode of the file to be created. - * Return 0 if permission is granted. - * @inode_link: - * Check permission before creating a new hard link to a file. - * @old_dentry contains the dentry structure for an existing - * link to the file. - * @dir contains the inode structure of the parent directory - * of the new link. - * @new_dentry contains the dentry structure for the new link. - * Return 0 if permission is granted. - * @path_link: - * Check permission before creating a new hard link to a file. - * @old_dentry contains the dentry structure for an existing link - * to the file. - * @new_dir contains the path structure of the parent directory of - * the new link. - * @new_dentry contains the dentry structure for the new link. - * Return 0 if permission is granted. - * @inode_unlink: - * Check the permission to remove a hard link to a file. - * @dir contains the inode structure of parent directory of the file. - * @dentry contains the dentry structure for file to be unlinked. - * Return 0 if permission is granted. - * @path_unlink: - * Check the permission to remove a hard link to a file. - * @dir contains the path structure of parent directory of the file. - * @dentry contains the dentry structure for file to be unlinked. - * Return 0 if permission is granted. - * @inode_symlink: - * Check the permission to create a symbolic link to a file. - * @dir contains the inode structure of parent directory of - * the symbolic link. - * @dentry contains the dentry structure of the symbolic link. - * @old_name contains the pathname of file. - * Return 0 if permission is granted. - * @path_symlink: - * Check the permission to create a symbolic link to a file. - * @dir contains the path structure of parent directory of - * the symbolic link. - * @dentry contains the dentry structure of the symbolic link. - * @old_name contains the pathname of file. - * Return 0 if permission is granted. - * @inode_mkdir: - * Check permissions to create a new directory in the existing directory - * associated with inode structure @dir. - * @dir contains the inode structure of parent of the directory - * to be created. - * @dentry contains the dentry structure of new directory. - * @mode contains the mode of new directory. - * Return 0 if permission is granted. - * @path_mkdir: - * Check permissions to create a new directory in the existing directory - * associated with path structure @path. - * @dir contains the path structure of parent of the directory - * to be created. - * @dentry contains the dentry structure of new directory. - * @mode contains the mode of new directory. - * Return 0 if permission is granted. - * @inode_rmdir: - * Check the permission to remove a directory. - * @dir contains the inode structure of parent of the directory - * to be removed. - * @dentry contains the dentry structure of directory to be removed. - * Return 0 if permission is granted. - * @path_rmdir: - * Check the permission to remove a directory. - * @dir contains the path structure of parent of the directory to be - * removed. - * @dentry contains the dentry structure of directory to be removed. - * Return 0 if permission is granted. - * @inode_mknod: - * Check permissions when creating a special file (or a socket or a fifo - * file created via the mknod system call). Note that if mknod operation - * is being done for a regular file, then the create hook will be called - * and not this hook. - * @dir contains the inode structure of parent of the new file. - * @dentry contains the dentry structure of the new file. - * @mode contains the mode of the new file. - * @dev contains the device number. - * Return 0 if permission is granted. - * @path_mknod: - * Check permissions when creating a file. Note that this hook is called - * even if mknod operation is being done for a regular file. - * @dir contains the path structure of parent of the new file. - * @dentry contains the dentry structure of the new file. - * @mode contains the mode of the new file. - * @dev contains the undecoded device number. Use new_decode_dev() to get - * the decoded device number. - * Return 0 if permission is granted. - * @inode_rename: - * Check for permission to rename a file or directory. - * @old_dir contains the inode structure for parent of the old link. - * @old_dentry contains the dentry structure of the old link. - * @new_dir contains the inode structure for parent of the new link. - * @new_dentry contains the dentry structure of the new link. - * Return 0 if permission is granted. - * @path_rename: - * Check for permission to rename a file or directory. - * @old_dir contains the path structure for parent of the old link. - * @old_dentry contains the dentry structure of the old link. - * @new_dir contains the path structure for parent of the new link. - * @new_dentry contains the dentry structure of the new link. - * @flags may contain rename options such as RENAME_EXCHANGE. - * Return 0 if permission is granted. - * @path_chmod: - * Check for permission to change a mode of the file @path. The new - * mode is specified in @mode. - * @path contains the path structure of the file to change the mode. - * @mode contains the new DAC's permission, which is a bitmask of - * constants from <include/uapi/linux/stat.h>. - * Return 0 if permission is granted. - * @path_chown: - * Check for permission to change owner/group of a file or directory. - * @path contains the path structure. - * @uid contains new owner's ID. - * @gid contains new group's ID. - * Return 0 if permission is granted. - * @path_chroot: - * Check for permission to change root directory. - * @path contains the path structure. - * Return 0 if permission is granted. - * @path_notify: - * Check permissions before setting a watch on events as defined by @mask, - * on an object at @path, whose type is defined by @obj_type. - * Return 0 if permission is granted. - * @inode_readlink: - * Check the permission to read the symbolic link. - * @dentry contains the dentry structure for the file link. - * Return 0 if permission is granted. - * @inode_follow_link: - * Check permission to follow a symbolic link when looking up a pathname. - * @dentry contains the dentry structure for the link. - * @inode contains the inode, which itself is not stable in RCU-walk. - * @rcu indicates whether we are in RCU-walk mode. - * Return 0 if permission is granted. - * @inode_permission: - * Check permission before accessing an inode. This hook is called by the - * existing Linux permission function, so a security module can use it to - * provide additional checking for existing Linux permission checks. - * Notice that this hook is called when a file is opened (as well as many - * other operations), whereas the file_security_ops permission hook is - * called when the actual read/write operations are performed. - * @inode contains the inode structure to check. - * @mask contains the permission mask. - * Return 0 if permission is granted. - * @inode_setattr: - * Check permission before setting file attributes. Note that the kernel - * call to notify_change is performed from several locations, whenever - * file attributes change (such as when a file is truncated, chown/chmod - * operations, transferring disk quotas, etc). - * @dentry contains the dentry structure for the file. - * @attr is the iattr structure containing the new file attributes. - * Return 0 if permission is granted. - * @path_truncate: - * Check permission before truncating the file indicated by path. - * Note that truncation permissions may also be checked based on - * already opened files, using the @file_truncate hook. - * @path contains the path structure for the file. - * Return 0 if permission is granted. - * @inode_getattr: - * Check permission before obtaining file attributes. - * @path contains the path structure for the file. - * Return 0 if permission is granted. - * @inode_setxattr: - * Check permission before setting the extended attributes - * @value identified by @name for @dentry. - * Return 0 if permission is granted. - * @inode_post_setxattr: - * Update inode security field after successful setxattr operation. - * @value identified by @name for @dentry. - * @inode_getxattr: - * Check permission before obtaining the extended attributes - * identified by @name for @dentry. - * Return 0 if permission is granted. - * @inode_listxattr: - * Check permission before obtaining the list of extended attribute - * names for @dentry. - * Return 0 if permission is granted. - * @inode_removexattr: - * Check permission before removing the extended attribute - * identified by @name for @dentry. - * Return 0 if permission is granted. - * @inode_set_acl: - * Check permission before setting posix acls - * The posix acls in @kacl are identified by @acl_name. - * Return 0 if permission is granted. - * @inode_get_acl: - * Check permission before getting osix acls - * The posix acls are identified by @acl_name. - * Return 0 if permission is granted. - * @inode_remove_acl: - * Check permission before removing posix acls - * The posix acls are identified by @acl_name. - * Return 0 if permission is granted. - * @inode_getsecurity: - * Retrieve a copy of the extended attribute representation of the - * security label associated with @name for @inode via @buffer. Note that - * @name is the remainder of the attribute name after the security prefix - * has been removed. @alloc is used to specify if the call should return a - * value via the buffer or just the value length. - * Return size of buffer on success. - * @inode_setsecurity: - * Set the security label associated with @name for @inode from the - * extended attribute value @value. @size indicates the size of the - * @value in bytes. @flags may be XATTR_CREATE, XATTR_REPLACE, or 0. - * Note that @name is the remainder of the attribute name after the - * security. prefix has been removed. - * Return 0 on success. - * @inode_listsecurity: - * Copy the extended attribute names for the security labels - * associated with @inode into @buffer. The maximum size of @buffer - * is specified by @buffer_size. @buffer may be NULL to request - * the size of the buffer required. - * Returns number of bytes used/required on success. - * @inode_need_killpriv: - * Called when an inode has been changed. - * @dentry is the dentry being changed. - * Return <0 on error to abort the inode change operation. - * Return 0 if inode_killpriv does not need to be called. - * Return >0 if inode_killpriv does need to be called. - * @inode_killpriv: - * The setuid bit is being removed. Remove similar security labels. - * Called with the dentry->d_inode->i_mutex held. - * @idmap: idmap of the mount. - * @dentry is the dentry being changed. - * Return 0 on success. If error is returned, then the operation - * causing setuid bit removal is failed. - * @inode_getsecid: - * Get the secid associated with the node. - * @inode contains a pointer to the inode. - * @secid contains a pointer to the location where result will be saved. - * In case of failure, @secid will be set to zero. - * @inode_copy_up: - * A file is about to be copied up from lower layer to upper layer of - * overlay filesystem. Security module can prepare a set of new creds - * and modify as need be and return new creds. Caller will switch to - * new creds temporarily to create new file and release newly allocated - * creds. - * @src indicates the union dentry of file that is being copied up. - * @new pointer to pointer to return newly allocated creds. - * Returns 0 on success or a negative error code on error. - * @inode_copy_up_xattr: - * Filter the xattrs being copied up when a unioned file is copied - * up from a lower layer to the union/overlay layer. - * @name indicates the name of the xattr. - * Returns 0 to accept the xattr, 1 to discard the xattr, -EOPNOTSUPP if - * security module does not know about attribute or a negative error code - * to abort the copy up. Note that the caller is responsible for reading - * and writing the xattrs as this hook is merely a filter. - * @d_instantiate: - * Fill in @inode security information for a @dentry if allowed. - * @getprocattr: - * Read attribute @name for process @p and store it into @value if allowed. - * Return the length of @value on success, a negative value otherwise. - * @setprocattr: - * Write (set) attribute @name to @value, size @size if allowed. - * Return written bytes on success, a negative value otherwise. - * - * Security hooks for kernfs node operations - * - * @kernfs_init_security: - * Initialize the security context of a newly created kernfs node based - * on its own and its parent's attributes. - * @kn_dir the parent kernfs node. - * @kn the new child kernfs node. - * Return 0 if permission is granted. - * - * Security hooks for file operations - * - * @file_permission: - * Check file permissions before accessing an open file. This hook is - * called by various operations that read or write files. A security - * module can use this hook to perform additional checking on these - * operations, e.g. to revalidate permissions on use to support privilege - * bracketing or policy changes. Notice that this hook is used when the - * actual read/write operations are performed, whereas the - * inode_security_ops hook is called when a file is opened (as well as - * many other operations). - * Caveat: Although this hook can be used to revalidate permissions for - * various system call operations that read or write files, it does not - * address the revalidation of permissions for memory-mapped files. - * Security modules must handle this separately if they need such - * revalidation. - * @file contains the file structure being accessed. - * @mask contains the requested permissions. - * Return 0 if permission is granted. - * @file_alloc_security: - * Allocate and attach a security structure to the file->f_security field. - * The security field is initialized to NULL when the structure is first - * created. - * @file contains the file structure to secure. - * Return 0 if the hook is successful and permission is granted. - * @file_free_security: - * Deallocate and free any security structures stored in file->f_security. - * @file contains the file structure being modified. - * @file_ioctl: - * @file contains the file structure. - * @cmd contains the operation to perform. - * @arg contains the operational arguments. - * Check permission for an ioctl operation on @file. Note that @arg - * sometimes represents a user space pointer; in other cases, it may be a - * simple integer value. When @arg represents a user space pointer, it - * should never be used by the security module. - * Return 0 if permission is granted. - * @mmap_addr: - * Check permissions for a mmap operation at @addr. - * @addr contains virtual address that will be used for the operation. - * Return 0 if permission is granted. - * @mmap_file: - * Check permissions for a mmap operation. The @file may be NULL, e.g. - * if mapping anonymous memory. - * @file contains the file structure for file to map (may be NULL). - * @reqprot contains the protection requested by the application. - * @prot contains the protection that will be applied by the kernel. - * @flags contains the operational flags. - * Return 0 if permission is granted. - * @file_mprotect: - * Check permissions before changing memory access permissions. - * @vma contains the memory region to modify. - * @reqprot contains the protection requested by the application. - * @prot contains the protection that will be applied by the kernel. - * Return 0 if permission is granted. - * @file_lock: - * Check permission before performing file locking operations. - * Note the hook mediates both flock and fcntl style locks. - * @file contains the file structure. - * @cmd contains the posix-translated lock operation to perform - * (e.g. F_RDLCK, F_WRLCK). - * Return 0 if permission is granted. - * @file_fcntl: - * Check permission before allowing the file operation specified by @cmd - * from being performed on the file @file. Note that @arg sometimes - * represents a user space pointer; in other cases, it may be a simple - * integer value. When @arg represents a user space pointer, it should - * never be used by the security module. - * @file contains the file structure. - * @cmd contains the operation to be performed. - * @arg contains the operational arguments. - * Return 0 if permission is granted. - * @file_set_fowner: - * Save owner security information (typically from current->security) in - * file->f_security for later use by the send_sigiotask hook. - * @file contains the file structure to update. - * Return 0 on success. - * @file_send_sigiotask: - * Check permission for the file owner @fown to send SIGIO or SIGURG to the - * process @tsk. Note that this hook is sometimes called from interrupt. - * Note that the fown_struct, @fown, is never outside the context of a - * struct file, so the file structure (and associated security information) - * can always be obtained: container_of(fown, struct file, f_owner) - * @tsk contains the structure of task receiving signal. - * @fown contains the file owner information. - * @sig is the signal that will be sent. When 0, kernel sends SIGIO. - * Return 0 if permission is granted. - * @file_receive: - * This hook allows security modules to control the ability of a process - * to receive an open file descriptor via socket IPC. - * @file contains the file structure being received. - * Return 0 if permission is granted. - * @file_truncate: - * Check permission before truncating a file, i.e. using ftruncate. - * Note that truncation permission may also be checked based on the path, - * using the @path_truncate hook. - * @file contains the file structure for the file. - * Return 0 if permission is granted. - * @file_open: - * Save open-time permission checking state for later use upon - * file_permission, and recheck access if anything has changed - * since inode_permission. - * Return 0 if permission is granted. - * - * Security hooks for task operations. - * - * @task_alloc: - * @task task being allocated. - * @clone_flags contains the flags indicating what should be shared. - * Handle allocation of task-related resources. - * Returns a zero on success, negative values on failure. - * @task_free: - * @task task about to be freed. - * Handle release of task-related resources. (Note that this can be called - * from interrupt context.) - * @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. - * Return 0 on success, negative values on failure. - * @cred_free: - * @cred points to the credentials. - * Deallocate and clear the cred->security field in a set of credentials. - * @cred_prepare: - * @new points to the new credentials. - * @old points to the original credentials. - * @gfp indicates the atomicity of any memory allocations. - * Prepare a new set of credentials by copying the data from the old set. - * Return 0 on success, negative values on failure. - * @cred_transfer: - * @new points to the new credentials. - * @old points to the original credentials. - * Transfer data from original creds to new creds - * @cred_getsecid: - * Retrieve the security identifier of the cred structure @c - * @c contains the credentials, secid will be placed into @secid. - * In case of failure, @secid will be set to zero. - * @kernel_act_as: - * Set the credentials for a kernel service to act as (subjective context). - * @new points to the credentials to be modified. - * @secid specifies the security ID to be set. - * The current task must be the one that nominated @secid. - * Return 0 if successful. - * @kernel_create_files_as: - * Set the file creation context in a set of credentials to be the same as - * the objective context of the specified inode. - * @new points to the credentials to be modified. - * @inode points to the inode to use as a reference. - * The current task must be the one that nominated @inode. - * Return 0 if successful. - * @kernel_module_request: - * Ability to trigger the kernel to automatically upcall to userspace for - * userspace to load a kernel module with the given name. - * @kmod_name name of the module requested by the kernel. - * Return 0 if successful. - * @kernel_load_data: - * Load data provided by userspace. - * @id kernel load data identifier. - * @contents if a subsequent @kernel_post_load_data will be called. - * Return 0 if permission is granted. - * @kernel_post_load_data: - * Load data provided by a non-file source (usually userspace buffer). - * @buf pointer to buffer containing the data contents. - * @size length of the data contents. - * @id kernel load data identifier. - * @description a text description of what was loaded, @id-specific. - * Return 0 if permission is granted. - * This must be paired with a prior @kernel_load_data call that had - * @contents set to true. - * @kernel_read_file: - * Read a file specified by userspace. - * @file contains the file structure pointing to the file being read - * by the kernel. - * @id kernel read file identifier. - * @contents if a subsequent @kernel_post_read_file will be called. - * Return 0 if permission is granted. - * @kernel_post_read_file: - * Read a file specified by userspace. - * @file contains the file structure pointing to the file being read - * by the kernel. - * @buf pointer to buffer containing the file contents. - * @size length of the file contents. - * @id kernel read file identifier. - * This must be paired with a prior @kernel_read_file call that had - * @contents set to true. - * Return 0 if permission is granted. - * @task_fix_setuid: - * Update the module's state after setting one or more of the user - * identity attributes of the current process. The @flags parameter - * indicates which of the set*uid system calls invoked this hook. If - * @new is the set of credentials that will be installed. Modifications - * should be made to this rather than to @current->cred. - * @old is the set of credentials that are being replaced. - * @flags contains one of the LSM_SETID_* values. - * Return 0 on success. - * @task_fix_setgid: - * Update the module's state after setting one or more of the group - * identity attributes of the current process. The @flags parameter - * indicates which of the set*gid system calls invoked this hook. - * @new is the set of credentials that will be installed. Modifications - * should be made to this rather than to @current->cred. - * @old is the set of credentials that are being replaced. - * @flags contains one of the LSM_SETID_* values. - * Return 0 on success. - * @task_fix_setgroups: - * Update the module's state after setting the supplementary group - * identity attributes of the current process. - * @new is the set of credentials that will be installed. Modifications - * should be made to this rather than to @current->cred. - * @old is the set of credentials that are being replaced. - * Return 0 on success. - * @task_setpgid: - * Check permission before setting the process group identifier of the - * process @p to @pgid. - * @p contains the task_struct for process being modified. - * @pgid contains the new pgid. - * Return 0 if permission is granted. - * @task_getpgid: - * Check permission before getting the process group identifier of the - * process @p. - * @p contains the task_struct for the process. - * Return 0 if permission is granted. - * @task_getsid: - * Check permission before getting the session identifier of the process - * @p. - * @p contains the task_struct for the process. - * Return 0 if permission is granted. - * @current_getsecid_subj: - * Retrieve the subjective security identifier of the current task and - * return it in @secid. - * In case of failure, @secid will be set to zero. - * @task_getsecid_obj: - * Retrieve the objective security identifier of the task_struct in @p - * and return it in @secid. - * In case of failure, @secid will be set to zero. - * - * @task_setnice: - * Check permission before setting the nice value of @p to @nice. - * @p contains the task_struct of process. - * @nice contains the new nice value. - * Return 0 if permission is granted. - * @task_setioprio: - * Check permission before setting the ioprio value of @p to @ioprio. - * @p contains the task_struct of process. - * @ioprio contains the new ioprio value. - * Return 0 if permission is granted. - * @task_getioprio: - * Check permission before getting the ioprio value of @p. - * @p contains the task_struct of process. - * Return 0 if permission is granted. - * @task_prlimit: - * Check permission before getting and/or setting the resource limits of - * another task. - * @cred points to the cred structure for the current task. - * @tcred points to the cred structure for the target task. - * @flags contains the LSM_PRLIMIT_* flag bits indicating whether the - * resource limits are being read, modified, or both. - * Return 0 if permission is granted. - * @task_setrlimit: - * Check permission before setting the resource limits of process @p - * for @resource to @new_rlim. The old resource limit values can - * be examined by dereferencing (p->signal->rlim + resource). - * @p points to the task_struct for the target task's group leader. - * @resource contains the resource whose limit is being set. - * @new_rlim contains the new limits for @resource. - * Return 0 if permission is granted. - * @task_setscheduler: - * Check permission before setting scheduling policy and/or parameters of - * process @p. - * @p contains the task_struct for process. - * Return 0 if permission is granted. - * @task_getscheduler: - * Check permission before obtaining scheduling information for process - * @p. - * @p contains the task_struct for process. - * Return 0 if permission is granted. - * @task_movememory: - * Check permission before moving memory owned by process @p. - * @p contains the task_struct for process. - * Return 0 if permission is granted. - * @task_kill: - * Check permission before sending signal @sig to @p. @info can be NULL, - * the constant 1, or a pointer to a kernel_siginfo structure. If @info is 1 or - * SI_FROMKERNEL(info) is true, then the signal should be viewed as coming - * from the kernel and should typically be permitted. - * SIGIO signals are handled separately by the send_sigiotask hook in - * file_security_ops. - * @p contains the task_struct for process. - * @info contains the signal information. - * @sig contains the signal value. - * @cred contains the cred of the process where the signal originated, or - * NULL if the current task is the originator. - * Return 0 if permission is granted. - * @task_prctl: - * Check permission before performing a process control operation on the - * current process. - * @option contains the operation. - * @arg2 contains a argument. - * @arg3 contains a argument. - * @arg4 contains a argument. - * @arg5 contains a argument. - * Return -ENOSYS if no-one wanted to handle this op, any other value to - * cause prctl() to return immediately with that value. - * @task_to_inode: - * Set the security attributes for an inode based on an associated task's - * security attributes, e.g. for /proc/pid inodes. - * @p contains the task_struct for the task. - * @inode contains the inode structure for the inode. - * @userns_create: - * Check permission prior to creating a new user namespace. - * @cred points to prepared creds. - * Return 0 if successful, otherwise < 0 error code. - * - * Security hooks for Netlink messaging. - * - * @netlink_send: - * Save security information for a netlink message so that permission - * checking can be performed when the message is processed. The security - * information can be saved using the eff_cap field of the - * netlink_skb_parms structure. Also may be used to provide fine - * grained control over message transmission. - * @sk associated sock of task sending the message. - * @skb contains the sk_buff structure for the netlink message. - * Return 0 if the information was successfully saved and message - * is allowed to be transmitted. - * - * Security hooks for Unix domain networking. - * - * @unix_stream_connect: - * Check permissions before establishing a Unix domain stream connection - * between @sock and @other. - * @sock contains the sock structure. - * @other contains the peer sock structure. - * @newsk contains the new sock structure. - * Return 0 if permission is granted. - * @unix_may_send: - * Check permissions before connecting or sending datagrams from @sock to - * @other. - * @sock contains the socket structure. - * @other contains the peer socket structure. - * Return 0 if permission is granted. - * - * The @unix_stream_connect and @unix_may_send hooks were necessary because - * Linux provides an alternative to the conventional file name space for Unix - * domain sockets. Whereas binding and connecting to sockets in the file name - * space is mediated by the typical file permissions (and caught by the mknod - * and permission hooks in inode_security_ops), binding and connecting to - * sockets in the abstract name space is completely unmediated. Sufficient - * control of Unix domain sockets in the abstract name space isn't possible - * using only the socket layer hooks, since we need to know the actual target - * socket, which is not looked up until we are inside the af_unix code. - * - * Security hooks for socket operations. - * - * @socket_create: - * Check permissions prior to creating a new socket. - * @family contains the requested protocol family. - * @type contains the requested communications type. - * @protocol contains the requested protocol. - * @kern set to 1 if a kernel socket. - * Return 0 if permission is granted. - * @socket_post_create: - * This hook allows a module to update or allocate a per-socket security - * structure. Note that the security field was not added directly to the - * socket structure, but rather, the socket security information is stored - * in the associated inode. Typically, the inode alloc_security hook will - * allocate and attach security information to - * SOCK_INODE(sock)->i_security. This hook may be used to update the - * SOCK_INODE(sock)->i_security field with additional information that - * wasn't available when the inode was allocated. - * @sock contains the newly created socket structure. - * @family contains the requested protocol family. - * @type contains the requested communications type. - * @protocol contains the requested protocol. - * @kern set to 1 if a kernel socket. - * Return 0 if permission is granted. - * @socket_socketpair: - * Check permissions before creating a fresh pair of sockets. - * @socka contains the first socket structure. - * @sockb contains the second socket structure. - * Return 0 if permission is granted and the connection was established. - * @socket_bind: - * Check permission before socket protocol layer bind operation is - * performed and the socket @sock is bound to the address specified in the - * @address parameter. - * @sock contains the socket structure. - * @address contains the address to bind to. - * @addrlen contains the length of address. - * Return 0 if permission is granted. - * @socket_connect: - * Check permission before socket protocol layer connect operation - * attempts to connect socket @sock to a remote address, @address. - * @sock contains the socket structure. - * @address contains the address of remote endpoint. - * @addrlen contains the length of address. - * Return 0 if permission is granted. - * @socket_listen: - * Check permission before socket protocol layer listen operation. - * @sock contains the socket structure. - * @backlog contains the maximum length for the pending connection queue. - * Return 0 if permission is granted. - * @socket_accept: - * Check permission before accepting a new connection. Note that the new - * socket, @newsock, has been created and some information copied to it, - * but the accept operation has not actually been performed. - * @sock contains the listening socket structure. - * @newsock contains the newly created server socket for connection. - * Return 0 if permission is granted. - * @socket_sendmsg: - * Check permission before transmitting a message to another socket. - * @sock contains the socket structure. - * @msg contains the message to be transmitted. - * @size contains the size of message. - * Return 0 if permission is granted. - * @socket_recvmsg: - * Check permission before receiving a message from a socket. - * @sock contains the socket structure. - * @msg contains the message structure. - * @size contains the size of message structure. - * @flags contains the operational flags. - * Return 0 if permission is granted. - * @socket_getsockname: - * Check permission before the local address (name) of the socket object - * @sock is retrieved. - * @sock contains the socket structure. - * Return 0 if permission is granted. - * @socket_getpeername: - * Check permission before the remote address (name) of a socket object - * @sock is retrieved. - * @sock contains the socket structure. - * Return 0 if permission is granted. - * @socket_getsockopt: - * Check permissions before retrieving the options associated with socket - * @sock. - * @sock contains the socket structure. - * @level contains the protocol level to retrieve option from. - * @optname contains the name of option to retrieve. - * Return 0 if permission is granted. - * @socket_setsockopt: - * Check permissions before setting the options associated with socket - * @sock. - * @sock contains the socket structure. - * @level contains the protocol level to set options for. - * @optname contains the name of the option to set. - * Return 0 if permission is granted. - * @socket_shutdown: - * Checks permission before all or part of a connection on the socket - * @sock is shut down. - * @sock contains the socket structure. - * @how contains the flag indicating how future sends and receives - * are handled. - * Return 0 if permission is granted. - * @socket_sock_rcv_skb: - * Check permissions on incoming network packets. This hook is distinct - * from Netfilter's IP input hooks since it is the first time that the - * incoming sk_buff @skb has been associated with a particular socket, @sk. - * Must not sleep inside this hook because some callers hold spinlocks. - * @sk contains the sock (not socket) associated with the incoming sk_buff. - * @skb contains the incoming network data. - * Return 0 if permission is granted. - * @socket_getpeersec_stream: - * This hook allows the security module to provide peer socket security - * state for unix or connected tcp sockets to userspace via getsockopt - * SO_GETPEERSEC. For tcp sockets this can be meaningful if the - * socket is associated with an ipsec SA. - * @sock is the local socket. - * @optval memory where the security state is to be copied. - * @optlen memory where the module should copy the actual length - * of the security state. - * @len as input is the maximum length to copy to userspace provided - * by the caller. - * Return 0 if all is well, otherwise, typical getsockopt return - * values. - * @socket_getpeersec_dgram: - * This hook allows the security module to provide peer socket security - * state for udp sockets on a per-packet basis to userspace via - * getsockopt SO_GETPEERSEC. The application must first have indicated - * the IP_PASSSEC option via getsockopt. It can then retrieve the - * security state returned by this hook for a packet via the SCM_SECURITY - * ancillary message type. - * @sock contains the peer socket. May be NULL. - * @skb is the sk_buff for the packet being queried. May be NULL. - * @secid pointer to store the secid of the packet. - * Return 0 on success, error on failure. - * @sk_alloc_security: - * Allocate and attach a security structure to the sk->sk_security field, - * which is used to copy security attributes between local stream sockets. - * Return 0 on success, error on failure. - * @sk_free_security: - * Deallocate security structure. - * @sk_clone_security: - * Clone/copy security structure. - * @sk_getsecid: - * Retrieve the LSM-specific secid for the sock to enable caching - * of network authorizations. - * @sock_graft: - * Sets the socket's isec sid to the sock's sid. - * @inet_conn_request: - * Sets the openreq's sid to socket's sid with MLS portion taken - * from peer sid. - * Return 0 if permission is granted. - * @inet_csk_clone: - * Sets the new child socket's sid to the openreq sid. - * @inet_conn_established: - * Sets the connection's peersid to the secmark on skb. - * @secmark_relabel_packet: - * Check if the process should be allowed to relabel packets to - * the given secid. - * Return 0 if permission is granted. - * @secmark_refcount_inc: - * Tells the LSM to increment the number of secmark labeling rules loaded. - * @secmark_refcount_dec: - * Tells the LSM to decrement the number of secmark labeling rules loaded. - * @req_classify_flow: - * Sets the flow's sid to the openreq sid. - * @tun_dev_alloc_security: - * This hook allows a module to allocate a security structure for a TUN - * device. - * @security pointer to a security structure pointer. - * Returns a zero on success, negative values on failure. - * @tun_dev_free_security: - * This hook allows a module to free the security structure for a TUN - * device. - * @security pointer to the TUN device's security structure. - * @tun_dev_create: - * Check permissions prior to creating a new TUN device. - * Return 0 if permission is granted. - * @tun_dev_attach_queue: - * Check permissions prior to attaching to a TUN device queue. - * @security pointer to the TUN device's security structure. - * Return 0 if permission is granted. - * @tun_dev_attach: - * This hook can 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 pointer to the TUN device's security structure. - * Return 0 if permission is granted. - * @tun_dev_open: - * This hook can be used by the module to update any security state - * associated with the TUN device's security structure. - * @security pointer to the TUN devices's security structure. - * Return 0 if permission is granted. - * - * Security hooks for SCTP - * - * @sctp_assoc_request: - * Passes the @asoc and @chunk->skb of the association INIT packet to - * the security module. - * @asoc pointer to sctp association structure. - * @skb pointer to skbuff of association packet. - * Return 0 on success, error on failure. - * @sctp_bind_connect: - * Validiate permissions required for each address associated with sock - * @sk. Depending on @optname, the addresses will be treated as either - * for a connect or bind service. The @addrlen is calculated on each - * ipv4 and ipv6 address using sizeof(struct sockaddr_in) or - * sizeof(struct sockaddr_in6). - * @sk pointer to sock structure. - * @optname name of the option to validate. - * @address list containing one or more ipv4/ipv6 addresses. - * @addrlen total length of address(s). - * Return 0 on success, error on failure. - * @sctp_sk_clone: - * Called whenever a new socket is created by accept(2) (i.e. a TCP - * style socket) or when a socket is 'peeled off' e.g userspace - * calls sctp_peeloff(3). - * @asoc pointer to current sctp association structure. - * @sk pointer to current sock structure. - * @newsk pointer to new sock structure. - * @sctp_assoc_established: - * Passes the @asoc and @chunk->skb of the association COOKIE_ACK packet - * to the security module. - * @asoc pointer to sctp association structure. - * @skb pointer to skbuff of association packet. - * Return 0 if permission is granted. - * - * Security hooks for Infiniband - * - * @ib_pkey_access: - * Check permission to access a pkey when modifing a QP. - * @subnet_prefix the subnet prefix of the port being used. - * @pkey the pkey to be accessed. - * @sec pointer to a security structure. - * Return 0 if permission is granted. - * @ib_endport_manage_subnet: - * Check permissions to send and receive SMPs on a end port. - * @dev_name the IB device name (i.e. mlx4_0). - * @port_num the port number. - * @sec pointer to a security structure. - * Return 0 if permission is granted. - * @ib_alloc_security: - * Allocate a security structure for Infiniband objects. - * @sec pointer to a security structure pointer. - * Returns 0 on success, non-zero on failure. - * @ib_free_security: - * Deallocate an Infiniband security structure. - * @sec contains the security structure to be freed. - * - * Security hooks for XFRM operations. - * - * @xfrm_policy_alloc_security: - * @ctxp is a pointer to the xfrm_sec_ctx being added to Security Policy - * Database used by the XFRM system. - * @sec_ctx contains the security context information being provided by - * the user-level policy update program (e.g., setkey). - * @gfp is to specify the context for the allocation. - * Allocate a security structure to the xp->security field; the security - * field is initialized to NULL when the xfrm_policy is allocated. - * Return 0 if operation was successful (memory to allocate, legal - * context). - * @xfrm_policy_clone_security: - * @old_ctx contains an existing xfrm_sec_ctx. - * @new_ctxp contains a new xfrm_sec_ctx being cloned from old. - * Allocate a security structure in new_ctxp that contains the - * information from the old_ctx structure. - * Return 0 if operation was successful (memory to allocate). - * @xfrm_policy_free_security: - * @ctx contains the xfrm_sec_ctx. - * Deallocate xp->security. - * @xfrm_policy_delete_security: - * @ctx contains the xfrm_sec_ctx. - * Authorize deletion of xp->security. - * Return 0 if permission is granted. - * @xfrm_state_alloc: - * @x contains the xfrm_state being added to the Security Association - * Database by the XFRM system. - * @sec_ctx contains the security context information being provided by - * the user-level SA generation program (e.g., setkey or racoon). - * Allocate a security structure to the x->security field; the security - * field is initialized to NULL when the xfrm_state is allocated. Set the - * context to correspond to sec_ctx. Return 0 if operation was successful - * (memory to allocate, legal context). - * @xfrm_state_alloc_acquire: - * @x contains the xfrm_state being added to the Security Association - * Database by the XFRM system. - * @polsec contains the policy's security context. - * @secid contains the secid from which to take the mls portion of the - * context. - * Allocate a security structure to the x->security field; the security - * field is initialized to NULL when the xfrm_state is allocated. Set the - * context to correspond to secid. Return 0 if operation was successful - * (memory to allocate, legal context). - * @xfrm_state_free_security: - * @x contains the xfrm_state. - * Deallocate x->security. - * @xfrm_state_delete_security: - * @x contains the xfrm_state. - * Authorize deletion of x->security. - * Return 0 if permission is granted. - * @xfrm_policy_lookup: - * @ctx contains the xfrm_sec_ctx for which the access control is being - * checked. - * @fl_secid contains the flow security label that is used to authorize - * access to the policy xp. - * @dir contains the direction of the flow (input or output). - * Check permission when a flow selects a xfrm_policy for processing - * XFRMs on a packet. The hook is called when selecting either a - * per-socket policy or a generic xfrm policy. - * Return 0 if permission is granted, -ESRCH otherwise, or -errno - * on other errors. - * @xfrm_state_pol_flow_match: - * @x contains the state to match. - * @xp contains the policy to check for a match. - * @flic contains the flowi_common struct to check for a match. - * Return 1 if there is a match. - * @xfrm_decode_session: - * @skb points to skb to decode. - * @secid points to the flow key secid to set. - * @ckall says if all xfrms used should be checked for same secid. - * Return 0 if ckall is zero or all xfrms used have the same secid. - * - * Security hooks affecting all Key Management operations - * - * @key_alloc: - * Permit allocation of a key and assign security data. Note that key does - * not have a serial number assigned at this point. - * @key points to the key. - * @flags is the allocation flags. - * Return 0 if permission is granted, -ve error otherwise. - * @key_free: - * Notification of destruction; free security data. - * @key points to the key. - * No return value. - * @key_permission: - * See whether a specific operational right is granted to a process on a - * key. - * @key_ref refers to the key (key pointer + possession attribute bit). - * @cred points to the credentials to provide the context against which to - * evaluate the security data on the key. - * @perm describes the combination of permissions required of this key. - * Return 0 if permission is granted, -ve error otherwise. - * @key_getsecurity: - * Get a textual representation of the security context attached to a key - * for the purposes of honouring KEYCTL_GETSECURITY. This function - * allocates the storage for the NUL-terminated string and the caller - * should free it. - * @key points to the key to be queried. - * @_buffer points to a pointer that should be set to point to the - * resulting string (if no label or an error occurs). - * Return the length of the string (including terminating NUL) or -ve if - * an error. - * May also return 0 (and a NULL buffer pointer) if there is no label. - * - * Security hooks affecting all System V IPC operations. - * - * @ipc_permission: - * Check permissions for access to IPC - * @ipcp contains the kernel IPC permission structure. - * @flag contains the desired (requested) permission set. - * Return 0 if permission is granted. - * @ipc_getsecid: - * Get the secid associated with the ipc object. - * @ipcp contains the kernel IPC permission structure. - * @secid contains a pointer to the location where result will be saved. - * In case of failure, @secid will be set to zero. - * - * Security hooks for individual messages held in System V IPC message queues - * - * @msg_msg_alloc_security: - * Allocate and attach a security structure to the msg->security field. - * The security field is initialized to NULL when the structure is first - * created. - * @msg contains the message structure to be modified. - * Return 0 if operation was successful and permission is granted. - * @msg_msg_free_security: - * Deallocate the security structure for this message. - * @msg contains the message structure to be modified. - * - * Security hooks for System V IPC Message Queues - * - * @msg_queue_alloc_security: - * Allocate and attach a security structure to the - * @perm->security field. The security field is initialized to - * NULL when the structure is first created. - * @perm contains the IPC permissions of the message queue. - * Return 0 if operation was successful and permission is granted. - * @msg_queue_free_security: - * Deallocate security field @perm->security for the message queue. - * @perm contains the IPC permissions of the message queue. - * @msg_queue_associate: - * Check permission when a message queue is requested through the - * msgget system call. This hook is only called when returning the - * message queue identifier for an existing message queue, not when a - * new message queue is created. - * @perm contains the IPC permissions of the message queue. - * @msqflg contains the operation control flags. - * Return 0 if permission is granted. - * @msg_queue_msgctl: - * Check permission when a message control operation specified by @cmd - * is to be performed on the message queue with permissions @perm. - * The @perm may be NULL, e.g. for IPC_INFO or MSG_INFO. - * @perm contains the IPC permissions of the msg queue. May be NULL. - * @cmd contains the operation to be performed. - * Return 0 if permission is granted. - * @msg_queue_msgsnd: - * Check permission before a message, @msg, is enqueued on the message - * queue with permissions @perm. - * @perm contains the IPC permissions of the message queue. - * @msg contains the message to be enqueued. - * @msqflg contains operational flags. - * Return 0 if permission is granted. - * @msg_queue_msgrcv: - * Check permission before a message, @msg, is removed from the message - * queue. The @target task structure contains a pointer to the - * process that will be receiving the message (not equal to the current - * process when inline receives are being performed). - * @perm contains the IPC permissions of the message queue. - * @msg contains the message destination. - * @target contains the task structure for recipient process. - * @type contains the type of message requested. - * @mode contains the operational flags. - * Return 0 if permission is granted. - * - * Security hooks for System V Shared Memory Segments - * - * @shm_alloc_security: - * Allocate and attach a security structure to the @perm->security - * field. The security field is initialized to NULL when the structure is - * first created. - * @perm contains the IPC permissions of the shared memory structure. - * Return 0 if operation was successful and permission is granted. - * @shm_free_security: - * Deallocate the security structure @perm->security for the memory segment. - * @perm contains the IPC permissions of the shared memory structure. - * @shm_associate: - * Check permission when a shared memory region is requested through the - * shmget system call. This hook is only called when returning the shared - * memory region identifier for an existing region, not when a new shared - * memory region is created. - * @perm contains the IPC permissions of the shared memory structure. - * @shmflg contains the operation control flags. - * Return 0 if permission is granted. - * @shm_shmctl: - * Check permission when a shared memory control operation specified by - * @cmd is to be performed on the shared memory region with permissions @perm. - * The @perm may be NULL, e.g. for IPC_INFO or SHM_INFO. - * @perm contains the IPC permissions of the shared memory structure. - * @cmd contains the operation to be performed. - * Return 0 if permission is granted. - * @shm_shmat: - * Check permissions prior to allowing the shmat system call to attach the - * shared memory segment with permissions @perm to the data segment of the - * calling process. The attaching address is specified by @shmaddr. - * @perm contains the IPC permissions of the shared memory structure. - * @shmaddr contains the address to attach memory region to. - * @shmflg contains the operational flags. - * Return 0 if permission is granted. - * - * Security hooks for System V Semaphores - * - * @sem_alloc_security: - * Allocate and attach a security structure to the @perm->security - * field. The security field is initialized to NULL when the structure is - * first created. - * @perm contains the IPC permissions of the semaphore. - * Return 0 if operation was successful and permission is granted. - * @sem_free_security: - * Deallocate security structure @perm->security for the semaphore. - * @perm contains the IPC permissions of the semaphore. - * @sem_associate: - * Check permission when a semaphore is requested through the semget - * system call. This hook is only called when returning the semaphore - * identifier for an existing semaphore, not when a new one must be - * created. - * @perm contains the IPC permissions of the semaphore. - * @semflg contains the operation control flags. - * Return 0 if permission is granted. - * @sem_semctl: - * Check permission when a semaphore operation specified by @cmd is to be - * performed on the semaphore. The @perm may be NULL, e.g. for - * IPC_INFO or SEM_INFO. - * @perm contains the IPC permissions of the semaphore. May be NULL. - * @cmd contains the operation to be performed. - * Return 0 if permission is granted. - * @sem_semop: - * Check permissions before performing operations on members of the - * semaphore set. If the @alter flag is nonzero, the semaphore set - * may be modified. - * @perm contains the IPC permissions of the semaphore. - * @sops contains the operations to perform. - * @nsops contains the number of operations to perform. - * @alter contains the flag indicating whether changes are to be made. - * Return 0 if permission is granted. - * - * @binder_set_context_mgr: - * Check whether @mgr is allowed to be the binder context manager. - * @mgr contains the struct cred for the current binder process. - * Return 0 if permission is granted. - * @binder_transaction: - * Check whether @from is allowed to invoke a binder transaction call - * to @to. - * @from contains the struct cred for the sending process. - * @to contains the struct cred for the receiving process. - * Return 0 if permission is granted. - * @binder_transfer_binder: - * Check whether @from is allowed to transfer a binder reference to @to. - * @from contains the struct cred for the sending process. - * @to contains the struct cred for the receiving process. - * Return 0 if permission is granted. - * @binder_transfer_file: - * Check whether @from is allowed to transfer @file to @to. - * @from contains the struct cred for the sending process. - * @file contains the struct file being transferred. - * @to contains the struct cred for the receiving process. - * Return 0 if permission is granted. - * - * @ptrace_access_check: - * Check permission before allowing the current process to trace the - * @child process. - * Security modules may also want to perform a process tracing check - * during an execve in the set_security or apply_creds hooks of - * tracing check during an execve in the bprm_set_creds hook of - * binprm_security_ops if the process is being traced and its security - * attributes would be changed by the execve. - * @child contains the task_struct structure for the target process. - * @mode contains the PTRACE_MODE flags indicating the form of access. - * Return 0 if permission is granted. - * @ptrace_traceme: - * Check that the @parent process has sufficient permission to trace the - * current process before allowing the current process to present itself - * to the @parent process for tracing. - * @parent contains the task_struct structure for debugger process. - * Return 0 if permission is granted. - * @capget: - * Get the @effective, @inheritable, and @permitted capability sets for - * the @target process. The hook may also perform permission checking to - * determine if the current process is allowed to see the capability sets - * of the @target process. - * @target contains the task_struct structure for target process. - * @effective contains the effective capability set. - * @inheritable contains the inheritable capability set. - * @permitted contains the permitted capability set. - * Return 0 if the capability sets were successfully obtained. - * @capset: - * Set the @effective, @inheritable, and @permitted capability sets for - * the current process. - * @new contains the new credentials structure for target process. - * @old contains the current credentials structure for target process. - * @effective contains the effective capability set. - * @inheritable contains the inheritable capability set. - * @permitted contains the permitted capability set. - * Return 0 and update @new if permission is granted. - * @capable: - * Check whether the @tsk process has the @cap capability in the indicated - * credentials. - * @cred contains the credentials to use. - * @ns contains the user namespace we want the capability in. - * @cap contains the capability <include/linux/capability.h>. - * @opts contains options for the capable check <include/linux/security.h>. - * Return 0 if the capability is granted for @tsk. - * @quotactl: - * Check whether the quotactl syscall is allowed for this @sb. - * Return 0 if permission is granted. - * @quota_on: - * Check whether QUOTAON is allowed for this @dentry. - * Return 0 if permission is granted. - * @syslog: - * Check permission before accessing the kernel message ring or changing - * logging to the console. - * See the syslog(2) manual page for an explanation of the @type values. - * @type contains the SYSLOG_ACTION_* constant from - * <include/linux/syslog.h>. - * Return 0 if permission is granted. - * @settime: - * Check permission to change the system time. - * struct timespec64 is defined in <include/linux/time64.h> and timezone - * is defined in <include/linux/time.h> - * @ts contains new time. - * @tz contains new timezone. - * Return 0 if permission is granted. - * @vm_enough_memory: - * Check permissions for allocating a new virtual mapping. - * @mm contains the mm struct it is being added to. - * @pages contains the number of pages. - * Return 0 if permission is granted by the LSM infrastructure to the - * caller. If all LSMs return a positive value, __vm_enough_memory() will - * be called with cap_sys_admin set. If at least one LSM returns 0 or - * negative, __vm_enough_memory() will be called with cap_sys_admin - * cleared. - * - * @ismaclabel: - * Check if the extended attribute specified by @name - * represents a MAC label. Returns 1 if name is a MAC - * attribute otherwise returns 0. - * @name full extended attribute name to check against - * LSM as a MAC label. - * - * @secid_to_secctx: - * Convert secid to security context. If secdata is NULL the length of - * the result will be returned in seclen, but no secdata will be returned. - * This does mean that the length could change between calls to check the - * length and the next call which actually allocates and returns the - * secdata. - * @secid contains the security ID. - * @secdata contains the pointer that stores the converted security - * context. - * @seclen pointer which contains the length of the data. - * Return 0 on success, error on failure. - * @secctx_to_secid: - * Convert security context to secid. - * @secid contains the pointer to the generated security ID. - * @secdata contains the security context. - * Return 0 on success, error on failure. - * - * @release_secctx: - * Release the security context. - * @secdata contains the security context. - * @seclen contains the length of the security context. - * - * Security hooks for Audit - * - * @audit_rule_init: - * Allocate and initialize an LSM audit rule structure. - * @field contains the required Audit action. - * Fields flags are defined in <include/linux/audit.h> - * @op contains the operator the rule uses. - * @rulestr contains the context where the rule will be applied to. - * @lsmrule contains a pointer to receive the result. - * Return 0 if @lsmrule has been successfully set, - * -EINVAL in case of an invalid rule. - * - * @audit_rule_known: - * Specifies whether given @krule contains any fields related to - * current LSM. - * @krule contains the audit rule of interest. - * Return 1 in case of relation found, 0 otherwise. - * - * @audit_rule_match: - * Determine if given @secid matches a rule previously approved - * by @audit_rule_known. - * @secid contains the security id in question. - * @field contains the field which relates to current LSM. - * @op contains the operator that will be used for matching. - * @lrule points to the audit rule that will be checked against. - * Return 1 if secid matches the rule, 0 if it does not, -ERRNO on failure. - * - * @audit_rule_free: - * Deallocate the LSM audit rule structure previously allocated by - * audit_rule_init. - * @lsmrule contains the allocated rule. - * - * @inode_invalidate_secctx: - * Notify the security module that it must revalidate the security context - * of an inode. - * - * @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. - * Return 0 on success, error on failure. - * - * @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. - * Return 0 on success, error on failure. - * - * @inode_getsecctx: - * On success, returns 0 and fills out @ctx and @ctxlen with the security - * context for the given @inode. - * @inode we wish to get 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. - * Return 0 on success, error on failure. - * - * Security hooks for the general notification queue: - * - * @post_notification: - * Check to see if a watch notification can be posted to a particular - * queue. - * @w_cred: The credentials of the whoever set the watch. - * @cred: The event-triggerer's credentials. - * @n: The notification being posted. - * Return 0 if permission is granted. - * - * @watch_key: - * Check to see if a process is allowed to watch for event notifications - * from a key or keyring. - * @key: The key to watch. - * Return 0 if permission is granted. - * - * Security hooks for using the eBPF maps and programs functionalities through - * eBPF syscalls. - * - * @bpf: - * Do a initial check for all bpf syscalls after the attribute is copied - * into the kernel. The actual security module can implement their own - * rules to check the specific cmd they need. - * Return 0 if permission is granted. - * - * @bpf_map: - * Do a check when the kernel generate and return a file descriptor for - * eBPF maps. - * @map: bpf map that we want to access. - * @mask: the access flags. - * Return 0 if permission is granted. - * - * @bpf_prog: - * Do a check when the kernel generate and return a file descriptor for - * eBPF programs. - * @prog: bpf prog that userspace want to use. - * Return 0 if permission is granted. - * - * @bpf_map_alloc_security: - * Initialize the security field inside bpf map. - * Return 0 on success, error on failure. - * - * @bpf_map_free_security: - * Clean up the security information stored inside bpf map. - * - * @bpf_prog_alloc_security: - * Initialize the security field inside bpf program. - * Return 0 on success, error on failure. - * - * @bpf_prog_free_security: - * Clean up the security information stored inside bpf prog. - * - * @locked_down: - * Determine whether a kernel feature that potentially enables arbitrary - * code execution in kernel space should be permitted. - * @what: kernel feature being accessed. - * Return 0 if permission is granted. - * - * Security hooks for perf events - * - * @perf_event_open: - * Check whether the @type of perf_event_open syscall is allowed. - * Return 0 if permission is granted. - * @perf_event_alloc: - * Allocate and save perf_event security info. - * Return 0 on success, error on failure. - * @perf_event_free: - * Release (free) perf_event security info. - * @perf_event_read: - * Read perf_event security info if allowed. - * Return 0 if permission is granted. - * @perf_event_write: - * Write perf_event security info if allowed. - * Return 0 if permission is granted. - * - * Security hooks for io_uring - * - * @uring_override_creds: - * Check if the current task, executing an io_uring operation, is allowed - * to override it's credentials with @new. - * @new: the new creds to use. - * Return 0 if permission is granted. - * - * @uring_sqpoll: - * Check whether the current task is allowed to spawn a io_uring polling - * thread (IORING_SETUP_SQPOLL). - * Return 0 if permission is granted. - * - * @uring_cmd: - * Check whether the file_operations uring_cmd is allowed to run. - * Return 0 if permission is granted. - * - */ union security_list_options { #define LSM_HOOK(RET, DEFAULT, NAME, ...) RET (*NAME)(__VA_ARGS__); #include "lsm_hook_defs.h" @@ -1716,6 +92,7 @@ extern void security_add_hooks(struct security_hook_list *hooks, int count, enum lsm_order { LSM_ORDER_FIRST = -1, /* This is only for capabilities. */ LSM_ORDER_MUTABLE = 0, + LSM_ORDER_LAST = 1, /* This is only for integrity. */ }; struct lsm_info { @@ -1740,36 +117,6 @@ extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[]; __used __section(".early_lsm_info.init") \ __aligned(sizeof(unsigned long)) -#ifdef CONFIG_SECURITY_SELINUX_DISABLE -/* - * Assuring the safety of deleting a security module is up to - * the security module involved. This may entail ordering the - * module's hook list in a particular way, refusing to disable - * the module once a policy is loaded or any number of other - * actions better imagined than described. - * - * The name of the configuration option reflects the only module - * that currently uses the mechanism. Any developer who thinks - * disabling their module is a good idea needs to be at least as - * careful as the SELinux team. - */ -static inline void security_delete_hooks(struct security_hook_list *hooks, - int count) -{ - int i; - - for (i = 0; i < count; i++) - hlist_del_rcu(&hooks[i].list); -} -#endif /* CONFIG_SECURITY_SELINUX_DISABLE */ - -/* Currently required to handle SELinux runtime hook disable. */ -#ifdef CONFIG_SECURITY_WRITABLE_HOOKS -#define __lsm_ro_after_init -#else -#define __lsm_ro_after_init __ro_after_init -#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */ - extern int lsm_inode_alloc(struct inode *inode); #endif /* ! __LINUX_LSM_HOOKS_H */ diff --git a/include/linux/security.h b/include/linux/security.h index 5984d0d550b4..cd23221ce9e6 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -336,9 +336,6 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, int security_inode_init_security_anon(struct inode *inode, const struct qstr *name, const struct inode *context_inode); -int security_old_inode_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr, const char **name, - void **value, size_t *len); int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode); int security_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry); @@ -778,15 +775,6 @@ static inline int security_inode_init_security_anon(struct inode *inode, return 0; } -static inline int security_old_inode_init_security(struct inode *inode, - struct inode *dir, - const struct qstr *qstr, - const char **name, - void **value, size_t *len) -{ - return -EOPNOTSUPP; -} - static inline int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode) diff --git a/include/linux/uio.h b/include/linux/uio.h index 27e3fd942960..ed35f4427a0a 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -49,14 +49,35 @@ struct iov_iter { size_t iov_offset; int last_offset; }; - size_t count; + /* + * Hack alert: overlay ubuf_iovec with iovec + count, so + * that the members resolve correctly regardless of the type + * of iterator used. This means that you can use: + * + * &iter->__ubuf_iovec or iter->__iov + * + * interchangably for the user_backed cases, hence simplifying + * some of the cases that need to deal with both. + */ union { - const struct iovec *iov; - const struct kvec *kvec; - const struct bio_vec *bvec; - struct xarray *xarray; - struct pipe_inode_info *pipe; - void __user *ubuf; + /* + * This really should be a const, but we cannot do that without + * also modifying any of the zero-filling iter init functions. + * Leave it non-const for now, but it should be treated as such. + */ + struct iovec __ubuf_iovec; + struct { + union { + /* use iter_iov() to get the current vec */ + const struct iovec *__iov; + const struct kvec *kvec; + const struct bio_vec *bvec; + struct xarray *xarray; + struct pipe_inode_info *pipe; + void __user *ubuf; + }; + size_t count; + }; }; union { unsigned long nr_segs; @@ -68,6 +89,16 @@ struct iov_iter { }; }; +static inline const struct iovec *iter_iov(const struct iov_iter *iter) +{ + if (iter->iter_type == ITER_UBUF) + return (const struct iovec *) &iter->__ubuf_iovec; + return iter->__iov; +} + +#define iter_iov_addr(iter) (iter_iov(iter)->iov_base + (iter)->iov_offset) +#define iter_iov_len(iter) (iter_iov(iter)->iov_len - (iter)->iov_offset) + static inline enum iter_type iov_iter_type(const struct iov_iter *i) { return i->iter_type; @@ -143,15 +174,6 @@ static inline size_t iov_length(const struct iovec *iov, unsigned long nr_segs) return ret; } -static inline struct iovec iov_iter_iovec(const struct iov_iter *iter) -{ - return (struct iovec) { - .iov_base = iter->iov->iov_base + iter->iov_offset, - .iov_len = min(iter->count, - iter->iov->iov_len - iter->iov_offset), - }; -} - size_t copy_page_from_iter_atomic(struct page *page, unsigned offset, size_t bytes, struct iov_iter *i); void iov_iter_advance(struct iov_iter *i, size_t bytes); @@ -359,7 +381,8 @@ static inline void iov_iter_ubuf(struct iov_iter *i, unsigned int direction, .user_backed = true, .data_source = direction, .ubuf = buf, - .count = count + .count = count, + .nr_segs = 1 }; } /* Flags for iov_iter_get/extract_pages*() */ diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h index f3223f964691..81d09ef9aa50 100644 --- a/include/uapi/linux/landlock.h +++ b/include/uapi/linux/landlock.h @@ -130,21 +130,37 @@ struct landlock_path_beneath_attr { * - %LANDLOCK_ACCESS_FS_MAKE_BLOCK: Create (or rename or link) a block device. * - %LANDLOCK_ACCESS_FS_MAKE_SYM: Create (or rename or link) a symbolic link. * - %LANDLOCK_ACCESS_FS_REFER: Link or rename a file from or to a different - * directory (i.e. reparent a file hierarchy). This access right is - * available since the second version of the Landlock ABI. This is also the - * only access right which is always considered handled by any ruleset in - * such a way that reparenting a file hierarchy is always denied by default. - * To avoid privilege escalation, it is not enough to add a rule with this - * access right. When linking or renaming a file, the destination directory - * hierarchy must also always have the same or a superset of restrictions of - * the source hierarchy. If it is not the case, or if the domain doesn't - * handle this access right, such actions are denied by default with errno - * set to ``EXDEV``. Linking also requires a ``LANDLOCK_ACCESS_FS_MAKE_*`` - * access right on the destination directory, and renaming also requires a - * ``LANDLOCK_ACCESS_FS_REMOVE_*`` access right on the source's (file or - * directory) parent. Otherwise, such actions are denied with errno set to - * ``EACCES``. The ``EACCES`` errno prevails over ``EXDEV`` to let user space - * efficiently deal with an unrecoverable error. + * directory (i.e. reparent a file hierarchy). + * + * This access right is available since the second version of the Landlock + * ABI. + * + * This is the only access right which is denied by default by any ruleset, + * even if the right is not specified as handled at ruleset creation time. + * The only way to make a ruleset grant this right is to explicitly allow it + * for a specific directory by adding a matching rule to the ruleset. + * + * In particular, when using the first Landlock ABI version, Landlock will + * always deny attempts to reparent files between different directories. + * + * In addition to the source and destination directories having the + * %LANDLOCK_ACCESS_FS_REFER access right, the attempted link or rename + * operation must meet the following constraints: + * + * * The reparented file may not gain more access rights in the destination + * directory than it previously had in the source directory. If this is + * attempted, the operation results in an ``EXDEV`` error. + * + * * When linking or renaming, the ``LANDLOCK_ACCESS_FS_MAKE_*`` right for the + * respective file type must be granted for the destination directory. + * Otherwise, the operation results in an ``EACCES`` error. + * + * * When renaming, the ``LANDLOCK_ACCESS_FS_REMOVE_*`` right for the + * respective file type must be granted for the source directory. Otherwise, + * the operation results in an ``EACCES`` error. + * + * If multiple requirements are not met, the ``EACCES`` error code takes + * precedence over ``EXDEV``. * * .. warning:: * diff --git a/io_uring/net.c b/io_uring/net.c index 4040cf093318..89e839013837 100644 --- a/io_uring/net.c +++ b/io_uring/net.c @@ -184,8 +184,8 @@ static int io_setup_async_msg(struct io_kiocb *req, async_msg->msg.msg_name = &async_msg->addr; /* if were using fast_iov, set it to the new one */ if (iter_is_iovec(&kmsg->msg.msg_iter) && !kmsg->free_iov) { - size_t fast_idx = kmsg->msg.msg_iter.iov - kmsg->fast_iov; - async_msg->msg.msg_iter.iov = &async_msg->fast_iov[fast_idx]; + size_t fast_idx = iter_iov(&kmsg->msg.msg_iter) - kmsg->fast_iov; + async_msg->msg.msg_iter.__iov = &async_msg->fast_iov[fast_idx]; } return -EAGAIN; diff --git a/io_uring/rw.c b/io_uring/rw.c index 4c233910e200..f33ba6f28247 100644 --- a/io_uring/rw.c +++ b/io_uring/rw.c @@ -447,26 +447,25 @@ static ssize_t loop_rw_iter(int ddir, struct io_rw *rw, struct iov_iter *iter) ppos = io_kiocb_ppos(kiocb); while (iov_iter_count(iter)) { - struct iovec iovec; + void __user *addr; + size_t len; ssize_t nr; if (iter_is_ubuf(iter)) { - iovec.iov_base = iter->ubuf + iter->iov_offset; - iovec.iov_len = iov_iter_count(iter); + addr = iter->ubuf + iter->iov_offset; + len = iov_iter_count(iter); } else if (!iov_iter_is_bvec(iter)) { - iovec = iov_iter_iovec(iter); + addr = iter_iov_addr(iter); + len = iter_iov_len(iter); } else { - iovec.iov_base = u64_to_user_ptr(rw->addr); - iovec.iov_len = rw->len; + addr = u64_to_user_ptr(rw->addr); + len = rw->len; } - if (ddir == READ) { - nr = file->f_op->read(file, iovec.iov_base, - iovec.iov_len, ppos); - } else { - nr = file->f_op->write(file, iovec.iov_base, - iovec.iov_len, ppos); - } + if (ddir == READ) + nr = file->f_op->read(file, addr, len, ppos); + else + nr = file->f_op->write(file, addr, len, ppos); if (nr < 0) { if (!ret) @@ -482,7 +481,7 @@ static ssize_t loop_rw_iter(int ddir, struct io_rw *rw, struct iov_iter *iter) if (!rw->len) break; } - if (nr != iovec.iov_len) + if (nr != len) break; } @@ -503,10 +502,10 @@ static void io_req_map_rw(struct io_kiocb *req, const struct iovec *iovec, if (!iovec) { unsigned iov_off = 0; - io->s.iter.iov = io->s.fast_iov; - if (iter->iov != fast_iov) { - iov_off = iter->iov - fast_iov; - io->s.iter.iov += iov_off; + io->s.iter.__iov = io->s.fast_iov; + if (iter->__iov != fast_iov) { + iov_off = iter_iov(iter) - fast_iov; + io->s.iter.__iov += iov_off; } if (io->s.fast_iov != fast_iov) memcpy(io->s.fast_iov + iov_off, fast_iov + iov_off, diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 274014e4eafe..967fba189c5f 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -126,13 +126,13 @@ __out: \ iterate_buf(i, n, base, len, off, \ i->ubuf, (I)) \ } else if (likely(iter_is_iovec(i))) { \ - const struct iovec *iov = i->iov; \ + const struct iovec *iov = iter_iov(i); \ void __user *base; \ size_t len; \ iterate_iovec(i, n, base, len, off, \ iov, (I)) \ - i->nr_segs -= iov - i->iov; \ - i->iov = iov; \ + i->nr_segs -= iov - iter_iov(i); \ + i->__iov = iov; \ } else if (iov_iter_is_bvec(i)) { \ const struct bio_vec *bvec = i->bvec; \ void *base; \ @@ -355,7 +355,7 @@ size_t fault_in_iov_iter_readable(const struct iov_iter *i, size_t size) size_t skip; size -= count; - for (p = i->iov, skip = i->iov_offset; count; p++, skip = 0) { + for (p = iter_iov(i), skip = i->iov_offset; count; p++, skip = 0) { size_t len = min(count, p->iov_len - skip); size_t ret; @@ -398,7 +398,7 @@ size_t fault_in_iov_iter_writeable(const struct iov_iter *i, size_t size) size_t skip; size -= count; - for (p = i->iov, skip = i->iov_offset; count; p++, skip = 0) { + for (p = iter_iov(i), skip = i->iov_offset; count; p++, skip = 0) { size_t len = min(count, p->iov_len - skip); size_t ret; @@ -425,7 +425,7 @@ void iov_iter_init(struct iov_iter *i, unsigned int direction, .nofault = false, .user_backed = true, .data_source = direction, - .iov = iov, + .__iov = iov, .nr_segs = nr_segs, .iov_offset = 0, .count = count @@ -876,14 +876,14 @@ static void iov_iter_iovec_advance(struct iov_iter *i, size_t size) i->count -= size; size += i->iov_offset; // from beginning of current segment - for (iov = i->iov, end = iov + i->nr_segs; iov < end; iov++) { + for (iov = iter_iov(i), end = iov + i->nr_segs; iov < end; iov++) { if (likely(size < iov->iov_len)) break; size -= iov->iov_len; } i->iov_offset = size; - i->nr_segs -= iov - i->iov; - i->iov = iov; + i->nr_segs -= iov - iter_iov(i); + i->__iov = iov; } void iov_iter_advance(struct iov_iter *i, size_t size) @@ -958,12 +958,12 @@ void iov_iter_revert(struct iov_iter *i, size_t unroll) unroll -= n; } } else { /* same logics for iovec and kvec */ - const struct iovec *iov = i->iov; + const struct iovec *iov = iter_iov(i); while (1) { size_t n = (--iov)->iov_len; i->nr_segs++; if (unroll <= n) { - i->iov = iov; + i->__iov = iov; i->iov_offset = n - unroll; return; } @@ -980,7 +980,7 @@ size_t iov_iter_single_seg_count(const struct iov_iter *i) { if (i->nr_segs > 1) { if (likely(iter_is_iovec(i) || iov_iter_is_kvec(i))) - return min(i->count, i->iov->iov_len - i->iov_offset); + return min(i->count, iter_iov(i)->iov_len - i->iov_offset); if (iov_iter_is_bvec(i)) return min(i->count, i->bvec->bv_len - i->iov_offset); } @@ -1095,13 +1095,14 @@ static bool iov_iter_aligned_iovec(const struct iov_iter *i, unsigned addr_mask, unsigned k; for (k = 0; k < i->nr_segs; k++, skip = 0) { - size_t len = i->iov[k].iov_len - skip; + const struct iovec *iov = iter_iov(i) + k; + size_t len = iov->iov_len - skip; if (len > size) len = size; if (len & len_mask) return false; - if ((unsigned long)(i->iov[k].iov_base + skip) & addr_mask) + if ((unsigned long)(iov->iov_base + skip) & addr_mask) return false; size -= len; @@ -1194,9 +1195,10 @@ static unsigned long iov_iter_alignment_iovec(const struct iov_iter *i) unsigned k; for (k = 0; k < i->nr_segs; k++, skip = 0) { - size_t len = i->iov[k].iov_len - skip; + const struct iovec *iov = iter_iov(i) + k; + size_t len = iov->iov_len - skip; if (len) { - res |= (unsigned long)i->iov[k].iov_base + skip; + res |= (unsigned long)iov->iov_base + skip; if (len > size) len = size; res |= len; @@ -1273,14 +1275,15 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i) return ~0U; for (k = 0; k < i->nr_segs; k++) { - if (i->iov[k].iov_len) { - unsigned long base = (unsigned long)i->iov[k].iov_base; + const struct iovec *iov = iter_iov(i) + k; + if (iov->iov_len) { + unsigned long base = (unsigned long)iov->iov_base; if (v) // if not the first one res |= base | v; // this start | previous end - v = base + i->iov[k].iov_len; - if (size <= i->iov[k].iov_len) + v = base + iov->iov_len; + if (size <= iov->iov_len) break; - size -= i->iov[k].iov_len; + size -= iov->iov_len; } } return res; @@ -1396,13 +1399,14 @@ static unsigned long first_iovec_segment(const struct iov_iter *i, size_t *size) return (unsigned long)i->ubuf + i->iov_offset; for (k = 0, skip = i->iov_offset; k < i->nr_segs; k++, skip = 0) { - size_t len = i->iov[k].iov_len - skip; + const struct iovec *iov = iter_iov(i) + k; + size_t len = iov->iov_len - skip; if (unlikely(!len)) continue; if (*size > len) *size = len; - return (unsigned long)i->iov[k].iov_base + skip; + return (unsigned long)iov->iov_base + skip; } BUG(); // if it had been empty, we wouldn't get called } @@ -1614,7 +1618,7 @@ static int iov_npages(const struct iov_iter *i, int maxpages) const struct iovec *p; int npages = 0; - for (p = i->iov; size; skip = 0, p++) { + for (p = iter_iov(i); size; skip = 0, p++) { unsigned offs = offset_in_page(p->iov_base + skip); size_t len = min(p->iov_len - skip, size); @@ -1691,14 +1695,14 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags) flags); else if (iov_iter_is_kvec(new) || iter_is_iovec(new)) /* iovec and kvec have identical layout */ - return new->iov = kmemdup(new->iov, + return new->__iov = kmemdup(new->__iov, new->nr_segs * sizeof(struct iovec), flags); return NULL; } EXPORT_SYMBOL(dup_iter); -static int copy_compat_iovec_from_user(struct iovec *iov, +static __noclone int copy_compat_iovec_from_user(struct iovec *iov, const struct iovec __user *uvec, unsigned long nr_segs) { const struct compat_iovec __user *uiov = @@ -1731,18 +1735,35 @@ uaccess_end: } static int copy_iovec_from_user(struct iovec *iov, - const struct iovec __user *uvec, unsigned long nr_segs) + const struct iovec __user *uiov, unsigned long nr_segs) { - unsigned long seg; + int ret = -EFAULT; - if (copy_from_user(iov, uvec, nr_segs * sizeof(*uvec))) + if (!user_access_begin(uiov, nr_segs * sizeof(*uiov))) return -EFAULT; - for (seg = 0; seg < nr_segs; seg++) { - if ((ssize_t)iov[seg].iov_len < 0) - return -EINVAL; - } - return 0; + do { + void __user *buf; + ssize_t len; + + unsafe_get_user(len, &uiov->iov_len, uaccess_end); + unsafe_get_user(buf, &uiov->iov_base, uaccess_end); + + /* check for size_t not fitting in ssize_t .. */ + if (unlikely(len < 0)) { + ret = -EINVAL; + goto uaccess_end; + } + iov->iov_base = buf; + iov->iov_len = len; + + uiov++; iov++; + } while (--nr_segs); + + ret = 0; +uaccess_end: + user_access_end(); + return ret; } struct iovec *iovec_from_user(const struct iovec __user *uvec, @@ -1767,7 +1788,7 @@ struct iovec *iovec_from_user(const struct iovec __user *uvec, return ERR_PTR(-ENOMEM); } - if (compat) + if (unlikely(compat)) ret = copy_compat_iovec_from_user(iov, uvec, nr_segs); else ret = copy_iovec_from_user(iov, uvec, nr_segs); @@ -1780,6 +1801,30 @@ struct iovec *iovec_from_user(const struct iovec __user *uvec, return iov; } +/* + * Single segment iovec supplied by the user, import it as ITER_UBUF. + */ +static ssize_t __import_iovec_ubuf(int type, const struct iovec __user *uvec, + struct iovec **iovp, struct iov_iter *i, + bool compat) +{ + struct iovec *iov = *iovp; + ssize_t ret; + + if (compat) + ret = copy_compat_iovec_from_user(iov, uvec, 1); + else + ret = copy_iovec_from_user(iov, uvec, 1); + if (unlikely(ret)) + return ret; + + ret = import_ubuf(type, iov->iov_base, iov->iov_len, i); + if (unlikely(ret)) + return ret; + *iovp = NULL; + return i->count; +} + ssize_t __import_iovec(int type, const struct iovec __user *uvec, unsigned nr_segs, unsigned fast_segs, struct iovec **iovp, struct iov_iter *i, bool compat) @@ -1788,6 +1833,9 @@ ssize_t __import_iovec(int type, const struct iovec __user *uvec, unsigned long seg; struct iovec *iov; + if (nr_segs == 1) + return __import_iovec_ubuf(type, uvec, iovp, i, compat); + iov = iovec_from_user(uvec, nr_segs, fast_segs, *iovp, compat); if (IS_ERR(iov)) { *iovp = NULL; @@ -1866,9 +1914,7 @@ int import_single_range(int rw, void __user *buf, size_t len, if (unlikely(!access_ok(buf, len))) return -EFAULT; - iov->iov_base = buf; - iov->iov_len = len; - iov_iter_init(i, rw, iov, 1, len); + iov_iter_ubuf(i, rw, buf, len); return 0; } EXPORT_SYMBOL(import_single_range); @@ -1918,7 +1964,7 @@ void iov_iter_restore(struct iov_iter *i, struct iov_iter_state *state) if (iov_iter_is_bvec(i)) i->bvec -= state->nr_segs - i->nr_segs; else - i->iov -= state->nr_segs - i->nr_segs; + i->__iov -= state->nr_segs - i->nr_segs; i->nr_segs = state->nr_segs; } diff --git a/mm/madvise.c b/mm/madvise.c index 340125d08c03..9f389c5304d2 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -1456,7 +1456,7 @@ SYSCALL_DEFINE5(process_madvise, int, pidfd, const struct iovec __user *, vec, size_t, vlen, int, behavior, unsigned int, flags) { ssize_t ret; - struct iovec iovstack[UIO_FASTIOV], iovec; + struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov = iovstack; struct iov_iter iter; struct task_struct *task; @@ -1503,12 +1503,11 @@ SYSCALL_DEFINE5(process_madvise, int, pidfd, const struct iovec __user *, vec, total_len = iov_iter_count(&iter); while (iov_iter_count(&iter)) { - iovec = iov_iter_iovec(&iter); - ret = do_madvise(mm, (unsigned long)iovec.iov_base, - iovec.iov_len, behavior); + ret = do_madvise(mm, (unsigned long)iter_iov_addr(&iter), + iter_iov_len(&iter), behavior); if (ret < 0) break; - iov_iter_advance(&iter, iovec.iov_len); + iov_iter_advance(&iter, iter_iov_len(&iter)); } ret = (total_len - iov_iter_count(&iter)) ? : ret; diff --git a/scripts/cc-version.sh b/scripts/cc-version.sh index 0573c92e841d..a7e28b6a514e 100755 --- a/scripts/cc-version.sh +++ b/scripts/cc-version.sh @@ -45,10 +45,6 @@ Clang) version=$2.$3.$4 min_version=$($min_tool_version llvm) ;; -ICC) - version=$(($2 / 100)).$(($2 % 100)).$3 - min_version=$($min_tool_version icc) - ;; *) echo "$orig_args: unknown C compiler" >&2 exit 1 diff --git a/security/Kconfig b/security/Kconfig index e6db09a779b7..cbf9bbc86b9c 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -32,11 +32,6 @@ config SECURITY If you are unsure how to answer this question, answer N. -config SECURITY_WRITABLE_HOOKS - depends on SECURITY - bool - default n - config SECURITYFS bool "Enable the securityfs filesystem" help @@ -246,15 +241,17 @@ endchoice config LSM string "Ordered list of enabled LSMs" - default "landlock,lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor,bpf" if DEFAULT_SECURITY_SMACK - default "landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf" if DEFAULT_SECURITY_APPARMOR - default "landlock,lockdown,yama,loadpin,safesetid,integrity,tomoyo,bpf" if DEFAULT_SECURITY_TOMOYO - default "landlock,lockdown,yama,loadpin,safesetid,integrity,bpf" if DEFAULT_SECURITY_DAC - default "landlock,lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor,bpf" + default "landlock,lockdown,yama,loadpin,safesetid,smack,selinux,tomoyo,apparmor,bpf" if DEFAULT_SECURITY_SMACK + default "landlock,lockdown,yama,loadpin,safesetid,apparmor,selinux,smack,tomoyo,bpf" if DEFAULT_SECURITY_APPARMOR + default "landlock,lockdown,yama,loadpin,safesetid,tomoyo,bpf" if DEFAULT_SECURITY_TOMOYO + default "landlock,lockdown,yama,loadpin,safesetid,bpf" if DEFAULT_SECURITY_DAC + default "landlock,lockdown,yama,loadpin,safesetid,selinux,smack,tomoyo,apparmor,bpf" help A comma-separated list of LSMs, in initialization order. - Any LSMs left off this list will be ignored. This can be - controlled at boot with the "lsm=" parameter. + Any LSMs left off this list, except for those with order + LSM_ORDER_FIRST and LSM_ORDER_LAST, which are always enabled + if selected in the kernel configuration, will be ignored. + This can be controlled at boot with the "lsm=" parameter. If unsure, leave this as the default. diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index d6cc4812ca53..cebba4824e60 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1209,13 +1209,13 @@ static int apparmor_inet_conn_request(const struct sock *sk, struct sk_buff *skb /* * The cred blob is a pointer to, not an instance of, an aa_label. */ -struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = { +struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = { .lbs_cred = sizeof(struct aa_label *), .lbs_file = sizeof(struct aa_file_ctx), .lbs_task = sizeof(struct aa_task_ctx), }; -static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { +static struct security_hook_list apparmor_hooks[] __ro_after_init = { LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), LSM_HOOK_INIT(capget, apparmor_capget), @@ -1427,7 +1427,7 @@ static const struct kernel_param_ops param_ops_aaintbool = { .get = param_get_aaintbool }; /* Boot time disable flag */ -static int apparmor_enabled __lsm_ro_after_init = 1; +static int apparmor_enabled __ro_after_init = 1; module_param_named(enabled, apparmor_enabled, aaintbool, 0444); static int __init apparmor_enabled_setup(char *str) diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c index e5971fa74fd7..cfaf1d0e6a5f 100644 --- a/security/bpf/hooks.c +++ b/security/bpf/hooks.c @@ -6,7 +6,7 @@ #include <linux/lsm_hooks.h> #include <linux/bpf_lsm.h> -static struct security_hook_list bpf_lsm_hooks[] __lsm_ro_after_init = { +static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = { #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ LSM_HOOK_INIT(NAME, bpf_lsm_##NAME), #include <linux/lsm_hook_defs.h> @@ -22,7 +22,7 @@ static int __init bpf_lsm_init(void) return 0; } -struct lsm_blob_sizes bpf_lsm_blob_sizes __lsm_ro_after_init = { +struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = { .lbs_inode = sizeof(struct bpf_storage_blob), .lbs_task = sizeof(struct bpf_storage_blob), }; diff --git a/security/commoncap.c b/security/commoncap.c index 5bb7d1e96277..0b3fc2f3afe7 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -1440,7 +1440,7 @@ int cap_mmap_file(struct file *file, unsigned long reqprot, #ifdef CONFIG_SECURITY -static struct security_hook_list capability_hooks[] __lsm_ro_after_init = { +static struct security_hook_list capability_hooks[] __ro_after_init = { LSM_HOOK_INIT(capable, cap_capable), LSM_HOOK_INIT(settime, cap_settime), LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check), diff --git a/security/device_cgroup.c b/security/device_cgroup.c index bef2b9285fb3..7507d14eacc7 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -216,7 +216,7 @@ static void devcgroup_offline(struct cgroup_subsys_state *css) } /* - * called from kernel/cgroup.c with cgroup_lock() held. + * called from kernel/cgroup/cgroup.c with cgroup_lock() held. */ static struct cgroup_subsys_state * devcgroup_css_alloc(struct cgroup_subsys_state *parent_css) diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 8638976f7990..c73858e8c6d5 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -98,14 +98,6 @@ struct integrity_iint_cache *integrity_inode_get(struct inode *inode) struct rb_node *node, *parent = NULL; struct integrity_iint_cache *iint, *test_iint; - /* - * The integrity's "iint_cache" is initialized at security_init(), - * unless it is not included in the ordered list of LSMs enabled - * on the boot command line. - */ - if (!iint_cache) - panic("%s: lsm=integrity required.\n", __func__); - iint = integrity_iint_find(inode); if (iint) return iint; @@ -182,6 +174,7 @@ static int __init integrity_iintcache_init(void) DEFINE_LSM(integrity) = { .name = "integrity", .init = integrity_iintcache_init, + .order = LSM_ORDER_LAST, }; diff --git a/security/landlock/cred.c b/security/landlock/cred.c index ec6c37f04a19..13dff2a31545 100644 --- a/security/landlock/cred.c +++ b/security/landlock/cred.c @@ -34,7 +34,7 @@ static void hook_cred_free(struct cred *const cred) landlock_put_ruleset_deferred(dom); } -static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = { +static struct security_hook_list landlock_hooks[] __ro_after_init = { LSM_HOOK_INIT(cred_prepare, hook_cred_prepare), LSM_HOOK_INIT(cred_free, hook_cred_free), }; diff --git a/security/landlock/fs.c b/security/landlock/fs.c index adcea0fe7e68..1c0c198f6fdb 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -1280,7 +1280,7 @@ static int hook_file_truncate(struct file *const file) return -EACCES; } -static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = { +static struct security_hook_list landlock_hooks[] __ro_after_init = { LSM_HOOK_INIT(inode_free_security, hook_inode_free_security), LSM_HOOK_INIT(sb_delete, hook_sb_delete), diff --git a/security/landlock/ptrace.c b/security/landlock/ptrace.c index 4c5b9cd71286..8a06d6c492bf 100644 --- a/security/landlock/ptrace.c +++ b/security/landlock/ptrace.c @@ -108,7 +108,7 @@ static int hook_ptrace_traceme(struct task_struct *const parent) return task_ptrace(parent, current); } -static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = { +static struct security_hook_list landlock_hooks[] __ro_after_init = { LSM_HOOK_INIT(ptrace_access_check, hook_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, hook_ptrace_traceme), }; diff --git a/security/landlock/setup.c b/security/landlock/setup.c index 3f196d2ce4f9..0f6113528fa4 100644 --- a/security/landlock/setup.c +++ b/security/landlock/setup.c @@ -15,9 +15,9 @@ #include "ptrace.h" #include "setup.h" -bool landlock_initialized __lsm_ro_after_init = false; +bool landlock_initialized __ro_after_init = false; -struct lsm_blob_sizes landlock_blob_sizes __lsm_ro_after_init = { +struct lsm_blob_sizes landlock_blob_sizes __ro_after_init = { .lbs_cred = sizeof(struct landlock_cred_security), .lbs_file = sizeof(struct landlock_file_security), .lbs_inode = sizeof(struct landlock_inode_security), diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index d73a281adf86..b9d773f11232 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -214,7 +214,7 @@ static int loadpin_load_data(enum kernel_load_data_id id, bool contents) return loadpin_check(NULL, (enum kernel_read_file_id) id); } -static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = { +static struct security_hook_list loadpin_hooks[] __ro_after_init = { LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security), LSM_HOOK_INIT(kernel_read_file, loadpin_read_file), LSM_HOOK_INIT(kernel_load_data, loadpin_load_data), diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c index a79b985e917e..68d19632aeb7 100644 --- a/security/lockdown/lockdown.c +++ b/security/lockdown/lockdown.c @@ -71,7 +71,7 @@ static int lockdown_is_locked_down(enum lockdown_reason what) return 0; } -static struct security_hook_list lockdown_hooks[] __lsm_ro_after_init = { +static struct security_hook_list lockdown_hooks[] __ro_after_init = { LSM_HOOK_INIT(locked_down, lockdown_is_locked_down), }; diff --git a/security/security.c b/security/security.c index cf6cc576736f..d5ff7ff45b77 100644 --- a/security/security.c +++ b/security/security.c @@ -6,6 +6,7 @@ * Copyright (C) 2001-2002 Greg Kroah-Hartman <[email protected]> * Copyright (C) 2001 Networks Associates Technology, Inc <[email protected]> * Copyright (C) 2016 Mellanox Technologies + * Copyright (C) 2023 Microsoft Corporation <[email protected]> */ #define pr_fmt(fmt) "LSM: " fmt @@ -41,7 +42,7 @@ * all security modules to use the same descriptions for auditing * purposes. */ -const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = { +const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = { [LOCKDOWN_NONE] = "none", [LOCKDOWN_MODULE_SIGNATURE] = "unsigned module loading", [LOCKDOWN_DEV_MEM] = "/dev/mem,kmem,port", @@ -74,20 +75,20 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = { [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality", }; -struct security_hook_heads security_hook_heads __lsm_ro_after_init; +struct security_hook_heads security_hook_heads __ro_after_init; static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain); static struct kmem_cache *lsm_file_cache; static struct kmem_cache *lsm_inode_cache; char *lsm_names; -static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init; +static struct lsm_blob_sizes blob_sizes __ro_after_init; /* Boot-time LSM user choice */ static __initdata const char *chosen_lsm_order; static __initdata const char *chosen_major_lsm; -static __initconst const char * const builtin_lsm_order = CONFIG_LSM; +static __initconst const char *const builtin_lsm_order = CONFIG_LSM; /* Ordered list of LSMs to initialize. */ static __initdata struct lsm_info **ordered_lsms; @@ -284,9 +285,9 @@ static void __init ordered_lsm_parse(const char *order, const char *origin) bool found = false; for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { - if (lsm->order == LSM_ORDER_MUTABLE && - strcmp(lsm->name, name) == 0) { - append_ordered_lsm(lsm, origin); + if (strcmp(lsm->name, name) == 0) { + if (lsm->order == LSM_ORDER_MUTABLE) + append_ordered_lsm(lsm, origin); found = true; } } @@ -306,6 +307,12 @@ static void __init ordered_lsm_parse(const char *order, const char *origin) } } + /* LSM_ORDER_LAST is always last. */ + for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { + if (lsm->order == LSM_ORDER_LAST) + append_ordered_lsm(lsm, " last"); + } + /* Disable all LSMs not in the ordered list. */ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { if (exists_ordered_lsm(lsm)) @@ -331,7 +338,8 @@ static void __init report_lsm_order(void) pr_info("initializing lsm="); /* Report each enabled LSM name, comma separated. */ - for (early = __start_early_lsm_info; early < __end_early_lsm_info; early++) + for (early = __start_early_lsm_info; + early < __end_early_lsm_info; early++) if (is_enabled(early)) pr_cont("%s%s", first++ == 0 ? "" : ",", early->name); for (lsm = ordered_lsms; *lsm; lsm++) @@ -346,7 +354,7 @@ static void __init ordered_lsm_init(void) struct lsm_info **lsm; ordered_lsms = kcalloc(LSM_COUNT + 1, sizeof(*ordered_lsms), - GFP_KERNEL); + GFP_KERNEL); if (chosen_lsm_order) { if (chosen_major_lsm) { @@ -419,9 +427,9 @@ int __init security_init(void) { struct lsm_info *lsm; - init_debug("legacy security=%s\n", chosen_major_lsm ?: " *unspecified*"); + init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*"); init_debug(" CONFIG_LSM=%s\n", builtin_lsm_order); - init_debug("boot arg lsm=%s\n", chosen_lsm_order ?: " *unspecified*"); + init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*"); /* * Append the names of the early LSM modules now that kmalloc() is @@ -509,7 +517,7 @@ static int lsm_append(const char *new, char **result) * Each LSM has to register its hooks with the infrastructure. */ void __init security_add_hooks(struct security_hook_list *hooks, int count, - const char *lsm) + const char *lsm) { int i; @@ -778,57 +786,157 @@ static int lsm_superblock_alloc(struct super_block *sb) /* Security operations */ +/** + * security_binder_set_context_mgr() - Check if becoming binder ctx mgr is ok + * @mgr: task credentials of current binder process + * + * Check whether @mgr is allowed to be the binder context manager. + * + * Return: Return 0 if permission is granted. + */ int security_binder_set_context_mgr(const struct cred *mgr) { return call_int_hook(binder_set_context_mgr, 0, mgr); } +/** + * security_binder_transaction() - Check if a binder transaction is allowed + * @from: sending process + * @to: receiving process + * + * Check whether @from is allowed to invoke a binder transaction call to @to. + * + * Return: Returns 0 if permission is granted. + */ int security_binder_transaction(const struct cred *from, const struct cred *to) { return call_int_hook(binder_transaction, 0, from, to); } +/** + * security_binder_transfer_binder() - Check if a binder transfer is allowed + * @from: sending process + * @to: receiving process + * + * Check whether @from is allowed to transfer a binder reference to @to. + * + * Return: Returns 0 if permission is granted. + */ int security_binder_transfer_binder(const struct cred *from, const struct cred *to) { return call_int_hook(binder_transfer_binder, 0, from, to); } +/** + * security_binder_transfer_file() - Check if a binder file xfer is allowed + * @from: sending process + * @to: receiving process + * @file: file being transferred + * + * Check whether @from is allowed to transfer @file to @to. + * + * Return: Returns 0 if permission is granted. + */ int security_binder_transfer_file(const struct cred *from, const struct cred *to, struct file *file) { return call_int_hook(binder_transfer_file, 0, from, to, file); } +/** + * security_ptrace_access_check() - Check if tracing is allowed + * @child: target process + * @mode: PTRACE_MODE flags + * + * Check permission before allowing the current process to trace the @child + * process. Security modules may also want to perform a process tracing check + * during an execve in the set_security or apply_creds hooks of tracing check + * during an execve in the bprm_set_creds hook of binprm_security_ops if the + * process is being traced and its security attributes would be changed by the + * execve. + * + * Return: Returns 0 if permission is granted. + */ int security_ptrace_access_check(struct task_struct *child, unsigned int mode) { return call_int_hook(ptrace_access_check, 0, child, mode); } +/** + * security_ptrace_traceme() - Check if tracing is allowed + * @parent: tracing process + * + * Check that the @parent process has sufficient permission to trace the + * current process before allowing the current process to present itself to the + * @parent process for tracing. + * + * Return: Returns 0 if permission is granted. + */ int security_ptrace_traceme(struct task_struct *parent) { return call_int_hook(ptrace_traceme, 0, parent); } +/** + * security_capget() - Get the capability sets for a process + * @target: target process + * @effective: effective capability set + * @inheritable: inheritable capability set + * @permitted: permitted capability set + * + * Get the @effective, @inheritable, and @permitted capability sets for the + * @target process. The hook may also perform permission checking to determine + * if the current process is allowed to see the capability sets of the @target + * process. + * + * Return: Returns 0 if the capability sets were successfully obtained. + */ int security_capget(struct task_struct *target, - kernel_cap_t *effective, - kernel_cap_t *inheritable, - kernel_cap_t *permitted) + kernel_cap_t *effective, + kernel_cap_t *inheritable, + kernel_cap_t *permitted) { return call_int_hook(capget, 0, target, - effective, inheritable, permitted); + effective, inheritable, permitted); } +/** + * security_capset() - Set the capability sets for a process + * @new: new credentials for the target process + * @old: current credentials of the target process + * @effective: effective capability set + * @inheritable: inheritable capability set + * @permitted: permitted capability set + * + * Set the @effective, @inheritable, and @permitted capability sets for the + * current process. + * + * Return: Returns 0 and update @new if permission is granted. + */ int security_capset(struct cred *new, const struct cred *old, const kernel_cap_t *effective, const kernel_cap_t *inheritable, const kernel_cap_t *permitted) { return call_int_hook(capset, 0, new, old, - effective, inheritable, permitted); + effective, inheritable, permitted); } +/** + * security_capable() - Check if a process has the necessary capability + * @cred: credentials to examine + * @ns: user namespace + * @cap: capability requested + * @opts: capability check options + * + * Check whether the @tsk process has the @cap capability in the indicated + * credentials. @cap contains the capability <include/linux/capability.h>. + * @opts contains options for the capable check <include/linux/security.h>. + * + * Return: Returns 0 if the capability is granted. + */ int security_capable(const struct cred *cred, struct user_namespace *ns, int cap, @@ -837,26 +945,78 @@ int security_capable(const struct cred *cred, return call_int_hook(capable, 0, cred, ns, cap, opts); } +/** + * security_quotactl() - Check if a quotactl() syscall is allowed for this fs + * @cmds: commands + * @type: type + * @id: id + * @sb: filesystem + * + * Check whether the quotactl syscall is allowed for this @sb. + * + * Return: Returns 0 if permission is granted. + */ int security_quotactl(int cmds, int type, int id, struct super_block *sb) { return call_int_hook(quotactl, 0, cmds, type, id, sb); } +/** + * security_quota_on() - Check if QUOTAON is allowed for a dentry + * @dentry: dentry + * + * Check whether QUOTAON is allowed for @dentry. + * + * Return: Returns 0 if permission is granted. + */ int security_quota_on(struct dentry *dentry) { return call_int_hook(quota_on, 0, dentry); } +/** + * security_syslog() - Check if accessing the kernel message ring is allowed + * @type: SYSLOG_ACTION_* type + * + * Check permission before accessing the kernel message ring or changing + * logging to the console. See the syslog(2) manual page for an explanation of + * the @type values. + * + * Return: Return 0 if permission is granted. + */ int security_syslog(int type) { return call_int_hook(syslog, 0, type); } +/** + * security_settime64() - Check if changing the system time is allowed + * @ts: new time + * @tz: timezone + * + * Check permission to change the system time, struct timespec64 is defined in + * <include/linux/time64.h> and timezone is defined in <include/linux/time.h>. + * + * Return: Returns 0 if permission is granted. + */ int security_settime64(const struct timespec64 *ts, const struct timezone *tz) { return call_int_hook(settime, 0, ts, tz); } +/** + * security_vm_enough_memory_mm() - Check if allocating a new mem map is allowed + * @mm: mm struct + * @pages: number of pages + * + * Check permissions for allocating a new virtual mapping. If all LSMs return + * a positive value, __vm_enough_memory() will be called with cap_sys_admin + * set. If at least one LSM returns 0 or negative, __vm_enough_memory() will be + * called with cap_sys_admin cleared. + * + * Return: Returns 0 if permission is granted by the LSM infrastructure to the + * caller. + */ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) { struct security_hook_list *hp; @@ -880,16 +1040,61 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) return __vm_enough_memory(mm, pages, cap_sys_admin); } +/** + * security_bprm_creds_for_exec() - Prepare the credentials for exec() + * @bprm: binary program information + * + * If the setup in prepare_exec_creds did not setup @bprm->cred->security + * properly for executing @bprm->file, update the LSM's portion of + * @bprm->cred->security to be what commit_creds needs to install for the new + * program. This hook may also optionally check permissions (e.g. for + * transitions between security domains). The hook must set @bprm->secureexec + * to 1 if AT_SECURE should be set to request libc enable secure mode. @bprm + * contains the linux_binprm structure. + * + * Return: Returns 0 if the hook is successful and permission is granted. + */ int security_bprm_creds_for_exec(struct linux_binprm *bprm) { return call_int_hook(bprm_creds_for_exec, 0, bprm); } +/** + * security_bprm_creds_from_file() - Update linux_binprm creds based on file + * @bprm: binary program information + * @file: associated file + * + * If @file is setpcap, suid, sgid or otherwise marked to change privilege upon + * exec, update @bprm->cred to reflect that change. This is called after + * finding the binary that will be executed without an interpreter. This + * ensures that the credentials will not be derived from a script that the + * binary will need to reopen, which when reopend may end up being a completely + * different file. This hook may also optionally check permissions (e.g. for + * transitions between security domains). The hook must set @bprm->secureexec + * to 1 if AT_SECURE should be set to request libc enable secure mode. The + * hook must add to @bprm->per_clear any personality flags that should be + * cleared from current->personality. @bprm contains the linux_binprm + * structure. + * + * Return: Returns 0 if the hook is successful and permission is granted. + */ int security_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file) { return call_int_hook(bprm_creds_from_file, 0, bprm, file); } +/** + * security_bprm_check() - Mediate binary handler search + * @bprm: binary program information + * + * This hook mediates the point when a search for a binary handler will begin. + * It allows a check against the @bprm->cred->security value which was set in + * the preceding creds_for_exec call. The argv list and envp list are reliably + * available in @bprm. This hook may be called multiple times during a single + * execve. @bprm contains the linux_binprm structure. + * + * Return: Returns 0 if the hook is successful and permission is granted. + */ int security_bprm_check(struct linux_binprm *bprm) { int ret; @@ -900,21 +1105,67 @@ int security_bprm_check(struct linux_binprm *bprm) return ima_bprm_check(bprm); } +/** + * security_bprm_committing_creds() - Install creds for a process during exec() + * @bprm: binary program information + * + * Prepare to install the new security attributes of a process being + * transformed by an execve operation, based on the old credentials pointed to + * by @current->cred and the information set in @bprm->cred by the + * bprm_creds_for_exec hook. @bprm points to the linux_binprm structure. This + * hook is a good place to perform state changes on the process such as closing + * open file descriptors to which access will no longer be granted when the + * attributes are changed. This is called immediately before commit_creds(). + */ void security_bprm_committing_creds(struct linux_binprm *bprm) { call_void_hook(bprm_committing_creds, bprm); } +/** + * security_bprm_committed_creds() - Tidy up after cred install during exec() + * @bprm: binary program information + * + * Tidy up after the installation of the new security attributes of a process + * being transformed by an execve operation. The new credentials have, by this + * point, been set to @current->cred. @bprm points to the linux_binprm + * structure. This hook is a good place to perform state changes on the + * process such as clearing out non-inheritable signal state. This is called + * immediately after commit_creds(). + */ void security_bprm_committed_creds(struct linux_binprm *bprm) { call_void_hook(bprm_committed_creds, bprm); } +/** + * security_fs_context_dup() - Duplicate a fs_context LSM blob + * @fc: destination filesystem context + * @src_fc: source filesystem context + * + * Allocate and attach a security structure to sc->security. This pointer is + * initialised to NULL by the caller. @fc indicates the new filesystem context. + * @src_fc indicates the original filesystem context. + * + * Return: Returns 0 on success or a negative error code on failure. + */ int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) { return call_int_hook(fs_context_dup, 0, fc, src_fc); } +/** + * security_fs_context_parse_param() - Configure a filesystem context + * @fc: filesystem context + * @param: filesystem parameter + * + * Userspace provided a parameter to configure a superblock. The LSM can + * consume the parameter or return it to the caller for use elsewhere. + * + * Return: If the parameter is used by the LSM it should return 0, if it is + * returned to the caller -ENOPARAM is returned, otherwise a negative + * error code is returned. + */ int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { @@ -933,6 +1184,16 @@ int security_fs_context_parse_param(struct fs_context *fc, return rc; } +/** + * security_sb_alloc() - Allocate a super_block LSM blob + * @sb: filesystem superblock + * + * Allocate and attach a security structure to the sb->s_security field. The + * s_security field is initialized to NULL when the structure is allocated. + * @sb contains the super_block structure to be modified. + * + * Return: Returns 0 if operation was successful. + */ int security_sb_alloc(struct super_block *sb) { int rc = lsm_superblock_alloc(sb); @@ -945,11 +1206,25 @@ int security_sb_alloc(struct super_block *sb) return rc; } +/** + * security_sb_delete() - Release super_block LSM associated objects + * @sb: filesystem superblock + * + * Release objects tied to a superblock (e.g. inodes). @sb contains the + * super_block structure being released. + */ void security_sb_delete(struct super_block *sb) { call_void_hook(sb_delete, sb); } +/** + * security_sb_free() - Free a super_block LSM blob + * @sb: filesystem superblock + * + * Deallocate and clear the sb->s_security field. @sb contains the super_block + * structure to be modified. + */ void security_sb_free(struct super_block *sb) { call_void_hook(sb_free_security, sb); @@ -957,6 +1232,12 @@ void security_sb_free(struct super_block *sb) sb->s_security = NULL; } +/** + * security_free_mnt_opts() - Free memory associated with mount options + * @mnt_opts: LSM processed mount options + * + * Free memory associated with @mnt_ops. + */ void security_free_mnt_opts(void **mnt_opts) { if (!*mnt_opts) @@ -966,12 +1247,31 @@ void security_free_mnt_opts(void **mnt_opts) } EXPORT_SYMBOL(security_free_mnt_opts); +/** + * security_sb_eat_lsm_opts() - Consume LSM mount options + * @options: mount options + * @mnt_opts: LSM processed mount options + * + * Eat (scan @options) and save them in @mnt_opts. + * + * Return: Returns 0 on success, negative values on failure. + */ int security_sb_eat_lsm_opts(char *options, void **mnt_opts) { return call_int_hook(sb_eat_lsm_opts, 0, options, mnt_opts); } EXPORT_SYMBOL(security_sb_eat_lsm_opts); +/** + * security_sb_mnt_opts_compat() - Check if new mount options are allowed + * @sb: filesystem superblock + * @mnt_opts: new mount options + * + * Determine if the new mount options in @mnt_opts are allowed given the + * existing mounted filesystem at @sb. @sb superblock being compared. + * + * Return: Returns 0 if options are compatible. + */ int security_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts) { @@ -979,6 +1279,16 @@ int security_sb_mnt_opts_compat(struct super_block *sb, } EXPORT_SYMBOL(security_sb_mnt_opts_compat); +/** + * security_sb_remount() - Verify no incompatible mount changes during remount + * @sb: filesystem superblock + * @mnt_opts: (re)mount options + * + * Extracts security system specific mount options and verifies no changes are + * being made to those options. + * + * Return: Returns 0 if permission is granted. + */ int security_sb_remount(struct super_block *sb, void *mnt_opts) { @@ -986,69 +1296,184 @@ int security_sb_remount(struct super_block *sb, } EXPORT_SYMBOL(security_sb_remount); +/** + * security_sb_kern_mount() - Check if a kernel mount is allowed + * @sb: filesystem superblock + * + * Mount this @sb if allowed by permissions. + * + * Return: Returns 0 if permission is granted. + */ int security_sb_kern_mount(struct super_block *sb) { return call_int_hook(sb_kern_mount, 0, sb); } +/** + * security_sb_show_options() - Output the mount options for a superblock + * @m: output file + * @sb: filesystem superblock + * + * Show (print on @m) mount options for this @sb. + * + * Return: Returns 0 on success, negative values on failure. + */ int security_sb_show_options(struct seq_file *m, struct super_block *sb) { return call_int_hook(sb_show_options, 0, m, sb); } +/** + * security_sb_statfs() - Check if accessing fs stats is allowed + * @dentry: superblock handle + * + * Check permission before obtaining filesystem statistics for the @mnt + * mountpoint. @dentry is a handle on the superblock for the filesystem. + * + * Return: Returns 0 if permission is granted. + */ int security_sb_statfs(struct dentry *dentry) { return call_int_hook(sb_statfs, 0, dentry); } +/** + * security_sb_mount() - Check permission for mounting a filesystem + * @dev_name: filesystem backing device + * @path: mount point + * @type: filesystem type + * @flags: mount flags + * @data: filesystem specific data + * + * Check permission before an object specified by @dev_name is mounted on the + * mount point named by @nd. For an ordinary mount, @dev_name identifies a + * device if the file system type requires a device. For a remount + * (@flags & MS_REMOUNT), @dev_name is irrelevant. For a loopback/bind mount + * (@flags & MS_BIND), @dev_name identifies the pathname of the object being + * mounted. + * + * Return: Returns 0 if permission is granted. + */ int security_sb_mount(const char *dev_name, const struct path *path, - const char *type, unsigned long flags, void *data) + const char *type, unsigned long flags, void *data) { return call_int_hook(sb_mount, 0, dev_name, path, type, flags, data); } +/** + * security_sb_umount() - Check permission for unmounting a filesystem + * @mnt: mounted filesystem + * @flags: unmount flags + * + * Check permission before the @mnt file system is unmounted. + * + * Return: Returns 0 if permission is granted. + */ int security_sb_umount(struct vfsmount *mnt, int flags) { return call_int_hook(sb_umount, 0, mnt, flags); } -int security_sb_pivotroot(const struct path *old_path, const struct path *new_path) +/** + * security_sb_pivotroot() - Check permissions for pivoting the rootfs + * @old_path: new location for current rootfs + * @new_path: location of the new rootfs + * + * Check permission before pivoting the root filesystem. + * + * Return: Returns 0 if permission is granted. + */ +int security_sb_pivotroot(const struct path *old_path, + const struct path *new_path) { return call_int_hook(sb_pivotroot, 0, old_path, new_path); } +/** + * security_sb_set_mnt_opts() - Set the mount options for a filesystem + * @sb: filesystem superblock + * @mnt_opts: binary mount options + * @kern_flags: kernel flags (in) + * @set_kern_flags: kernel flags (out) + * + * Set the security relevant mount options used for a superblock. + * + * Return: Returns 0 on success, error on failure. + */ int security_sb_set_mnt_opts(struct super_block *sb, - void *mnt_opts, - unsigned long kern_flags, - unsigned long *set_kern_flags) + void *mnt_opts, + unsigned long kern_flags, + unsigned long *set_kern_flags) { return call_int_hook(sb_set_mnt_opts, - mnt_opts ? -EOPNOTSUPP : 0, sb, - mnt_opts, kern_flags, set_kern_flags); + mnt_opts ? -EOPNOTSUPP : 0, sb, + mnt_opts, kern_flags, set_kern_flags); } EXPORT_SYMBOL(security_sb_set_mnt_opts); +/** + * security_sb_clone_mnt_opts() - Duplicate superblock mount options + * @oldsb: source superblock + * @newsb: destination superblock + * @kern_flags: kernel flags (in) + * @set_kern_flags: kernel flags (out) + * + * Copy all security options from a given superblock to another. + * + * Return: Returns 0 on success, error on failure. + */ int security_sb_clone_mnt_opts(const struct super_block *oldsb, - struct super_block *newsb, - unsigned long kern_flags, - unsigned long *set_kern_flags) + struct super_block *newsb, + unsigned long kern_flags, + unsigned long *set_kern_flags) { return call_int_hook(sb_clone_mnt_opts, 0, oldsb, newsb, - kern_flags, set_kern_flags); + kern_flags, set_kern_flags); } EXPORT_SYMBOL(security_sb_clone_mnt_opts); -int security_move_mount(const struct path *from_path, const struct path *to_path) +/** + * security_move_mount() - Check permissions for moving a mount + * @from_path: source mount point + * @to_path: destination mount point + * + * Check permission before a mount is moved. + * + * Return: Returns 0 if permission is granted. + */ +int security_move_mount(const struct path *from_path, + const struct path *to_path) { return call_int_hook(move_mount, 0, from_path, to_path); } +/** + * security_path_notify() - Check if setting a watch is allowed + * @path: file path + * @mask: event mask + * @obj_type: file path type + * + * Check permissions before setting a watch on events as defined by @mask, on + * an object at @path, whose type is defined by @obj_type. + * + * Return: Returns 0 if permission is granted. + */ int security_path_notify(const struct path *path, u64 mask, - unsigned int obj_type) + unsigned int obj_type) { return call_int_hook(path_notify, 0, path, mask, obj_type); } +/** + * security_inode_alloc() - Allocate an inode LSM blob + * @inode: the inode + * + * Allocate and attach a security structure to @inode->i_security. The + * i_security field is initialized to NULL when the inode structure is + * allocated. + * + * Return: Return 0 if operation was successful. + */ int security_inode_alloc(struct inode *inode) { int rc = lsm_inode_alloc(inode); @@ -1069,6 +1494,12 @@ static void inode_free_by_rcu(struct rcu_head *head) kmem_cache_free(lsm_inode_cache, head); } +/** + * security_inode_free() - Free an inode's LSM blob + * @inode: the inode + * + * Deallocate the inode security structure and set @inode->i_security to NULL. + */ void security_inode_free(struct inode *inode) { integrity_inode_free(inode); @@ -1084,9 +1515,24 @@ void security_inode_free(struct inode *inode) */ if (inode->i_security) call_rcu((struct rcu_head *)inode->i_security, - inode_free_by_rcu); + inode_free_by_rcu); } +/** + * security_dentry_init_security() - Perform dentry initialization + * @dentry: the dentry to initialize + * @mode: mode used to determine resource type + * @name: name of the last path component + * @xattr_name: name of the security/LSM xattr + * @ctx: pointer to the resulting LSM context + * @ctxlen: length of @ctx + * + * Compute a context for a dentry as the inode is not yet available since NFSv4 + * has no label backed by an EA anyway. It is important to note that + * @xattr_name does not need to be free'd by the caller, it is a static string. + * + * Return: Returns 0 on success, negative values on failure. + */ int security_dentry_init_security(struct dentry *dentry, int mode, const struct qstr *name, const char **xattr_name, void **ctx, @@ -1098,7 +1544,8 @@ int security_dentry_init_security(struct dentry *dentry, int mode, /* * Only one module will provide a security context. */ - hlist_for_each_entry(hp, &security_hook_heads.dentry_init_security, list) { + hlist_for_each_entry(hp, &security_hook_heads.dentry_init_security, + list) { rc = hp->hook.dentry_init_security(dentry, mode, name, xattr_name, ctx, ctxlen); if (rc != LSM_RET_DEFAULT(dentry_init_security)) @@ -1108,15 +1555,51 @@ int security_dentry_init_security(struct dentry *dentry, int mode, } EXPORT_SYMBOL(security_dentry_init_security); +/** + * security_dentry_create_files_as() - Perform dentry initialization + * @dentry: the dentry to initialize + * @mode: mode used to determine resource type + * @name: name of the last path component + * @old: creds to use for LSM context calculations + * @new: creds to modify + * + * Compute a context for a dentry as the inode is not yet available and set + * that context in passed in creds so that new files are created using that + * context. Context is calculated using the passed in creds and not the creds + * of the caller. + * + * Return: Returns 0 on success, error on failure. + */ int security_dentry_create_files_as(struct dentry *dentry, int mode, struct qstr *name, const struct cred *old, struct cred *new) { return call_int_hook(dentry_create_files_as, 0, dentry, mode, - name, old, new); + name, old, new); } EXPORT_SYMBOL(security_dentry_create_files_as); +/** + * security_inode_init_security() - Initialize an inode's LSM context + * @inode: the inode + * @dir: parent directory + * @qstr: last component of the pathname + * @initxattrs: callback function to write xattrs + * @fs_data: filesystem specific data + * + * Obtain the security attribute name suffix and value to set on a newly + * created inode and set up the incore security field for the new inode. This + * hook is called by the fs code as part of the inode creation transaction and + * provides for atomic labeling of the inode, unlike the post_create/mkdir/... + * hooks called by the VFS. The hook function is expected to allocate the name + * and value via kmalloc, with the caller being responsible for calling kfree + * after using them. If the security module does not use security attributes + * or does not wish to put a security attribute on this particular inode, then + * it should return -EOPNOTSUPP to skip this processing. + * + * Return: Returns 0 on success, -EOPNOTSUPP if no security attribute is + * needed, or -ENOMEM on memory allocation failure. + */ int security_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const initxattrs initxattrs, void *fs_data) @@ -1134,9 +1617,9 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, memset(new_xattrs, 0, sizeof(new_xattrs)); lsm_xattr = new_xattrs; ret = call_int_hook(inode_init_security, -EOPNOTSUPP, inode, dir, qstr, - &lsm_xattr->name, - &lsm_xattr->value, - &lsm_xattr->value_len); + &lsm_xattr->name, + &lsm_xattr->value, + &lsm_xattr->value_len); if (ret) goto out; @@ -1152,6 +1635,18 @@ out: } EXPORT_SYMBOL(security_inode_init_security); +/** + * security_inode_init_security_anon() - Initialize an anonymous inode + * @inode: the inode + * @name: the anonymous inode class + * @context_inode: an optional related inode + * + * Set up the incore security field for the new anonymous inode and return + * whether the inode creation is permitted by the security module or not. + * + * Return: Returns 0 on success, -EACCES if the security module denies the + * creation of this inode, or another -errno upon other errors. + */ int security_inode_init_security_anon(struct inode *inode, const struct qstr *name, const struct inode *context_inode) @@ -1160,20 +1655,21 @@ int security_inode_init_security_anon(struct inode *inode, context_inode); } -int security_old_inode_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr, const char **name, - void **value, size_t *len) -{ - if (unlikely(IS_PRIVATE(inode))) - return -EOPNOTSUPP; - return call_int_hook(inode_init_security, -EOPNOTSUPP, inode, dir, - qstr, name, value, len); -} -EXPORT_SYMBOL(security_old_inode_init_security); - #ifdef CONFIG_SECURITY_PATH -int security_path_mknod(const struct path *dir, struct dentry *dentry, umode_t mode, - unsigned int dev) +/** + * security_path_mknod() - Check if creating a special file is allowed + * @dir: parent directory + * @dentry: new file + * @mode: new file mode + * @dev: device number + * + * Check permissions when creating a file. Note that this hook is called even + * if mknod operation is being done for a regular file. + * + * Return: Returns 0 if permission is granted. + */ +int security_path_mknod(const struct path *dir, struct dentry *dentry, + umode_t mode, unsigned int dev) { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) return 0; @@ -1181,7 +1677,18 @@ int security_path_mknod(const struct path *dir, struct dentry *dentry, umode_t m } EXPORT_SYMBOL(security_path_mknod); -int security_path_mkdir(const struct path *dir, struct dentry *dentry, umode_t mode) +/** + * security_path_mkdir() - Check if creating a new directory is allowed + * @dir: parent directory + * @dentry: new directory + * @mode: new directory mode + * + * Check permissions to create a new directory in the existing directory. + * + * Return: Returns 0 if permission is granted. + */ +int security_path_mkdir(const struct path *dir, struct dentry *dentry, + umode_t mode) { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) return 0; @@ -1189,6 +1696,15 @@ int security_path_mkdir(const struct path *dir, struct dentry *dentry, umode_t m } EXPORT_SYMBOL(security_path_mkdir); +/** + * security_path_rmdir() - Check if removing a directory is allowed + * @dir: parent directory + * @dentry: directory to remove + * + * Check the permission to remove a directory. + * + * Return: Returns 0 if permission is granted. + */ int security_path_rmdir(const struct path *dir, struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) @@ -1196,6 +1712,15 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry) return call_int_hook(path_rmdir, 0, dir, dentry); } +/** + * security_path_unlink() - Check if removing a hard link is allowed + * @dir: parent directory + * @dentry: file + * + * Check the permission to remove a hard link to a file. + * + * Return: Returns 0 if permission is granted. + */ int security_path_unlink(const struct path *dir, struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) @@ -1204,6 +1729,16 @@ int security_path_unlink(const struct path *dir, struct dentry *dentry) } EXPORT_SYMBOL(security_path_unlink); +/** + * security_path_symlink() - Check if creating a symbolic link is allowed + * @dir: parent directory + * @dentry: symbolic link + * @old_name: file pathname + * + * Check the permission to create a symbolic link to a file. + * + * Return: Returns 0 if permission is granted. + */ int security_path_symlink(const struct path *dir, struct dentry *dentry, const char *old_name) { @@ -1212,6 +1747,16 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry, return call_int_hook(path_symlink, 0, dir, dentry, old_name); } +/** + * security_path_link - Check if creating a hard link is allowed + * @old_dentry: existing file + * @new_dir: new parent directory + * @new_dentry: new link + * + * Check permission before creating a new hard link to a file. + * + * Return: Returns 0 if permission is granted. + */ int security_path_link(struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry) { @@ -1220,19 +1765,42 @@ int security_path_link(struct dentry *old_dentry, const struct path *new_dir, return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry); } +/** + * security_path_rename() - Check if renaming a file is allowed + * @old_dir: parent directory of the old file + * @old_dentry: the old file + * @new_dir: parent directory of the new file + * @new_dentry: the new file + * @flags: flags + * + * Check for permission to rename a file or directory. + * + * Return: Returns 0 if permission is granted. + */ int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry, unsigned int flags) { if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) || - (d_is_positive(new_dentry) && IS_PRIVATE(d_backing_inode(new_dentry))))) + (d_is_positive(new_dentry) && + IS_PRIVATE(d_backing_inode(new_dentry))))) return 0; return call_int_hook(path_rename, 0, old_dir, old_dentry, new_dir, - new_dentry, flags); + new_dentry, flags); } EXPORT_SYMBOL(security_path_rename); +/** + * security_path_truncate() - Check if truncating a file is allowed + * @path: file + * + * Check permission before truncating the file indicated by path. Note that + * truncation permissions may also be checked based on already opened files, + * using the security_file_truncate() hook. + * + * Return: Returns 0 if permission is granted. + */ int security_path_truncate(const struct path *path) { if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry)))) @@ -1240,6 +1808,17 @@ int security_path_truncate(const struct path *path) return call_int_hook(path_truncate, 0, path); } +/** + * security_path_chmod() - Check if changing the file's mode is allowed + * @path: file + * @mode: new mode + * + * Check for permission to change a mode of the file @path. The new mode is + * specified in @mode which is a bitmask of constants from + * <include/uapi/linux/stat.h>. + * + * Return: Returns 0 if permission is granted. + */ int security_path_chmod(const struct path *path, umode_t mode) { if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry)))) @@ -1247,6 +1826,16 @@ int security_path_chmod(const struct path *path, umode_t mode) return call_int_hook(path_chmod, 0, path, mode); } +/** + * security_path_chown() - Check if changing the file's owner/group is allowed + * @path: file + * @uid: file owner + * @gid: file group + * + * Check for permission to change owner/group of a file or directory. + * + * Return: Returns 0 if permission is granted. + */ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) { if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry)))) @@ -1254,13 +1843,32 @@ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) return call_int_hook(path_chown, 0, path, uid, gid); } +/** + * security_path_chroot() - Check if changing the root directory is allowed + * @path: directory + * + * Check for permission to change root directory. + * + * Return: Returns 0 if permission is granted. + */ int security_path_chroot(const struct path *path) { return call_int_hook(path_chroot, 0, path); } -#endif +#endif /* CONFIG_SECURITY_PATH */ -int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode) +/** + * security_inode_create() - Check if creating a file is allowed + * @dir: the parent directory + * @dentry: the file being created + * @mode: requested file mode + * + * Check permission to create a regular file. + * + * Return: Returns 0 if permission is granted. + */ +int security_inode_create(struct inode *dir, struct dentry *dentry, + umode_t mode) { if (unlikely(IS_PRIVATE(dir))) return 0; @@ -1268,14 +1876,33 @@ int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode } EXPORT_SYMBOL_GPL(security_inode_create); +/** + * security_inode_link() - Check if creating a hard link is allowed + * @old_dentry: existing file + * @dir: new parent directory + * @new_dentry: new link + * + * Check permission before creating a new hard link to a file. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *new_dentry) + struct dentry *new_dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)))) return 0; return call_int_hook(inode_link, 0, old_dentry, dir, new_dentry); } +/** + * security_inode_unlink() - Check if removing a hard link is allowed + * @dir: parent directory + * @dentry: file + * + * Check the permission to remove a hard link to a file. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_unlink(struct inode *dir, struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) @@ -1283,14 +1910,35 @@ int security_inode_unlink(struct inode *dir, struct dentry *dentry) return call_int_hook(inode_unlink, 0, dir, dentry); } +/** + * security_inode_symlink() - Check if creating a symbolic link is allowed + * @dir: parent directory + * @dentry: symbolic link + * @old_name: existing filename + * + * Check the permission to create a symbolic link to a file. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_symlink(struct inode *dir, struct dentry *dentry, - const char *old_name) + const char *old_name) { if (unlikely(IS_PRIVATE(dir))) return 0; return call_int_hook(inode_symlink, 0, dir, dentry, old_name); } +/** + * security_inode_mkdir() - Check if creation a new director is allowed + * @dir: parent directory + * @dentry: new directory + * @mode: new directory mode + * + * Check permissions to create a new directory in the existing directory + * associated with inode structure @dir. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { if (unlikely(IS_PRIVATE(dir))) @@ -1299,6 +1947,15 @@ int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) } EXPORT_SYMBOL_GPL(security_inode_mkdir); +/** + * security_inode_rmdir() - Check if removing a directory is allowed + * @dir: parent directory + * @dentry: directory to be removed + * + * Check the permission to remove a directory. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_rmdir(struct inode *dir, struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) @@ -1306,32 +1963,68 @@ int security_inode_rmdir(struct inode *dir, struct dentry *dentry) return call_int_hook(inode_rmdir, 0, dir, dentry); } -int security_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) +/** + * security_inode_mknod() - Check if creating a special file is allowed + * @dir: parent directory + * @dentry: new file + * @mode: new file mode + * @dev: device number + * + * Check permissions when creating a special file (or a socket or a fifo file + * created via the mknod system call). Note that if mknod operation is being + * done for a regular file, then the create hook will be called and not this + * hook. + * + * Return: Returns 0 if permission is granted. + */ +int security_inode_mknod(struct inode *dir, struct dentry *dentry, + umode_t mode, dev_t dev) { if (unlikely(IS_PRIVATE(dir))) return 0; return call_int_hook(inode_mknod, 0, dir, dentry, mode, dev); } +/** + * security_inode_rename() - Check if renaming a file is allowed + * @old_dir: parent directory of the old file + * @old_dentry: the old file + * @new_dir: parent directory of the new file + * @new_dentry: the new file + * @flags: flags + * + * Check for permission to rename a file or directory. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) { - if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) || - (d_is_positive(new_dentry) && IS_PRIVATE(d_backing_inode(new_dentry))))) + if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) || + (d_is_positive(new_dentry) && + IS_PRIVATE(d_backing_inode(new_dentry))))) return 0; if (flags & RENAME_EXCHANGE) { int err = call_int_hook(inode_rename, 0, new_dir, new_dentry, - old_dir, old_dentry); + old_dir, old_dentry); if (err) return err; } return call_int_hook(inode_rename, 0, old_dir, old_dentry, - new_dir, new_dentry); + new_dir, new_dentry); } +/** + * security_inode_readlink() - Check if reading a symbolic link is allowed + * @dentry: link + * + * Check the permission to read the symbolic link. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_readlink(struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) @@ -1339,6 +2032,17 @@ int security_inode_readlink(struct dentry *dentry) return call_int_hook(inode_readlink, 0, dentry); } +/** + * security_inode_follow_link() - Check if following a symbolic link is allowed + * @dentry: link dentry + * @inode: link inode + * @rcu: true if in RCU-walk mode + * + * Check permission to follow a symbolic link when looking up a pathname. If + * @rcu is true, @inode is not stable. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_follow_link(struct dentry *dentry, struct inode *inode, bool rcu) { @@ -1347,6 +2051,20 @@ int security_inode_follow_link(struct dentry *dentry, struct inode *inode, return call_int_hook(inode_follow_link, 0, dentry, inode, rcu); } +/** + * security_inode_permission() - Check if accessing an inode is allowed + * @inode: inode + * @mask: access mask + * + * Check permission before accessing an inode. This hook is called by the + * existing Linux permission function, so a security module can use it to + * provide additional checking for existing Linux permission checks. Notice + * that this hook is called when a file is opened (as well as many other + * operations), whereas the file_security_ops permission hook is called when + * the actual read/write operations are performed. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_permission(struct inode *inode, int mask) { if (unlikely(IS_PRIVATE(inode))) @@ -1354,6 +2072,19 @@ int security_inode_permission(struct inode *inode, int mask) return call_int_hook(inode_permission, 0, inode, mask); } +/** + * security_inode_setattr() - Check if setting file attributes is allowed + * @idmap: idmap of the mount + * @dentry: file + * @attr: new attributes + * + * Check permission before setting file attributes. Note that the kernel call + * to notify_change is performed from several locations, whenever file + * attributes change (such as when a file is truncated, chown/chmod operations, + * transferring disk quotas, etc). + * + * Return: Returns 0 if permission is granted. + */ int security_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *attr) { @@ -1368,6 +2099,14 @@ int security_inode_setattr(struct mnt_idmap *idmap, } EXPORT_SYMBOL_GPL(security_inode_setattr); +/** + * security_inode_getattr() - Check if getting file attributes is allowed + * @path: file + * + * Check permission before obtaining file attributes. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_getattr(const struct path *path) { if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry)))) @@ -1375,6 +2114,19 @@ int security_inode_getattr(const struct path *path) return call_int_hook(inode_getattr, 0, path); } +/** + * security_inode_setxattr() - Check if setting file xattrs is allowed + * @idmap: idmap of the mount + * @dentry: file + * @name: xattr name + * @value: xattr value + * @size: size of xattr value + * @flags: flags + * + * Check permission before setting the extended attributes. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) @@ -1400,6 +2152,18 @@ int security_inode_setxattr(struct mnt_idmap *idmap, return evm_inode_setxattr(idmap, dentry, name, value, size); } +/** + * security_inode_set_acl() - Check if setting posix acls is allowed + * @idmap: idmap of the mount + * @dentry: file + * @acl_name: acl name + * @kacl: acl struct + * + * Check permission before setting posix acls, the posix acls in @kacl are + * identified by @acl_name. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name, struct posix_acl *kacl) @@ -1418,6 +2182,17 @@ int security_inode_set_acl(struct mnt_idmap *idmap, return evm_inode_set_acl(idmap, dentry, acl_name, kacl); } +/** + * security_inode_get_acl() - Check if reading posix acls is allowed + * @idmap: idmap of the mount + * @dentry: file + * @acl_name: acl name + * + * Check permission before getting osix acls, the posix acls are identified by + * @acl_name. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_get_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name) { @@ -1426,6 +2201,17 @@ int security_inode_get_acl(struct mnt_idmap *idmap, return call_int_hook(inode_get_acl, 0, idmap, dentry, acl_name); } +/** + * security_inode_remove_acl() - Check if removing a posix acl is allowed + * @idmap: idmap of the mount + * @dentry: file + * @acl_name: acl name + * + * Check permission before removing posix acls, the posix acls are identified + * by @acl_name. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name) { @@ -1442,6 +2228,16 @@ int security_inode_remove_acl(struct mnt_idmap *idmap, return evm_inode_remove_acl(idmap, dentry, acl_name); } +/** + * security_inode_post_setxattr() - Update the inode after a setxattr operation + * @dentry: file + * @name: xattr name + * @value: xattr value + * @size: xattr value size + * @flags: flags + * + * Update inode security field after successful setxattr operation. + */ void security_inode_post_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { @@ -1451,6 +2247,16 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name, evm_inode_post_setxattr(dentry, name, value, size); } +/** + * security_inode_getxattr() - Check if xattr access is allowed + * @dentry: file + * @name: xattr name + * + * Check permission before obtaining the extended attributes identified by + * @name for @dentry. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_getxattr(struct dentry *dentry, const char *name) { if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) @@ -1458,6 +2264,15 @@ int security_inode_getxattr(struct dentry *dentry, const char *name) return call_int_hook(inode_getxattr, 0, dentry, name); } +/** + * security_inode_listxattr() - Check if listing xattrs is allowed + * @dentry: file + * + * Check permission before obtaining the list of extended attribute names for + * @dentry. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_listxattr(struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) @@ -1465,6 +2280,17 @@ int security_inode_listxattr(struct dentry *dentry) return call_int_hook(inode_listxattr, 0, dentry); } +/** + * security_inode_removexattr() - Check if removing an xattr is allowed + * @idmap: idmap of the mount + * @dentry: file + * @name: xattr name + * + * Check permission before removing the extended attribute identified by @name + * for @dentry. + * + * Return: Returns 0 if permission is granted. + */ int security_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry, const char *name) { @@ -1487,17 +2313,55 @@ int security_inode_removexattr(struct mnt_idmap *idmap, return evm_inode_removexattr(idmap, dentry, name); } +/** + * security_inode_need_killpriv() - Check if security_inode_killpriv() required + * @dentry: associated dentry + * + * Called when an inode has been changed to determine if + * security_inode_killpriv() should be called. + * + * Return: Return <0 on error to abort the inode change operation, return 0 if + * security_inode_killpriv() does not need to be called, return >0 if + * security_inode_killpriv() does need to be called. + */ int security_inode_need_killpriv(struct dentry *dentry) { return call_int_hook(inode_need_killpriv, 0, dentry); } +/** + * security_inode_killpriv() - The setuid bit is removed, update LSM state + * @idmap: idmap of the mount + * @dentry: associated dentry + * + * The @dentry's setuid bit is being removed. Remove similar security labels. + * Called with the dentry->d_inode->i_mutex held. + * + * Return: Return 0 on success. If error is returned, then the operation + * causing setuid bit removal is failed. + */ int security_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry) { return call_int_hook(inode_killpriv, 0, idmap, dentry); } +/** + * security_inode_getsecurity() - Get the xattr security label of an inode + * @idmap: idmap of the mount + * @inode: inode + * @name: xattr name + * @buffer: security label buffer + * @alloc: allocation flag + * + * Retrieve a copy of the extended attribute representation of the security + * label associated with @name for @inode via @buffer. Note that @name is the + * remainder of the attribute name after the security prefix has been removed. + * @alloc is used to specify if the call should return a value via the buffer + * or just the value length. + * + * Return: Returns size of buffer on success. + */ int security_inode_getsecurity(struct mnt_idmap *idmap, struct inode *inode, const char *name, void **buffer, bool alloc) @@ -1511,14 +2375,31 @@ int security_inode_getsecurity(struct mnt_idmap *idmap, * Only one module will provide an attribute with a given name. */ hlist_for_each_entry(hp, &security_hook_heads.inode_getsecurity, list) { - rc = hp->hook.inode_getsecurity(idmap, inode, name, buffer, alloc); + rc = hp->hook.inode_getsecurity(idmap, inode, name, buffer, + alloc); if (rc != LSM_RET_DEFAULT(inode_getsecurity)) return rc; } return LSM_RET_DEFAULT(inode_getsecurity); } -int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) +/** + * security_inode_setsecurity() - Set the xattr security label of an inode + * @inode: inode + * @name: xattr name + * @value: security label + * @size: length of security label + * @flags: flags + * + * Set the security label associated with @name for @inode from the extended + * attribute value @value. @size indicates the size of the @value in bytes. + * @flags may be XATTR_CREATE, XATTR_REPLACE, or 0. Note that @name is the + * remainder of the attribute name after the security. prefix has been removed. + * + * Return: Returns 0 on success. + */ +int security_inode_setsecurity(struct inode *inode, const char *name, + const void *value, size_t size, int flags) { struct security_hook_list *hp; int rc; @@ -1530,14 +2411,28 @@ int security_inode_setsecurity(struct inode *inode, const char *name, const void */ hlist_for_each_entry(hp, &security_hook_heads.inode_setsecurity, list) { rc = hp->hook.inode_setsecurity(inode, name, value, size, - flags); + flags); if (rc != LSM_RET_DEFAULT(inode_setsecurity)) return rc; } return LSM_RET_DEFAULT(inode_setsecurity); } -int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size) +/** + * security_inode_listsecurity() - List the xattr security label names + * @inode: inode + * @buffer: buffer + * @buffer_size: size of buffer + * + * Copy the extended attribute names for the security labels associated with + * @inode into @buffer. The maximum size of @buffer is specified by + * @buffer_size. @buffer may be NULL to request the size of the buffer + * required. + * + * Return: Returns number of bytes used/required on success. + */ +int security_inode_listsecurity(struct inode *inode, + char *buffer, size_t buffer_size) { if (unlikely(IS_PRIVATE(inode))) return 0; @@ -1545,17 +2440,49 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer } EXPORT_SYMBOL(security_inode_listsecurity); +/** + * security_inode_getsecid() - Get an inode's secid + * @inode: inode + * @secid: secid to return + * + * Get the secid associated with the node. In case of failure, @secid will be + * set to zero. + */ void security_inode_getsecid(struct inode *inode, u32 *secid) { call_void_hook(inode_getsecid, inode, secid); } +/** + * security_inode_copy_up() - Create new creds for an overlayfs copy-up op + * @src: union dentry of copy-up file + * @new: newly created creds + * + * A file is about to be copied up from lower layer to upper layer of overlay + * filesystem. Security module can prepare a set of new creds and modify as + * need be and return new creds. Caller will switch to new creds temporarily to + * create new file and release newly allocated creds. + * + * Return: Returns 0 on success or a negative error code on error. + */ int security_inode_copy_up(struct dentry *src, struct cred **new) { return call_int_hook(inode_copy_up, 0, src, new); } EXPORT_SYMBOL(security_inode_copy_up); +/** + * security_inode_copy_up_xattr() - Filter xattrs in an overlayfs copy-up op + * @name: xattr name + * + * Filter the xattrs being copied up when a unioned file is copied up from a + * lower layer to the union/overlay layer. The caller is responsible for + * reading and writing the xattrs, this hook is merely a filter. + * + * Return: Returns 0 to accept the xattr, 1 to discard the xattr, -EOPNOTSUPP + * if the security module does not know about attribute, or a negative + * error code to abort the copy up. + */ int security_inode_copy_up_xattr(const char *name) { struct security_hook_list *hp; @@ -1567,7 +2494,7 @@ int security_inode_copy_up_xattr(const char *name) * any other error code incase of an error. */ hlist_for_each_entry(hp, - &security_hook_heads.inode_copy_up_xattr, list) { + &security_hook_heads.inode_copy_up_xattr, list) { rc = hp->hook.inode_copy_up_xattr(name); if (rc != LSM_RET_DEFAULT(inode_copy_up_xattr)) return rc; @@ -1577,12 +2504,41 @@ int security_inode_copy_up_xattr(const char *name) } EXPORT_SYMBOL(security_inode_copy_up_xattr); +/** + * security_kernfs_init_security() - Init LSM context for a kernfs node + * @kn_dir: parent kernfs node + * @kn: the kernfs node to initialize + * + * Initialize the security context of a newly created kernfs node based on its + * own and its parent's attributes. + * + * Return: Returns 0 if permission is granted. + */ int security_kernfs_init_security(struct kernfs_node *kn_dir, struct kernfs_node *kn) { return call_int_hook(kernfs_init_security, 0, kn_dir, kn); } +/** + * security_file_permission() - Check file permissions + * @file: file + * @mask: requested permissions + * + * Check file permissions before accessing an open file. This hook is called + * by various operations that read or write files. A security module can use + * this hook to perform additional checking on these operations, e.g. to + * revalidate permissions on use to support privilege bracketing or policy + * changes. Notice that this hook is used when the actual read/write + * operations are performed, whereas the inode_security_ops hook is called when + * a file is opened (as well as many other operations). Although this hook can + * be used to revalidate permissions for various system call operations that + * read or write files, it does not address the revalidation of permissions for + * memory-mapped files. Security modules must handle this separately if they + * need such revalidation. + * + * Return: Returns 0 if permission is granted. + */ int security_file_permission(struct file *file, int mask) { int ret; @@ -1594,6 +2550,15 @@ int security_file_permission(struct file *file, int mask) return fsnotify_perm(file, mask); } +/** + * security_file_alloc() - Allocate and init a file's LSM blob + * @file: the file + * + * Allocate and attach a security structure to the file->f_security field. The + * security field is initialized to NULL when the structure is first created. + * + * Return: Return 0 if the hook is successful and permission is granted. + */ int security_file_alloc(struct file *file) { int rc = lsm_file_alloc(file); @@ -1606,6 +2571,12 @@ int security_file_alloc(struct file *file) return rc; } +/** + * security_file_free() - Free a file's LSM blob + * @file: the file + * + * Deallocate and free any security structures stored in file->f_security. + */ void security_file_free(struct file *file) { void *blob; @@ -1619,6 +2590,19 @@ void security_file_free(struct file *file) } } +/** + * security_file_ioctl() - Check if an ioctl is allowed + * @file: associated file + * @cmd: ioctl cmd + * @arg: ioctl arguments + * + * Check permission for an ioctl operation on @file. Note that @arg sometimes + * represents a user space pointer; in other cases, it may be a simple integer + * value. When @arg represents a user space pointer, it should never be used + * by the security module. + * + * Return: Returns 0 if permission is granted. + */ int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return call_int_hook(file_ioctl, 0, file, cmd, arg); @@ -1658,8 +2642,19 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot) return prot; } +/** + * security_mmap_file() - Check if mmap'ing a file is allowed + * @file: file + * @prot: protection applied by the kernel + * @flags: flags + * + * Check permissions for a mmap operation. The @file may be NULL, e.g. if + * mapping anonymous memory. + * + * Return: Returns 0 if permission is granted. + */ int security_mmap_file(struct file *file, unsigned long prot, - unsigned long flags) + unsigned long flags) { unsigned long prot_adj = mmap_prot(file, prot); int ret; @@ -1670,13 +2665,31 @@ int security_mmap_file(struct file *file, unsigned long prot, return ima_file_mmap(file, prot, prot_adj, flags); } +/** + * security_mmap_addr() - Check if mmap'ing an address is allowed + * @addr: address + * + * Check permissions for a mmap operation at @addr. + * + * Return: Returns 0 if permission is granted. + */ int security_mmap_addr(unsigned long addr) { return call_int_hook(mmap_addr, 0, addr); } +/** + * security_file_mprotect() - Check if changing memory protections is allowed + * @vma: memory region + * @reqprot: application requested protection + * @prot: protection applied by the kernel + * + * Check permissions before changing memory access permissions. + * + * Return: Returns 0 if permission is granted. + */ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, - unsigned long prot) + unsigned long prot) { int ret; @@ -1686,32 +2699,97 @@ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, return ima_file_mprotect(vma, prot); } +/** + * security_file_lock() - Check if a file lock is allowed + * @file: file + * @cmd: lock operation (e.g. F_RDLCK, F_WRLCK) + * + * Check permission before performing file locking operations. Note the hook + * mediates both flock and fcntl style locks. + * + * Return: Returns 0 if permission is granted. + */ int security_file_lock(struct file *file, unsigned int cmd) { return call_int_hook(file_lock, 0, file, cmd); } +/** + * security_file_fcntl() - Check if fcntl() op is allowed + * @file: file + * @cmd: fnctl command + * @arg: command argument + * + * Check permission before allowing the file operation specified by @cmd from + * being performed on the file @file. Note that @arg sometimes represents a + * user space pointer; in other cases, it may be a simple integer value. When + * @arg represents a user space pointer, it should never be used by the + * security module. + * + * Return: Returns 0 if permission is granted. + */ int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg) { return call_int_hook(file_fcntl, 0, file, cmd, arg); } +/** + * security_file_set_fowner() - Set the file owner info in the LSM blob + * @file: the file + * + * Save owner security information (typically from current->security) in + * file->f_security for later use by the send_sigiotask hook. + * + * Return: Returns 0 on success. + */ void security_file_set_fowner(struct file *file) { call_void_hook(file_set_fowner, file); } +/** + * security_file_send_sigiotask() - Check if sending SIGIO/SIGURG is allowed + * @tsk: target task + * @fown: signal sender + * @sig: signal to be sent, SIGIO is sent if 0 + * + * Check permission for the file owner @fown to send SIGIO or SIGURG to the + * process @tsk. Note that this hook is sometimes called from interrupt. Note + * that the fown_struct, @fown, is never outside the context of a struct file, + * so the file structure (and associated security information) can always be + * obtained: container_of(fown, struct file, f_owner). + * + * Return: Returns 0 if permission is granted. + */ int security_file_send_sigiotask(struct task_struct *tsk, - struct fown_struct *fown, int sig) + struct fown_struct *fown, int sig) { return call_int_hook(file_send_sigiotask, 0, tsk, fown, sig); } +/** + * security_file_receive() - Check is receiving a file via IPC is allowed + * @file: file being received + * + * This hook allows security modules to control the ability of a process to + * receive an open file descriptor via socket IPC. + * + * Return: Returns 0 if permission is granted. + */ int security_file_receive(struct file *file) { return call_int_hook(file_receive, 0, file); } +/** + * security_file_open() - Save open() time state for late use by the LSM + * @file: + * + * Save open-time permission checking state for later use upon file_permission, + * and recheck access if anything has changed since inode_permission. + * + * Return: Returns 0 if permission is granted. + */ int security_file_open(struct file *file) { int ret; @@ -1723,11 +2801,30 @@ int security_file_open(struct file *file) return fsnotify_perm(file, MAY_OPEN); } +/** + * security_file_truncate() - Check if truncating a file is allowed + * @file: file + * + * Check permission before truncating a file, i.e. using ftruncate. Note that + * truncation permission may also be checked based on the path, using the + * @path_truncate hook. + * + * Return: Returns 0 if permission is granted. + */ int security_file_truncate(struct file *file) { return call_int_hook(file_truncate, 0, file); } +/** + * security_task_alloc() - Allocate a task's LSM blob + * @task: the task + * @clone_flags: flags indicating what is being shared + * + * Handle allocation of task-related resources. + * + * Return: Returns a zero on success, negative values on failure. + */ int security_task_alloc(struct task_struct *task, unsigned long clone_flags) { int rc = lsm_task_alloc(task); @@ -1740,6 +2837,13 @@ int security_task_alloc(struct task_struct *task, unsigned long clone_flags) return rc; } +/** + * security_task_free() - Free a task's LSM blob and related resources + * @task: task + * + * Handle release of task-related resources. Note that this can be called from + * interrupt context. + */ void security_task_free(struct task_struct *task) { call_void_hook(task_free, task); @@ -1748,6 +2852,16 @@ void security_task_free(struct task_struct *task) task->security = NULL; } +/** + * security_cred_alloc_blank() - Allocate the min memory to allow cred_transfer + * @cred: credentials + * @gfp: gfp flags + * + * Only allocate sufficient memory and attach to @cred such that + * cred_transfer() will not get ENOMEM. + * + * Return: Returns 0 on success, negative values on failure. + */ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) { int rc = lsm_cred_alloc(cred, gfp); @@ -1761,6 +2875,12 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) return rc; } +/** + * security_cred_free() - Free the cred's LSM blob and associated resources + * @cred: credentials + * + * Deallocate and clear the cred->security field in a set of credentials. + */ void security_cred_free(struct cred *cred) { /* @@ -1776,6 +2896,16 @@ void security_cred_free(struct cred *cred) cred->security = NULL; } +/** + * security_prepare_creds() - Prepare a new set of credentials + * @new: new credentials + * @old: original credentials + * @gfp: gfp flags + * + * Prepare a new set of credentials by copying the data from the old set. + * + * Return: Returns 0 on success, negative values on failure. + */ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) { int rc = lsm_cred_alloc(new, gfp); @@ -1789,11 +2919,26 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) return rc; } +/** + * security_transfer_creds() - Transfer creds + * @new: target credentials + * @old: original credentials + * + * Transfer data from original creds to new creds. + */ void security_transfer_creds(struct cred *new, const struct cred *old) { call_void_hook(cred_transfer, new, old); } +/** + * security_cred_getsecid() - Get the secid from a set of credentials + * @c: credentials + * @secid: secid value + * + * Retrieve the security identifier of the cred structure @c. In case of + * failure, @secid will be set to zero. + */ void security_cred_getsecid(const struct cred *c, u32 *secid) { *secid = 0; @@ -1801,16 +2946,46 @@ void security_cred_getsecid(const struct cred *c, u32 *secid) } EXPORT_SYMBOL(security_cred_getsecid); +/** + * security_kernel_act_as() - Set the kernel credentials to act as secid + * @new: credentials + * @secid: secid + * + * Set the credentials for a kernel service to act as (subjective context). + * The current task must be the one that nominated @secid. + * + * Return: Returns 0 if successful. + */ int security_kernel_act_as(struct cred *new, u32 secid) { return call_int_hook(kernel_act_as, 0, new, secid); } +/** + * security_kernel_create_files_as() - Set file creation context using an inode + * @new: target credentials + * @inode: reference inode + * + * Set the file creation context in a set of credentials to be the same as the + * objective context of the specified inode. The current task must be the one + * that nominated @inode. + * + * Return: Returns 0 if successful. + */ int security_kernel_create_files_as(struct cred *new, struct inode *inode) { return call_int_hook(kernel_create_files_as, 0, new, inode); } +/** + * security_kernel_module_request() - Check is loading a module is allowed + * @kmod_name: module name + * + * Ability to trigger the kernel to automatically upcall to userspace for + * userspace to load a kernel module with the given name. + * + * Return: Returns 0 if successful. + */ int security_kernel_module_request(char *kmod_name) { int ret; @@ -1821,6 +2996,16 @@ int security_kernel_module_request(char *kmod_name) return integrity_kernel_module_request(kmod_name); } +/** + * security_kernel_read_file() - Read a file specified by userspace + * @file: file + * @id: file identifier + * @contents: trust if security_kernel_post_read_file() will be called + * + * Read a file specified by userspace. + * + * Return: Returns 0 if permission is granted. + */ int security_kernel_read_file(struct file *file, enum kernel_read_file_id id, bool contents) { @@ -1833,6 +3018,19 @@ int security_kernel_read_file(struct file *file, enum kernel_read_file_id id, } EXPORT_SYMBOL_GPL(security_kernel_read_file); +/** + * security_kernel_post_read_file() - Read a file specified by userspace + * @file: file + * @buf: file contents + * @size: size of file contents + * @id: file identifier + * + * Read a file specified by userspace. This must be paired with a prior call + * to security_kernel_read_file() call that indicated this hook would also be + * called, see security_kernel_read_file() for more information. + * + * Return: Returns 0 if permission is granted. + */ int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, enum kernel_read_file_id id) { @@ -1845,6 +3043,15 @@ int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, } EXPORT_SYMBOL_GPL(security_kernel_post_read_file); +/** + * security_kernel_load_data() - Load data provided by userspace + * @id: data identifier + * @contents: true if security_kernel_post_load_data() will be called + * + * Load data provided by userspace. + * + * Return: Returns 0 if permission is granted. + */ int security_kernel_load_data(enum kernel_load_data_id id, bool contents) { int ret; @@ -1856,6 +3063,20 @@ int security_kernel_load_data(enum kernel_load_data_id id, bool contents) } EXPORT_SYMBOL_GPL(security_kernel_load_data); +/** + * security_kernel_post_load_data() - Load userspace data from a non-file source + * @buf: data + * @size: size of data + * @id: data identifier + * @description: text description of data, specific to the id value + * + * Load data provided by a non-file source (usually userspace buffer). This + * must be paired with a prior security_kernel_load_data() call that indicated + * this hook would also be called, see security_kernel_load_data() for more + * information. + * + * Return: Returns 0 if permission is granted. + */ int security_kernel_post_load_data(char *buf, loff_t size, enum kernel_load_data_id id, char *description) @@ -1870,38 +3091,112 @@ int security_kernel_post_load_data(char *buf, loff_t size, } EXPORT_SYMBOL_GPL(security_kernel_post_load_data); +/** + * security_task_fix_setuid() - Update LSM with new user id attributes + * @new: updated credentials + * @old: credentials being replaced + * @flags: LSM_SETID_* flag values + * + * Update the module's state after setting one or more of the user identity + * attributes of the current process. The @flags parameter indicates which of + * the set*uid system calls invoked this hook. If @new is the set of + * credentials that will be installed. Modifications should be made to this + * rather than to @current->cred. + * + * Return: Returns 0 on success. + */ int security_task_fix_setuid(struct cred *new, const struct cred *old, int flags) { return call_int_hook(task_fix_setuid, 0, new, old, flags); } +/** + * security_task_fix_setgid() - Update LSM with new group id attributes + * @new: updated credentials + * @old: credentials being replaced + * @flags: LSM_SETID_* flag value + * + * Update the module's state after setting one or more of the group identity + * attributes of the current process. The @flags parameter indicates which of + * the set*gid system calls invoked this hook. @new is the set of credentials + * that will be installed. Modifications should be made to this rather than to + * @current->cred. + * + * Return: Returns 0 on success. + */ int security_task_fix_setgid(struct cred *new, const struct cred *old, - int flags) + int flags) { return call_int_hook(task_fix_setgid, 0, new, old, flags); } +/** + * security_task_fix_setgroups() - Update LSM with new supplementary groups + * @new: updated credentials + * @old: credentials being replaced + * + * Update the module's state after setting the supplementary group identity + * attributes of the current process. @new is the set of credentials that will + * be installed. Modifications should be made to this rather than to + * @current->cred. + * + * Return: Returns 0 on success. + */ int security_task_fix_setgroups(struct cred *new, const struct cred *old) { return call_int_hook(task_fix_setgroups, 0, new, old); } +/** + * security_task_setpgid() - Check if setting the pgid is allowed + * @p: task being modified + * @pgid: new pgid + * + * Check permission before setting the process group identifier of the process + * @p to @pgid. + * + * Return: Returns 0 if permission is granted. + */ int security_task_setpgid(struct task_struct *p, pid_t pgid) { return call_int_hook(task_setpgid, 0, p, pgid); } +/** + * security_task_getpgid() - Check if getting the pgid is allowed + * @p: task + * + * Check permission before getting the process group identifier of the process + * @p. + * + * Return: Returns 0 if permission is granted. + */ int security_task_getpgid(struct task_struct *p) { return call_int_hook(task_getpgid, 0, p); } +/** + * security_task_getsid() - Check if getting the session id is allowed + * @p: task + * + * Check permission before getting the session identifier of the process @p. + * + * Return: Returns 0 if permission is granted. + */ int security_task_getsid(struct task_struct *p) { return call_int_hook(task_getsid, 0, p); } +/** + * security_current_getsecid_subj() - Get the current task's subjective secid + * @secid: secid value + * + * Retrieve the subjective security identifier of the current task and return + * it in @secid. In case of failure, @secid will be set to zero. + */ void security_current_getsecid_subj(u32 *secid) { *secid = 0; @@ -1909,6 +3204,14 @@ void security_current_getsecid_subj(u32 *secid) } EXPORT_SYMBOL(security_current_getsecid_subj); +/** + * security_task_getsecid_obj() - Get a task's objective secid + * @p: target task + * @secid: secid value + * + * Retrieve the objective security identifier of the task_struct in @p and + * return it in @secid. In case of failure, @secid will be set to zero. + */ void security_task_getsecid_obj(struct task_struct *p, u32 *secid) { *secid = 0; @@ -1916,56 +3219,159 @@ void security_task_getsecid_obj(struct task_struct *p, u32 *secid) } EXPORT_SYMBOL(security_task_getsecid_obj); +/** + * security_task_setnice() - Check if setting a task's nice value is allowed + * @p: target task + * @nice: nice value + * + * Check permission before setting the nice value of @p to @nice. + * + * Return: Returns 0 if permission is granted. + */ int security_task_setnice(struct task_struct *p, int nice) { return call_int_hook(task_setnice, 0, p, nice); } +/** + * security_task_setioprio() - Check if setting a task's ioprio is allowed + * @p: target task + * @ioprio: ioprio value + * + * Check permission before setting the ioprio value of @p to @ioprio. + * + * Return: Returns 0 if permission is granted. + */ int security_task_setioprio(struct task_struct *p, int ioprio) { return call_int_hook(task_setioprio, 0, p, ioprio); } +/** + * security_task_getioprio() - Check if getting a task's ioprio is allowed + * @p: task + * + * Check permission before getting the ioprio value of @p. + * + * Return: Returns 0 if permission is granted. + */ int security_task_getioprio(struct task_struct *p) { return call_int_hook(task_getioprio, 0, p); } +/** + * security_task_prlimit() - Check if get/setting resources limits is allowed + * @cred: current task credentials + * @tcred: target task credentials + * @flags: LSM_PRLIMIT_* flag bits indicating a get/set/both + * + * Check permission before getting and/or setting the resource limits of + * another task. + * + * Return: Returns 0 if permission is granted. + */ int security_task_prlimit(const struct cred *cred, const struct cred *tcred, unsigned int flags) { return call_int_hook(task_prlimit, 0, cred, tcred, flags); } +/** + * security_task_setrlimit() - Check if setting a new rlimit value is allowed + * @p: target task's group leader + * @resource: resource whose limit is being set + * @new_rlim: new resource limit + * + * Check permission before setting the resource limits of process @p for + * @resource to @new_rlim. The old resource limit values can be examined by + * dereferencing (p->signal->rlim + resource). + * + * Return: Returns 0 if permission is granted. + */ int security_task_setrlimit(struct task_struct *p, unsigned int resource, - struct rlimit *new_rlim) + struct rlimit *new_rlim) { return call_int_hook(task_setrlimit, 0, p, resource, new_rlim); } +/** + * security_task_setscheduler() - Check if setting sched policy/param is allowed + * @p: target task + * + * Check permission before setting scheduling policy and/or parameters of + * process @p. + * + * Return: Returns 0 if permission is granted. + */ int security_task_setscheduler(struct task_struct *p) { return call_int_hook(task_setscheduler, 0, p); } +/** + * security_task_getscheduler() - Check if getting scheduling info is allowed + * @p: target task + * + * Check permission before obtaining scheduling information for process @p. + * + * Return: Returns 0 if permission is granted. + */ int security_task_getscheduler(struct task_struct *p) { return call_int_hook(task_getscheduler, 0, p); } +/** + * security_task_movememory() - Check if moving memory is allowed + * @p: task + * + * Check permission before moving memory owned by process @p. + * + * Return: Returns 0 if permission is granted. + */ int security_task_movememory(struct task_struct *p) { return call_int_hook(task_movememory, 0, p); } +/** + * security_task_kill() - Check if sending a signal is allowed + * @p: target process + * @info: signal information + * @sig: signal value + * @cred: credentials of the signal sender, NULL if @current + * + * Check permission before sending signal @sig to @p. @info can be NULL, the + * constant 1, or a pointer to a kernel_siginfo structure. If @info is 1 or + * SI_FROMKERNEL(info) is true, then the signal should be viewed as coming from + * the kernel and should typically be permitted. SIGIO signals are handled + * separately by the send_sigiotask hook in file_security_ops. + * + * Return: Returns 0 if permission is granted. + */ int security_task_kill(struct task_struct *p, struct kernel_siginfo *info, - int sig, const struct cred *cred) + int sig, const struct cred *cred) { return call_int_hook(task_kill, 0, p, info, sig, cred); } +/** + * security_task_prctl() - Check if a prctl op is allowed + * @option: operation + * @arg2: argument + * @arg3: argument + * @arg4: argument + * @arg5: argument + * + * Check permission before performing a process control operation on the + * current process. + * + * Return: Return -ENOSYS if no-one wanted to handle this op, any other value + * to cause prctl() to return immediately with that value. + */ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) + unsigned long arg4, unsigned long arg5) { int thisrc; int rc = LSM_RET_DEFAULT(task_prctl); @@ -1982,27 +3388,69 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, return rc; } +/** + * security_task_to_inode() - Set the security attributes of a task's inode + * @p: task + * @inode: inode + * + * Set the security attributes for an inode based on an associated task's + * security attributes, e.g. for /proc/pid inodes. + */ void security_task_to_inode(struct task_struct *p, struct inode *inode) { call_void_hook(task_to_inode, p, inode); } +/** + * security_create_user_ns() - Check if creating a new userns is allowed + * @cred: prepared creds + * + * Check permission prior to creating a new user namespace. + * + * Return: Returns 0 if successful, otherwise < 0 error code. + */ int security_create_user_ns(const struct cred *cred) { return call_int_hook(userns_create, 0, cred); } +/** + * security_ipc_permission() - Check if sysv ipc access is allowed + * @ipcp: ipc permission structure + * @flag: requested permissions + * + * Check permissions for access to IPC. + * + * Return: Returns 0 if permission is granted. + */ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag) { return call_int_hook(ipc_permission, 0, ipcp, flag); } +/** + * security_ipc_getsecid() - Get the sysv ipc object's secid + * @ipcp: ipc permission structure + * @secid: secid pointer + * + * Get the secid associated with the ipc object. In case of failure, @secid + * will be set to zero. + */ void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) { *secid = 0; call_void_hook(ipc_getsecid, ipcp, secid); } +/** + * security_msg_msg_alloc() - Allocate a sysv ipc message LSM blob + * @msg: message structure + * + * Allocate and attach a security structure to the msg->security field. The + * security field is initialized to NULL when the structure is first created. + * + * Return: Return 0 if operation was successful and permission is granted. + */ int security_msg_msg_alloc(struct msg_msg *msg) { int rc = lsm_msg_msg_alloc(msg); @@ -2015,6 +3463,12 @@ int security_msg_msg_alloc(struct msg_msg *msg) return rc; } +/** + * security_msg_msg_free() - Free a sysv ipc message LSM blob + * @msg: message structure + * + * Deallocate the security structure for this message. + */ void security_msg_msg_free(struct msg_msg *msg) { call_void_hook(msg_msg_free_security, msg); @@ -2022,6 +3476,15 @@ void security_msg_msg_free(struct msg_msg *msg) msg->security = NULL; } +/** + * security_msg_queue_alloc() - Allocate a sysv ipc msg queue LSM blob + * @msq: sysv ipc permission structure + * + * Allocate and attach a security structure to @msg. The security field is + * initialized to NULL when the structure is first created. + * + * Return: Returns 0 if operation was successful and permission is granted. + */ int security_msg_queue_alloc(struct kern_ipc_perm *msq) { int rc = lsm_ipc_alloc(msq); @@ -2034,6 +3497,12 @@ int security_msg_queue_alloc(struct kern_ipc_perm *msq) return rc; } +/** + * security_msg_queue_free() - Free a sysv ipc msg queue LSM blob + * @msq: sysv ipc permission structure + * + * Deallocate security field @perm->security for the message queue. + */ void security_msg_queue_free(struct kern_ipc_perm *msq) { call_void_hook(msg_queue_free_security, msq); @@ -2041,28 +3510,84 @@ void security_msg_queue_free(struct kern_ipc_perm *msq) msq->security = NULL; } +/** + * security_msg_queue_associate() - Check if a msg queue operation is allowed + * @msq: sysv ipc permission structure + * @msqflg: operation flags + * + * Check permission when a message queue is requested through the msgget system + * call. This hook is only called when returning the message queue identifier + * for an existing message queue, not when a new message queue is created. + * + * Return: Return 0 if permission is granted. + */ int security_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) { return call_int_hook(msg_queue_associate, 0, msq, msqflg); } +/** + * security_msg_queue_msgctl() - Check if a msg queue operation is allowed + * @msq: sysv ipc permission structure + * @cmd: operation + * + * Check permission when a message control operation specified by @cmd is to be + * performed on the message queue with permissions. + * + * Return: Returns 0 if permission is granted. + */ int security_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd) { return call_int_hook(msg_queue_msgctl, 0, msq, cmd); } +/** + * security_msg_queue_msgsnd() - Check if sending a sysv ipc message is allowed + * @msq: sysv ipc permission structure + * @msg: message + * @msqflg: operation flags + * + * Check permission before a message, @msg, is enqueued on the message queue + * with permissions specified in @msq. + * + * Return: Returns 0 if permission is granted. + */ int security_msg_queue_msgsnd(struct kern_ipc_perm *msq, - struct msg_msg *msg, int msqflg) + struct msg_msg *msg, int msqflg) { return call_int_hook(msg_queue_msgsnd, 0, msq, msg, msqflg); } +/** + * security_msg_queue_msgrcv() - Check if receiving a sysv ipc msg is allowed + * @msq: sysv ipc permission structure + * @msg: message + * @target: target task + * @type: type of message requested + * @mode: operation flags + * + * Check permission before a message, @msg, is removed from the message queue. + * The @target task structure contains a pointer to the process that will be + * receiving the message (not equal to the current process when inline receives + * are being performed). + * + * Return: Returns 0 if permission is granted. + */ int security_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg, - struct task_struct *target, long type, int mode) + struct task_struct *target, long type, int mode) { return call_int_hook(msg_queue_msgrcv, 0, msq, msg, target, type, mode); } +/** + * security_shm_alloc() - Allocate a sysv shm LSM blob + * @shp: sysv ipc permission structure + * + * Allocate and attach a security structure to the @shp security field. The + * security field is initialized to NULL when the structure is first created. + * + * Return: Returns 0 if operation was successful and permission is granted. + */ int security_shm_alloc(struct kern_ipc_perm *shp) { int rc = lsm_ipc_alloc(shp); @@ -2075,6 +3600,12 @@ int security_shm_alloc(struct kern_ipc_perm *shp) return rc; } +/** + * security_shm_free() - Free a sysv shm LSM blob + * @shp: sysv ipc permission structure + * + * Deallocate the security structure @perm->security for the memory segment. + */ void security_shm_free(struct kern_ipc_perm *shp) { call_void_hook(shm_free_security, shp); @@ -2082,21 +3613,65 @@ void security_shm_free(struct kern_ipc_perm *shp) shp->security = NULL; } +/** + * security_shm_associate() - Check if a sysv shm operation is allowed + * @shp: sysv ipc permission structure + * @shmflg: operation flags + * + * Check permission when a shared memory region is requested through the shmget + * system call. This hook is only called when returning the shared memory + * region identifier for an existing region, not when a new shared memory + * region is created. + * + * Return: Returns 0 if permission is granted. + */ int security_shm_associate(struct kern_ipc_perm *shp, int shmflg) { return call_int_hook(shm_associate, 0, shp, shmflg); } +/** + * security_shm_shmctl() - Check if a sysv shm operation is allowed + * @shp: sysv ipc permission structure + * @cmd: operation + * + * Check permission when a shared memory control operation specified by @cmd is + * to be performed on the shared memory region with permissions in @shp. + * + * Return: Return 0 if permission is granted. + */ int security_shm_shmctl(struct kern_ipc_perm *shp, int cmd) { return call_int_hook(shm_shmctl, 0, shp, cmd); } -int security_shm_shmat(struct kern_ipc_perm *shp, char __user *shmaddr, int shmflg) +/** + * security_shm_shmat() - Check if a sysv shm attach operation is allowed + * @shp: sysv ipc permission structure + * @shmaddr: address of memory region to attach + * @shmflg: operation flags + * + * Check permissions prior to allowing the shmat system call to attach the + * shared memory segment with permissions @shp to the data segment of the + * calling process. The attaching address is specified by @shmaddr. + * + * Return: Returns 0 if permission is granted. + */ +int security_shm_shmat(struct kern_ipc_perm *shp, + char __user *shmaddr, int shmflg) { return call_int_hook(shm_shmat, 0, shp, shmaddr, shmflg); } +/** + * security_sem_alloc() - Allocate a sysv semaphore LSM blob + * @sma: sysv ipc permission structure + * + * Allocate and attach a security structure to the @sma security field. The + * security field is initialized to NULL when the structure is first created. + * + * Return: Returns 0 if operation was successful and permission is granted. + */ int security_sem_alloc(struct kern_ipc_perm *sma) { int rc = lsm_ipc_alloc(sma); @@ -2109,6 +3684,12 @@ int security_sem_alloc(struct kern_ipc_perm *sma) return rc; } +/** + * security_sem_free() - Free a sysv semaphore LSM blob + * @sma: sysv ipc permission structure + * + * Deallocate security structure @sma->security for the semaphore. + */ void security_sem_free(struct kern_ipc_perm *sma) { call_void_hook(sem_free_security, sma); @@ -2116,22 +3697,62 @@ void security_sem_free(struct kern_ipc_perm *sma) sma->security = NULL; } +/** + * security_sem_associate() - Check if a sysv semaphore operation is allowed + * @sma: sysv ipc permission structure + * @semflg: operation flags + * + * Check permission when a semaphore is requested through the semget system + * call. This hook is only called when returning the semaphore identifier for + * an existing semaphore, not when a new one must be created. + * + * Return: Returns 0 if permission is granted. + */ int security_sem_associate(struct kern_ipc_perm *sma, int semflg) { return call_int_hook(sem_associate, 0, sma, semflg); } +/** + * security_sem_semctl() - Check if a sysv semaphore operation is allowed + * @sma: sysv ipc permission structure + * @cmd: operation + * + * Check permission when a semaphore operation specified by @cmd is to be + * performed on the semaphore. + * + * Return: Returns 0 if permission is granted. + */ int security_sem_semctl(struct kern_ipc_perm *sma, int cmd) { return call_int_hook(sem_semctl, 0, sma, cmd); } +/** + * security_sem_semop() - Check if a sysv semaphore operation is allowed + * @sma: sysv ipc permission structure + * @sops: operations to perform + * @nsops: number of operations + * @alter: flag indicating changes will be made + * + * Check permissions before performing operations on members of the semaphore + * set. If the @alter flag is nonzero, the semaphore set may be modified. + * + * Return: Returns 0 if permission is granted. + */ int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops, - unsigned nsops, int alter) + unsigned nsops, int alter) { return call_int_hook(sem_semop, 0, sma, sops, nsops, alter); } +/** + * security_d_instantiate() - Populate an inode's LSM state based on a dentry + * @dentry: dentry + * @inode: inode + * + * Fill in @inode security information for a @dentry if allowed. + */ void security_d_instantiate(struct dentry *dentry, struct inode *inode) { if (unlikely(inode && IS_PRIVATE(inode))) @@ -2140,6 +3761,17 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode) } EXPORT_SYMBOL(security_d_instantiate); +/** + * security_getprocattr() - Read an attribute for a task + * @p: the task + * @lsm: LSM name + * @name: attribute name + * @value: attribute value + * + * Read attribute @name for task @p and store it into @value if allowed. + * + * Return: Returns the length of @value on success, a negative value otherwise. + */ int security_getprocattr(struct task_struct *p, const char *lsm, const char *name, char **value) { @@ -2153,6 +3785,18 @@ int security_getprocattr(struct task_struct *p, const char *lsm, return LSM_RET_DEFAULT(getprocattr); } +/** + * security_setprocattr() - Set an attribute for a task + * @lsm: LSM name + * @name: attribute name + * @value: attribute value + * @size: attribute value size + * + * Write (set) the current task's attribute @name to @value, size @size if + * allowed. + * + * Return: Returns bytes written on success, a negative value otherwise. + */ int security_setprocattr(const char *lsm, const char *name, void *value, size_t size) { @@ -2166,17 +3810,51 @@ int security_setprocattr(const char *lsm, const char *name, void *value, return LSM_RET_DEFAULT(setprocattr); } +/** + * security_netlink_send() - Save info and check if netlink sending is allowed + * @sk: sending socket + * @skb: netlink message + * + * Save security information for a netlink message so that permission checking + * can be performed when the message is processed. The security information + * can be saved using the eff_cap field of the netlink_skb_parms structure. + * Also may be used to provide fine grained control over message transmission. + * + * Return: Returns 0 if the information was successfully saved and message is + * allowed to be transmitted. + */ int security_netlink_send(struct sock *sk, struct sk_buff *skb) { return call_int_hook(netlink_send, 0, sk, skb); } +/** + * security_ismaclabel() - Check is the named attribute is a MAC label + * @name: full extended attribute name + * + * Check if the extended attribute specified by @name represents a MAC label. + * + * Return: Returns 1 if name is a MAC attribute otherwise returns 0. + */ int security_ismaclabel(const char *name) { return call_int_hook(ismaclabel, 0, name); } EXPORT_SYMBOL(security_ismaclabel); +/** + * security_secid_to_secctx() - Convert a secid to a secctx + * @secid: secid + * @secdata: secctx + * @seclen: secctx length + * + * Convert secid to security context. If @secdata is NULL the length of the + * result will be returned in @seclen, but no @secdata will be returned. This + * does mean that the length could change between calls to check the length and + * the next call which actually allocates and returns the @secdata. + * + * Return: Return 0 on success, error on failure. + */ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { struct security_hook_list *hp; @@ -2196,6 +3874,16 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) } EXPORT_SYMBOL(security_secid_to_secctx); +/** + * security_secctx_to_secid() - Convert a secctx to a secid + * @secdata: secctx + * @seclen: length of secctx + * @secid: secid + * + * Convert security context to secid. + * + * Return: Returns 0 on success, error on failure. + */ int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) { *secid = 0; @@ -2203,30 +3891,86 @@ int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) } EXPORT_SYMBOL(security_secctx_to_secid); +/** + * security_release_secctx() - Free a secctx buffer + * @secdata: secctx + * @seclen: length of secctx + * + * Release the security context. + */ void security_release_secctx(char *secdata, u32 seclen) { call_void_hook(release_secctx, secdata, seclen); } EXPORT_SYMBOL(security_release_secctx); +/** + * security_inode_invalidate_secctx() - Invalidate an inode's security label + * @inode: inode + * + * Notify the security module that it must revalidate the security context of + * an inode. + */ void security_inode_invalidate_secctx(struct inode *inode) { call_void_hook(inode_invalidate_secctx, inode); } EXPORT_SYMBOL(security_inode_invalidate_secctx); +/** + * security_inode_notifysecctx() - Nofify the LSM of an inode's security label + * @inode: inode + * @ctx: secctx + * @ctxlen: length of secctx + * + * 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. + * + * Return: Returns 0 on success, error on failure. + */ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) { return call_int_hook(inode_notifysecctx, 0, inode, ctx, ctxlen); } EXPORT_SYMBOL(security_inode_notifysecctx); +/** + * security_inode_setsecctx() - Change the security label of an inode + * @dentry: inode + * @ctx: secctx + * @ctxlen: length of secctx + * + * 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. + * + * Return: Returns 0 on success, error on failure. + */ int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) { return call_int_hook(inode_setsecctx, 0, dentry, ctx, ctxlen); } EXPORT_SYMBOL(security_inode_setsecctx); +/** + * security_inode_getsecctx() - Get the security label of an inode + * @inode: inode + * @ctx: secctx + * @ctxlen: length of secctx + * + * On success, returns 0 and fills out @ctx and @ctxlen with the security + * context for the given @inode. + * + * Return: Returns 0 on success, error on failure. + */ int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) { return call_int_hook(inode_getsecctx, -EOPNOTSUPP, inode, ctx, ctxlen); @@ -2234,6 +3978,16 @@ int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) EXPORT_SYMBOL(security_inode_getsecctx); #ifdef CONFIG_WATCH_QUEUE +/** + * security_post_notification() - Check if a watch notification can be posted + * @w_cred: credentials of the task that set the watch + * @cred: credentials of the task which triggered the watch + * @n: the notification + * + * Check to see if a watch notification can be posted to a particular queue. + * + * Return: Returns 0 if permission is granted. + */ int security_post_notification(const struct cred *w_cred, const struct cred *cred, struct watch_notification *n) @@ -2243,106 +3997,336 @@ int security_post_notification(const struct cred *w_cred, #endif /* CONFIG_WATCH_QUEUE */ #ifdef CONFIG_KEY_NOTIFICATIONS +/** + * security_watch_key() - Check if a task is allowed to watch for key events + * @key: the key to watch + * + * Check to see if a process is allowed to watch for event notifications from + * a key or keyring. + * + * Return: Returns 0 if permission is granted. + */ int security_watch_key(struct key *key) { return call_int_hook(watch_key, 0, key); } -#endif +#endif /* CONFIG_KEY_NOTIFICATIONS */ #ifdef CONFIG_SECURITY_NETWORK - -int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk) +/** + * security_unix_stream_connect() - Check if a AF_UNIX stream is allowed + * @sock: originating sock + * @other: peer sock + * @newsk: new sock + * + * Check permissions before establishing a Unix domain stream connection + * between @sock and @other. + * + * The @unix_stream_connect and @unix_may_send hooks were necessary because + * Linux provides an alternative to the conventional file name space for Unix + * domain sockets. Whereas binding and connecting to sockets in the file name + * space is mediated by the typical file permissions (and caught by the mknod + * and permission hooks in inode_security_ops), binding and connecting to + * sockets in the abstract name space is completely unmediated. Sufficient + * control of Unix domain sockets in the abstract name space isn't possible + * using only the socket layer hooks, since we need to know the actual target + * socket, which is not looked up until we are inside the af_unix code. + * + * Return: Returns 0 if permission is granted. + */ +int security_unix_stream_connect(struct sock *sock, struct sock *other, + struct sock *newsk) { return call_int_hook(unix_stream_connect, 0, sock, other, newsk); } EXPORT_SYMBOL(security_unix_stream_connect); +/** + * security_unix_may_send() - Check if AF_UNIX socket can send datagrams + * @sock: originating sock + * @other: peer sock + * + * Check permissions before connecting or sending datagrams from @sock to + * @other. + * + * The @unix_stream_connect and @unix_may_send hooks were necessary because + * Linux provides an alternative to the conventional file name space for Unix + * domain sockets. Whereas binding and connecting to sockets in the file name + * space is mediated by the typical file permissions (and caught by the mknod + * and permission hooks in inode_security_ops), binding and connecting to + * sockets in the abstract name space is completely unmediated. Sufficient + * control of Unix domain sockets in the abstract name space isn't possible + * using only the socket layer hooks, since we need to know the actual target + * socket, which is not looked up until we are inside the af_unix code. + * + * Return: Returns 0 if permission is granted. + */ int security_unix_may_send(struct socket *sock, struct socket *other) { return call_int_hook(unix_may_send, 0, sock, other); } EXPORT_SYMBOL(security_unix_may_send); +/** + * security_socket_create() - Check if creating a new socket is allowed + * @family: protocol family + * @type: communications type + * @protocol: requested protocol + * @kern: set to 1 if a kernel socket is requested + * + * Check permissions prior to creating a new socket. + * + * Return: Returns 0 if permission is granted. + */ int security_socket_create(int family, int type, int protocol, int kern) { return call_int_hook(socket_create, 0, family, type, protocol, kern); } +/** + * security_socket_post_create() - Initialize a newly created socket + * @sock: socket + * @family: protocol family + * @type: communications type + * @protocol: requested protocol + * @kern: set to 1 if a kernel socket is requested + * + * This hook allows a module to update or allocate a per-socket security + * structure. Note that the security field was not added directly to the socket + * structure, but rather, the socket security information is stored in the + * associated inode. Typically, the inode alloc_security hook will allocate + * and attach security information to SOCK_INODE(sock)->i_security. This hook + * may be used to update the SOCK_INODE(sock)->i_security field with additional + * information that wasn't available when the inode was allocated. + * + * Return: Returns 0 if permission is granted. + */ int security_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern) { return call_int_hook(socket_post_create, 0, sock, family, type, - protocol, kern); + protocol, kern); } +/** + * security_socket_socketpair() - Check if creating a socketpair is allowed + * @socka: first socket + * @sockb: second socket + * + * Check permissions before creating a fresh pair of sockets. + * + * Return: Returns 0 if permission is granted and the connection was + * established. + */ int security_socket_socketpair(struct socket *socka, struct socket *sockb) { return call_int_hook(socket_socketpair, 0, socka, sockb); } EXPORT_SYMBOL(security_socket_socketpair); -int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) +/** + * security_socket_bind() - Check if a socket bind operation is allowed + * @sock: socket + * @address: requested bind address + * @addrlen: length of address + * + * Check permission before socket protocol layer bind operation is performed + * and the socket @sock is bound to the address specified in the @address + * parameter. + * + * Return: Returns 0 if permission is granted. + */ +int security_socket_bind(struct socket *sock, + struct sockaddr *address, int addrlen) { return call_int_hook(socket_bind, 0, sock, address, addrlen); } -int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) +/** + * security_socket_connect() - Check if a socket connect operation is allowed + * @sock: socket + * @address: address of remote connection point + * @addrlen: length of address + * + * Check permission before socket protocol layer connect operation attempts to + * connect socket @sock to a remote address, @address. + * + * Return: Returns 0 if permission is granted. + */ +int security_socket_connect(struct socket *sock, + struct sockaddr *address, int addrlen) { return call_int_hook(socket_connect, 0, sock, address, addrlen); } +/** + * security_socket_listen() - Check if a socket is allowed to listen + * @sock: socket + * @backlog: connection queue size + * + * Check permission before socket protocol layer listen operation. + * + * Return: Returns 0 if permission is granted. + */ int security_socket_listen(struct socket *sock, int backlog) { return call_int_hook(socket_listen, 0, sock, backlog); } +/** + * security_socket_accept() - Check if a socket is allowed to accept connections + * @sock: listening socket + * @newsock: newly creation connection socket + * + * Check permission before accepting a new connection. Note that the new + * socket, @newsock, has been created and some information copied to it, but + * the accept operation has not actually been performed. + * + * Return: Returns 0 if permission is granted. + */ int security_socket_accept(struct socket *sock, struct socket *newsock) { return call_int_hook(socket_accept, 0, sock, newsock); } +/** + * security_socket_sendmsg() - Check is sending a message is allowed + * @sock: sending socket + * @msg: message to send + * @size: size of message + * + * Check permission before transmitting a message to another socket. + * + * Return: Returns 0 if permission is granted. + */ int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) { return call_int_hook(socket_sendmsg, 0, sock, msg, size); } +/** + * security_socket_recvmsg() - Check if receiving a message is allowed + * @sock: receiving socket + * @msg: message to receive + * @size: size of message + * @flags: operational flags + * + * Check permission before receiving a message from a socket. + * + * Return: Returns 0 if permission is granted. + */ int security_socket_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags) { return call_int_hook(socket_recvmsg, 0, sock, msg, size, flags); } +/** + * security_socket_getsockname() - Check if reading the socket addr is allowed + * @sock: socket + * + * Check permission before reading the local address (name) of the socket + * object. + * + * Return: Returns 0 if permission is granted. + */ int security_socket_getsockname(struct socket *sock) { return call_int_hook(socket_getsockname, 0, sock); } +/** + * security_socket_getpeername() - Check if reading the peer's addr is allowed + * @sock: socket + * + * Check permission before the remote address (name) of a socket object. + * + * Return: Returns 0 if permission is granted. + */ int security_socket_getpeername(struct socket *sock) { return call_int_hook(socket_getpeername, 0, sock); } +/** + * security_socket_getsockopt() - Check if reading a socket option is allowed + * @sock: socket + * @level: option's protocol level + * @optname: option name + * + * Check permissions before retrieving the options associated with socket + * @sock. + * + * Return: Returns 0 if permission is granted. + */ int security_socket_getsockopt(struct socket *sock, int level, int optname) { return call_int_hook(socket_getsockopt, 0, sock, level, optname); } +/** + * security_socket_setsockopt() - Check if setting a socket option is allowed + * @sock: socket + * @level: option's protocol level + * @optname: option name + * + * Check permissions before setting the options associated with socket @sock. + * + * Return: Returns 0 if permission is granted. + */ int security_socket_setsockopt(struct socket *sock, int level, int optname) { return call_int_hook(socket_setsockopt, 0, sock, level, optname); } +/** + * security_socket_shutdown() - Checks if shutting down the socket is allowed + * @sock: socket + * @how: flag indicating how sends and receives are handled + * + * Checks permission before all or part of a connection on the socket @sock is + * shut down. + * + * Return: Returns 0 if permission is granted. + */ int security_socket_shutdown(struct socket *sock, int how) { return call_int_hook(socket_shutdown, 0, sock, how); } +/** + * security_sock_rcv_skb() - Check if an incoming network packet is allowed + * @sk: destination sock + * @skb: incoming packet + * + * Check permissions on incoming network packets. This hook is distinct from + * Netfilter's IP input hooks since it is the first time that the incoming + * sk_buff @skb has been associated with a particular socket, @sk. Must not + * sleep inside this hook because some callers hold spinlocks. + * + * Return: Returns 0 if permission is granted. + */ int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) { return call_int_hook(socket_sock_rcv_skb, 0, sk, skb); } EXPORT_SYMBOL(security_sock_rcv_skb); +/** + * security_socket_getpeersec_stream() - Get the remote peer label + * @sock: socket + * @optval: destination buffer + * @optlen: size of peer label copied into the buffer + * @len: maximum size of the destination buffer + * + * This hook allows the security module to provide peer socket security state + * for unix or connected tcp sockets to userspace via getsockopt SO_GETPEERSEC. + * For tcp sockets this can be meaningful if the socket is associated with an + * ipsec SA. + * + * Return: Returns 0 if all is well, otherwise, typical getsockopt return + * values. + */ int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval, sockptr_t optlen, unsigned int len) { @@ -2350,23 +4334,62 @@ int security_socket_getpeersec_stream(struct socket *sock, sockptr_t optval, optval, optlen, len); } -int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) +/** + * security_socket_getpeersec_dgram() - Get the remote peer label + * @sock: socket + * @skb: datagram packet + * @secid: remote peer label secid + * + * This hook allows the security module to provide peer socket security state + * for udp sockets on a per-packet basis to userspace via getsockopt + * SO_GETPEERSEC. The application must first have indicated the IP_PASSSEC + * option via getsockopt. It can then retrieve the security state returned by + * this hook for a packet via the SCM_SECURITY ancillary message type. + * + * Return: Returns 0 on success, error on failure. + */ +int security_socket_getpeersec_dgram(struct socket *sock, + struct sk_buff *skb, u32 *secid) { return call_int_hook(socket_getpeersec_dgram, -ENOPROTOOPT, sock, skb, secid); } EXPORT_SYMBOL(security_socket_getpeersec_dgram); +/** + * security_sk_alloc() - Allocate and initialize a sock's LSM blob + * @sk: sock + * @family: protocol family + * @priority: gfp flags + * + * Allocate and attach a security structure to the sk->sk_security field, which + * is used to copy security attributes between local stream sockets. + * + * Return: Returns 0 on success, error on failure. + */ int security_sk_alloc(struct sock *sk, int family, gfp_t priority) { return call_int_hook(sk_alloc_security, 0, sk, family, priority); } +/** + * security_sk_free() - Free the sock's LSM blob + * @sk: sock + * + * Deallocate security structure. + */ void security_sk_free(struct sock *sk) { call_void_hook(sk_free_security, sk); } +/** + * security_sk_clone() - Clone a sock's LSM state + * @sk: original sock + * @newsk: target sock + * + * Clone/copy security structure. + */ void security_sk_clone(const struct sock *sk, struct sock *newsk) { call_void_hook(sk_clone_security, sk, newsk); @@ -2379,6 +4402,13 @@ void security_sk_classify_flow(struct sock *sk, struct flowi_common *flic) } EXPORT_SYMBOL(security_sk_classify_flow); +/** + * security_req_classify_flow() - Set a flow's secid based on request_sock + * @req: request_sock + * @flic: target flow + * + * Sets @flic's secid to @req's secid. + */ void security_req_classify_flow(const struct request_sock *req, struct flowi_common *flic) { @@ -2386,92 +4416,215 @@ void security_req_classify_flow(const struct request_sock *req, } EXPORT_SYMBOL(security_req_classify_flow); +/** + * security_sock_graft() - Reconcile LSM state when grafting a sock on a socket + * @sk: sock being grafted + * @parent: target parent socket + * + * Sets @parent's inode secid to @sk's secid and update @sk with any necessary + * LSM state from @parent. + */ void security_sock_graft(struct sock *sk, struct socket *parent) { call_void_hook(sock_graft, sk, parent); } EXPORT_SYMBOL(security_sock_graft); +/** + * security_inet_conn_request() - Set request_sock state using incoming connect + * @sk: parent listening sock + * @skb: incoming connection + * @req: new request_sock + * + * Initialize the @req LSM state based on @sk and the incoming connect in @skb. + * + * Return: Returns 0 if permission is granted. + */ int security_inet_conn_request(const struct sock *sk, - struct sk_buff *skb, struct request_sock *req) + struct sk_buff *skb, struct request_sock *req) { return call_int_hook(inet_conn_request, 0, sk, skb, req); } EXPORT_SYMBOL(security_inet_conn_request); +/** + * security_inet_csk_clone() - Set new sock LSM state based on request_sock + * @newsk: new sock + * @req: connection request_sock + * + * Set that LSM state of @sock using the LSM state from @req. + */ void security_inet_csk_clone(struct sock *newsk, - const struct request_sock *req) + const struct request_sock *req) { call_void_hook(inet_csk_clone, newsk, req); } +/** + * security_inet_conn_established() - Update sock's LSM state with connection + * @sk: sock + * @skb: connection packet + * + * Update @sock's LSM state to represent a new connection from @skb. + */ void security_inet_conn_established(struct sock *sk, - struct sk_buff *skb) + struct sk_buff *skb) { call_void_hook(inet_conn_established, sk, skb); } EXPORT_SYMBOL(security_inet_conn_established); +/** + * security_secmark_relabel_packet() - Check if setting a secmark is allowed + * @secid: new secmark value + * + * Check if the process should be allowed to relabel packets to @secid. + * + * Return: Returns 0 if permission is granted. + */ int security_secmark_relabel_packet(u32 secid) { return call_int_hook(secmark_relabel_packet, 0, secid); } EXPORT_SYMBOL(security_secmark_relabel_packet); +/** + * security_secmark_refcount_inc() - Increment the secmark labeling rule count + * + * Tells the LSM to increment the number of secmark labeling rules loaded. + */ void security_secmark_refcount_inc(void) { call_void_hook(secmark_refcount_inc); } EXPORT_SYMBOL(security_secmark_refcount_inc); +/** + * security_secmark_refcount_dec() - Decrement the secmark labeling rule count + * + * Tells the LSM to decrement the number of secmark labeling rules loaded. + */ void security_secmark_refcount_dec(void) { call_void_hook(secmark_refcount_dec); } EXPORT_SYMBOL(security_secmark_refcount_dec); +/** + * security_tun_dev_alloc_security() - Allocate a LSM blob for a TUN device + * @security: pointer to the LSM blob + * + * This hook allows a module to allocate a security structure for a TUN device, + * returning the pointer in @security. + * + * Return: Returns a zero on success, negative values on failure. + */ int security_tun_dev_alloc_security(void **security) { return call_int_hook(tun_dev_alloc_security, 0, security); } EXPORT_SYMBOL(security_tun_dev_alloc_security); +/** + * security_tun_dev_free_security() - Free a TUN device LSM blob + * @security: LSM blob + * + * This hook allows a module to free the security structure for a TUN device. + */ void security_tun_dev_free_security(void *security) { call_void_hook(tun_dev_free_security, security); } EXPORT_SYMBOL(security_tun_dev_free_security); +/** + * security_tun_dev_create() - Check if creating a TUN device is allowed + * + * Check permissions prior to creating a new TUN device. + * + * Return: Returns 0 if permission is granted. + */ int security_tun_dev_create(void) { return call_int_hook(tun_dev_create, 0); } EXPORT_SYMBOL(security_tun_dev_create); +/** + * security_tun_dev_attach_queue() - Check if attaching a TUN queue is allowed + * @security: TUN device LSM blob + * + * Check permissions prior to attaching to a TUN device queue. + * + * Return: Returns 0 if permission is granted. + */ int security_tun_dev_attach_queue(void *security) { return call_int_hook(tun_dev_attach_queue, 0, security); } EXPORT_SYMBOL(security_tun_dev_attach_queue); +/** + * security_tun_dev_attach() - Update TUN device LSM state on attach + * @sk: associated sock + * @security: TUN device LSM blob + * + * This hook can be used by the module to update any security state associated + * with the TUN device's sock structure. + * + * Return: Returns 0 if permission is granted. + */ int security_tun_dev_attach(struct sock *sk, void *security) { return call_int_hook(tun_dev_attach, 0, sk, security); } EXPORT_SYMBOL(security_tun_dev_attach); +/** + * security_tun_dev_open() - Update TUN device LSM state on open + * @security: TUN device LSM blob + * + * This hook can be used by the module to update any security state associated + * with the TUN device's security structure. + * + * Return: Returns 0 if permission is granted. + */ int security_tun_dev_open(void *security) { return call_int_hook(tun_dev_open, 0, security); } EXPORT_SYMBOL(security_tun_dev_open); -int security_sctp_assoc_request(struct sctp_association *asoc, struct sk_buff *skb) +/** + * security_sctp_assoc_request() - Update the LSM on a SCTP association req + * @asoc: SCTP association + * @skb: packet requesting the association + * + * Passes the @asoc and @chunk->skb of the association INIT packet to the LSM. + * + * Return: Returns 0 on success, error on failure. + */ +int security_sctp_assoc_request(struct sctp_association *asoc, + struct sk_buff *skb) { return call_int_hook(sctp_assoc_request, 0, asoc, skb); } EXPORT_SYMBOL(security_sctp_assoc_request); +/** + * security_sctp_bind_connect() - Validate a list of addrs for a SCTP option + * @sk: socket + * @optname: SCTP option to validate + * @address: list of IP addresses to validate + * @addrlen: length of the address list + * + * Validiate permissions required for each address associated with sock @sk. + * Depending on @optname, the addresses will be treated as either a connect or + * bind service. The @addrlen is calculated on each IPv4 and IPv6 address using + * sizeof(struct sockaddr_in) or sizeof(struct sockaddr_in6). + * + * Return: Returns 0 on success, error on failure. + */ int security_sctp_bind_connect(struct sock *sk, int optname, struct sockaddr *address, int addrlen) { @@ -2480,6 +4633,16 @@ int security_sctp_bind_connect(struct sock *sk, int optname, } EXPORT_SYMBOL(security_sctp_bind_connect); +/** + * security_sctp_sk_clone() - Clone a SCTP sock's LSM state + * @asoc: SCTP association + * @sk: original sock + * @newsk: target sock + * + * Called whenever a new socket is created by accept(2) (i.e. a TCP style + * socket) or when a socket is 'peeled off' e.g userspace calls + * sctp_peeloff(3). + */ void security_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk, struct sock *newsk) { @@ -2487,6 +4650,16 @@ void security_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk, } EXPORT_SYMBOL(security_sctp_sk_clone); +/** + * security_sctp_assoc_established() - Update LSM state when assoc established + * @asoc: SCTP association + * @skb: packet establishing the association + * + * Passes the @asoc and @chunk->skb of the association COOKIE_ACK packet to the + * security module. + * + * Return: Returns 0 if permission is granted. + */ int security_sctp_assoc_established(struct sctp_association *asoc, struct sk_buff *skb) { @@ -2497,25 +4670,60 @@ EXPORT_SYMBOL(security_sctp_assoc_established); #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_INFINIBAND - +/** + * security_ib_pkey_access() - Check if access to an IB pkey is allowed + * @sec: LSM blob + * @subnet_prefix: subnet prefix of the port + * @pkey: IB pkey + * + * Check permission to access a pkey when modifing a QP. + * + * Return: Returns 0 if permission is granted. + */ int security_ib_pkey_access(void *sec, u64 subnet_prefix, u16 pkey) { return call_int_hook(ib_pkey_access, 0, sec, subnet_prefix, pkey); } EXPORT_SYMBOL(security_ib_pkey_access); -int security_ib_endport_manage_subnet(void *sec, const char *dev_name, u8 port_num) +/** + * security_ib_endport_manage_subnet() - Check if SMPs traffic is allowed + * @sec: LSM blob + * @dev_name: IB device name + * @port_num: port number + * + * Check permissions to send and receive SMPs on a end port. + * + * Return: Returns 0 if permission is granted. + */ +int security_ib_endport_manage_subnet(void *sec, + const char *dev_name, u8 port_num) { - return call_int_hook(ib_endport_manage_subnet, 0, sec, dev_name, port_num); + return call_int_hook(ib_endport_manage_subnet, 0, sec, + dev_name, port_num); } EXPORT_SYMBOL(security_ib_endport_manage_subnet); +/** + * security_ib_alloc_security() - Allocate an Infiniband LSM blob + * @sec: LSM blob + * + * Allocate a security structure for Infiniband objects. + * + * Return: Returns 0 on success, non-zero on failure. + */ int security_ib_alloc_security(void **sec) { return call_int_hook(ib_alloc_security, 0, sec); } EXPORT_SYMBOL(security_ib_alloc_security); +/** + * security_ib_free_security() - Free an Infiniband LSM blob + * @sec: LSM blob + * + * Deallocate an Infiniband security structure. + */ void security_ib_free_security(void *sec) { call_void_hook(ib_free_security, sec); @@ -2524,7 +4732,17 @@ EXPORT_SYMBOL(security_ib_free_security); #endif /* CONFIG_SECURITY_INFINIBAND */ #ifdef CONFIG_SECURITY_NETWORK_XFRM - +/** + * security_xfrm_policy_alloc() - Allocate a xfrm policy LSM blob + * @ctxp: xfrm security context being added to the SPD + * @sec_ctx: security label provided by userspace + * @gfp: gfp flags + * + * Allocate a security structure to the xp->security field; the security field + * is initialized to NULL when the xfrm_policy is allocated. + * + * Return: Return 0 if operation was successful. + */ int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp) @@ -2533,23 +4751,58 @@ int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, } EXPORT_SYMBOL(security_xfrm_policy_alloc); +/** + * security_xfrm_policy_clone() - Clone xfrm policy LSM state + * @old_ctx: xfrm security context + * @new_ctxp: target xfrm security context + * + * Allocate a security structure in new_ctxp that contains the information from + * the old_ctx structure. + * + * Return: Return 0 if operation was successful. + */ int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, - struct xfrm_sec_ctx **new_ctxp) + struct xfrm_sec_ctx **new_ctxp) { return call_int_hook(xfrm_policy_clone_security, 0, old_ctx, new_ctxp); } +/** + * security_xfrm_policy_free() - Free a xfrm security context + * @ctx: xfrm security context + * + * Free LSM resources associated with @ctx. + */ void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx) { call_void_hook(xfrm_policy_free_security, ctx); } EXPORT_SYMBOL(security_xfrm_policy_free); +/** + * security_xfrm_policy_delete() - Check if deleting a xfrm policy is allowed + * @ctx: xfrm security context + * + * Authorize deletion of a SPD entry. + * + * Return: Returns 0 if permission is granted. + */ int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) { return call_int_hook(xfrm_policy_delete_security, 0, ctx); } +/** + * security_xfrm_state_alloc() - Allocate a xfrm state LSM blob + * @x: xfrm state being added to the SAD + * @sec_ctx: security label provided by userspace + * + * Allocate a security structure to the @x->security field; the security field + * is initialized to NULL when the xfrm_state is allocated. Set the context to + * correspond to @sec_ctx. + * + * Return: Return 0 if operation was successful. + */ int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) { @@ -2557,28 +4810,76 @@ int security_xfrm_state_alloc(struct xfrm_state *x, } EXPORT_SYMBOL(security_xfrm_state_alloc); +/** + * security_xfrm_state_alloc_acquire() - Allocate a xfrm state LSM blob + * @x: xfrm state being added to the SAD + * @polsec: associated policy's security context + * @secid: secid from the flow + * + * Allocate a security structure to the x->security field; the security field + * is initialized to NULL when the xfrm_state is allocated. Set the context to + * correspond to secid. + * + * Return: Returns 0 if operation was successful. + */ int security_xfrm_state_alloc_acquire(struct xfrm_state *x, struct xfrm_sec_ctx *polsec, u32 secid) { return call_int_hook(xfrm_state_alloc_acquire, 0, x, polsec, secid); } +/** + * security_xfrm_state_delete() - Check if deleting a xfrm state is allowed + * @x: xfrm state + * + * Authorize deletion of x->security. + * + * Return: Returns 0 if permission is granted. + */ int security_xfrm_state_delete(struct xfrm_state *x) { return call_int_hook(xfrm_state_delete_security, 0, x); } EXPORT_SYMBOL(security_xfrm_state_delete); +/** + * security_xfrm_state_free() - Free a xfrm state + * @x: xfrm state + * + * Deallocate x->security. + */ void security_xfrm_state_free(struct xfrm_state *x) { call_void_hook(xfrm_state_free_security, x); } +/** + * security_xfrm_policy_lookup() - Check if using a xfrm policy is allowed + * @ctx: target xfrm security context + * @fl_secid: flow secid used to authorize access + * + * Check permission when a flow selects a xfrm_policy for processing XFRMs on a + * packet. The hook is called when selecting either a per-socket policy or a + * generic xfrm policy. + * + * Return: Return 0 if permission is granted, -ESRCH otherwise, or -errno on + * other errors. + */ int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid) { return call_int_hook(xfrm_policy_lookup, 0, ctx, fl_secid); } +/** + * security_xfrm_state_pol_flow_match() - Check for a xfrm match + * @x: xfrm state to match + * @xp: xfrm policy to check for a match + * @flic: flow to check for a match. + * + * Check @xp and @flic for a match with @x. + * + * Return: Returns 1 if there is a match. + */ int security_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, const struct flowi_common *flic) @@ -2596,13 +4897,22 @@ int security_xfrm_state_pol_flow_match(struct xfrm_state *x, * using the macro */ hlist_for_each_entry(hp, &security_hook_heads.xfrm_state_pol_flow_match, - list) { + list) { rc = hp->hook.xfrm_state_pol_flow_match(x, xp, flic); break; } return rc; } +/** + * security_xfrm_decode_session() - Determine the xfrm secid for a packet + * @skb: xfrm packet + * @secid: secid + * + * Decode the packet in @skb and return the security label in @secid. + * + * Return: Return 0 if all xfrms used have the same secid. + */ int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) { return call_int_hook(xfrm_decode_session, 0, skb, secid, 1); @@ -2611,58 +4921,135 @@ int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) void security_skb_classify_flow(struct sk_buff *skb, struct flowi_common *flic) { int rc = call_int_hook(xfrm_decode_session, 0, skb, &flic->flowic_secid, - 0); + 0); BUG_ON(rc); } EXPORT_SYMBOL(security_skb_classify_flow); - #endif /* CONFIG_SECURITY_NETWORK_XFRM */ #ifdef CONFIG_KEYS - +/** + * security_key_alloc() - Allocate and initialize a kernel key LSM blob + * @key: key + * @cred: credentials + * @flags: allocation flags + * + * Permit allocation of a key and assign security data. Note that key does not + * have a serial number assigned at this point. + * + * Return: Return 0 if permission is granted, -ve error otherwise. + */ int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags) { return call_int_hook(key_alloc, 0, key, cred, flags); } +/** + * security_key_free() - Free a kernel key LSM blob + * @key: key + * + * Notification of destruction; free security data. + */ void security_key_free(struct key *key) { call_void_hook(key_free, key); } +/** + * security_key_permission() - Check if a kernel key operation is allowed + * @key_ref: key reference + * @cred: credentials of actor requesting access + * @need_perm: requested permissions + * + * See whether a specific operational right is granted to a process on a key. + * + * Return: Return 0 if permission is granted, -ve error otherwise. + */ int security_key_permission(key_ref_t key_ref, const struct cred *cred, enum key_need_perm need_perm) { return call_int_hook(key_permission, 0, key_ref, cred, need_perm); } -int security_key_getsecurity(struct key *key, char **_buffer) +/** + * security_key_getsecurity() - Get the key's security label + * @key: key + * @buffer: security label buffer + * + * Get a textual representation of the security context attached to a key for + * the purposes of honouring KEYCTL_GETSECURITY. This function allocates the + * storage for the NUL-terminated string and the caller should free it. + * + * Return: Returns the length of @buffer (including terminating NUL) or -ve if + * an error occurs. May also return 0 (and a NULL buffer pointer) if + * there is no security label assigned to the key. + */ +int security_key_getsecurity(struct key *key, char **buffer) { - *_buffer = NULL; - return call_int_hook(key_getsecurity, 0, key, _buffer); + *buffer = NULL; + return call_int_hook(key_getsecurity, 0, key, buffer); } - #endif /* CONFIG_KEYS */ #ifdef CONFIG_AUDIT - +/** + * security_audit_rule_init() - Allocate and init an LSM audit rule struct + * @field: audit action + * @op: rule operator + * @rulestr: rule context + * @lsmrule: receive buffer for audit rule struct + * + * Allocate and initialize an LSM audit rule structure. + * + * Return: Return 0 if @lsmrule has been successfully set, -EINVAL in case of + * an invalid rule. + */ int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule) { return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule); } +/** + * security_audit_rule_known() - Check if an audit rule contains LSM fields + * @krule: audit rule + * + * Specifies whether given @krule contains any fields related to the current + * LSM. + * + * Return: Returns 1 in case of relation found, 0 otherwise. + */ int security_audit_rule_known(struct audit_krule *krule) { return call_int_hook(audit_rule_known, 0, krule); } +/** + * security_audit_rule_free() - Free an LSM audit rule struct + * @lsmrule: audit rule struct + * + * Deallocate the LSM audit rule structure previously allocated by + * audit_rule_init(). + */ void security_audit_rule_free(void *lsmrule) { call_void_hook(audit_rule_free, lsmrule); } +/** + * security_audit_rule_match() - Check if a label matches an audit rule + * @secid: security label + * @field: LSM audit field + * @op: matching operator + * @lsmrule: audit rule + * + * Determine if given @secid matches a rule previously approved by + * security_audit_rule_known(). + * + * Return: Returns 1 if secid matches the rule, 0 if it does not, -ERRNO on + * failure. + */ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule) { return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule); @@ -2670,36 +5057,110 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule) #endif /* CONFIG_AUDIT */ #ifdef CONFIG_BPF_SYSCALL +/** + * security_bpf() - Check if the bpf syscall operation is allowed + * @cmd: command + * @attr: bpf attribute + * @size: size + * + * Do a initial check for all bpf syscalls after the attribute is copied into + * the kernel. The actual security module can implement their own rules to + * check the specific cmd they need. + * + * Return: Returns 0 if permission is granted. + */ int security_bpf(int cmd, union bpf_attr *attr, unsigned int size) { return call_int_hook(bpf, 0, cmd, attr, size); } + +/** + * security_bpf_map() - Check if access to a bpf map is allowed + * @map: bpf map + * @fmode: mode + * + * Do a check when the kernel generates and returns a file descriptor for eBPF + * maps. + * + * Return: Returns 0 if permission is granted. + */ int security_bpf_map(struct bpf_map *map, fmode_t fmode) { return call_int_hook(bpf_map, 0, map, fmode); } + +/** + * security_bpf_prog() - Check if access to a bpf program is allowed + * @prog: bpf program + * + * Do a check when the kernel generates and returns a file descriptor for eBPF + * programs. + * + * Return: Returns 0 if permission is granted. + */ int security_bpf_prog(struct bpf_prog *prog) { return call_int_hook(bpf_prog, 0, prog); } + +/** + * security_bpf_map_alloc() - Allocate a bpf map LSM blob + * @map: bpf map + * + * Initialize the security field inside bpf map. + * + * Return: Returns 0 on success, error on failure. + */ int security_bpf_map_alloc(struct bpf_map *map) { return call_int_hook(bpf_map_alloc_security, 0, map); } + +/** + * security_bpf_prog_alloc() - Allocate a bpf program LSM blob + * @aux: bpf program aux info struct + * + * Initialize the security field inside bpf program. + * + * Return: Returns 0 on success, error on failure. + */ int security_bpf_prog_alloc(struct bpf_prog_aux *aux) { return call_int_hook(bpf_prog_alloc_security, 0, aux); } + +/** + * security_bpf_map_free() - Free a bpf map's LSM blob + * @map: bpf map + * + * Clean up the security information stored inside bpf map. + */ void security_bpf_map_free(struct bpf_map *map) { call_void_hook(bpf_map_free_security, map); } + +/** + * security_bpf_prog_free() - Free a bpf program's LSM blob + * @aux: bpf program aux info struct + * + * Clean up the security information stored inside bpf prog. + */ void security_bpf_prog_free(struct bpf_prog_aux *aux) { call_void_hook(bpf_prog_free_security, aux); } #endif /* CONFIG_BPF_SYSCALL */ +/** + * security_locked_down() - Check if a kernel feature is allowed + * @what: requested kernel feature + * + * Determine whether a kernel feature that potentially enables arbitrary code + * execution in kernel space should be permitted. + * + * Return: Returns 0 if permission is granted. + */ int security_locked_down(enum lockdown_reason what) { return call_int_hook(locked_down, 0, what); @@ -2707,26 +5168,65 @@ int security_locked_down(enum lockdown_reason what) EXPORT_SYMBOL(security_locked_down); #ifdef CONFIG_PERF_EVENTS +/** + * security_perf_event_open() - Check if a perf event open is allowed + * @attr: perf event attribute + * @type: type of event + * + * Check whether the @type of perf_event_open syscall is allowed. + * + * Return: Returns 0 if permission is granted. + */ int security_perf_event_open(struct perf_event_attr *attr, int type) { return call_int_hook(perf_event_open, 0, attr, type); } +/** + * security_perf_event_alloc() - Allocate a perf event LSM blob + * @event: perf event + * + * Allocate and save perf_event security info. + * + * Return: Returns 0 on success, error on failure. + */ int security_perf_event_alloc(struct perf_event *event) { return call_int_hook(perf_event_alloc, 0, event); } +/** + * security_perf_event_free() - Free a perf event LSM blob + * @event: perf event + * + * Release (free) perf_event security info. + */ void security_perf_event_free(struct perf_event *event) { call_void_hook(perf_event_free, event); } +/** + * security_perf_event_read() - Check if reading a perf event label is allowed + * @event: perf event + * + * Read perf_event security info if allowed. + * + * Return: Returns 0 if permission is granted. + */ int security_perf_event_read(struct perf_event *event) { return call_int_hook(perf_event_read, 0, event); } +/** + * security_perf_event_write() - Check if writing a perf event label is allowed + * @event: perf event + * + * Write perf_event security info if allowed. + * + * Return: Returns 0 if permission is granted. + */ int security_perf_event_write(struct perf_event *event) { return call_int_hook(perf_event_write, 0, event); @@ -2734,15 +5234,41 @@ int security_perf_event_write(struct perf_event *event) #endif /* CONFIG_PERF_EVENTS */ #ifdef CONFIG_IO_URING +/** + * security_uring_override_creds() - Check if overriding creds is allowed + * @new: new credentials + * + * Check if the current task, executing an io_uring operation, is allowed to + * override it's credentials with @new. + * + * Return: Returns 0 if permission is granted. + */ int security_uring_override_creds(const struct cred *new) { return call_int_hook(uring_override_creds, 0, new); } +/** + * security_uring_sqpoll() - Check if IORING_SETUP_SQPOLL is allowed + * + * Check whether the current task is allowed to spawn a io_uring polling thread + * (IORING_SETUP_SQPOLL). + * + * Return: Returns 0 if permission is granted. + */ int security_uring_sqpoll(void) { return call_int_hook(uring_sqpoll, 0); } + +/** + * security_uring_cmd() - Check if a io_uring passthrough command is allowed + * @ioucmd: command + * + * Check whether the file_operations uring_cmd is allowed to run. + * + * Return: Returns 0 if permission is granted. + */ int security_uring_cmd(struct io_uring_cmd *ioucmd) { return call_int_hook(uring_cmd, 0, ioucmd); diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 9e921fc72538..95a186ec0fcb 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -23,30 +23,6 @@ config SECURITY_SELINUX_BOOTPARAM If you are unsure how to answer this question, answer N. -config SECURITY_SELINUX_DISABLE - bool "NSA SELinux runtime disable" - depends on SECURITY_SELINUX - select SECURITY_WRITABLE_HOOKS - default n - help - This option enables writing to a selinuxfs node 'disable', which - allows SELinux to be disabled at runtime prior to the policy load. - SELinux will then remain disabled until the next boot. - This option is similar to the selinux=0 boot parameter, but is to - support runtime disabling of SELinux, e.g. from /sbin/init, for - portability across platforms where boot parameters are difficult - to employ. - - NOTE: selecting this option will disable the '__ro_after_init' - kernel hardening feature for security hooks. Please consider - using the selinux=0 boot parameter instead of enabling this - option. - - WARNING: this option is deprecated and will be removed in a future - kernel release. - - If you are unsure how to answer this question, answer N. - config SECURITY_SELINUX_DEVELOP bool "NSA SELinux Development Support" depends on SECURITY_SELINUX @@ -70,29 +46,6 @@ config SECURITY_SELINUX_AVC_STATS /sys/fs/selinux/avc/cache_stats, which may be monitored via tools such as avcstat. -config SECURITY_SELINUX_CHECKREQPROT_VALUE - int "NSA SELinux checkreqprot default value" - depends on SECURITY_SELINUX - range 0 1 - default 0 - help - This option sets the default value for the 'checkreqprot' flag - that determines whether SELinux checks the protection requested - by the application or the protection that will be applied by the - kernel (including any implied execute for read-implies-exec) for - mmap and mprotect calls. If this option is set to 0 (zero), - SELinux will default to checking the protection that will be applied - by the kernel. If this option is set to 1 (one), SELinux will - default to checking the protection requested by the application. - The checkreqprot flag may be changed from the default via the - 'checkreqprot=' boot parameter. It may also be changed at runtime - via /sys/fs/selinux/checkreqprot if authorized by policy. - - WARNING: this option is deprecated and will be removed in a future - kernel release. - - If you are unsure how to answer this question, answer 0. - config SECURITY_SELINUX_SIDTAB_HASH_BITS int "NSA SELinux sidtab hashtable size" depends on SECURITY_SELINUX diff --git a/security/selinux/Makefile b/security/selinux/Makefile index 776162444882..0aecf9334ec3 100644 --- a/security/selinux/Makefile +++ b/security/selinux/Makefile @@ -23,8 +23,8 @@ ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include $(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h quiet_cmd_flask = GEN $(obj)/flask.h $(obj)/av_permissions.h - cmd_flask = scripts/selinux/genheaders/genheaders $(obj)/flask.h $(obj)/av_permissions.h + cmd_flask = $< $(obj)/flask.h $(obj)/av_permissions.h targets += flask.h av_permissions.h -$(obj)/flask.h: $(src)/include/classmap.h FORCE +$(obj)/flask.h $(obj)/av_permissions.h &: scripts/selinux/genheaders/genheaders FORCE $(call if_changed,flask) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 9a43af0ebd7d..eaed5c2da02b 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -93,7 +93,7 @@ struct selinux_avc { static struct selinux_avc selinux_avc; -void selinux_avc_init(struct selinux_avc **avc) +void selinux_avc_init(void) { int i; @@ -104,18 +104,16 @@ void selinux_avc_init(struct selinux_avc **avc) } atomic_set(&selinux_avc.avc_cache.active_nodes, 0); atomic_set(&selinux_avc.avc_cache.lru_hint, 0); - *avc = &selinux_avc; } -unsigned int avc_get_cache_threshold(struct selinux_avc *avc) +unsigned int avc_get_cache_threshold(void) { - return avc->avc_cache_threshold; + return selinux_avc.avc_cache_threshold; } -void avc_set_cache_threshold(struct selinux_avc *avc, - unsigned int cache_threshold) +void avc_set_cache_threshold(unsigned int cache_threshold) { - avc->avc_cache_threshold = cache_threshold; + selinux_avc.avc_cache_threshold = cache_threshold; } static struct avc_callback_node *avc_callbacks __ro_after_init; @@ -150,7 +148,7 @@ void __init avc_init(void) 0, SLAB_PANIC, NULL); } -int avc_get_hash_stats(struct selinux_avc *avc, char *page) +int avc_get_hash_stats(char *page) { int i, chain_len, max_chain_len, slots_used; struct avc_node *node; @@ -161,7 +159,7 @@ int avc_get_hash_stats(struct selinux_avc *avc, char *page) slots_used = 0; max_chain_len = 0; for (i = 0; i < AVC_CACHE_SLOTS; i++) { - head = &avc->avc_cache.slots[i]; + head = &selinux_avc.avc_cache.slots[i]; if (!hlist_empty(head)) { slots_used++; chain_len = 0; @@ -176,7 +174,7 @@ int avc_get_hash_stats(struct selinux_avc *avc, char *page) return scnprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n" "longest chain: %d\n", - atomic_read(&avc->avc_cache.active_nodes), + atomic_read(&selinux_avc.avc_cache.active_nodes), slots_used, AVC_CACHE_SLOTS, max_chain_len); } @@ -414,8 +412,7 @@ static inline u32 avc_xperms_audit_required(u32 requested, return audited; } -static inline int avc_xperms_audit(struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass, +static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct av_decision *avd, struct extended_perms_decision *xpd, u8 perm, int result, @@ -427,7 +424,7 @@ static inline int avc_xperms_audit(struct selinux_state *state, requested, avd, xpd, perm, result, &denied); if (likely(!audited)) return 0; - return slow_avc_audit(state, ssid, tsid, tclass, requested, + return slow_avc_audit(ssid, tsid, tclass, requested, audited, denied, result, ad); } @@ -439,30 +436,29 @@ static void avc_node_free(struct rcu_head *rhead) avc_cache_stats_incr(frees); } -static void avc_node_delete(struct selinux_avc *avc, struct avc_node *node) +static void avc_node_delete(struct avc_node *node) { hlist_del_rcu(&node->list); call_rcu(&node->rhead, avc_node_free); - atomic_dec(&avc->avc_cache.active_nodes); + atomic_dec(&selinux_avc.avc_cache.active_nodes); } -static void avc_node_kill(struct selinux_avc *avc, struct avc_node *node) +static void avc_node_kill(struct avc_node *node) { avc_xperms_free(node->ae.xp_node); kmem_cache_free(avc_node_cachep, node); avc_cache_stats_incr(frees); - atomic_dec(&avc->avc_cache.active_nodes); + atomic_dec(&selinux_avc.avc_cache.active_nodes); } -static void avc_node_replace(struct selinux_avc *avc, - struct avc_node *new, struct avc_node *old) +static void avc_node_replace(struct avc_node *new, struct avc_node *old) { hlist_replace_rcu(&old->list, &new->list); call_rcu(&old->rhead, avc_node_free); - atomic_dec(&avc->avc_cache.active_nodes); + atomic_dec(&selinux_avc.avc_cache.active_nodes); } -static inline int avc_reclaim_node(struct selinux_avc *avc) +static inline int avc_reclaim_node(void) { struct avc_node *node; int hvalue, try, ecx; @@ -471,17 +467,17 @@ static inline int avc_reclaim_node(struct selinux_avc *avc) spinlock_t *lock; for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) { - hvalue = atomic_inc_return(&avc->avc_cache.lru_hint) & + hvalue = atomic_inc_return(&selinux_avc.avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1); - head = &avc->avc_cache.slots[hvalue]; - lock = &avc->avc_cache.slots_lock[hvalue]; + head = &selinux_avc.avc_cache.slots[hvalue]; + lock = &selinux_avc.avc_cache.slots_lock[hvalue]; if (!spin_trylock_irqsave(lock, flags)) continue; rcu_read_lock(); hlist_for_each_entry(node, head, list) { - avc_node_delete(avc, node); + avc_node_delete(node); avc_cache_stats_incr(reclaims); ecx++; if (ecx >= AVC_CACHE_RECLAIM) { @@ -497,7 +493,7 @@ out: return ecx; } -static struct avc_node *avc_alloc_node(struct selinux_avc *avc) +static struct avc_node *avc_alloc_node(void) { struct avc_node *node; @@ -508,9 +504,9 @@ static struct avc_node *avc_alloc_node(struct selinux_avc *avc) INIT_HLIST_NODE(&node->list); avc_cache_stats_incr(allocations); - if (atomic_inc_return(&avc->avc_cache.active_nodes) > - avc->avc_cache_threshold) - avc_reclaim_node(avc); + if (atomic_inc_return(&selinux_avc.avc_cache.active_nodes) > + selinux_avc.avc_cache_threshold) + avc_reclaim_node(); out: return node; @@ -524,15 +520,14 @@ static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tcl memcpy(&node->ae.avd, avd, sizeof(node->ae.avd)); } -static inline struct avc_node *avc_search_node(struct selinux_avc *avc, - u32 ssid, u32 tsid, u16 tclass) +static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass) { struct avc_node *node, *ret = NULL; int hvalue; struct hlist_head *head; hvalue = avc_hash(ssid, tsid, tclass); - head = &avc->avc_cache.slots[hvalue]; + head = &selinux_avc.avc_cache.slots[hvalue]; hlist_for_each_entry_rcu(node, head, list) { if (ssid == node->ae.ssid && tclass == node->ae.tclass && @@ -547,7 +542,6 @@ static inline struct avc_node *avc_search_node(struct selinux_avc *avc, /** * avc_lookup - Look up an AVC entry. - * @avc: the access vector cache * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class @@ -558,13 +552,12 @@ static inline struct avc_node *avc_search_node(struct selinux_avc *avc, * then this function returns the avc_node. * Otherwise, this function returns NULL. */ -static struct avc_node *avc_lookup(struct selinux_avc *avc, - u32 ssid, u32 tsid, u16 tclass) +static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass) { struct avc_node *node; avc_cache_stats_incr(lookups); - node = avc_search_node(avc, ssid, tsid, tclass); + node = avc_search_node(ssid, tsid, tclass); if (node) return node; @@ -573,8 +566,7 @@ static struct avc_node *avc_lookup(struct selinux_avc *avc, return NULL; } -static int avc_latest_notif_update(struct selinux_avc *avc, - int seqno, int is_insert) +static int avc_latest_notif_update(int seqno, int is_insert) { int ret = 0; static DEFINE_SPINLOCK(notif_lock); @@ -582,14 +574,14 @@ static int avc_latest_notif_update(struct selinux_avc *avc, spin_lock_irqsave(¬if_lock, flag); if (is_insert) { - if (seqno < avc->avc_cache.latest_notif) { + if (seqno < selinux_avc.avc_cache.latest_notif) { pr_warn("SELinux: avc: seqno %d < latest_notif %d\n", - seqno, avc->avc_cache.latest_notif); + seqno, selinux_avc.avc_cache.latest_notif); ret = -EAGAIN; } } else { - if (seqno > avc->avc_cache.latest_notif) - avc->avc_cache.latest_notif = seqno; + if (seqno > selinux_avc.avc_cache.latest_notif) + selinux_avc.avc_cache.latest_notif = seqno; } spin_unlock_irqrestore(¬if_lock, flag); @@ -598,7 +590,6 @@ static int avc_latest_notif_update(struct selinux_avc *avc, /** * avc_insert - Insert an AVC entry. - * @avc: the access vector cache * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class @@ -612,13 +603,10 @@ static int avc_latest_notif_update(struct selinux_avc *avc, * response to a security_compute_av() call. If the * sequence number @avd->seqno is not less than the latest * revocation notification, then the function copies - * the access vectors into a cache entry, returns - * avc_node inserted. Otherwise, this function returns NULL. + * the access vectors into a cache entry. */ -static struct avc_node *avc_insert(struct selinux_avc *avc, - u32 ssid, u32 tsid, u16 tclass, - struct av_decision *avd, - struct avc_xperms_node *xp_node) +static void avc_insert(u32 ssid, u32 tsid, u16 tclass, + struct av_decision *avd, struct avc_xperms_node *xp_node) { struct avc_node *pos, *node = NULL; int hvalue; @@ -626,35 +614,35 @@ static struct avc_node *avc_insert(struct selinux_avc *avc, spinlock_t *lock; struct hlist_head *head; - if (avc_latest_notif_update(avc, avd->seqno, 1)) - return NULL; + if (avc_latest_notif_update(avd->seqno, 1)) + return; - node = avc_alloc_node(avc); + node = avc_alloc_node(); if (!node) - return NULL; + return; avc_node_populate(node, ssid, tsid, tclass, avd); if (avc_xperms_populate(node, xp_node)) { - avc_node_kill(avc, node); - return NULL; + avc_node_kill(node); + return; } hvalue = avc_hash(ssid, tsid, tclass); - head = &avc->avc_cache.slots[hvalue]; - lock = &avc->avc_cache.slots_lock[hvalue]; + head = &selinux_avc.avc_cache.slots[hvalue]; + lock = &selinux_avc.avc_cache.slots_lock[hvalue]; spin_lock_irqsave(lock, flag); hlist_for_each_entry(pos, head, list) { if (pos->ae.ssid == ssid && pos->ae.tsid == tsid && pos->ae.tclass == tclass) { - avc_node_replace(avc, node, pos); + avc_node_replace(node, pos); goto found; } } hlist_add_head_rcu(&node->list, head); found: spin_unlock_irqrestore(lock, flag); - return node; + return; } /** @@ -715,14 +703,14 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) u32 tcontext_len; int rc; - rc = security_sid_to_context(sad->state, sad->ssid, &scontext, + rc = security_sid_to_context(sad->ssid, &scontext, &scontext_len); if (rc) audit_log_format(ab, " ssid=%d", sad->ssid); else audit_log_format(ab, " scontext=%s", scontext); - rc = security_sid_to_context(sad->state, sad->tsid, &tcontext, + rc = security_sid_to_context(sad->tsid, &tcontext, &tcontext_len); if (rc) audit_log_format(ab, " tsid=%d", sad->tsid); @@ -740,7 +728,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) kfree(scontext); /* in case of invalid context report also the actual context string */ - rc = security_sid_to_context_inval(sad->state, sad->ssid, &scontext, + rc = security_sid_to_context_inval(sad->ssid, &scontext, &scontext_len); if (!rc && scontext) { if (scontext_len && scontext[scontext_len - 1] == '\0') @@ -750,7 +738,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) kfree(scontext); } - rc = security_sid_to_context_inval(sad->state, sad->tsid, &scontext, + rc = security_sid_to_context_inval(sad->tsid, &scontext, &scontext_len); if (!rc && scontext) { if (scontext_len && scontext[scontext_len - 1] == '\0') @@ -766,8 +754,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) * Note that it is non-blocking and can be called from under * rcu_read_lock(). */ -noinline int slow_avc_audit(struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass, +noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a) { @@ -789,7 +776,6 @@ noinline int slow_avc_audit(struct selinux_state *state, sad.audited = audited; sad.denied = denied; sad.result = result; - sad.state = state; a->selinux_audit_data = &sad; @@ -827,7 +813,6 @@ out: /** * avc_update_node - Update an AVC entry - * @avc: the access vector cache * @event : Updating event * @perms : Permission mask bits * @driver: xperm driver information @@ -844,8 +829,7 @@ out: * otherwise, this function updates the AVC entry. The original AVC-entry object * will release later by RCU. */ -static int avc_update_node(struct selinux_avc *avc, - u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, +static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, u32 tsid, u16 tclass, u32 seqno, struct extended_perms_decision *xpd, u32 flags) @@ -856,7 +840,7 @@ static int avc_update_node(struct selinux_avc *avc, struct hlist_head *head; spinlock_t *lock; - node = avc_alloc_node(avc); + node = avc_alloc_node(); if (!node) { rc = -ENOMEM; goto out; @@ -865,8 +849,8 @@ static int avc_update_node(struct selinux_avc *avc, /* Lock the target slot */ hvalue = avc_hash(ssid, tsid, tclass); - head = &avc->avc_cache.slots[hvalue]; - lock = &avc->avc_cache.slots_lock[hvalue]; + head = &selinux_avc.avc_cache.slots[hvalue]; + lock = &selinux_avc.avc_cache.slots_lock[hvalue]; spin_lock_irqsave(lock, flag); @@ -882,7 +866,7 @@ static int avc_update_node(struct selinux_avc *avc, if (!orig) { rc = -ENOENT; - avc_node_kill(avc, node); + avc_node_kill(node); goto out_unlock; } @@ -895,7 +879,7 @@ static int avc_update_node(struct selinux_avc *avc, if (orig->ae.xp_node) { rc = avc_xperms_populate(node, orig->ae.xp_node); if (rc) { - avc_node_kill(avc, node); + avc_node_kill(node); goto out_unlock; } } @@ -926,7 +910,7 @@ static int avc_update_node(struct selinux_avc *avc, avc_add_xperms_decision(node, xpd); break; } - avc_node_replace(avc, node, orig); + avc_node_replace(node, orig); out_unlock: spin_unlock_irqrestore(lock, flag); out: @@ -935,9 +919,8 @@ out: /** * avc_flush - Flush the cache - * @avc: the access vector cache */ -static void avc_flush(struct selinux_avc *avc) +static void avc_flush(void) { struct hlist_head *head; struct avc_node *node; @@ -946,8 +929,8 @@ static void avc_flush(struct selinux_avc *avc) int i; for (i = 0; i < AVC_CACHE_SLOTS; i++) { - head = &avc->avc_cache.slots[i]; - lock = &avc->avc_cache.slots_lock[i]; + head = &selinux_avc.avc_cache.slots[i]; + lock = &selinux_avc.avc_cache.slots_lock[i]; spin_lock_irqsave(lock, flag); /* @@ -956,7 +939,7 @@ static void avc_flush(struct selinux_avc *avc) */ rcu_read_lock(); hlist_for_each_entry(node, head, list) - avc_node_delete(avc, node); + avc_node_delete(node); rcu_read_unlock(); spin_unlock_irqrestore(lock, flag); } @@ -964,15 +947,14 @@ static void avc_flush(struct selinux_avc *avc) /** * avc_ss_reset - Flush the cache and revalidate migrated permissions. - * @avc: the access vector cache * @seqno: policy sequence number */ -int avc_ss_reset(struct selinux_avc *avc, u32 seqno) +int avc_ss_reset(u32 seqno) { struct avc_callback_node *c; int rc = 0, tmprc; - avc_flush(avc); + avc_flush(); for (c = avc_callbacks; c; c = c->next) { if (c->events & AVC_CALLBACK_RESET) { @@ -984,34 +966,32 @@ int avc_ss_reset(struct selinux_avc *avc, u32 seqno) } } - avc_latest_notif_update(avc, seqno, 0); + avc_latest_notif_update(seqno, 0); return rc; } -/* - * Slow-path helper function for avc_has_perm_noaudit, - * when the avc_node lookup fails. We get called with - * the RCU read lock held, and need to return with it - * still held, but drop if for the security compute. +/** + * avc_compute_av - Add an entry to the AVC based on the security policy + * @ssid: subject + * @tsid: object/target + * @tclass: object class + * @avd: access vector decision + * @xp_node: AVC extended permissions node * - * Don't inline this, since it's the slow-path and just - * results in a bigger stack frame. + * Slow-path helper function for avc_has_perm_noaudit, when the avc_node lookup + * fails. Don't inline this, since it's the slow-path and just results in a + * bigger stack frame. */ -static noinline -struct avc_node *avc_compute_av(struct selinux_state *state, - u32 ssid, u32 tsid, - u16 tclass, struct av_decision *avd, - struct avc_xperms_node *xp_node) +static noinline void avc_compute_av(u32 ssid, u32 tsid, u16 tclass, + struct av_decision *avd, + struct avc_xperms_node *xp_node) { - rcu_read_unlock(); INIT_LIST_HEAD(&xp_node->xpd_head); - security_compute_av(state, ssid, tsid, tclass, avd, &xp_node->xp); - rcu_read_lock(); - return avc_insert(state->avc, ssid, tsid, tclass, avd, xp_node); + security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp); + avc_insert(ssid, tsid, tclass, avd, xp_node); } -static noinline int avc_denied(struct selinux_state *state, - u32 ssid, u32 tsid, +static noinline int avc_denied(u32 ssid, u32 tsid, u16 tclass, u32 requested, u8 driver, u8 xperm, unsigned int flags, struct av_decision *avd) @@ -1019,11 +999,11 @@ static noinline int avc_denied(struct selinux_state *state, if (flags & AVC_STRICT) return -EACCES; - if (enforcing_enabled(state) && + if (enforcing_enabled() && !(avd->flags & AVD_FLAGS_PERMISSIVE)) return -EACCES; - avc_update_node(state->avc, AVC_CALLBACK_GRANT, requested, driver, + avc_update_node(AVC_CALLBACK_GRANT, requested, driver, xperm, ssid, tsid, tclass, avd->seqno, NULL, flags); return 0; } @@ -1035,8 +1015,7 @@ static noinline int avc_denied(struct selinux_state *state, * as-is the case with ioctls, then multiple may be chained together and the * driver field is used to specify which set contains the permission. */ -int avc_has_extended_perms(struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass, u32 requested, +int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, u8 driver, u8 xperm, struct common_audit_data *ad) { struct avc_node *node; @@ -1057,9 +1036,9 @@ int avc_has_extended_perms(struct selinux_state *state, rcu_read_lock(); - node = avc_lookup(state->avc, ssid, tsid, tclass); + node = avc_lookup(ssid, tsid, tclass); if (unlikely(!node)) { - avc_compute_av(state, ssid, tsid, tclass, &avd, xp_node); + avc_compute_av(ssid, tsid, tclass, &avd, xp_node); } else { memcpy(&avd, &node->ae.avd, sizeof(avd)); xp_node = node->ae.xp_node; @@ -1083,10 +1062,10 @@ int avc_has_extended_perms(struct selinux_state *state, goto decision; } rcu_read_unlock(); - security_compute_xperms_decision(state, ssid, tsid, tclass, + security_compute_xperms_decision(ssid, tsid, tclass, driver, &local_xpd); rcu_read_lock(); - avc_update_node(state->avc, AVC_CALLBACK_ADD_XPERMS, requested, + avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver, xperm, ssid, tsid, tclass, avd.seqno, &local_xpd, 0); } else { @@ -1100,12 +1079,12 @@ int avc_has_extended_perms(struct selinux_state *state, decision: denied = requested & ~(avd.allowed); if (unlikely(denied)) - rc = avc_denied(state, ssid, tsid, tclass, requested, + rc = avc_denied(ssid, tsid, tclass, requested, driver, xperm, AVC_EXTENDED_PERMS, &avd); rcu_read_unlock(); - rc2 = avc_xperms_audit(state, ssid, tsid, tclass, requested, + rc2 = avc_xperms_audit(ssid, tsid, tclass, requested, &avd, xpd, xperm, rc, ad); if (rc2) return rc2; @@ -1113,8 +1092,35 @@ decision: } /** + * avc_perm_nonode - Add an entry to the AVC + * @ssid: subject + * @tsid: object/target + * @tclass: object class + * @requested: requested permissions + * @flags: AVC flags + * @avd: access vector decision + * + * This is the "we have no node" part of avc_has_perm_noaudit(), which is + * unlikely and needs extra stack space for the new node that we generate, so + * don't inline it. + */ +static noinline int avc_perm_nonode(u32 ssid, u32 tsid, u16 tclass, + u32 requested, unsigned int flags, + struct av_decision *avd) +{ + u32 denied; + struct avc_xperms_node xp_node; + + avc_compute_av(ssid, tsid, tclass, avd, &xp_node); + denied = requested & ~(avd->allowed); + if (unlikely(denied)) + return avc_denied(ssid, tsid, tclass, requested, 0, 0, + flags, avd); + return 0; +} + +/** * avc_has_perm_noaudit - Check permissions but perform no auditing. - * @state: SELinux state * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class @@ -1133,40 +1139,36 @@ decision: * auditing, e.g. in cases where a lock must be held for the check but * should be released for the auditing. */ -inline int avc_has_perm_noaudit(struct selinux_state *state, - u32 ssid, u32 tsid, +inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested, unsigned int flags, struct av_decision *avd) { - struct avc_node *node; - struct avc_xperms_node xp_node; - int rc = 0; u32 denied; + struct avc_node *node; if (WARN_ON(!requested)) return -EACCES; rcu_read_lock(); + node = avc_lookup(ssid, tsid, tclass); + if (unlikely(!node)) { + rcu_read_unlock(); + return avc_perm_nonode(ssid, tsid, tclass, requested, + flags, avd); + } + denied = requested & ~node->ae.avd.allowed; + memcpy(avd, &node->ae.avd, sizeof(*avd)); + rcu_read_unlock(); - node = avc_lookup(state->avc, ssid, tsid, tclass); - if (unlikely(!node)) - avc_compute_av(state, ssid, tsid, tclass, avd, &xp_node); - else - memcpy(avd, &node->ae.avd, sizeof(*avd)); - - denied = requested & ~(avd->allowed); if (unlikely(denied)) - rc = avc_denied(state, ssid, tsid, tclass, requested, 0, 0, - flags, avd); - - rcu_read_unlock(); - return rc; + return avc_denied(ssid, tsid, tclass, requested, 0, 0, + flags, avd); + return 0; } /** * avc_has_perm - Check permissions and perform any appropriate auditing. - * @state: SELinux state * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class @@ -1181,25 +1183,25 @@ inline int avc_has_perm_noaudit(struct selinux_state *state, * permissions are granted, -%EACCES if any permissions are denied, or * another -errno upon other errors. */ -int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass, +int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata) { struct av_decision avd; int rc, rc2; - rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0, + rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); - rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc, + rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata); if (rc2) return rc2; return rc; } -u32 avc_policy_seqno(struct selinux_state *state) +u32 avc_policy_seqno(void) { - return state->avc->avc_cache.latest_notif; + return selinux_avc.avc_cache.latest_notif; } void avc_disable(void) @@ -1216,7 +1218,7 @@ void avc_disable(void) * the cache and get that memory back. */ if (avc_node_cachep) { - avc_flush(selinux_state.avc); + avc_flush(); /* kmem_cache_destroy(avc_node_cachep); */ } } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9a5bdfc21314..79b4890e9936 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -136,17 +136,13 @@ static int __init selinux_enabled_setup(char *str) __setup("selinux=", selinux_enabled_setup); #endif -static unsigned int selinux_checkreqprot_boot = - CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; - static int __init checkreqprot_setup(char *str) { unsigned long checkreqprot; if (!kstrtoul(str, 0, &checkreqprot)) { - selinux_checkreqprot_boot = checkreqprot ? 1 : 0; if (checkreqprot) - pr_err("SELinux: checkreqprot set to 1 via kernel parameter. This is deprecated and will be rejected in a future kernel release.\n"); + pr_err("SELinux: checkreqprot set to 1 via kernel parameter. This is no longer supported.\n"); } return 1; } @@ -257,7 +253,7 @@ static int __inode_security_revalidate(struct inode *inode, might_sleep_if(may_sleep); - if (selinux_initialized(&selinux_state) && + if (selinux_initialized() && isec->initialized != LABEL_INITIALIZED) { if (!may_sleep) return -ECHILD; @@ -403,14 +399,12 @@ static int may_context_mount_sb_relabel(u32 sid, const struct task_security_struct *tsec = selinux_cred(cred); int rc; - rc = avc_has_perm(&selinux_state, - tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, + rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__RELABELFROM, NULL); if (rc) return rc; - rc = avc_has_perm(&selinux_state, - tsec->sid, sid, SECCLASS_FILESYSTEM, + rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, FILESYSTEM__RELABELTO, NULL); return rc; } @@ -421,14 +415,12 @@ static int may_context_mount_inode_relabel(u32 sid, { const struct task_security_struct *tsec = selinux_cred(cred); int rc; - rc = avc_has_perm(&selinux_state, - tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, + rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__RELABELFROM, NULL); if (rc) return rc; - rc = avc_has_perm(&selinux_state, - sid, sbsec->sid, SECCLASS_FILESYSTEM, + rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE, NULL); return rc; } @@ -511,7 +503,7 @@ static int sb_check_xattr_support(struct super_block *sb) fallback: /* No xattr support - try to fallback to genfs if possible. */ - rc = security_genfs_sid(&selinux_state, sb->s_type->name, "/", + rc = security_genfs_sid(sb->s_type->name, "/", SECCLASS_DIR, &sid); if (rc) return -EOPNOTSUPP; @@ -615,7 +607,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, mutex_lock(&sbsec->lock); - if (!selinux_initialized(&selinux_state)) { + if (!selinux_initialized()) { if (!opts) { /* Defer initialization until selinux_complete_init, after the initial policy is loaded and the security @@ -716,7 +708,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, * Determine the labeling behavior to use for this * filesystem type. */ - rc = security_fs_use(&selinux_state, sb); + rc = security_fs_use(sb); if (rc) { pr_warn("%s: security_fs_use(%s) returned %d\n", __func__, sb->s_type->name, rc); @@ -741,8 +733,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, } if (sbsec->behavior == SECURITY_FS_USE_XATTR) { sbsec->behavior = SECURITY_FS_USE_MNTPOINT; - rc = security_transition_sid(&selinux_state, - current_sid(), + rc = security_transition_sid(current_sid(), current_sid(), SECCLASS_FILE, NULL, &sbsec->mntpoint_sid); @@ -881,7 +872,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, * if the parent was able to be mounted it clearly had no special lsm * mount options. thus we can safely deal with this superblock later */ - if (!selinux_initialized(&selinux_state)) + if (!selinux_initialized()) return 0; /* @@ -911,7 +902,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, if (newsbsec->behavior == SECURITY_FS_USE_NATIVE && !(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) { - rc = security_fs_use(&selinux_state, newsb); + rc = security_fs_use(newsb); if (rc) goto out; } @@ -960,7 +951,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts) if (!s) return -EINVAL; - if (!selinux_initialized(&selinux_state)) { + if (!selinux_initialized()) { pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n"); return -EINVAL; } @@ -997,7 +988,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts) WARN_ON(1); return -EINVAL; } - rc = security_context_str_to_sid(&selinux_state, s, dst_sid, GFP_KERNEL); + rc = security_context_str_to_sid(s, dst_sid, GFP_KERNEL); if (rc) pr_warn("SELinux: security_context_str_to_sid (%s) failed with errno=%d\n", s, rc); @@ -1014,8 +1005,7 @@ static int show_sid(struct seq_file *m, u32 sid) u32 len; int rc; - rc = security_sid_to_context(&selinux_state, sid, - &context, &len); + rc = security_sid_to_context(sid, &context, &len); if (!rc) { bool has_comma = strchr(context, ','); @@ -1038,7 +1028,7 @@ static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) if (!(sbsec->flags & SE_SBINITIALIZED)) return 0; - if (!selinux_initialized(&selinux_state)) + if (!selinux_initialized()) return 0; if (sbsec->flags & FSCONTEXT_MNT) { @@ -1292,7 +1282,7 @@ static int selinux_genfs_get_sid(struct dentry *dentry, path++; } } - rc = security_genfs_sid(&selinux_state, sb->s_type->name, + rc = security_genfs_sid(sb->s_type->name, path, tclass, sid); if (rc == -ENOENT) { /* No match in policy, mark as unlabeled. */ @@ -1347,7 +1337,7 @@ static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry, return 0; } - rc = security_context_to_sid_default(&selinux_state, context, rc, sid, + rc = security_context_to_sid_default(context, rc, sid, def_sid, GFP_NOFS); if (rc) { char *dev = inode->i_sb->s_id; @@ -1454,7 +1444,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent sid = sbsec->sid; /* Try to obtain a transition SID. */ - rc = security_transition_sid(&selinux_state, task_sid, sid, + rc = security_transition_sid(task_sid, sid, sclass, NULL, &sid); if (rc) goto out; @@ -1599,11 +1589,9 @@ static int cred_has_capability(const struct cred *cred, return -EINVAL; } - rc = avc_has_perm_noaudit(&selinux_state, - sid, sid, sclass, av, 0, &avd); + rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); if (!(opts & CAP_OPT_NOAUDIT)) { - int rc2 = avc_audit(&selinux_state, - sid, sid, sclass, av, &avd, rc, &ad); + int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad); if (rc2) return rc2; } @@ -1629,8 +1617,7 @@ static int inode_has_perm(const struct cred *cred, sid = cred_sid(cred); isec = selinux_inode(inode); - return avc_has_perm(&selinux_state, - sid, isec->sid, isec->sclass, perms, adp); + return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); } /* Same as inode_has_perm, but pass explicit audit data containing @@ -1703,8 +1690,7 @@ static int file_has_perm(const struct cred *cred, ad.u.file = file; if (sid != fsec->sid) { - rc = avc_has_perm(&selinux_state, - sid, fsec->sid, + rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); @@ -1747,7 +1733,7 @@ selinux_determine_inode_label(const struct task_security_struct *tsec, *_new_isid = tsec->create_sid; } else { const struct inode_security_struct *dsec = inode_security(dir); - return security_transition_sid(&selinux_state, tsec->sid, + return security_transition_sid(tsec->sid, dsec->sid, tclass, name, _new_isid); } @@ -1775,8 +1761,7 @@ static int may_create(struct inode *dir, ad.type = LSM_AUDIT_DATA_DENTRY; ad.u.dentry = dentry; - rc = avc_has_perm(&selinux_state, - sid, dsec->sid, SECCLASS_DIR, + rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, DIR__ADD_NAME | DIR__SEARCH, &ad); if (rc) @@ -1787,13 +1772,11 @@ static int may_create(struct inode *dir, if (rc) return rc; - rc = avc_has_perm(&selinux_state, - sid, newsid, tclass, FILE__CREATE, &ad); + rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad); if (rc) return rc; - return avc_has_perm(&selinux_state, - newsid, sbsec->sid, + return avc_has_perm(newsid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE, &ad); } @@ -1822,8 +1805,7 @@ static int may_link(struct inode *dir, av = DIR__SEARCH; av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); - rc = avc_has_perm(&selinux_state, - sid, dsec->sid, SECCLASS_DIR, av, &ad); + rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad); if (rc) return rc; @@ -1843,8 +1825,7 @@ static int may_link(struct inode *dir, return 0; } - rc = avc_has_perm(&selinux_state, - sid, isec->sid, isec->sclass, av, &ad); + rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad); return rc; } @@ -1868,19 +1849,16 @@ static inline int may_rename(struct inode *old_dir, ad.type = LSM_AUDIT_DATA_DENTRY; ad.u.dentry = old_dentry; - rc = avc_has_perm(&selinux_state, - sid, old_dsec->sid, SECCLASS_DIR, + rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, DIR__REMOVE_NAME | DIR__SEARCH, &ad); if (rc) return rc; - rc = avc_has_perm(&selinux_state, - sid, old_isec->sid, + rc = avc_has_perm(sid, old_isec->sid, old_isec->sclass, FILE__RENAME, &ad); if (rc) return rc; if (old_is_dir && new_dir != old_dir) { - rc = avc_has_perm(&selinux_state, - sid, old_isec->sid, + rc = avc_has_perm(sid, old_isec->sid, old_isec->sclass, DIR__REPARENT, &ad); if (rc) return rc; @@ -1890,15 +1868,13 @@ static inline int may_rename(struct inode *old_dir, av = DIR__ADD_NAME | DIR__SEARCH; if (d_is_positive(new_dentry)) av |= DIR__REMOVE_NAME; - rc = avc_has_perm(&selinux_state, - sid, new_dsec->sid, SECCLASS_DIR, av, &ad); + rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad); if (rc) return rc; if (d_is_positive(new_dentry)) { new_isec = backing_inode_security(new_dentry); new_is_dir = d_is_dir(new_dentry); - rc = avc_has_perm(&selinux_state, - sid, new_isec->sid, + rc = avc_has_perm(sid, new_isec->sid, new_isec->sclass, (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad); if (rc) @@ -1918,8 +1894,7 @@ static int superblock_has_perm(const struct cred *cred, u32 sid = cred_sid(cred); sbsec = selinux_superblock(sb); - return avc_has_perm(&selinux_state, - sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad); + return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad); } /* Convert a Linux mode and permission mask to an access vector. */ @@ -1993,8 +1968,7 @@ static inline u32 open_file_to_av(struct file *file) static int selinux_binder_set_context_mgr(const struct cred *mgr) { - return avc_has_perm(&selinux_state, - current_sid(), cred_sid(mgr), SECCLASS_BINDER, + return avc_has_perm(current_sid(), cred_sid(mgr), SECCLASS_BINDER, BINDER__SET_CONTEXT_MGR, NULL); } @@ -2007,22 +1981,20 @@ static int selinux_binder_transaction(const struct cred *from, int rc; if (mysid != fromsid) { - rc = avc_has_perm(&selinux_state, - mysid, fromsid, SECCLASS_BINDER, + rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, BINDER__IMPERSONATE, NULL); if (rc) return rc; } - return avc_has_perm(&selinux_state, fromsid, tosid, + return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, NULL); } static int selinux_binder_transfer_binder(const struct cred *from, const struct cred *to) { - return avc_has_perm(&selinux_state, - cred_sid(from), cred_sid(to), + return avc_has_perm(cred_sid(from), cred_sid(to), SECCLASS_BINDER, BINDER__TRANSFER, NULL); } @@ -2042,8 +2014,7 @@ static int selinux_binder_transfer_file(const struct cred *from, ad.u.path = file->f_path; if (sid != fsec->sid) { - rc = avc_has_perm(&selinux_state, - sid, fsec->sid, + rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); @@ -2061,8 +2032,7 @@ static int selinux_binder_transfer_file(const struct cred *from, return 0; isec = backing_inode_security(dentry); - return avc_has_perm(&selinux_state, - sid, isec->sid, isec->sclass, file_to_av(file), + return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file), &ad); } @@ -2073,26 +2043,24 @@ static int selinux_ptrace_access_check(struct task_struct *child, u32 csid = task_sid_obj(child); if (mode & PTRACE_MODE_READ) - return avc_has_perm(&selinux_state, - sid, csid, SECCLASS_FILE, FILE__READ, NULL); + return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, + NULL); - return avc_has_perm(&selinux_state, - sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL); + return avc_has_perm(sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, + NULL); } static int selinux_ptrace_traceme(struct task_struct *parent) { - return avc_has_perm(&selinux_state, - task_sid_obj(parent), task_sid_obj(current), + return avc_has_perm(task_sid_obj(parent), task_sid_obj(current), SECCLASS_PROCESS, PROCESS__PTRACE, NULL); } static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted) { - return avc_has_perm(&selinux_state, - current_sid(), task_sid_obj(target), SECCLASS_PROCESS, - PROCESS__GETCAP, NULL); + return avc_has_perm(current_sid(), task_sid_obj(target), + SECCLASS_PROCESS, PROCESS__GETCAP, NULL); } static int selinux_capset(struct cred *new, const struct cred *old, @@ -2100,8 +2068,7 @@ static int selinux_capset(struct cred *new, const struct cred *old, const kernel_cap_t *inheritable, const kernel_cap_t *permitted) { - return avc_has_perm(&selinux_state, - cred_sid(old), cred_sid(new), SECCLASS_PROCESS, + return avc_has_perm(cred_sid(old), cred_sid(new), SECCLASS_PROCESS, PROCESS__SETCAP, NULL); } @@ -2168,21 +2135,18 @@ static int selinux_syslog(int type) switch (type) { case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ - return avc_has_perm(&selinux_state, - current_sid(), SECINITSID_KERNEL, + return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL); case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */ case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */ /* Set level of messages printed to console */ case SYSLOG_ACTION_CONSOLE_LEVEL: - return avc_has_perm(&selinux_state, - current_sid(), SECINITSID_KERNEL, + return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, NULL); } /* All other syslog types */ - return avc_has_perm(&selinux_state, - current_sid(), SECINITSID_KERNEL, + return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL); } @@ -2249,8 +2213,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm, av |= PROCESS2__NNP_TRANSITION; if (nosuid) av |= PROCESS2__NOSUID_TRANSITION; - rc = avc_has_perm(&selinux_state, - old_tsec->sid, new_tsec->sid, + rc = avc_has_perm(old_tsec->sid, new_tsec->sid, SECCLASS_PROCESS2, av, NULL); if (!rc) return 0; @@ -2261,7 +2224,7 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm, * i.e. SIDs that are guaranteed to only be allowed a subset * of the permissions of the current SID. */ - rc = security_bounded_transition(&selinux_state, old_tsec->sid, + rc = security_bounded_transition(old_tsec->sid, new_tsec->sid); if (!rc) return 0; @@ -2312,7 +2275,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm) return rc; } else { /* Check for a default transition on this program. */ - rc = security_transition_sid(&selinux_state, old_tsec->sid, + rc = security_transition_sid(old_tsec->sid, isec->sid, SECCLASS_PROCESS, NULL, &new_tsec->sid); if (rc) @@ -2331,29 +2294,25 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm) ad.u.file = bprm->file; if (new_tsec->sid == old_tsec->sid) { - rc = avc_has_perm(&selinux_state, - old_tsec->sid, isec->sid, + rc = avc_has_perm(old_tsec->sid, isec->sid, SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); if (rc) return rc; } else { /* Check permissions for the transition. */ - rc = avc_has_perm(&selinux_state, - old_tsec->sid, new_tsec->sid, + rc = avc_has_perm(old_tsec->sid, new_tsec->sid, SECCLASS_PROCESS, PROCESS__TRANSITION, &ad); if (rc) return rc; - rc = avc_has_perm(&selinux_state, - new_tsec->sid, isec->sid, + rc = avc_has_perm(new_tsec->sid, isec->sid, SECCLASS_FILE, FILE__ENTRYPOINT, &ad); if (rc) return rc; /* Check for shared state */ if (bprm->unsafe & LSM_UNSAFE_SHARE) { - rc = avc_has_perm(&selinux_state, - old_tsec->sid, new_tsec->sid, + rc = avc_has_perm(old_tsec->sid, new_tsec->sid, SECCLASS_PROCESS, PROCESS__SHARE, NULL); if (rc) @@ -2365,8 +2324,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm) if (bprm->unsafe & LSM_UNSAFE_PTRACE) { u32 ptsid = ptrace_parent_sid(); if (ptsid != 0) { - rc = avc_has_perm(&selinux_state, - ptsid, new_tsec->sid, + rc = avc_has_perm(ptsid, new_tsec->sid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL); if (rc) @@ -2380,8 +2338,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm) /* Enable secure mode for SIDs transitions unless the noatsecure permission is granted between the two SIDs, i.e. ahp returns 0. */ - rc = avc_has_perm(&selinux_state, - old_tsec->sid, new_tsec->sid, + rc = avc_has_perm(old_tsec->sid, new_tsec->sid, SECCLASS_PROCESS, PROCESS__NOATSECURE, NULL); bprm->secureexec |= !!rc; @@ -2473,8 +2430,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm) * higher than the default soft limit for cases where the default is * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK. */ - rc = avc_has_perm(&selinux_state, - new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS, + rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS, PROCESS__RLIMITINH, NULL); if (rc) { /* protect against do_prlimit() */ @@ -2513,8 +2469,7 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) * This must occur _after_ the task SID has been updated so that any * kill done after the flush will be checked against the new SID. */ - rc = avc_has_perm(&selinux_state, - osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL); + rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL); if (rc) { clear_itimer(); @@ -2841,7 +2796,7 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode, if (xattr_name) *xattr_name = XATTR_NAME_SELINUX; - return security_sid_to_context(&selinux_state, newsid, (char **)ctx, + return security_sid_to_context(newsid, (char **)ctx, ctxlen); } @@ -2895,7 +2850,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, isec->initialized = LABEL_INITIALIZED; } - if (!selinux_initialized(&selinux_state) || + if (!selinux_initialized() || !(sbsec->flags & SBLABEL_MNT)) return -EOPNOTSUPP; @@ -2903,7 +2858,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, *name = XATTR_SELINUX_SUFFIX; if (value && len) { - rc = security_sid_to_context_force(&selinux_state, newsid, + rc = security_sid_to_context_force(newsid, &context, &clen); if (rc) return rc; @@ -2923,7 +2878,7 @@ static int selinux_inode_init_security_anon(struct inode *inode, struct inode_security_struct *isec; int rc; - if (unlikely(!selinux_initialized(&selinux_state))) + if (unlikely(!selinux_initialized())) return 0; isec = selinux_inode(inode); @@ -2947,7 +2902,7 @@ static int selinux_inode_init_security_anon(struct inode *inode, } else { isec->sclass = SECCLASS_ANON_INODE; rc = security_transition_sid( - &selinux_state, tsec->sid, tsec->sid, + tsec->sid, tsec->sid, isec->sclass, name, &isec->sid); if (rc) return rc; @@ -2962,8 +2917,7 @@ static int selinux_inode_init_security_anon(struct inode *inode, ad.type = LSM_AUDIT_DATA_ANONINODE; ad.u.anonclass = name ? (const char *)name->name : "?"; - return avc_has_perm(&selinux_state, - tsec->sid, + return avc_has_perm(tsec->sid, isec->sid, isec->sclass, FILE__CREATE, @@ -3035,8 +2989,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode, if (IS_ERR(isec)) return PTR_ERR(isec); - return avc_has_perm(&selinux_state, - sid, isec->sid, isec->sclass, FILE__READ, &ad); + return avc_has_perm(sid, isec->sid, isec->sclass, FILE__READ, &ad); } static noinline int audit_inode_permission(struct inode *inode, @@ -3049,8 +3002,7 @@ static noinline int audit_inode_permission(struct inode *inode, ad.type = LSM_AUDIT_DATA_INODE; ad.u.inode = inode; - return slow_avc_audit(&selinux_state, - current_sid(), isec->sid, isec->sclass, perms, + return slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms, audited, denied, result, &ad); } @@ -3085,8 +3037,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) if (IS_ERR(isec)) return PTR_ERR(isec); - rc = avc_has_perm_noaudit(&selinux_state, - sid, isec->sid, isec->sclass, perms, 0, + rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd); audited = avc_audit_required(perms, &avd, rc, from_access ? FILE__AUDIT_ACCESS : 0, @@ -3166,7 +3117,7 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap, return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); } - if (!selinux_initialized(&selinux_state)) + if (!selinux_initialized()) return (inode_owner_or_capable(idmap, inode) ? 0 : -EPERM); sbsec = selinux_superblock(inode->i_sb); @@ -3180,13 +3131,12 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap, ad.u.dentry = dentry; isec = backing_inode_security(dentry); - rc = avc_has_perm(&selinux_state, - sid, isec->sid, isec->sclass, + rc = avc_has_perm(sid, isec->sid, isec->sclass, FILE__RELABELFROM, &ad); if (rc) return rc; - rc = security_context_to_sid(&selinux_state, value, size, &newsid, + rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL); if (rc == -EINVAL) { if (!has_cap_mac_admin(true)) { @@ -3215,25 +3165,23 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap, return rc; } - rc = security_context_to_sid_force(&selinux_state, value, + rc = security_context_to_sid_force(value, size, &newsid); } if (rc) return rc; - rc = avc_has_perm(&selinux_state, - sid, newsid, isec->sclass, + rc = avc_has_perm(sid, newsid, isec->sclass, FILE__RELABELTO, &ad); if (rc) return rc; - rc = security_validate_transition(&selinux_state, isec->sid, newsid, + rc = security_validate_transition(isec->sid, newsid, sid, isec->sclass); if (rc) return rc; - return avc_has_perm(&selinux_state, - newsid, + return avc_has_perm(newsid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE, @@ -3273,7 +3221,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, return; } - if (!selinux_initialized(&selinux_state)) { + if (!selinux_initialized()) { /* If we haven't even been initialized, then we can't validate * against a policy, so leave the label as invalid. It may * resolve to a valid label on the next revalidation try if @@ -3282,7 +3230,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, return; } - rc = security_context_to_sid_force(&selinux_state, value, size, + rc = security_context_to_sid_force(value, size, &newsid); if (rc) { pr_err("SELinux: unable to map context to SID" @@ -3326,7 +3274,7 @@ static int selinux_inode_removexattr(struct mnt_idmap *idmap, return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); } - if (!selinux_initialized(&selinux_state)) + if (!selinux_initialized()) return 0; /* No one is allowed to remove a SELinux security label. @@ -3396,7 +3344,7 @@ static int selinux_inode_getsecurity(struct mnt_idmap *idmap, * If we're not initialized yet, then we can't validate contexts, so * just let vfs_getxattr fall back to using the on-disk xattr. */ - if (!selinux_initialized(&selinux_state) || + if (!selinux_initialized() || strcmp(name, XATTR_SELINUX_SUFFIX)) return -EOPNOTSUPP; @@ -3411,11 +3359,10 @@ static int selinux_inode_getsecurity(struct mnt_idmap *idmap, */ isec = inode_security(inode); if (has_cap_mac_admin(false)) - error = security_sid_to_context_force(&selinux_state, - isec->sid, &context, + error = security_sid_to_context_force(isec->sid, &context, &size); else - error = security_sid_to_context(&selinux_state, isec->sid, + error = security_sid_to_context(isec->sid, &context, &size); if (error) return error; @@ -3447,7 +3394,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, if (!value || !size) return -EACCES; - rc = security_context_to_sid(&selinux_state, value, size, &newsid, + rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL); if (rc) return rc; @@ -3464,7 +3411,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t { const int len = sizeof(XATTR_NAME_SELINUX); - if (!selinux_initialized(&selinux_state)) + if (!selinux_initialized()) return 0; if (buffer && len <= buffer_size) @@ -3540,7 +3487,7 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir, return rc; } - rc = security_context_to_sid(&selinux_state, context, clen, &parent_sid, + rc = security_context_to_sid(context, clen, &parent_sid, GFP_KERNEL); kfree(context); if (rc) @@ -3555,14 +3502,14 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir, q.name = kn->name; q.hash_len = hashlen_string(kn_dir, kn->name); - rc = security_transition_sid(&selinux_state, tsec->sid, + rc = security_transition_sid(tsec->sid, parent_sid, secclass, &q, &newsid); if (rc) return rc; } - rc = security_sid_to_context_force(&selinux_state, newsid, + rc = security_sid_to_context_force(newsid, &context, &clen); if (rc) return rc; @@ -3602,7 +3549,7 @@ static int selinux_file_permission(struct file *file, int mask) isec = inode_security(inode); if (sid == fsec->sid && fsec->isid == isec->sid && - fsec->pseqno == avc_policy_seqno(&selinux_state)) + fsec->pseqno == avc_policy_seqno()) /* No change since file_open check. */ return 0; @@ -3643,8 +3590,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file, ad.u.op->path = file->f_path; if (ssid != fsec->sid) { - rc = avc_has_perm(&selinux_state, - ssid, fsec->sid, + rc = avc_has_perm(ssid, fsec->sid, SECCLASS_FD, FD__USE, &ad); @@ -3656,8 +3602,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file, return 0; isec = inode_security(inode); - rc = avc_has_extended_perms(&selinux_state, - ssid, isec->sid, isec->sclass, + rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, requested, driver, xperm, &ad); out: return rc; @@ -3726,8 +3671,7 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared * private file mapping that will also be writable. * This has an additional check. */ - rc = avc_has_perm(&selinux_state, - sid, sid, SECCLASS_PROCESS, + rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__EXECMEM, NULL); if (rc) goto error; @@ -3757,15 +3701,15 @@ static int selinux_mmap_addr(unsigned long addr) if (addr < CONFIG_LSM_MMAP_MIN_ADDR) { u32 sid = current_sid(); - rc = avc_has_perm(&selinux_state, - sid, sid, SECCLASS_MEMPROTECT, + rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, NULL); } return rc; } -static int selinux_mmap_file(struct file *file, unsigned long reqprot, +static int selinux_mmap_file(struct file *file, + unsigned long reqprot __always_unused, unsigned long prot, unsigned long flags) { struct common_audit_data ad; @@ -3780,37 +3724,29 @@ static int selinux_mmap_file(struct file *file, unsigned long reqprot, return rc; } - if (checkreqprot_get(&selinux_state)) - prot = reqprot; - return file_map_prot_check(file, prot, (flags & MAP_TYPE) == MAP_SHARED); } static int selinux_file_mprotect(struct vm_area_struct *vma, - unsigned long reqprot, + unsigned long reqprot __always_unused, unsigned long prot) { const struct cred *cred = current_cred(); u32 sid = cred_sid(cred); - if (checkreqprot_get(&selinux_state)) - prot = reqprot; - if (default_noexec && (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { int rc = 0; if (vma->vm_start >= vma->vm_mm->start_brk && vma->vm_end <= vma->vm_mm->brk) { - rc = avc_has_perm(&selinux_state, - sid, sid, SECCLASS_PROCESS, + rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__EXECHEAP, NULL); } else if (!vma->vm_file && ((vma->vm_start <= vma->vm_mm->start_stack && vma->vm_end >= vma->vm_mm->start_stack) || vma_is_stack_for_current(vma))) { - rc = avc_has_perm(&selinux_state, - sid, sid, SECCLASS_PROCESS, + rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__EXECSTACK, NULL); } else if (vma->vm_file && vma->anon_vma) { /* @@ -3902,8 +3838,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk, else perm = signal_to_av(signum); - return avc_has_perm(&selinux_state, - fsec->fown_sid, sid, + return avc_has_perm(fsec->fown_sid, sid, SECCLASS_PROCESS, perm, NULL); } @@ -3929,7 +3864,7 @@ static int selinux_file_open(struct file *file) * struct as its SID. */ fsec->isid = isec->sid; - fsec->pseqno = avc_policy_seqno(&selinux_state); + fsec->pseqno = avc_policy_seqno(); /* * Since the inode label or policy seqno may have changed * between the selinux_inode_permission check and the saving @@ -3948,8 +3883,7 @@ static int selinux_task_alloc(struct task_struct *task, { u32 sid = current_sid(); - return avc_has_perm(&selinux_state, - sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL); + return avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL); } /* @@ -3991,8 +3925,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid) u32 sid = current_sid(); int ret; - ret = avc_has_perm(&selinux_state, - sid, secid, + ret = avc_has_perm(sid, secid, SECCLASS_KERNEL_SERVICE, KERNEL_SERVICE__USE_AS_OVERRIDE, NULL); @@ -4016,8 +3949,7 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) u32 sid = current_sid(); int ret; - ret = avc_has_perm(&selinux_state, - sid, isec->sid, + ret = avc_has_perm(sid, isec->sid, SECCLASS_KERNEL_SERVICE, KERNEL_SERVICE__CREATE_FILES_AS, NULL); @@ -4034,8 +3966,7 @@ static int selinux_kernel_module_request(char *kmod_name) ad.type = LSM_AUDIT_DATA_KMOD; ad.u.kmod_name = kmod_name; - return avc_has_perm(&selinux_state, - current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, + return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, SYSTEM__MODULE_REQUEST, &ad); } @@ -4049,8 +3980,7 @@ static int selinux_kernel_module_from_file(struct file *file) /* init_module */ if (file == NULL) - return avc_has_perm(&selinux_state, - sid, sid, SECCLASS_SYSTEM, + return avc_has_perm(sid, sid, SECCLASS_SYSTEM, SYSTEM__MODULE_LOAD, NULL); /* finit_module */ @@ -4060,15 +3990,13 @@ static int selinux_kernel_module_from_file(struct file *file) fsec = selinux_file(file); if (sid != fsec->sid) { - rc = avc_has_perm(&selinux_state, - sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); + rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); if (rc) return rc; } isec = inode_security(file_inode(file)); - return avc_has_perm(&selinux_state, - sid, isec->sid, SECCLASS_SYSTEM, + return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM, SYSTEM__MODULE_LOAD, &ad); } @@ -4106,22 +4034,19 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents) static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) { - return avc_has_perm(&selinux_state, - current_sid(), task_sid_obj(p), SECCLASS_PROCESS, + return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETPGID, NULL); } static int selinux_task_getpgid(struct task_struct *p) { - return avc_has_perm(&selinux_state, - current_sid(), task_sid_obj(p), SECCLASS_PROCESS, + return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__GETPGID, NULL); } static int selinux_task_getsid(struct task_struct *p) { - return avc_has_perm(&selinux_state, - current_sid(), task_sid_obj(p), SECCLASS_PROCESS, + return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__GETSESSION, NULL); } @@ -4137,22 +4062,19 @@ static void selinux_task_getsecid_obj(struct task_struct *p, u32 *secid) static int selinux_task_setnice(struct task_struct *p, int nice) { - return avc_has_perm(&selinux_state, - current_sid(), task_sid_obj(p), SECCLASS_PROCESS, + return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETSCHED, NULL); } static int selinux_task_setioprio(struct task_struct *p, int ioprio) { - return avc_has_perm(&selinux_state, - current_sid(), task_sid_obj(p), SECCLASS_PROCESS, + return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETSCHED, NULL); } static int selinux_task_getioprio(struct task_struct *p) { - return avc_has_perm(&selinux_state, - current_sid(), task_sid_obj(p), SECCLASS_PROCESS, + return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__GETSCHED, NULL); } @@ -4167,8 +4089,7 @@ static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcre av |= PROCESS__SETRLIMIT; if (flags & LSM_PRLIMIT_READ) av |= PROCESS__GETRLIMIT; - return avc_has_perm(&selinux_state, - cred_sid(cred), cred_sid(tcred), + return avc_has_perm(cred_sid(cred), cred_sid(tcred), SECCLASS_PROCESS, av, NULL); } @@ -4182,8 +4103,7 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, later be used as a safe reset point for the soft limit upon context transitions. See selinux_bprm_committing_creds. */ if (old_rlim->rlim_max != new_rlim->rlim_max) - return avc_has_perm(&selinux_state, - current_sid(), task_sid_obj(p), + return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL); return 0; @@ -4191,22 +4111,19 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, static int selinux_task_setscheduler(struct task_struct *p) { - return avc_has_perm(&selinux_state, - current_sid(), task_sid_obj(p), SECCLASS_PROCESS, + return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETSCHED, NULL); } static int selinux_task_getscheduler(struct task_struct *p) { - return avc_has_perm(&selinux_state, - current_sid(), task_sid_obj(p), SECCLASS_PROCESS, + return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__GETSCHED, NULL); } static int selinux_task_movememory(struct task_struct *p) { - return avc_has_perm(&selinux_state, - current_sid(), task_sid_obj(p), SECCLASS_PROCESS, + return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS, PROCESS__SETSCHED, NULL); } @@ -4224,8 +4141,7 @@ static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info, secid = current_sid(); else secid = cred_sid(cred); - return avc_has_perm(&selinux_state, - secid, task_sid_obj(p), SECCLASS_PROCESS, perm, NULL); + return avc_has_perm(secid, task_sid_obj(p), SECCLASS_PROCESS, perm, NULL); } static void selinux_task_to_inode(struct task_struct *p, @@ -4245,8 +4161,8 @@ static int selinux_userns_create(const struct cred *cred) { u32 sid = current_sid(); - return avc_has_perm(&selinux_state, sid, sid, SECCLASS_USER_NAMESPACE, - USER_NAMESPACE__CREATE, NULL); + return avc_has_perm(sid, sid, SECCLASS_USER_NAMESPACE, + USER_NAMESPACE__CREATE, NULL); } /* Returns error only if unable to parse addresses */ @@ -4504,7 +4420,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) if (unlikely(err)) return -EACCES; - err = security_net_peersid_resolve(&selinux_state, nlbl_sid, + err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid); if (unlikely(err)) { pr_warn( @@ -4533,7 +4449,7 @@ static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid) int err = 0; if (skb_sid != SECSID_NULL) - err = security_sid_mls_copy(&selinux_state, sk_sid, skb_sid, + err = security_sid_mls_copy(sk_sid, skb_sid, conn_sid); else *conn_sid = sk_sid; @@ -4551,7 +4467,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec, return 0; } - return security_transition_sid(&selinux_state, tsec->sid, tsec->sid, + return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL, socksid); } @@ -4568,8 +4484,7 @@ static int sock_has_perm(struct sock *sk, u32 perms) ad.u.net = &net; ad.u.net->sk = sk; - return avc_has_perm(&selinux_state, - current_sid(), sksec->sid, sksec->sclass, perms, + return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms, &ad); } @@ -4589,8 +4504,7 @@ static int selinux_socket_create(int family, int type, if (rc) return rc; - return avc_has_perm(&selinux_state, - tsec->sid, newsid, secclass, SOCKET__CREATE, NULL); + return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL); } static int selinux_socket_post_create(struct socket *sock, int family, @@ -4719,8 +4633,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in snum, &sid); if (err) goto out; - err = avc_has_perm(&selinux_state, - sksec->sid, sid, + err = avc_has_perm(sksec->sid, sid, sksec->sclass, SOCKET__NAME_BIND, &ad); if (err) @@ -4759,8 +4672,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in else ad.u.net->v6info.saddr = addr6->sin6_addr; - err = avc_has_perm(&selinux_state, - sksec->sid, sid, + err = avc_has_perm(sksec->sid, sid, sksec->sclass, node_perm, &ad); if (err) goto out; @@ -4858,8 +4770,7 @@ static int selinux_socket_connect_helper(struct socket *sock, ad.u.net = &net; ad.u.net->dport = htons(snum); ad.u.net->family = address->sa_family; - err = avc_has_perm(&selinux_state, - sksec->sid, sid, sksec->sclass, perm, &ad); + err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad); if (err) return err; } @@ -4971,8 +4882,7 @@ static int selinux_socket_unix_stream_connect(struct sock *sock, ad.u.net = &net; ad.u.net->sk = other; - err = avc_has_perm(&selinux_state, - sksec_sock->sid, sksec_other->sid, + err = avc_has_perm(sksec_sock->sid, sksec_other->sid, sksec_other->sclass, UNIX_STREAM_SOCKET__CONNECTTO, &ad); if (err) @@ -4980,7 +4890,7 @@ static int selinux_socket_unix_stream_connect(struct sock *sock, /* server child socket */ sksec_new->peer_sid = sksec_sock->sid; - err = security_sid_mls_copy(&selinux_state, sksec_other->sid, + err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid, &sksec_new->sid); if (err) return err; @@ -5003,8 +4913,7 @@ static int selinux_socket_unix_may_send(struct socket *sock, ad.u.net = &net; ad.u.net->sk = other->sk; - return avc_has_perm(&selinux_state, - ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO, + return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO, &ad); } @@ -5019,8 +4928,7 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex, err = sel_netif_sid(ns, ifindex, &if_sid); if (err) return err; - err = avc_has_perm(&selinux_state, - peer_sid, if_sid, + err = avc_has_perm(peer_sid, if_sid, SECCLASS_NETIF, NETIF__INGRESS, ad); if (err) return err; @@ -5028,8 +4936,7 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex, err = sel_netnode_sid(addrp, family, &node_sid); if (err) return err; - return avc_has_perm(&selinux_state, - peer_sid, node_sid, + return avc_has_perm(peer_sid, node_sid, SECCLASS_NODE, NODE__RECVFROM, ad); } @@ -5052,8 +4959,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, return err; if (selinux_secmark_enabled()) { - err = avc_has_perm(&selinux_state, - sk_sid, skb->secmark, SECCLASS_PACKET, + err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, PACKET__RECV, &ad); if (err) return err; @@ -5118,8 +5024,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) selinux_netlbl_err(skb, family, err, 0); return err; } - err = avc_has_perm(&selinux_state, - sk_sid, peer_sid, SECCLASS_PEER, + err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, PEER__RECV, &ad); if (err) { selinux_netlbl_err(skb, family, err, 0); @@ -5128,8 +5033,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) } if (secmark_active) { - err = avc_has_perm(&selinux_state, - sk_sid, skb->secmark, SECCLASS_PACKET, + err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, PACKET__RECV, &ad); if (err) return err; @@ -5155,7 +5059,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, if (peer_sid == SECSID_NULL) return -ENOPROTOOPT; - err = security_sid_to_context(&selinux_state, peer_sid, &scontext, + err = security_sid_to_context(peer_sid, &scontext, &scontext_len); if (err) return err; @@ -5312,8 +5216,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc, ad.type = LSM_AUDIT_DATA_NET; ad.u.net = &net; ad.u.net->sk = asoc->base.sk; - err = avc_has_perm(&selinux_state, - sksec->peer_sid, asoc->peer_secid, + err = avc_has_perm(sksec->peer_sid, asoc->peer_secid, sksec->sclass, SCTP_SOCKET__ASSOCIATION, &ad); if (err) @@ -5534,8 +5437,7 @@ static int selinux_secmark_relabel_packet(u32 sid) __tsec = selinux_cred(current_cred()); tsid = __tsec->sid; - return avc_has_perm(&selinux_state, - tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, + return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL); } @@ -5584,8 +5486,7 @@ static int selinux_tun_dev_create(void) * connections unlike traditional sockets - check the TUN driver to * get a better understanding of why this socket is special */ - return avc_has_perm(&selinux_state, - sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE, + return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE, NULL); } @@ -5593,8 +5494,7 @@ static int selinux_tun_dev_attach_queue(void *security) { struct tun_security_struct *tunsec = security; - return avc_has_perm(&selinux_state, - current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET, + return avc_has_perm(current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__ATTACH_QUEUE, NULL); } @@ -5622,13 +5522,11 @@ static int selinux_tun_dev_open(void *security) u32 sid = current_sid(); int err; - err = avc_has_perm(&selinux_state, - sid, tunsec->sid, SECCLASS_TUN_SOCKET, + err = avc_has_perm(sid, tunsec->sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__RELABELFROM, NULL); if (err) return err; - err = avc_has_perm(&selinux_state, - sid, sid, SECCLASS_TUN_SOCKET, + err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__RELABELTO, NULL); if (err) return err; @@ -5682,8 +5580,7 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb, } if (secmark_active) - if (avc_has_perm(&selinux_state, - peer_sid, skb->secmark, + if (avc_has_perm(peer_sid, skb->secmark, SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) return NF_DROP; @@ -5763,8 +5660,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, return NF_DROP; if (selinux_secmark_enabled()) - if (avc_has_perm(&selinux_state, - sksec->sid, skb->secmark, + if (avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, PACKET__SEND, &ad)) return NF_DROP_ERR(-ECONNREFUSED); @@ -5889,8 +5785,7 @@ static unsigned int selinux_ip_postroute(void *priv, return NF_DROP; if (secmark_active) - if (avc_has_perm(&selinux_state, - peer_sid, skb->secmark, + if (avc_has_perm(peer_sid, skb->secmark, SECCLASS_PACKET, secmark_perm, &ad)) return NF_DROP_ERR(-ECONNREFUSED); @@ -5900,15 +5795,13 @@ static unsigned int selinux_ip_postroute(void *priv, if (sel_netif_sid(state->net, ifindex, &if_sid)) return NF_DROP; - if (avc_has_perm(&selinux_state, - peer_sid, if_sid, + if (avc_has_perm(peer_sid, if_sid, SECCLASS_NETIF, NETIF__EGRESS, &ad)) return NF_DROP_ERR(-ECONNREFUSED); if (sel_netnode_sid(addrp, family, &node_sid)) return NF_DROP; - if (avc_has_perm(&selinux_state, - peer_sid, node_sid, + if (avc_has_perm(peer_sid, node_sid, SECCLASS_NODE, NODE__SENDTO, &ad)) return NF_DROP_ERR(-ECONNREFUSED); } @@ -5953,8 +5846,8 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) sk->sk_protocol, nlh->nlmsg_type, secclass_map[sclass - 1].name, task_pid_nr(current), current->comm); - if (enforcing_enabled(&selinux_state) && - !security_get_allow_unknown(&selinux_state)) + if (enforcing_enabled() && + !security_get_allow_unknown()) return rc; rc = 0; } else if (rc == -ENOENT) { @@ -5993,8 +5886,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, ad.type = LSM_AUDIT_DATA_IPC; ad.u.ipc_id = ipc_perms->key; - return avc_has_perm(&selinux_state, - sid, isec->sid, isec->sclass, perms, &ad); + return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); } static int selinux_msg_msg_alloc_security(struct msg_msg *msg) @@ -6020,8 +5912,7 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq) ad.type = LSM_AUDIT_DATA_IPC; ad.u.ipc_id = msq->key; - return avc_has_perm(&selinux_state, - sid, isec->sid, SECCLASS_MSGQ, + return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, MSGQ__CREATE, &ad); } @@ -6036,8 +5927,7 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) ad.type = LSM_AUDIT_DATA_IPC; ad.u.ipc_id = msq->key; - return avc_has_perm(&selinux_state, - sid, isec->sid, SECCLASS_MSGQ, + return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, MSGQ__ASSOCIATE, &ad); } @@ -6050,8 +5940,7 @@ static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd) case IPC_INFO: case MSG_INFO: /* No specific object, just general system-wide information. */ - return avc_has_perm(&selinux_state, - current_sid(), SECINITSID_KERNEL, + return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case IPC_STAT: case MSG_STAT: @@ -6091,7 +5980,7 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m * Compute new sid based on current process and * message queue this message will be stored in */ - rc = security_transition_sid(&selinux_state, sid, isec->sid, + rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG, NULL, &msec->sid); if (rc) return rc; @@ -6101,18 +5990,15 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m ad.u.ipc_id = msq->key; /* Can this process write to the queue? */ - rc = avc_has_perm(&selinux_state, - sid, isec->sid, SECCLASS_MSGQ, + rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, MSGQ__WRITE, &ad); if (!rc) /* Can this process send the message */ - rc = avc_has_perm(&selinux_state, - sid, msec->sid, SECCLASS_MSG, + rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG, MSG__SEND, &ad); if (!rc) /* Can the message be put in the queue? */ - rc = avc_has_perm(&selinux_state, - msec->sid, isec->sid, SECCLASS_MSGQ, + rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ, MSGQ__ENQUEUE, &ad); return rc; @@ -6134,12 +6020,10 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m ad.type = LSM_AUDIT_DATA_IPC; ad.u.ipc_id = msq->key; - rc = avc_has_perm(&selinux_state, - sid, isec->sid, + rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, MSGQ__READ, &ad); if (!rc) - rc = avc_has_perm(&selinux_state, - sid, msec->sid, + rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG, MSG__RECEIVE, &ad); return rc; } @@ -6157,8 +6041,7 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp) ad.type = LSM_AUDIT_DATA_IPC; ad.u.ipc_id = shp->key; - return avc_has_perm(&selinux_state, - sid, isec->sid, SECCLASS_SHM, + return avc_has_perm(sid, isec->sid, SECCLASS_SHM, SHM__CREATE, &ad); } @@ -6173,8 +6056,7 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg) ad.type = LSM_AUDIT_DATA_IPC; ad.u.ipc_id = shp->key; - return avc_has_perm(&selinux_state, - sid, isec->sid, SECCLASS_SHM, + return avc_has_perm(sid, isec->sid, SECCLASS_SHM, SHM__ASSOCIATE, &ad); } @@ -6188,8 +6070,7 @@ static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd) case IPC_INFO: case SHM_INFO: /* No specific object, just general system-wide information. */ - return avc_has_perm(&selinux_state, - current_sid(), SECINITSID_KERNEL, + return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case IPC_STAT: case SHM_STAT: @@ -6240,8 +6121,7 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma) ad.type = LSM_AUDIT_DATA_IPC; ad.u.ipc_id = sma->key; - return avc_has_perm(&selinux_state, - sid, isec->sid, SECCLASS_SEM, + return avc_has_perm(sid, isec->sid, SECCLASS_SEM, SEM__CREATE, &ad); } @@ -6256,8 +6136,7 @@ static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg) ad.type = LSM_AUDIT_DATA_IPC; ad.u.ipc_id = sma->key; - return avc_has_perm(&selinux_state, - sid, isec->sid, SECCLASS_SEM, + return avc_has_perm(sid, isec->sid, SECCLASS_SEM, SEM__ASSOCIATE, &ad); } @@ -6271,8 +6150,7 @@ static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd) case IPC_INFO: case SEM_INFO: /* No specific object, just general system-wide information. */ - return avc_has_perm(&selinux_state, - current_sid(), SECINITSID_KERNEL, + return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); case GETPID: case GETNCNT: @@ -6359,8 +6237,7 @@ static int selinux_getprocattr(struct task_struct *p, __tsec = selinux_cred(__task_cred(p)); if (current != p) { - error = avc_has_perm(&selinux_state, - current_sid(), __tsec->sid, + error = avc_has_perm(current_sid(), __tsec->sid, SECCLASS_PROCESS, PROCESS__GETATTR, NULL); if (error) goto bad; @@ -6387,7 +6264,7 @@ static int selinux_getprocattr(struct task_struct *p, if (!sid) return 0; - error = security_sid_to_context(&selinux_state, sid, value, &len); + error = security_sid_to_context(sid, value, &len); if (error) return error; return len; @@ -6409,24 +6286,19 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) * Basic control over ability to set these attributes at all. */ if (!strcmp(name, "exec")) - error = avc_has_perm(&selinux_state, - mysid, mysid, SECCLASS_PROCESS, + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, PROCESS__SETEXEC, NULL); else if (!strcmp(name, "fscreate")) - error = avc_has_perm(&selinux_state, - mysid, mysid, SECCLASS_PROCESS, + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, PROCESS__SETFSCREATE, NULL); else if (!strcmp(name, "keycreate")) - error = avc_has_perm(&selinux_state, - mysid, mysid, SECCLASS_PROCESS, + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, PROCESS__SETKEYCREATE, NULL); else if (!strcmp(name, "sockcreate")) - error = avc_has_perm(&selinux_state, - mysid, mysid, SECCLASS_PROCESS, + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, PROCESS__SETSOCKCREATE, NULL); else if (!strcmp(name, "current")) - error = avc_has_perm(&selinux_state, - mysid, mysid, SECCLASS_PROCESS, + error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, PROCESS__SETCURRENT, NULL); else error = -EINVAL; @@ -6439,7 +6311,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) str[size-1] = 0; size--; } - error = security_context_to_sid(&selinux_state, value, size, + error = security_context_to_sid(value, size, &sid, GFP_KERNEL); if (error == -EINVAL && !strcmp(name, "fscreate")) { if (!has_cap_mac_admin(true)) { @@ -6463,9 +6335,8 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) return error; } - error = security_context_to_sid_force( - &selinux_state, - value, size, &sid); + error = security_context_to_sid_force(value, size, + &sid); } if (error) return error; @@ -6488,7 +6359,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) tsec->create_sid = sid; } else if (!strcmp(name, "keycreate")) { if (sid) { - error = avc_has_perm(&selinux_state, mysid, sid, + error = avc_has_perm(mysid, sid, SECCLASS_KEY, KEY__CREATE, NULL); if (error) goto abort_change; @@ -6503,15 +6374,13 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) /* Only allow single threaded processes to change context */ if (!current_is_single_threaded()) { - error = security_bounded_transition(&selinux_state, - tsec->sid, sid); + error = security_bounded_transition(tsec->sid, sid); if (error) goto abort_change; } /* Check permissions for the transition. */ - error = avc_has_perm(&selinux_state, - tsec->sid, sid, SECCLASS_PROCESS, + error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, PROCESS__DYNTRANSITION, NULL); if (error) goto abort_change; @@ -6520,8 +6389,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) Otherwise, leave SID unchanged and fail. */ ptsid = ptrace_parent_sid(); if (ptsid != 0) { - error = avc_has_perm(&selinux_state, - ptsid, sid, SECCLASS_PROCESS, + error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL); if (error) goto abort_change; @@ -6548,13 +6416,13 @@ static int selinux_ismaclabel(const char *name) static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { - return security_sid_to_context(&selinux_state, secid, + return security_sid_to_context(secid, secdata, seclen); } static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) { - return security_context_to_sid(&selinux_state, secdata, seclen, + return security_context_to_sid(secdata, seclen, secid, GFP_KERNEL); } @@ -6674,8 +6542,7 @@ static int selinux_key_permission(key_ref_t key_ref, key = key_ref_to_ptr(key_ref); ksec = key->security; - return avc_has_perm(&selinux_state, - sid, ksec->sid, SECCLASS_KEY, perm, NULL); + return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL); } static int selinux_key_getsecurity(struct key *key, char **_buffer) @@ -6685,7 +6552,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) unsigned len; int rc; - rc = security_sid_to_context(&selinux_state, ksec->sid, + rc = security_sid_to_context(ksec->sid, &context, &len); if (!rc) rc = len; @@ -6699,8 +6566,7 @@ static int selinux_watch_key(struct key *key) struct key_security_struct *ksec = key->security; u32 sid = current_sid(); - return avc_has_perm(&selinux_state, - sid, ksec->sid, SECCLASS_KEY, KEY__VIEW, NULL); + return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, KEY__VIEW, NULL); } #endif #endif @@ -6722,8 +6588,7 @@ static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val) ibpkey.subnet_prefix = subnet_prefix; ibpkey.pkey = pkey_val; ad.u.ibpkey = &ibpkey; - return avc_has_perm(&selinux_state, - sec->sid, sid, + return avc_has_perm(sec->sid, sid, SECCLASS_INFINIBAND_PKEY, INFINIBAND_PKEY__ACCESS, &ad); } @@ -6737,7 +6602,7 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name, struct ib_security_struct *sec = ib_sec; struct lsm_ibendport_audit ibendport; - err = security_ib_endport_sid(&selinux_state, dev_name, port_num, + err = security_ib_endport_sid(dev_name, port_num, &sid); if (err) @@ -6747,8 +6612,7 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name, ibendport.dev_name = dev_name; ibendport.port = port_num; ad.u.ibendport = &ibendport; - return avc_has_perm(&selinux_state, - sec->sid, sid, + return avc_has_perm(sec->sid, sid, SECCLASS_INFINIBAND_ENDPORT, INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad); } @@ -6781,13 +6645,11 @@ static int selinux_bpf(int cmd, union bpf_attr *attr, switch (cmd) { case BPF_MAP_CREATE: - ret = avc_has_perm(&selinux_state, - sid, sid, SECCLASS_BPF, BPF__MAP_CREATE, + ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE, NULL); break; case BPF_PROG_LOAD: - ret = avc_has_perm(&selinux_state, - sid, sid, SECCLASS_BPF, BPF__PROG_LOAD, + ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD, NULL); break; default: @@ -6827,16 +6689,14 @@ static int bpf_fd_pass(struct file *file, u32 sid) if (file->f_op == &bpf_map_fops) { map = file->private_data; bpfsec = map->security; - ret = avc_has_perm(&selinux_state, - sid, bpfsec->sid, SECCLASS_BPF, + ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, bpf_map_fmode_to_av(file->f_mode), NULL); if (ret) return ret; } else if (file->f_op == &bpf_prog_fops) { prog = file->private_data; bpfsec = prog->aux->security; - ret = avc_has_perm(&selinux_state, - sid, bpfsec->sid, SECCLASS_BPF, + ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, BPF__PROG_RUN, NULL); if (ret) return ret; @@ -6850,8 +6710,7 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode) struct bpf_security_struct *bpfsec; bpfsec = map->security; - return avc_has_perm(&selinux_state, - sid, bpfsec->sid, SECCLASS_BPF, + return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, bpf_map_fmode_to_av(fmode), NULL); } @@ -6861,8 +6720,7 @@ static int selinux_bpf_prog(struct bpf_prog *prog) struct bpf_security_struct *bpfsec; bpfsec = prog->aux->security; - return avc_has_perm(&selinux_state, - sid, bpfsec->sid, SECCLASS_BPF, + return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, BPF__PROG_RUN, NULL); } @@ -6911,7 +6769,7 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) } #endif -struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = { +struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { .lbs_cred = sizeof(struct task_security_struct), .lbs_file = sizeof(struct file_security_struct), .lbs_inode = sizeof(struct inode_security_struct), @@ -6936,7 +6794,7 @@ static int selinux_perf_event_open(struct perf_event_attr *attr, int type) else return -EINVAL; - return avc_has_perm(&selinux_state, sid, sid, SECCLASS_PERF_EVENT, + return avc_has_perm(sid, sid, SECCLASS_PERF_EVENT, requested, NULL); } @@ -6967,7 +6825,7 @@ static int selinux_perf_event_read(struct perf_event *event) struct perf_event_security_struct *perfsec = event->security; u32 sid = current_sid(); - return avc_has_perm(&selinux_state, sid, perfsec->sid, + return avc_has_perm(sid, perfsec->sid, SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL); } @@ -6976,7 +6834,7 @@ static int selinux_perf_event_write(struct perf_event *event) struct perf_event_security_struct *perfsec = event->security; u32 sid = current_sid(); - return avc_has_perm(&selinux_state, sid, perfsec->sid, + return avc_has_perm(sid, perfsec->sid, SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL); } #endif @@ -6991,7 +6849,7 @@ static int selinux_perf_event_write(struct perf_event *event) */ static int selinux_uring_override_creds(const struct cred *new) { - return avc_has_perm(&selinux_state, current_sid(), cred_sid(new), + return avc_has_perm(current_sid(), cred_sid(new), SECCLASS_IO_URING, IO_URING__OVERRIDE_CREDS, NULL); } @@ -7005,7 +6863,7 @@ static int selinux_uring_sqpoll(void) { int sid = current_sid(); - return avc_has_perm(&selinux_state, sid, sid, + return avc_has_perm(sid, sid, SECCLASS_IO_URING, IO_URING__SQPOLL, NULL); } @@ -7027,7 +6885,7 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd) ad.type = LSM_AUDIT_DATA_FILE; ad.u.file = file; - return avc_has_perm(&selinux_state, current_sid(), isec->sid, + return avc_has_perm(current_sid(), isec->sid, SECCLASS_IO_URING, IO_URING__CMD, &ad); } #endif /* CONFIG_IO_URING */ @@ -7047,7 +6905,7 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd) * safely. Breaking the ordering rules above might lead to NULL pointer derefs * when disabling SELinux at runtime. */ -static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { +static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder), @@ -7334,11 +7192,8 @@ static __init int selinux_init(void) pr_info("SELinux: Initializing.\n"); memset(&selinux_state, 0, sizeof(selinux_state)); - enforcing_set(&selinux_state, selinux_enforcing_boot); - if (CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE) - pr_err("SELinux: CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE is non-zero. This is deprecated and will be rejected in a future kernel release.\n"); - checkreqprot_set(&selinux_state, selinux_checkreqprot_boot); - selinux_avc_init(&selinux_state.avc); + enforcing_set(selinux_enforcing_boot); + selinux_avc_init(); mutex_init(&selinux_state.status_lock); mutex_init(&selinux_state.policy_mutex); @@ -7398,7 +7253,6 @@ DEFINE_LSM(selinux) = { }; #if defined(CONFIG_NETFILTER) - static const struct nf_hook_ops selinux_nf_ops[] = { { .hook = selinux_ip_postroute, @@ -7473,56 +7327,4 @@ static int __init selinux_nf_ip_init(void) return 0; } __initcall(selinux_nf_ip_init); - -#ifdef CONFIG_SECURITY_SELINUX_DISABLE -static void selinux_nf_ip_exit(void) -{ - pr_debug("SELinux: Unregistering netfilter hooks\n"); - - unregister_pernet_subsys(&selinux_net_ops); -} -#endif - -#else /* CONFIG_NETFILTER */ - -#ifdef CONFIG_SECURITY_SELINUX_DISABLE -#define selinux_nf_ip_exit() -#endif - #endif /* CONFIG_NETFILTER */ - -#ifdef CONFIG_SECURITY_SELINUX_DISABLE -int selinux_disable(struct selinux_state *state) -{ - if (selinux_initialized(state)) { - /* Not permitted after initial policy load. */ - return -EINVAL; - } - - if (selinux_disabled(state)) { - /* Only do this once. */ - return -EINVAL; - } - - selinux_mark_disabled(state); - - pr_info("SELinux: Disabled at runtime.\n"); - - /* - * Unregister netfilter hooks. - * Must be done before security_delete_hooks() to avoid breaking - * runtime disable. - */ - selinux_nf_ip_exit(); - - security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks)); - - /* Try to destroy the avc node cache */ - avc_disable(); - - /* Unregister selinuxfs. */ - exit_sel_fs(); - - return 0; -} -#endif diff --git a/security/selinux/ibpkey.c b/security/selinux/ibpkey.c index 5839ca7bb9c7..48f537b41c58 100644 --- a/security/selinux/ibpkey.c +++ b/security/selinux/ibpkey.c @@ -141,7 +141,7 @@ static int sel_ib_pkey_sid_slow(u64 subnet_prefix, u16 pkey_num, u32 *sid) return 0; } - ret = security_ib_pkey_sid(&selinux_state, subnet_prefix, pkey_num, + ret = security_ib_pkey_sid(subnet_prefix, pkey_num, sid); if (ret) goto out; diff --git a/security/selinux/ima.c b/security/selinux/ima.c index a915b89d55b0..7daf59667f59 100644 --- a/security/selinux/ima.c +++ b/security/selinux/ima.c @@ -15,12 +15,10 @@ /* * selinux_ima_collect_state - Read selinux configuration settings * - * @state: selinux_state - * * On success returns the configuration settings string. * On error, returns NULL. */ -static char *selinux_ima_collect_state(struct selinux_state *state) +static char *selinux_ima_collect_state(void) { const char *on = "=1;", *off = "=0;"; char *buf; @@ -39,26 +37,27 @@ static char *selinux_ima_collect_state(struct selinux_state *state) rc = strscpy(buf, "initialized", buf_len); WARN_ON(rc < 0); - rc = strlcat(buf, selinux_initialized(state) ? on : off, buf_len); + rc = strlcat(buf, selinux_initialized() ? on : off, buf_len); WARN_ON(rc >= buf_len); rc = strlcat(buf, "enforcing", buf_len); WARN_ON(rc >= buf_len); - rc = strlcat(buf, enforcing_enabled(state) ? on : off, buf_len); + rc = strlcat(buf, enforcing_enabled() ? on : off, buf_len); WARN_ON(rc >= buf_len); rc = strlcat(buf, "checkreqprot", buf_len); WARN_ON(rc >= buf_len); - rc = strlcat(buf, checkreqprot_get(state) ? on : off, buf_len); + rc = strlcat(buf, checkreqprot_get() ? on : off, buf_len); WARN_ON(rc >= buf_len); for (i = 0; i < __POLICYDB_CAP_MAX; i++) { rc = strlcat(buf, selinux_policycap_names[i], buf_len); WARN_ON(rc >= buf_len); - rc = strlcat(buf, state->policycap[i] ? on : off, buf_len); + rc = strlcat(buf, selinux_state.policycap[i] ? on : off, + buf_len); WARN_ON(rc >= buf_len); } @@ -67,19 +66,17 @@ static char *selinux_ima_collect_state(struct selinux_state *state) /* * selinux_ima_measure_state_locked - Measure SELinux state and hash of policy - * - * @state: selinux state struct */ -void selinux_ima_measure_state_locked(struct selinux_state *state) +void selinux_ima_measure_state_locked(void) { char *state_str = NULL; void *policy = NULL; size_t policy_len; int rc = 0; - lockdep_assert_held(&state->policy_mutex); + lockdep_assert_held(&selinux_state.policy_mutex); - state_str = selinux_ima_collect_state(state); + state_str = selinux_ima_collect_state(); if (!state_str) { pr_err("SELinux: %s: failed to read state.\n", __func__); return; @@ -94,10 +91,10 @@ void selinux_ima_measure_state_locked(struct selinux_state *state) /* * Measure SELinux policy only after initialization is completed. */ - if (!selinux_initialized(state)) + if (!selinux_initialized()) return; - rc = security_read_state_kernel(state, &policy, &policy_len); + rc = security_read_state_kernel(&policy, &policy_len); if (rc) { pr_err("SELinux: %s: failed to read policy %d.\n", __func__, rc); return; @@ -112,14 +109,12 @@ void selinux_ima_measure_state_locked(struct selinux_state *state) /* * selinux_ima_measure_state - Measure SELinux state and hash of policy - * - * @state: selinux state struct */ -void selinux_ima_measure_state(struct selinux_state *state) +void selinux_ima_measure_state(void) { - lockdep_assert_not_held(&state->policy_mutex); + lockdep_assert_not_held(&selinux_state.policy_mutex); - mutex_lock(&state->policy_mutex); - selinux_ima_measure_state_locked(state); - mutex_unlock(&state->policy_mutex); + mutex_lock(&selinux_state.policy_mutex); + selinux_ima_measure_state_locked(); + mutex_unlock(&selinux_state.policy_mutex); } diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 5525b94fd266..9301222c8e55 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -52,7 +52,6 @@ struct selinux_audit_data { u32 audited; u32 denied; int result; - struct selinux_state *state; } __randomize_layout; /* @@ -97,14 +96,12 @@ static inline u32 avc_audit_required(u32 requested, return audited; } -int slow_avc_audit(struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass, +int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, u32 audited, u32 denied, int result, struct common_audit_data *a); /** * avc_audit - Audit the granting or denial of permissions. - * @state: SELinux state * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class @@ -122,8 +119,7 @@ int slow_avc_audit(struct selinux_state *state, * be performed under a lock, to allow the lock to be released * before calling the auditing code. */ -static inline int avc_audit(struct selinux_state *state, - u32 ssid, u32 tsid, +static inline int avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct av_decision *avd, int result, @@ -133,30 +129,27 @@ static inline int avc_audit(struct selinux_state *state, audited = avc_audit_required(requested, avd, result, 0, &denied); if (likely(!audited)) return 0; - return slow_avc_audit(state, ssid, tsid, tclass, + return slow_avc_audit(ssid, tsid, tclass, requested, audited, denied, result, a); } #define AVC_STRICT 1 /* Ignore permissive mode. */ #define AVC_EXTENDED_PERMS 2 /* update extended permissions */ -int avc_has_perm_noaudit(struct selinux_state *state, - u32 ssid, u32 tsid, +int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested, unsigned flags, struct av_decision *avd); -int avc_has_perm(struct selinux_state *state, - u32 ssid, u32 tsid, +int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata); -int avc_has_extended_perms(struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass, u32 requested, +int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, u8 driver, u8 perm, struct common_audit_data *ad); -u32 avc_policy_seqno(struct selinux_state *state); +u32 avc_policy_seqno(void); #define AVC_CALLBACK_GRANT 1 #define AVC_CALLBACK_TRY_REVOKE 2 @@ -171,11 +164,9 @@ u32 avc_policy_seqno(struct selinux_state *state); int avc_add_callback(int (*callback)(u32 event), u32 events); /* Exported to selinuxfs */ -struct selinux_avc; -int avc_get_hash_stats(struct selinux_avc *avc, char *page); -unsigned int avc_get_cache_threshold(struct selinux_avc *avc); -void avc_set_cache_threshold(struct selinux_avc *avc, - unsigned int cache_threshold); +int avc_get_hash_stats(char *page); +unsigned int avc_get_cache_threshold(void); +void avc_set_cache_threshold(unsigned int cache_threshold); /* Attempt to free avc node cache */ void avc_disable(void); diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h index 42912c917fd4..b9668be7b443 100644 --- a/security/selinux/include/avc_ss.h +++ b/security/selinux/include/avc_ss.h @@ -9,8 +9,7 @@ #include <linux/types.h> -struct selinux_avc; -int avc_ss_reset(struct selinux_avc *avc, u32 seqno); +int avc_ss_reset(u32 seqno); /* Class/perm mapping support */ struct security_class_mapping { diff --git a/security/selinux/include/conditional.h b/security/selinux/include/conditional.h index b09343346e3f..693a654714eb 100644 --- a/security/selinux/include/conditional.h +++ b/security/selinux/include/conditional.h @@ -16,8 +16,8 @@ int security_get_bools(struct selinux_policy *policy, u32 *len, char ***names, int **values); -int security_set_bools(struct selinux_state *state, u32 len, int *values); +int security_set_bools(u32 len, int *values); -int security_get_bool_value(struct selinux_state *state, u32 index); +int security_get_bool_value(u32 index); #endif diff --git a/security/selinux/include/ima.h b/security/selinux/include/ima.h index 75ca92b4a462..05e04172c86d 100644 --- a/security/selinux/include/ima.h +++ b/security/selinux/include/ima.h @@ -14,15 +14,13 @@ #include "security.h" #ifdef CONFIG_IMA -extern void selinux_ima_measure_state(struct selinux_state *selinux_state); -extern void selinux_ima_measure_state_locked( - struct selinux_state *selinux_state); +extern void selinux_ima_measure_state(void); +extern void selinux_ima_measure_state_locked(void); #else -static inline void selinux_ima_measure_state(struct selinux_state *selinux_state) +static inline void selinux_ima_measure_state(void) { } -static inline void selinux_ima_measure_state_locked( - struct selinux_state *selinux_state) +static inline void selinux_ima_measure_state_locked(void) { } #endif diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 393aff41d3ef..8746fafeb778 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -86,94 +86,65 @@ extern int selinux_enabled_boot; /* limitation of boundary depth */ #define POLICYDB_BOUNDS_MAXDEPTH 4 -struct selinux_avc; struct selinux_policy; struct selinux_state { -#ifdef CONFIG_SECURITY_SELINUX_DISABLE - bool disabled; -#endif #ifdef CONFIG_SECURITY_SELINUX_DEVELOP bool enforcing; #endif - bool checkreqprot; bool initialized; bool policycap[__POLICYDB_CAP_MAX]; struct page *status_page; struct mutex status_lock; - struct selinux_avc *avc; struct selinux_policy __rcu *policy; struct mutex policy_mutex; } __randomize_layout; -void selinux_avc_init(struct selinux_avc **avc); +void selinux_avc_init(void); extern struct selinux_state selinux_state; -static inline bool selinux_initialized(const struct selinux_state *state) +static inline bool selinux_initialized(void) { /* do a synchronized load to avoid race conditions */ - return smp_load_acquire(&state->initialized); + return smp_load_acquire(&selinux_state.initialized); } -static inline void selinux_mark_initialized(struct selinux_state *state) +static inline void selinux_mark_initialized(void) { /* do a synchronized write to avoid race conditions */ - smp_store_release(&state->initialized, true); + smp_store_release(&selinux_state.initialized, true); } #ifdef CONFIG_SECURITY_SELINUX_DEVELOP -static inline bool enforcing_enabled(struct selinux_state *state) +static inline bool enforcing_enabled(void) { - return READ_ONCE(state->enforcing); + return READ_ONCE(selinux_state.enforcing); } -static inline void enforcing_set(struct selinux_state *state, bool value) +static inline void enforcing_set(bool value) { - WRITE_ONCE(state->enforcing, value); + WRITE_ONCE(selinux_state.enforcing, value); } #else -static inline bool enforcing_enabled(struct selinux_state *state) +static inline bool enforcing_enabled(void) { return true; } -static inline void enforcing_set(struct selinux_state *state, bool value) +static inline void enforcing_set(bool value) { } #endif -static inline bool checkreqprot_get(const struct selinux_state *state) -{ - return READ_ONCE(state->checkreqprot); -} - -static inline void checkreqprot_set(struct selinux_state *state, bool value) +static inline bool checkreqprot_get(void) { - if (value) - pr_err("SELinux: https://github.com/SELinuxProject/selinux-kernel/wiki/DEPRECATE-checkreqprot\n"); - WRITE_ONCE(state->checkreqprot, value); + /* non-zero/true checkreqprot values are no longer supported */ + return 0; } -#ifdef CONFIG_SECURITY_SELINUX_DISABLE -static inline bool selinux_disabled(struct selinux_state *state) -{ - return READ_ONCE(state->disabled); -} - -static inline void selinux_mark_disabled(struct selinux_state *state) -{ - WRITE_ONCE(state->disabled, true); -} -#else -static inline bool selinux_disabled(struct selinux_state *state) -{ - return false; -} -#endif - static inline bool selinux_policycap_netpeer(void) { struct selinux_state *state = &selinux_state; @@ -237,20 +208,14 @@ struct selinux_load_state { struct selinux_policy_convert_data *convert_data; }; -int security_mls_enabled(struct selinux_state *state); -int security_load_policy(struct selinux_state *state, - void *data, size_t len, +int security_mls_enabled(void); +int security_load_policy(void *data, size_t len, struct selinux_load_state *load_state); -void selinux_policy_commit(struct selinux_state *state, - struct selinux_load_state *load_state); -void selinux_policy_cancel(struct selinux_state *state, - struct selinux_load_state *load_state); -int security_read_policy(struct selinux_state *state, - void **data, size_t *len); -int security_read_state_kernel(struct selinux_state *state, - void **data, size_t *len); -int security_policycap_supported(struct selinux_state *state, - unsigned int req_cap); +void selinux_policy_commit(struct selinux_load_state *load_state); +void selinux_policy_cancel(struct selinux_load_state *load_state); +int security_read_policy(void **data, size_t *len); +int security_read_state_kernel(void **data, size_t *len); +int security_policycap_supported(unsigned int req_cap); #define SEL_VEC_MAX 32 struct av_decision { @@ -287,94 +252,68 @@ struct extended_perms { /* definitions of av_decision.flags */ #define AVD_FLAGS_PERMISSIVE 0x0001 -void security_compute_av(struct selinux_state *state, - u32 ssid, u32 tsid, +void security_compute_av(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd, struct extended_perms *xperms); -void security_compute_xperms_decision(struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass, +void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, u8 driver, struct extended_perms_decision *xpermd); -void security_compute_av_user(struct selinux_state *state, - u32 ssid, u32 tsid, +void security_compute_av_user(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd); -int security_transition_sid(struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass, +int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, const struct qstr *qstr, u32 *out_sid); -int security_transition_sid_user(struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass, +int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, const char *objname, u32 *out_sid); -int security_member_sid(struct selinux_state *state, u32 ssid, u32 tsid, - u16 tclass, u32 *out_sid); +int security_member_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid); -int security_change_sid(struct selinux_state *state, u32 ssid, u32 tsid, - u16 tclass, u32 *out_sid); +int security_change_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid); -int security_sid_to_context(struct selinux_state *state, u32 sid, - char **scontext, u32 *scontext_len); +int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len); -int security_sid_to_context_force(struct selinux_state *state, - u32 sid, char **scontext, u32 *scontext_len); +int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len); -int security_sid_to_context_inval(struct selinux_state *state, - u32 sid, char **scontext, u32 *scontext_len); +int security_sid_to_context_inval(u32 sid, char **scontext, u32 *scontext_len); -int security_context_to_sid(struct selinux_state *state, - const char *scontext, u32 scontext_len, +int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *out_sid, gfp_t gfp); -int security_context_str_to_sid(struct selinux_state *state, - const char *scontext, u32 *out_sid, gfp_t gfp); +int security_context_str_to_sid(const char *scontext, u32 *out_sid, gfp_t gfp); -int security_context_to_sid_default(struct selinux_state *state, - const char *scontext, u32 scontext_len, +int security_context_to_sid_default(const char *scontext, u32 scontext_len, u32 *out_sid, u32 def_sid, gfp_t gfp_flags); -int security_context_to_sid_force(struct selinux_state *state, - const char *scontext, u32 scontext_len, +int security_context_to_sid_force(const char *scontext, u32 scontext_len, u32 *sid); -int security_get_user_sids(struct selinux_state *state, - u32 callsid, char *username, - u32 **sids, u32 *nel); +int security_get_user_sids(u32 callsid, char *username, u32 **sids, u32 *nel); -int security_port_sid(struct selinux_state *state, - u8 protocol, u16 port, u32 *out_sid); +int security_port_sid(u8 protocol, u16 port, u32 *out_sid); -int security_ib_pkey_sid(struct selinux_state *state, - u64 subnet_prefix, u16 pkey_num, u32 *out_sid); +int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid); -int security_ib_endport_sid(struct selinux_state *state, - const char *dev_name, u8 port_num, u32 *out_sid); +int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid); -int security_netif_sid(struct selinux_state *state, - char *name, u32 *if_sid); +int security_netif_sid(char *name, u32 *if_sid); -int security_node_sid(struct selinux_state *state, - u16 domain, void *addr, u32 addrlen, +int security_node_sid(u16 domain, void *addr, u32 addrlen, u32 *out_sid); -int security_validate_transition(struct selinux_state *state, - u32 oldsid, u32 newsid, u32 tasksid, +int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, u16 tclass); -int security_validate_transition_user(struct selinux_state *state, - u32 oldsid, u32 newsid, u32 tasksid, +int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid, u16 tclass); -int security_bounded_transition(struct selinux_state *state, - u32 oldsid, u32 newsid); +int security_bounded_transition(u32 oldsid, u32 newsid); -int security_sid_mls_copy(struct selinux_state *state, - u32 sid, u32 mls_sid, u32 *new_sid); +int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); -int security_net_peersid_resolve(struct selinux_state *state, - u32 nlbl_sid, u32 nlbl_type, +int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, u32 xfrm_sid, u32 *peer_sid); @@ -382,8 +321,8 @@ int security_get_classes(struct selinux_policy *policy, char ***classes, int *nclasses); int security_get_permissions(struct selinux_policy *policy, char *class, char ***perms, int *nperms); -int security_get_reject_unknown(struct selinux_state *state); -int security_get_allow_unknown(struct selinux_state *state); +int security_get_reject_unknown(void); +int security_get_allow_unknown(void); #define SECURITY_FS_USE_XATTR 1 /* use xattr */ #define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */ @@ -394,10 +333,9 @@ int security_get_allow_unknown(struct selinux_state *state); #define SECURITY_FS_USE_NATIVE 7 /* use native label support */ #define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */ -int security_fs_use(struct selinux_state *state, struct super_block *sb); +int security_fs_use(struct super_block *sb); -int security_genfs_sid(struct selinux_state *state, - const char *fstype, const char *path, u16 sclass, +int security_genfs_sid(const char *fstype, const char *path, u16 sclass, u32 *sid); int selinux_policy_genfs_sid(struct selinux_policy *policy, @@ -405,23 +343,19 @@ int selinux_policy_genfs_sid(struct selinux_policy *policy, u32 *sid); #ifdef CONFIG_NETLABEL -int security_netlbl_secattr_to_sid(struct selinux_state *state, - struct netlbl_lsm_secattr *secattr, +int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, u32 *sid); -int security_netlbl_sid_to_secattr(struct selinux_state *state, - u32 sid, +int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr); #else -static inline int security_netlbl_secattr_to_sid(struct selinux_state *state, - struct netlbl_lsm_secattr *secattr, +static inline int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, u32 *sid) { return -EIDRM; } -static inline int security_netlbl_sid_to_secattr(struct selinux_state *state, - u32 sid, +static inline int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) { return -ENOENT; @@ -433,7 +367,7 @@ const char *security_get_initial_sid_context(u32 sid); /* * status notifier using mmap interface */ -extern struct page *selinux_kernel_status_page(struct selinux_state *state); +extern struct page *selinux_kernel_status_page(void); #define SELINUX_KERNEL_STATUS_VERSION 1 struct selinux_kernel_status { @@ -447,12 +381,9 @@ struct selinux_kernel_status { */ } __packed; -extern void selinux_status_update_setenforce(struct selinux_state *state, - int enforcing); -extern void selinux_status_update_policyload(struct selinux_state *state, - int seqno); +extern void selinux_status_update_setenforce(int enforcing); +extern void selinux_status_update_policyload(int seqno); extern void selinux_complete_init(void); -extern int selinux_disable(struct selinux_state *state); extern void exit_sel_fs(void); extern struct path selinux_null; extern void selnl_notify_setenforce(int val); @@ -462,6 +393,6 @@ extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); extern void avtab_cache_init(void); extern void ebitmap_cache_init(void); extern void hashtab_cache_init(void); -extern int security_sidtab_hash_stats(struct selinux_state *state, char *page); +extern int security_sidtab_hash_stats(char *page); #endif /* _SELINUX_SECURITY_H_ */ diff --git a/security/selinux/netif.c b/security/selinux/netif.c index 1ab03efe7494..adbe9bea2d26 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c @@ -153,7 +153,7 @@ static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid) goto out; } - ret = security_netif_sid(&selinux_state, dev->name, sid); + ret = security_netif_sid(dev->name, sid); if (ret != 0) goto out; new = kzalloc(sizeof(*new), GFP_ATOMIC); diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 1321f15799e2..767c670d33ea 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -46,7 +46,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, { int rc; - rc = security_netlbl_secattr_to_sid(&selinux_state, secattr, sid); + rc = security_netlbl_secattr_to_sid(secattr, sid); if (rc == 0 && (secattr->flags & NETLBL_SECATTR_CACHEABLE) && (secattr->flags & NETLBL_SECATTR_CACHE)) @@ -77,8 +77,7 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) secattr = netlbl_secattr_alloc(GFP_ATOMIC); if (secattr == NULL) return NULL; - rc = security_netlbl_sid_to_secattr(&selinux_state, sksec->sid, - secattr); + rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); if (rc != 0) { netlbl_secattr_free(secattr); return NULL; @@ -245,8 +244,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, if (secattr == NULL) { secattr = &secattr_storage; netlbl_secattr_init(secattr); - rc = security_netlbl_sid_to_secattr(&selinux_state, sid, - secattr); + rc = security_netlbl_sid_to_secattr(sid, secattr); if (rc != 0) goto skbuff_setsid_return; } @@ -283,8 +281,7 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc, return 0; netlbl_secattr_init(&secattr); - rc = security_netlbl_sid_to_secattr(&selinux_state, - asoc->secid, &secattr); + rc = security_netlbl_sid_to_secattr(asoc->secid, &secattr); if (rc != 0) goto assoc_request_return; @@ -332,8 +329,7 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family) return 0; netlbl_secattr_init(&secattr); - rc = security_netlbl_sid_to_secattr(&selinux_state, req->secid, - &secattr); + rc = security_netlbl_sid_to_secattr(req->secid, &secattr); if (rc != 0) goto inet_conn_request_return; rc = netlbl_req_setattr(req, &secattr); @@ -463,8 +459,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, perm = RAWIP_SOCKET__RECVFROM; } - rc = avc_has_perm(&selinux_state, - sksec->sid, nlbl_sid, sksec->sclass, perm, ad); + rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad); if (rc == 0) return 0; diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 0ac7df9a9367..5c8c77e50aad 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c @@ -204,13 +204,13 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) new = kzalloc(sizeof(*new), GFP_ATOMIC); switch (family) { case PF_INET: - ret = security_node_sid(&selinux_state, PF_INET, + ret = security_node_sid(PF_INET, addr, sizeof(struct in_addr), sid); if (new) new->nsec.addr.ipv4 = *(__be32 *)addr; break; case PF_INET6: - ret = security_node_sid(&selinux_state, PF_INET6, + ret = security_node_sid(PF_INET6, addr, sizeof(struct in6_addr), sid); if (new) new->nsec.addr.ipv6 = *(struct in6_addr *)addr; diff --git a/security/selinux/netport.c b/security/selinux/netport.c index 8eec6347cf01..2e22ad9c2bd0 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c @@ -148,7 +148,7 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) return 0; } - ret = security_port_sid(&selinux_state, protocol, pnum, sid); + ret = security_port_sid(protocol, pnum, sid); if (ret != 0) goto out; new = kzalloc(sizeof(*new), GFP_ATOMIC); diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 18498979a640..69a583b91fc5 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -77,7 +77,6 @@ struct selinux_fs_info { bool policy_opened; struct dentry *policycap_dir; unsigned long last_ino; - struct selinux_state *state; struct super_block *sb; }; @@ -90,7 +89,6 @@ static int selinux_fs_info_create(struct super_block *sb) return -ENOMEM; fsi->last_ino = SEL_INO_NEXT - 1; - fsi->state = &selinux_state; fsi->sb = sb; sb->s_fs_info = fsi; return 0; @@ -125,12 +123,11 @@ static void selinux_fs_info_free(struct super_block *sb) static ssize_t sel_read_enforce(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info; char tmpbuf[TMPBUFLEN]; ssize_t length; length = scnprintf(tmpbuf, TMPBUFLEN, "%d", - enforcing_enabled(fsi->state)); + enforcing_enabled()); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); } @@ -139,8 +136,6 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char *page = NULL; ssize_t length; int old_value, new_value; @@ -162,10 +157,9 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, new_value = !!new_value; - old_value = enforcing_enabled(state); + old_value = enforcing_enabled(); if (new_value != old_value) { - length = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__SETENFORCE, NULL); if (length) @@ -176,15 +170,15 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, new_value, old_value, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); - enforcing_set(state, new_value); + enforcing_set(new_value); if (new_value) - avc_ss_reset(state->avc, 0); + avc_ss_reset(0); selnl_notify_setenforce(new_value); - selinux_status_update_setenforce(state, new_value); + selinux_status_update_setenforce(new_value); if (!new_value) call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL); - selinux_ima_measure_state(state); + selinux_ima_measure_state(); } length = count; out: @@ -204,14 +198,12 @@ static const struct file_operations sel_enforce_ops = { static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char tmpbuf[TMPBUFLEN]; ssize_t length; ino_t ino = file_inode(filp)->i_ino; int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ? - security_get_reject_unknown(state) : - !security_get_allow_unknown(state); + security_get_reject_unknown() : + !security_get_allow_unknown(); length = scnprintf(tmpbuf, TMPBUFLEN, "%d", handle_unknown); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); @@ -224,8 +216,7 @@ static const struct file_operations sel_handle_unknown_ops = { static int sel_open_handle_status(struct inode *inode, struct file *filp) { - struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info; - struct page *status = selinux_kernel_status_page(fsi->state); + struct page *status = selinux_kernel_status_page(); if (!status) return -ENOMEM; @@ -276,25 +267,13 @@ static const struct file_operations sel_handle_status_ops = { .llseek = generic_file_llseek, }; -#ifdef CONFIG_SECURITY_SELINUX_DISABLE static ssize_t sel_write_disable(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; char *page; ssize_t length; int new_value; - int enforcing; - - /* NOTE: we are now officially considering runtime disable as - * deprecated, and using it will become increasingly painful - * (e.g. sleeping/blocking) as we progress through future - * kernel releases until eventually it is removed - */ - pr_err("SELinux: Runtime disable is deprecated, use selinux=0 on the kernel cmdline.\n"); - pr_err("SELinux: https://github.com/SELinuxProject/selinux-kernel/wiki/DEPRECATE-runtime-disable\n"); - ssleep(15); if (count >= PAGE_SIZE) return -ENOMEM; @@ -307,31 +286,21 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf, if (IS_ERR(page)) return PTR_ERR(page); - length = -EINVAL; - if (sscanf(page, "%d", &new_value) != 1) + if (sscanf(page, "%d", &new_value) != 1) { + length = -EINVAL; goto out; + } + length = count; if (new_value) { - enforcing = enforcing_enabled(fsi->state); - length = selinux_disable(fsi->state); - if (length) - goto out; - audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS, - "enforcing=%d old_enforcing=%d auid=%u ses=%u" - " enabled=0 old-enabled=1 lsm=selinux res=1", - enforcing, enforcing, - from_kuid(&init_user_ns, audit_get_loginuid(current)), - audit_get_sessionid(current)); + pr_err("SELinux: https://github.com/SELinuxProject/selinux-kernel/wiki/DEPRECATE-runtime-disable\n"); + pr_err("SELinux: Runtime disable is not supported, use selinux=0 on the kernel cmdline.\n"); } - length = count; out: kfree(page); return length; } -#else -#define sel_write_disable NULL -#endif static const struct file_operations sel_disable_ops = { .write = sel_write_disable, @@ -375,12 +344,11 @@ static void sel_remove_entries(struct dentry *de); static ssize_t sel_read_mls(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info; char tmpbuf[TMPBUFLEN]; ssize_t length; length = scnprintf(tmpbuf, TMPBUFLEN, "%d", - security_mls_enabled(fsi->state)); + security_mls_enabled()); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); } @@ -397,16 +365,14 @@ struct policy_load_memory { static int sel_open_policy(struct inode *inode, struct file *filp) { struct selinux_fs_info *fsi = inode->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; struct policy_load_memory *plm = NULL; int rc; BUG_ON(filp->private_data); - mutex_lock(&fsi->state->policy_mutex); + mutex_lock(&selinux_state.policy_mutex); - rc = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + rc = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL); if (rc) goto err; @@ -420,7 +386,7 @@ static int sel_open_policy(struct inode *inode, struct file *filp) if (!plm) goto err; - rc = security_read_policy(state, &plm->data, &plm->len); + rc = security_read_policy(&plm->data, &plm->len); if (rc) goto err; @@ -434,11 +400,11 @@ static int sel_open_policy(struct inode *inode, struct file *filp) filp->private_data = plm; - mutex_unlock(&fsi->state->policy_mutex); + mutex_unlock(&selinux_state.policy_mutex); return 0; err: - mutex_unlock(&fsi->state->policy_mutex); + mutex_unlock(&selinux_state.policy_mutex); if (plm) vfree(plm->data); @@ -467,8 +433,7 @@ static ssize_t sel_read_policy(struct file *filp, char __user *buf, struct policy_load_memory *plm = filp->private_data; int ret; - ret = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + ret = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL); if (ret) return ret; @@ -621,10 +586,9 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, ssize_t length; void *data = NULL; - mutex_lock(&fsi->state->policy_mutex); + mutex_lock(&selinux_state.policy_mutex); - length = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL); if (length) goto out; @@ -643,7 +607,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, if (copy_from_user(data, buf, count) != 0) goto out; - length = security_load_policy(fsi->state, data, count, &load_state); + length = security_load_policy(data, count, &load_state); if (length) { pr_warn_ratelimited("SELinux: failed to load policy\n"); goto out; @@ -652,11 +616,11 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, length = sel_make_policy_nodes(fsi, load_state.policy); if (length) { pr_warn_ratelimited("SELinux: failed to initialize selinuxfs\n"); - selinux_policy_cancel(fsi->state, &load_state); + selinux_policy_cancel(&load_state); goto out; } - selinux_policy_commit(fsi->state, &load_state); + selinux_policy_commit(&load_state); length = count; @@ -665,7 +629,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, from_kuid(&init_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); out: - mutex_unlock(&fsi->state->policy_mutex); + mutex_unlock(&selinux_state.policy_mutex); vfree(data); return length; } @@ -677,23 +641,20 @@ static const struct file_operations sel_load_ops = { static ssize_t sel_write_context(struct file *file, char *buf, size_t size) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char *canon = NULL; u32 sid, len; ssize_t length; - length = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL); if (length) goto out; - length = security_context_to_sid(state, buf, size, &sid, GFP_KERNEL); + length = security_context_to_sid(buf, size, &sid, GFP_KERNEL); if (length) goto out; - length = security_sid_to_context(state, sid, &canon, &len); + length = security_sid_to_context(sid, &canon, &len); if (length) goto out; @@ -714,25 +675,22 @@ out: static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info; char tmpbuf[TMPBUFLEN]; ssize_t length; length = scnprintf(tmpbuf, TMPBUFLEN, "%u", - checkreqprot_get(fsi->state)); + checkreqprot_get()); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); } static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; char *page; ssize_t length; unsigned int new_value; - length = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT, NULL); if (length) @@ -749,24 +707,21 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, if (IS_ERR(page)) return PTR_ERR(page); - length = -EINVAL; - if (sscanf(page, "%u", &new_value) != 1) + if (sscanf(page, "%u", &new_value) != 1) { + length = -EINVAL; goto out; + } + length = count; if (new_value) { char comm[sizeof(current->comm)]; memcpy(comm, current->comm, sizeof(comm)); - pr_err("SELinux: %s (%d) set checkreqprot to 1. This is deprecated and will be rejected in a future kernel release.\n", + pr_err("SELinux: %s (%d) set checkreqprot to 1. This is no longer supported.\n", comm, current->pid); } - checkreqprot_set(fsi->state, (new_value ? 1 : 0)); - if (new_value) - ssleep(15); - length = count; - - selinux_ima_measure_state(fsi->state); + selinux_ima_measure_state(); out: kfree(page); @@ -782,16 +737,13 @@ static ssize_t sel_write_validatetrans(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char *oldcon = NULL, *newcon = NULL, *taskcon = NULL; char *req = NULL; u32 osid, nsid, tsid; u16 tclass; int rc; - rc = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + rc = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL); if (rc) goto out; @@ -829,19 +781,19 @@ static ssize_t sel_write_validatetrans(struct file *file, if (sscanf(req, "%s %s %hu %s", oldcon, newcon, &tclass, taskcon) != 4) goto out; - rc = security_context_str_to_sid(state, oldcon, &osid, GFP_KERNEL); + rc = security_context_str_to_sid(oldcon, &osid, GFP_KERNEL); if (rc) goto out; - rc = security_context_str_to_sid(state, newcon, &nsid, GFP_KERNEL); + rc = security_context_str_to_sid(newcon, &nsid, GFP_KERNEL); if (rc) goto out; - rc = security_context_str_to_sid(state, taskcon, &tsid, GFP_KERNEL); + rc = security_context_str_to_sid(taskcon, &tsid, GFP_KERNEL); if (rc) goto out; - rc = security_validate_transition_user(state, osid, nsid, tsid, tclass); + rc = security_validate_transition_user(osid, nsid, tsid, tclass); if (!rc) rc = count; out: @@ -911,16 +863,13 @@ static const struct file_operations transaction_ops = { static ssize_t sel_write_access(struct file *file, char *buf, size_t size) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char *scon = NULL, *tcon = NULL; u32 ssid, tsid; u16 tclass; struct av_decision avd; ssize_t length; - length = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL); if (length) goto out; @@ -939,15 +888,15 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out; - length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL); + length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL); if (length) goto out; - length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL); + length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL); if (length) goto out; - security_compute_av_user(state, ssid, tsid, tclass, &avd); + security_compute_av_user(ssid, tsid, tclass, &avd); length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%x %x %x %x %u %x", @@ -962,8 +911,6 @@ out: static ssize_t sel_write_create(struct file *file, char *buf, size_t size) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char *scon = NULL, *tcon = NULL; char *namebuf = NULL, *objname = NULL; u32 ssid, tsid, newsid; @@ -973,8 +920,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) u32 len; int nargs; - length = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, NULL); if (length) @@ -1030,20 +976,20 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) objname = namebuf; } - length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL); + length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL); if (length) goto out; - length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL); + length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL); if (length) goto out; - length = security_transition_sid_user(state, ssid, tsid, tclass, + length = security_transition_sid_user(ssid, tsid, tclass, objname, &newsid); if (length) goto out; - length = security_sid_to_context(state, newsid, &newcon, &len); + length = security_sid_to_context(newsid, &newcon, &len); if (length) goto out; @@ -1066,8 +1012,6 @@ out: static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char *scon = NULL, *tcon = NULL; u32 ssid, tsid, newsid; u16 tclass; @@ -1075,8 +1019,7 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) char *newcon = NULL; u32 len; - length = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, NULL); if (length) @@ -1096,19 +1039,19 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out; - length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL); + length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL); if (length) goto out; - length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL); + length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL); if (length) goto out; - length = security_change_sid(state, ssid, tsid, tclass, &newsid); + length = security_change_sid(ssid, tsid, tclass, &newsid); if (length) goto out; - length = security_sid_to_context(state, newsid, &newcon, &len); + length = security_sid_to_context(newsid, &newcon, &len); if (length) goto out; @@ -1127,8 +1070,6 @@ out: static ssize_t sel_write_user(struct file *file, char *buf, size_t size) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char *con = NULL, *user = NULL, *ptr; u32 sid, *sids = NULL; ssize_t length; @@ -1136,8 +1077,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) int i, rc; u32 len, nsids; - length = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__COMPUTE_USER, NULL); if (length) @@ -1157,18 +1097,18 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) if (sscanf(buf, "%s %s", con, user) != 2) goto out; - length = security_context_str_to_sid(state, con, &sid, GFP_KERNEL); + length = security_context_str_to_sid(con, &sid, GFP_KERNEL); if (length) goto out; - length = security_get_user_sids(state, sid, user, &sids, &nsids); + length = security_get_user_sids(sid, user, &sids, &nsids); if (length) goto out; length = sprintf(buf, "%u", nsids) + 1; ptr = buf + length; for (i = 0; i < nsids; i++) { - rc = security_sid_to_context(state, sids[i], &newcon, &len); + rc = security_sid_to_context(sids[i], &newcon, &len); if (rc) { length = rc; goto out; @@ -1192,8 +1132,6 @@ out: static ssize_t sel_write_member(struct file *file, char *buf, size_t size) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char *scon = NULL, *tcon = NULL; u32 ssid, tsid, newsid; u16 tclass; @@ -1201,8 +1139,7 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) char *newcon = NULL; u32 len; - length = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER, NULL); if (length) @@ -1222,19 +1159,19 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out; - length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL); + length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL); if (length) goto out; - length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL); + length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL); if (length) goto out; - length = security_member_sid(state, ssid, tsid, tclass, &newsid); + length = security_member_sid(ssid, tsid, tclass, &newsid); if (length) goto out; - length = security_sid_to_context(state, newsid, &newcon, &len); + length = security_sid_to_context(newsid, &newcon, &len); if (length) goto out; @@ -1276,7 +1213,7 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK; const char *name = filep->f_path.dentry->d_name.name; - mutex_lock(&fsi->state->policy_mutex); + mutex_lock(&selinux_state.policy_mutex); ret = -EINVAL; if (index >= fsi->bool_num || strcmp(name, @@ -1288,21 +1225,21 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, if (!page) goto out_unlock; - cur_enforcing = security_get_bool_value(fsi->state, index); + cur_enforcing = security_get_bool_value(index); if (cur_enforcing < 0) { ret = cur_enforcing; goto out_unlock; } length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, fsi->bool_pending_values[index]); - mutex_unlock(&fsi->state->policy_mutex); + mutex_unlock(&selinux_state.policy_mutex); ret = simple_read_from_buffer(buf, count, ppos, page, length); out_free: free_page((unsigned long)page); return ret; out_unlock: - mutex_unlock(&fsi->state->policy_mutex); + mutex_unlock(&selinux_state.policy_mutex); goto out_free; } @@ -1327,10 +1264,9 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, if (IS_ERR(page)) return PTR_ERR(page); - mutex_lock(&fsi->state->policy_mutex); + mutex_lock(&selinux_state.policy_mutex); - length = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__SETBOOL, NULL); if (length) @@ -1352,7 +1288,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, length = count; out: - mutex_unlock(&fsi->state->policy_mutex); + mutex_unlock(&selinux_state.policy_mutex); kfree(page); return length; } @@ -1383,10 +1319,9 @@ static ssize_t sel_commit_bools_write(struct file *filep, if (IS_ERR(page)) return PTR_ERR(page); - mutex_lock(&fsi->state->policy_mutex); + mutex_lock(&selinux_state.policy_mutex); - length = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + length = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__SETBOOL, NULL); if (length) @@ -1398,14 +1333,14 @@ static ssize_t sel_commit_bools_write(struct file *filep, length = 0; if (new_value && fsi->bool_pending_values) - length = security_set_bools(fsi->state, fsi->bool_num, + length = security_set_bools(fsi->bool_num, fsi->bool_pending_values); if (!length) length = count; out: - mutex_unlock(&fsi->state->policy_mutex); + mutex_unlock(&selinux_state.policy_mutex); kfree(page); return length; } @@ -1503,13 +1438,11 @@ out: static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char tmpbuf[TMPBUFLEN]; ssize_t length; length = scnprintf(tmpbuf, TMPBUFLEN, "%u", - avc_get_cache_threshold(state->avc)); + avc_get_cache_threshold()); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); } @@ -1518,14 +1451,11 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char *page; ssize_t ret; unsigned int new_value; - ret = avc_has_perm(&selinux_state, - current_sid(), SECINITSID_SECURITY, + ret = avc_has_perm(current_sid(), SECINITSID_SECURITY, SECCLASS_SECURITY, SECURITY__SETSECPARAM, NULL); if (ret) @@ -1546,7 +1476,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file, if (sscanf(page, "%u", &new_value) != 1) goto out; - avc_set_cache_threshold(state->avc, new_value); + avc_set_cache_threshold(new_value); ret = count; out: @@ -1557,8 +1487,6 @@ out: static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char *page; ssize_t length; @@ -1566,7 +1494,7 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf, if (!page) return -ENOMEM; - length = avc_get_hash_stats(state->avc, page); + length = avc_get_hash_stats(page); if (length >= 0) length = simple_read_from_buffer(buf, count, ppos, page, length); free_page((unsigned long)page); @@ -1577,8 +1505,6 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf, static ssize_t sel_read_sidtab_hash_stats(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info; - struct selinux_state *state = fsi->state; char *page; ssize_t length; @@ -1586,7 +1512,7 @@ static ssize_t sel_read_sidtab_hash_stats(struct file *filp, char __user *buf, if (!page) return -ENOMEM; - length = security_sidtab_hash_stats(state, page); + length = security_sidtab_hash_stats(page); if (length >= 0) length = simple_read_from_buffer(buf, count, ppos, page, length); @@ -1752,13 +1678,12 @@ static int sel_make_ss_files(struct dentry *dir) static ssize_t sel_read_initcon(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; char *con; u32 sid, len; ssize_t ret; sid = file_inode(file)->i_ino&SEL_INO_MASK; - ret = security_sid_to_context(fsi->state, sid, &con, &len); + ret = security_sid_to_context(sid, &con, &len); if (ret) return ret; @@ -1852,13 +1777,12 @@ static const struct file_operations sel_perm_ops = { static ssize_t sel_read_policycap(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; int value; char tmpbuf[TMPBUFLEN]; ssize_t length; unsigned long i_ino = file_inode(file)->i_ino; - value = security_policycap_supported(fsi->state, i_ino & SEL_INO_MASK); + value = security_policycap_supported(i_ino & SEL_INO_MASK); length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); @@ -2249,13 +2173,3 @@ static int __init init_sel_fs(void) } __initcall(init_sel_fs); - -#ifdef CONFIG_SECURITY_SELINUX_DISABLE -void exit_sel_fs(void) -{ - sysfs_remove_mount_point(fs_kobj, "selinux"); - dput(selinux_null.dentry); - kern_unmount(selinuxfs_mount); - unregister_filesystem(&sel_fs_type); -} -#endif diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 0092b29022f5..f14d1ffe54c5 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -235,16 +235,16 @@ static void map_decision(struct selinux_map *map, } } -int security_mls_enabled(struct selinux_state *state) +int security_mls_enabled(void) { int mls_enabled; struct selinux_policy *policy; - if (!selinux_initialized(state)) + if (!selinux_initialized()) return 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); mls_enabled = policy->policydb.mls_enabled; rcu_read_unlock(); return mls_enabled; @@ -713,8 +713,7 @@ static void context_struct_compute_av(struct policydb *policydb, tclass, avd); } -static int security_validtrans_handle_fail(struct selinux_state *state, - struct selinux_policy *policy, +static int security_validtrans_handle_fail(struct selinux_policy *policy, struct sidtab_entry *oentry, struct sidtab_entry *nentry, struct sidtab_entry *tentry, @@ -740,13 +739,12 @@ out: kfree(n); kfree(t); - if (!enforcing_enabled(state)) + if (!enforcing_enabled()) return 0; return -EPERM; } -static int security_compute_validatetrans(struct selinux_state *state, - u32 oldsid, u32 newsid, u32 tasksid, +static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid, u16 orig_tclass, bool user) { struct selinux_policy *policy; @@ -761,12 +759,12 @@ static int security_compute_validatetrans(struct selinux_state *state, int rc = 0; - if (!selinux_initialized(state)) + if (!selinux_initialized()) return 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -813,8 +811,7 @@ static int security_compute_validatetrans(struct selinux_state *state, if (user) rc = -EPERM; else - rc = security_validtrans_handle_fail(state, - policy, + rc = security_validtrans_handle_fail(policy, oentry, nentry, tentry, @@ -829,19 +826,17 @@ out: return rc; } -int security_validate_transition_user(struct selinux_state *state, - u32 oldsid, u32 newsid, u32 tasksid, +int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid, u16 tclass) { - return security_compute_validatetrans(state, oldsid, newsid, tasksid, + return security_compute_validatetrans(oldsid, newsid, tasksid, tclass, true); } -int security_validate_transition(struct selinux_state *state, - u32 oldsid, u32 newsid, u32 tasksid, +int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, u16 orig_tclass) { - return security_compute_validatetrans(state, oldsid, newsid, tasksid, + return security_compute_validatetrans(oldsid, newsid, tasksid, orig_tclass, false); } @@ -851,12 +846,10 @@ int security_validate_transition(struct selinux_state *state, * It returns 0, if @newsid is bounded by @oldsid. * Otherwise, it returns error code. * - * @state: SELinux state * @oldsid : current security identifier * @newsid : destinated security identifier */ -int security_bounded_transition(struct selinux_state *state, - u32 old_sid, u32 new_sid) +int security_bounded_transition(u32 old_sid, u32 new_sid) { struct selinux_policy *policy; struct policydb *policydb; @@ -866,11 +859,11 @@ int security_bounded_transition(struct selinux_state *state, int index; int rc; - if (!selinux_initialized(state)) + if (!selinux_initialized()) return 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -1004,8 +997,7 @@ void services_compute_xperms_decision(struct extended_perms_decision *xpermd, } } -void security_compute_xperms_decision(struct selinux_state *state, - u32 ssid, +void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 orig_tclass, u8 driver, @@ -1029,10 +1021,10 @@ void security_compute_xperms_decision(struct selinux_state *state, memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); rcu_read_lock(); - if (!selinux_initialized(state)) + if (!selinux_initialized()) goto allow; - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -1091,7 +1083,6 @@ allow: /** * security_compute_av - Compute access vector decisions. - * @state: SELinux state * @ssid: source security identifier * @tsid: target security identifier * @orig_tclass: target security class @@ -1101,8 +1092,7 @@ allow: * Compute a set of access vector decisions based on the * SID pair (@ssid, @tsid) for the permissions in @tclass. */ -void security_compute_av(struct selinux_state *state, - u32 ssid, +void security_compute_av(u32 ssid, u32 tsid, u16 orig_tclass, struct av_decision *avd, @@ -1115,10 +1105,10 @@ void security_compute_av(struct selinux_state *state, struct context *scontext = NULL, *tcontext = NULL; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); avd_init(policy, avd); xperms->len = 0; - if (!selinux_initialized(state)) + if (!selinux_initialized()) goto allow; policydb = &policy->policydb; @@ -1160,8 +1150,7 @@ allow: goto out; } -void security_compute_av_user(struct selinux_state *state, - u32 ssid, +void security_compute_av_user(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) @@ -1172,9 +1161,9 @@ void security_compute_av_user(struct selinux_state *state, struct context *scontext = NULL, *tcontext = NULL; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); avd_init(policy, avd); - if (!selinux_initialized(state)) + if (!selinux_initialized()) goto allow; policydb = &policy->policydb; @@ -1290,19 +1279,19 @@ static int sidtab_entry_to_string(struct policydb *p, #include "initial_sid_to_string.h" -int security_sidtab_hash_stats(struct selinux_state *state, char *page) +int security_sidtab_hash_stats(char *page) { struct selinux_policy *policy; int rc; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { pr_err("SELinux: %s: called before initial load_policy\n", __func__); return -EINVAL; } rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); rc = sidtab_hash_stats(policy->sidtab, page); rcu_read_unlock(); @@ -1316,8 +1305,7 @@ const char *security_get_initial_sid_context(u32 sid) return initial_sid_to_string[sid]; } -static int security_sid_to_context_core(struct selinux_state *state, - u32 sid, char **scontext, +static int security_sid_to_context_core(u32 sid, char **scontext, u32 *scontext_len, int force, int only_invalid) { @@ -1331,7 +1319,7 @@ static int security_sid_to_context_core(struct selinux_state *state, *scontext = NULL; *scontext_len = 0; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { if (sid <= SECINITSID_NUM) { char *scontextp; const char *s = initial_sid_to_string[sid]; @@ -1352,7 +1340,7 @@ static int security_sid_to_context_core(struct selinux_state *state, return -EINVAL; } rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -1380,7 +1368,6 @@ out_unlock: /** * security_sid_to_context - Obtain a context for a given SID. - * @state: SELinux state * @sid: security identifier, SID * @scontext: security context * @scontext_len: length in bytes @@ -1389,24 +1376,22 @@ out_unlock: * into a dynamically allocated string of the correct size. Set @scontext * to point to this string and set @scontext_len to the length of the string. */ -int security_sid_to_context(struct selinux_state *state, - u32 sid, char **scontext, u32 *scontext_len) +int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) { - return security_sid_to_context_core(state, sid, scontext, + return security_sid_to_context_core(sid, scontext, scontext_len, 0, 0); } -int security_sid_to_context_force(struct selinux_state *state, u32 sid, +int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len) { - return security_sid_to_context_core(state, sid, scontext, + return security_sid_to_context_core(sid, scontext, scontext_len, 1, 0); } /** * security_sid_to_context_inval - Obtain a context for a given SID if it * is invalid. - * @state: SELinux state * @sid: security identifier, SID * @scontext: security context * @scontext_len: length in bytes @@ -1417,10 +1402,10 @@ int security_sid_to_context_force(struct selinux_state *state, u32 sid, * this string (or NULL if the context is valid) and set @scontext_len to * the length of the string (or 0 if the context is valid). */ -int security_sid_to_context_inval(struct selinux_state *state, u32 sid, +int security_sid_to_context_inval(u32 sid, char **scontext, u32 *scontext_len) { - return security_sid_to_context_core(state, sid, scontext, + return security_sid_to_context_core(sid, scontext, scontext_len, 1, 1); } @@ -1505,8 +1490,7 @@ out: return rc; } -static int security_context_to_sid_core(struct selinux_state *state, - const char *scontext, u32 scontext_len, +static int security_context_to_sid_core(const char *scontext, u32 scontext_len, u32 *sid, u32 def_sid, gfp_t gfp_flags, int force) { @@ -1526,7 +1510,7 @@ static int security_context_to_sid_core(struct selinux_state *state, if (!scontext2) return -ENOMEM; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { int i; for (i = 1; i < SECINITSID_NUM; i++) { @@ -1551,7 +1535,7 @@ static int security_context_to_sid_core(struct selinux_state *state, } retry: rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; rc = string_to_context_struct(policydb, sidtab, scontext2, @@ -1583,7 +1567,6 @@ out: /** * security_context_to_sid - Obtain a SID for a given security context. - * @state: SELinux state * @scontext: security context * @scontext_len: length in bytes * @sid: security identifier, SID @@ -1594,18 +1577,16 @@ out: * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient * memory is available, or 0 on success. */ -int security_context_to_sid(struct selinux_state *state, - const char *scontext, u32 scontext_len, u32 *sid, +int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid, gfp_t gfp) { - return security_context_to_sid_core(state, scontext, scontext_len, + return security_context_to_sid_core(scontext, scontext_len, sid, SECSID_NULL, gfp, 0); } -int security_context_str_to_sid(struct selinux_state *state, - const char *scontext, u32 *sid, gfp_t gfp) +int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp) { - return security_context_to_sid(state, scontext, strlen(scontext), + return security_context_to_sid(scontext, strlen(scontext), sid, gfp); } @@ -1613,7 +1594,6 @@ int security_context_str_to_sid(struct selinux_state *state, * security_context_to_sid_default - Obtain a SID for a given security context, * falling back to specified default if needed. * - * @state: SELinux state * @scontext: security context * @scontext_len: length in bytes * @sid: security identifier, SID @@ -1629,24 +1609,21 @@ int security_context_str_to_sid(struct selinux_state *state, * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient * memory is available, or 0 on success. */ -int security_context_to_sid_default(struct selinux_state *state, - const char *scontext, u32 scontext_len, +int security_context_to_sid_default(const char *scontext, u32 scontext_len, u32 *sid, u32 def_sid, gfp_t gfp_flags) { - return security_context_to_sid_core(state, scontext, scontext_len, + return security_context_to_sid_core(scontext, scontext_len, sid, def_sid, gfp_flags, 1); } -int security_context_to_sid_force(struct selinux_state *state, - const char *scontext, u32 scontext_len, +int security_context_to_sid_force(const char *scontext, u32 scontext_len, u32 *sid) { - return security_context_to_sid_core(state, scontext, scontext_len, + return security_context_to_sid_core(scontext, scontext_len, sid, SECSID_NULL, GFP_KERNEL, 1); } static int compute_sid_handle_invalid_context( - struct selinux_state *state, struct selinux_policy *policy, struct sidtab_entry *sentry, struct sidtab_entry *tentry, @@ -1679,7 +1656,7 @@ out: kfree(s); kfree(t); kfree(n); - if (!enforcing_enabled(state)) + if (!enforcing_enabled()) return 0; return -EACCES; } @@ -1714,8 +1691,7 @@ static void filename_compute_type(struct policydb *policydb, } } -static int security_compute_sid(struct selinux_state *state, - u32 ssid, +static int security_compute_sid(u32 ssid, u32 tsid, u16 orig_tclass, u32 specified, @@ -1736,7 +1712,7 @@ static int security_compute_sid(struct selinux_state *state, int rc = 0; bool sock; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { switch (orig_tclass) { case SECCLASS_PROCESS: /* kernel value */ *out_sid = ssid; @@ -1754,7 +1730,7 @@ retry: rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); if (kern) { tclass = unmap_class(&policy->map, orig_tclass); @@ -1886,7 +1862,7 @@ retry: /* Check the validity of the context. */ if (!policydb_context_isvalid(policydb, &newcontext)) { - rc = compute_sid_handle_invalid_context(state, policy, sentry, + rc = compute_sid_handle_invalid_context(policy, sentry, tentry, tclass, &newcontext); if (rc) @@ -1908,7 +1884,6 @@ out: /** * security_transition_sid - Compute the SID for a new subject/object. - * @state: SELinux state * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class @@ -1921,27 +1896,24 @@ out: * if insufficient memory is available, or %0 if the new SID was * computed successfully. */ -int security_transition_sid(struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass, +int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, const struct qstr *qstr, u32 *out_sid) { - return security_compute_sid(state, ssid, tsid, tclass, + return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, qstr ? qstr->name : NULL, out_sid, true); } -int security_transition_sid_user(struct selinux_state *state, - u32 ssid, u32 tsid, u16 tclass, +int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, const char *objname, u32 *out_sid) { - return security_compute_sid(state, ssid, tsid, tclass, + return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, objname, out_sid, false); } /** * security_member_sid - Compute the SID for member selection. - * @state: SELinux state * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class @@ -1953,20 +1925,18 @@ int security_transition_sid_user(struct selinux_state *state, * if insufficient memory is available, or %0 if the SID was * computed successfully. */ -int security_member_sid(struct selinux_state *state, - u32 ssid, +int security_member_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid) { - return security_compute_sid(state, ssid, tsid, tclass, + return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, NULL, out_sid, false); } /** * security_change_sid - Compute the SID for object relabeling. - * @state: SELinux state * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class @@ -1978,26 +1948,23 @@ int security_member_sid(struct selinux_state *state, * if insufficient memory is available, or %0 if the SID was * computed successfully. */ -int security_change_sid(struct selinux_state *state, - u32 ssid, +int security_change_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid) { - return security_compute_sid(state, - ssid, tsid, tclass, AVTAB_CHANGE, NULL, + return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL, out_sid, false); } static inline int convert_context_handle_invalid_context( - struct selinux_state *state, struct policydb *policydb, struct context *context) { char *s; u32 len; - if (enforcing_enabled(state)) + if (enforcing_enabled()) return -EINVAL; if (!context_struct_to_string(policydb, context, &s, &len)) { @@ -2115,8 +2082,7 @@ int services_convert_context(struct convert_context_args *args, /* Check the validity of the new context. */ if (!policydb_context_isvalid(args->newp, newc)) { - rc = convert_context_handle_invalid_context(args->state, - args->oldp, oldc); + rc = convert_context_handle_invalid_context(args->oldp, oldc); if (rc) goto bad; } @@ -2135,8 +2101,7 @@ bad: return 0; } -static void security_load_policycaps(struct selinux_state *state, - struct selinux_policy *policy) +static void security_load_policycaps(struct selinux_policy *policy) { struct policydb *p; unsigned int i; @@ -2144,8 +2109,8 @@ static void security_load_policycaps(struct selinux_state *state, p = &policy->policydb; - for (i = 0; i < ARRAY_SIZE(state->policycap); i++) - WRITE_ONCE(state->policycap[i], + for (i = 0; i < ARRAY_SIZE(selinux_state.policycap); i++) + WRITE_ONCE(selinux_state.policycap[i], ebitmap_get_bit(&p->policycaps, i)); for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++) @@ -2181,9 +2146,9 @@ static void selinux_policy_cond_free(struct selinux_policy *policy) kfree(policy); } -void selinux_policy_cancel(struct selinux_state *state, - struct selinux_load_state *load_state) +void selinux_policy_cancel(struct selinux_load_state *load_state) { + struct selinux_state *state = &selinux_state; struct selinux_policy *oldpolicy; oldpolicy = rcu_dereference_protected(state->policy, @@ -2194,21 +2159,20 @@ void selinux_policy_cancel(struct selinux_state *state, kfree(load_state->convert_data); } -static void selinux_notify_policy_change(struct selinux_state *state, - u32 seqno) +static void selinux_notify_policy_change(u32 seqno) { /* Flush external caches and notify userspace of policy load */ - avc_ss_reset(state->avc, seqno); + avc_ss_reset(seqno); selnl_notify_policyload(seqno); - selinux_status_update_policyload(state, seqno); + selinux_status_update_policyload(seqno); selinux_netlbl_cache_invalidate(); selinux_xfrm_notify_policyload(); - selinux_ima_measure_state_locked(state); + selinux_ima_measure_state_locked(); } -void selinux_policy_commit(struct selinux_state *state, - struct selinux_load_state *load_state) +void selinux_policy_commit(struct selinux_load_state *load_state) { + struct selinux_state *state = &selinux_state; struct selinux_policy *oldpolicy, *newpolicy = load_state->policy; unsigned long flags; u32 seqno; @@ -2241,15 +2205,15 @@ void selinux_policy_commit(struct selinux_state *state, } /* Load the policycaps from the new policy */ - security_load_policycaps(state, newpolicy); + security_load_policycaps(newpolicy); - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { /* * After first policy load, the security server is * marked as initialized and ready to handle requests and * any objects created prior to policy load are then labeled. */ - selinux_mark_initialized(state); + selinux_mark_initialized(); selinux_complete_init(); } @@ -2259,12 +2223,11 @@ void selinux_policy_commit(struct selinux_state *state, kfree(load_state->convert_data); /* Notify others of the policy change */ - selinux_notify_policy_change(state, seqno); + selinux_notify_policy_change(seqno); } /** * security_load_policy - Load a security policy configuration. - * @state: SELinux state * @data: binary policy data * @len: length of data in bytes * @load_state: policy load state @@ -2274,9 +2237,10 @@ void selinux_policy_commit(struct selinux_state *state, * This function will flush the access vector cache after * loading the new policy. */ -int security_load_policy(struct selinux_state *state, void *data, size_t len, +int security_load_policy(void *data, size_t len, struct selinux_load_state *load_state) { + struct selinux_state *state = &selinux_state; struct selinux_policy *newpolicy, *oldpolicy; struct selinux_policy_convert_data *convert_data; int rc = 0; @@ -2308,7 +2272,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len, goto err_mapping; } - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { /* First policy load, so no need to preserve state from old policy */ load_state->policy = newpolicy; load_state->convert_data = NULL; @@ -2336,7 +2300,6 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len, goto err_free_isids; } - convert_data->args.state = state; convert_data->args.oldp = &oldpolicy->policydb; convert_data->args.newp = &newpolicy->policydb; @@ -2410,13 +2373,11 @@ static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c, /** * security_port_sid - Obtain the SID for a port. - * @state: SELinux state * @protocol: protocol number * @port: port number * @out_sid: security identifier */ -int security_port_sid(struct selinux_state *state, - u8 protocol, u16 port, u32 *out_sid) +int security_port_sid(u8 protocol, u16 port, u32 *out_sid) { struct selinux_policy *policy; struct policydb *policydb; @@ -2424,7 +2385,7 @@ int security_port_sid(struct selinux_state *state, struct ocontext *c; int rc; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { *out_sid = SECINITSID_PORT; return 0; } @@ -2432,7 +2393,7 @@ int security_port_sid(struct selinux_state *state, retry: rc = 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -2464,13 +2425,11 @@ out: /** * security_ib_pkey_sid - Obtain the SID for a pkey. - * @state: SELinux state * @subnet_prefix: Subnet Prefix * @pkey_num: pkey number * @out_sid: security identifier */ -int security_ib_pkey_sid(struct selinux_state *state, - u64 subnet_prefix, u16 pkey_num, u32 *out_sid) +int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid) { struct selinux_policy *policy; struct policydb *policydb; @@ -2478,7 +2437,7 @@ int security_ib_pkey_sid(struct selinux_state *state, struct ocontext *c; int rc; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { *out_sid = SECINITSID_UNLABELED; return 0; } @@ -2486,7 +2445,7 @@ int security_ib_pkey_sid(struct selinux_state *state, retry: rc = 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -2518,13 +2477,11 @@ out: /** * security_ib_endport_sid - Obtain the SID for a subnet management interface. - * @state: SELinux state * @dev_name: device name * @port_num: port number * @out_sid: security identifier */ -int security_ib_endport_sid(struct selinux_state *state, - const char *dev_name, u8 port_num, u32 *out_sid) +int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid) { struct selinux_policy *policy; struct policydb *policydb; @@ -2532,7 +2489,7 @@ int security_ib_endport_sid(struct selinux_state *state, struct ocontext *c; int rc; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { *out_sid = SECINITSID_UNLABELED; return 0; } @@ -2540,7 +2497,7 @@ int security_ib_endport_sid(struct selinux_state *state, retry: rc = 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -2573,12 +2530,10 @@ out: /** * security_netif_sid - Obtain the SID for a network interface. - * @state: SELinux state * @name: interface name * @if_sid: interface SID */ -int security_netif_sid(struct selinux_state *state, - char *name, u32 *if_sid) +int security_netif_sid(char *name, u32 *if_sid) { struct selinux_policy *policy; struct policydb *policydb; @@ -2586,7 +2541,7 @@ int security_netif_sid(struct selinux_state *state, int rc; struct ocontext *c; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { *if_sid = SECINITSID_NETIF; return 0; } @@ -2594,7 +2549,7 @@ int security_netif_sid(struct selinux_state *state, retry: rc = 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -2636,14 +2591,12 @@ static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) /** * security_node_sid - Obtain the SID for a node (host). - * @state: SELinux state * @domain: communication domain aka address family * @addrp: address * @addrlen: address length in bytes * @out_sid: security identifier */ -int security_node_sid(struct selinux_state *state, - u16 domain, +int security_node_sid(u16 domain, void *addrp, u32 addrlen, u32 *out_sid) @@ -2654,14 +2607,14 @@ int security_node_sid(struct selinux_state *state, int rc; struct ocontext *c; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { *out_sid = SECINITSID_NODE; return 0; } retry: rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -2725,7 +2678,6 @@ out: /** * security_get_user_sids - Obtain reachable SIDs for a user. - * @state: SELinux state * @fromsid: starting SID * @username: username * @sids: array of reachable SIDs for user @@ -2738,8 +2690,7 @@ out: * number of elements in the array. */ -int security_get_user_sids(struct selinux_state *state, - u32 fromsid, +int security_get_user_sids(u32 fromsid, char *username, u32 **sids, u32 *nel) @@ -2758,7 +2709,7 @@ int security_get_user_sids(struct selinux_state *state, *sids = NULL; *nel = 0; - if (!selinux_initialized(state)) + if (!selinux_initialized()) return 0; mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL); @@ -2768,7 +2719,7 @@ int security_get_user_sids(struct selinux_state *state, retry: mynel = 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -2834,8 +2785,7 @@ out_unlock: } for (i = 0, j = 0; i < mynel; i++) { struct av_decision dummy_avd; - rc = avc_has_perm_noaudit(state, - fromsid, mysids[i], + rc = avc_has_perm_noaudit(fromsid, mysids[i], SECCLASS_PROCESS, /* kernel value */ PROCESS__TRANSITION, AVC_STRICT, &dummy_avd); @@ -2908,7 +2858,6 @@ static inline int __security_genfs_sid(struct selinux_policy *policy, /** * security_genfs_sid - Obtain a SID for a file in a filesystem - * @state: SELinux state * @fstype: filesystem type * @path: path from root of mount * @orig_sclass: file security class @@ -2917,8 +2866,7 @@ static inline int __security_genfs_sid(struct selinux_policy *policy, * Acquire policy_rwlock before calling __security_genfs_sid() and release * it afterward. */ -int security_genfs_sid(struct selinux_state *state, - const char *fstype, +int security_genfs_sid(const char *fstype, const char *path, u16 orig_sclass, u32 *sid) @@ -2926,14 +2874,14 @@ int security_genfs_sid(struct selinux_state *state, struct selinux_policy *policy; int retval; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { *sid = SECINITSID_UNLABELED; return 0; } do { rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); retval = __security_genfs_sid(policy, fstype, path, orig_sclass, sid); rcu_read_unlock(); @@ -2953,10 +2901,9 @@ int selinux_policy_genfs_sid(struct selinux_policy *policy, /** * security_fs_use - Determine how to handle labeling for a filesystem. - * @state: SELinux state * @sb: superblock in question */ -int security_fs_use(struct selinux_state *state, struct super_block *sb) +int security_fs_use(struct super_block *sb) { struct selinux_policy *policy; struct policydb *policydb; @@ -2966,7 +2913,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb) struct superblock_security_struct *sbsec = selinux_superblock(sb); const char *fstype = sb->s_type->name; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { sbsec->behavior = SECURITY_FS_USE_NONE; sbsec->sid = SECINITSID_UNLABELED; return 0; @@ -2974,7 +2921,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb) retry: rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -3067,13 +3014,14 @@ err: } -int security_set_bools(struct selinux_state *state, u32 len, int *values) +int security_set_bools(u32 len, int *values) { + struct selinux_state *state = &selinux_state; struct selinux_policy *newpolicy, *oldpolicy; int rc; u32 i, seqno = 0; - if (!selinux_initialized(state)) + if (!selinux_initialized()) return -EINVAL; oldpolicy = rcu_dereference_protected(state->policy, @@ -3134,23 +3082,22 @@ int security_set_bools(struct selinux_state *state, u32 len, int *values) selinux_policy_cond_free(oldpolicy); /* Notify others of the policy change */ - selinux_notify_policy_change(state, seqno); + selinux_notify_policy_change(seqno); return 0; } -int security_get_bool_value(struct selinux_state *state, - u32 index) +int security_get_bool_value(u32 index) { struct selinux_policy *policy; struct policydb *policydb; int rc; u32 len; - if (!selinux_initialized(state)) + if (!selinux_initialized()) return 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; rc = -EFAULT; @@ -3197,8 +3144,7 @@ out: * security_sid_mls_copy() - computes a new sid based on the given * sid and the mls portion of mls_sid. */ -int security_sid_mls_copy(struct selinux_state *state, - u32 sid, u32 mls_sid, u32 *new_sid) +int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) { struct selinux_policy *policy; struct policydb *policydb; @@ -3210,7 +3156,7 @@ int security_sid_mls_copy(struct selinux_state *state, u32 len; int rc; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { *new_sid = sid; return 0; } @@ -3220,7 +3166,7 @@ retry: context_init(&newcon); rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -3254,7 +3200,7 @@ retry: /* Check the validity of the new context. */ if (!policydb_context_isvalid(policydb, &newcon)) { - rc = convert_context_handle_invalid_context(state, policydb, + rc = convert_context_handle_invalid_context(policydb, &newcon); if (rc) { if (!context_struct_to_string(policydb, &newcon, &s, @@ -3288,7 +3234,6 @@ out_unlock: /** * security_net_peersid_resolve - Compare and resolve two network peer SIDs - * @state: SELinux state * @nlbl_sid: NetLabel SID * @nlbl_type: NetLabel labeling protocol type * @xfrm_sid: XFRM SID @@ -3308,8 +3253,7 @@ out_unlock: * multiple, inconsistent labels | -<errno> | SECSID_NULL * */ -int security_net_peersid_resolve(struct selinux_state *state, - u32 nlbl_sid, u32 nlbl_type, +int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, u32 xfrm_sid, u32 *peer_sid) { @@ -3337,11 +3281,11 @@ int security_net_peersid_resolve(struct selinux_state *state, return 0; } - if (!selinux_initialized(state)) + if (!selinux_initialized()) return 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -3482,31 +3426,31 @@ err: return rc; } -int security_get_reject_unknown(struct selinux_state *state) +int security_get_reject_unknown(void) { struct selinux_policy *policy; int value; - if (!selinux_initialized(state)) + if (!selinux_initialized()) return 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); value = policy->policydb.reject_unknown; rcu_read_unlock(); return value; } -int security_get_allow_unknown(struct selinux_state *state) +int security_get_allow_unknown(void) { struct selinux_policy *policy; int value; - if (!selinux_initialized(state)) + if (!selinux_initialized()) return 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); value = policy->policydb.allow_unknown; rcu_read_unlock(); return value; @@ -3514,7 +3458,6 @@ int security_get_allow_unknown(struct selinux_state *state) /** * security_policycap_supported - Check for a specific policy capability - * @state: SELinux state * @req_cap: capability * * Description: @@ -3523,17 +3466,16 @@ int security_get_allow_unknown(struct selinux_state *state) * supported, false (0) if it isn't supported. * */ -int security_policycap_supported(struct selinux_state *state, - unsigned int req_cap) +int security_policycap_supported(unsigned int req_cap) { struct selinux_policy *policy; int rc; - if (!selinux_initialized(state)) + if (!selinux_initialized()) return 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap); rcu_read_unlock(); @@ -3569,7 +3511,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) *rule = NULL; - if (!selinux_initialized(state)) + if (!selinux_initialized()) return -EOPNOTSUPP; switch (field) { @@ -3696,7 +3638,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) return -ENOENT; } - if (!selinux_initialized(state)) + if (!selinux_initialized()) return 0; rcu_read_lock(); @@ -3849,7 +3791,6 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, /** * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID - * @state: SELinux state * @secattr: the NetLabel packet security attributes * @sid: the SELinux SID * @@ -3863,8 +3804,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, * failure. * */ -int security_netlbl_secattr_to_sid(struct selinux_state *state, - struct netlbl_lsm_secattr *secattr, +int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, u32 *sid) { struct selinux_policy *policy; @@ -3874,7 +3814,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state, struct context *ctx; struct context ctx_new; - if (!selinux_initialized(state)) { + if (!selinux_initialized()) { *sid = SECSID_NULL; return 0; } @@ -3882,7 +3822,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state, retry: rc = 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; sidtab = policy->sidtab; @@ -3932,7 +3872,6 @@ out: /** * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr - * @state: SELinux state * @sid: the SELinux SID * @secattr: the NetLabel packet security attributes * @@ -3941,19 +3880,18 @@ out: * Returns zero on success, negative values on failure. * */ -int security_netlbl_sid_to_secattr(struct selinux_state *state, - u32 sid, struct netlbl_lsm_secattr *secattr) +int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) { struct selinux_policy *policy; struct policydb *policydb; int rc; struct context *ctx; - if (!selinux_initialized(state)) + if (!selinux_initialized()) return 0; rcu_read_lock(); - policy = rcu_dereference(state->policy); + policy = rcu_dereference(selinux_state.policy); policydb = &policy->policydb; rc = -ENOENT; @@ -4003,14 +3941,13 @@ static int __security_read_policy(struct selinux_policy *policy, /** * security_read_policy - read the policy. - * @state: selinux_state * @data: binary policy data * @len: length of data in bytes * */ -int security_read_policy(struct selinux_state *state, - void **data, size_t *len) +int security_read_policy(void **data, size_t *len) { + struct selinux_state *state = &selinux_state; struct selinux_policy *policy; policy = rcu_dereference_protected( @@ -4028,7 +3965,6 @@ int security_read_policy(struct selinux_state *state, /** * security_read_state_kernel - read the policy. - * @state: selinux_state * @data: binary policy data * @len: length of data in bytes * @@ -4038,10 +3974,10 @@ int security_read_policy(struct selinux_state *state, * * This function must be called with policy_mutex held. */ -int security_read_state_kernel(struct selinux_state *state, - void **data, size_t *len) +int security_read_state_kernel(void **data, size_t *len) { int err; + struct selinux_state *state = &selinux_state; struct selinux_policy *policy; policy = rcu_dereference_protected( diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h index c4301626487f..8a9b85f44b66 100644 --- a/security/selinux/ss/services.h +++ b/security/selinux/ss/services.h @@ -30,7 +30,6 @@ struct selinux_policy { } __randomize_layout; struct convert_context_args { - struct selinux_state *state; struct policydb *oldp; struct policydb *newp; }; diff --git a/security/selinux/status.c b/security/selinux/status.c index 4bc8f809934c..19ef929a075c 100644 --- a/security/selinux/status.c +++ b/security/selinux/status.c @@ -39,21 +39,21 @@ * It returns a reference to selinux_status_page. If the status page is * not allocated yet, it also tries to allocate it at the first time. */ -struct page *selinux_kernel_status_page(struct selinux_state *state) +struct page *selinux_kernel_status_page(void) { struct selinux_kernel_status *status; struct page *result = NULL; - mutex_lock(&state->status_lock); - if (!state->status_page) { - state->status_page = alloc_page(GFP_KERNEL|__GFP_ZERO); + mutex_lock(&selinux_state.status_lock); + if (!selinux_state.status_page) { + selinux_state.status_page = alloc_page(GFP_KERNEL|__GFP_ZERO); - if (state->status_page) { - status = page_address(state->status_page); + if (selinux_state.status_page) { + status = page_address(selinux_state.status_page); status->version = SELINUX_KERNEL_STATUS_VERSION; status->sequence = 0; - status->enforcing = enforcing_enabled(state); + status->enforcing = enforcing_enabled(); /* * NOTE: the next policyload event shall set * a positive value on the status->policyload, @@ -62,11 +62,11 @@ struct page *selinux_kernel_status_page(struct selinux_state *state) */ status->policyload = 0; status->deny_unknown = - !security_get_allow_unknown(state); + !security_get_allow_unknown(); } } - result = state->status_page; - mutex_unlock(&state->status_lock); + result = selinux_state.status_page; + mutex_unlock(&selinux_state.status_lock); return result; } @@ -76,14 +76,13 @@ struct page *selinux_kernel_status_page(struct selinux_state *state) * * It updates status of the current enforcing/permissive mode. */ -void selinux_status_update_setenforce(struct selinux_state *state, - int enforcing) +void selinux_status_update_setenforce(int enforcing) { struct selinux_kernel_status *status; - mutex_lock(&state->status_lock); - if (state->status_page) { - status = page_address(state->status_page); + mutex_lock(&selinux_state.status_lock); + if (selinux_state.status_page) { + status = page_address(selinux_state.status_page); status->sequence++; smp_wmb(); @@ -93,7 +92,7 @@ void selinux_status_update_setenforce(struct selinux_state *state, smp_wmb(); status->sequence++; } - mutex_unlock(&state->status_lock); + mutex_unlock(&selinux_state.status_lock); } /* @@ -102,23 +101,22 @@ void selinux_status_update_setenforce(struct selinux_state *state, * It updates status of the times of policy reloaded, and current * setting of deny_unknown. */ -void selinux_status_update_policyload(struct selinux_state *state, - int seqno) +void selinux_status_update_policyload(int seqno) { struct selinux_kernel_status *status; - mutex_lock(&state->status_lock); - if (state->status_page) { - status = page_address(state->status_page); + mutex_lock(&selinux_state.status_lock); + if (selinux_state.status_page) { + status = page_address(selinux_state.status_page); status->sequence++; smp_wmb(); status->policyload = seqno; - status->deny_unknown = !security_get_allow_unknown(state); + status->deny_unknown = !security_get_allow_unknown(); smp_wmb(); status->sequence++; } - mutex_unlock(&state->status_lock); + mutex_unlock(&selinux_state.status_lock); } diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index c576832febc6..1fca42c4d0ae 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -98,13 +98,12 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp, ctx->ctx_len = str_len; memcpy(ctx->ctx_str, &uctx[1], str_len); ctx->ctx_str[str_len] = '\0'; - rc = security_context_to_sid(&selinux_state, ctx->ctx_str, str_len, + rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid, gfp); if (rc) goto err; - rc = avc_has_perm(&selinux_state, - tsec->sid, ctx->ctx_sid, + rc = avc_has_perm(tsec->sid, ctx->ctx_sid, SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL); if (rc) goto err; @@ -140,8 +139,7 @@ static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx) if (!ctx) return 0; - return avc_has_perm(&selinux_state, - tsec->sid, ctx->ctx_sid, + return avc_has_perm(tsec->sid, ctx->ctx_sid, SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL); } @@ -163,8 +161,7 @@ int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid) if (!selinux_authorizable_ctx(ctx)) return -EINVAL; - rc = avc_has_perm(&selinux_state, - fl_secid, ctx->ctx_sid, + rc = avc_has_perm(fl_secid, ctx->ctx_sid, SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL); return (rc == -EACCES ? -ESRCH : rc); } @@ -205,7 +202,7 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, /* We don't need a separate SA Vs. policy polmatch check since the SA * is now of the same label as the flow and a flow Vs. policy polmatch * check had already happened in selinux_xfrm_policy_lookup() above. */ - return (avc_has_perm(&selinux_state, flic_sid, state_sid, + return (avc_has_perm(flic_sid, state_sid, SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, NULL) ? 0 : 1); } @@ -355,7 +352,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, if (secid == 0) return -EINVAL; - rc = security_sid_to_context(&selinux_state, secid, &ctx_str, + rc = security_sid_to_context(secid, &ctx_str, &str_len); if (rc) return rc; @@ -424,8 +421,7 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb, /* This check even when there's no association involved is intended, * according to Trent Jaeger, to make sure a process can't engage in * non-IPsec communication unless explicitly allowed by policy. */ - return avc_has_perm(&selinux_state, - sk_sid, peer_sid, + return avc_has_perm(sk_sid, peer_sid, SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad); } @@ -468,6 +464,6 @@ int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb, /* This check even when there's no association involved is intended, * according to Trent Jaeger, to make sure a process can't engage in * non-IPsec communication unless explicitly allowed by policy. */ - return avc_has_perm(&selinux_state, sk_sid, SECINITSID_UNLABELED, + return avc_has_perm(sk_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad); } diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index cfcbb748da25..7a3e9ab137d8 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -550,23 +550,22 @@ static int smack_sb_alloc_security(struct super_block *sb) } struct smack_mnt_opts { - const char *fsdefault, *fsfloor, *fshat, *fsroot, *fstransmute; + const char *fsdefault; + const char *fsfloor; + const char *fshat; + const char *fsroot; + const char *fstransmute; }; static void smack_free_mnt_opts(void *mnt_opts) { - struct smack_mnt_opts *opts = mnt_opts; - kfree(opts->fsdefault); - kfree(opts->fsfloor); - kfree(opts->fshat); - kfree(opts->fsroot); - kfree(opts->fstransmute); - kfree(opts); + kfree(mnt_opts); } static int smack_add_opt(int token, const char *s, void **mnt_opts) { struct smack_mnt_opts *opts = *mnt_opts; + struct smack_known *skp; if (!opts) { opts = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL); @@ -577,31 +576,35 @@ static int smack_add_opt(int token, const char *s, void **mnt_opts) if (!s) return -ENOMEM; + skp = smk_import_entry(s, 0); + if (IS_ERR(skp)) + return PTR_ERR(skp); + switch (token) { case Opt_fsdefault: if (opts->fsdefault) goto out_opt_err; - opts->fsdefault = s; + opts->fsdefault = skp->smk_known; break; case Opt_fsfloor: if (opts->fsfloor) goto out_opt_err; - opts->fsfloor = s; + opts->fsfloor = skp->smk_known; break; case Opt_fshat: if (opts->fshat) goto out_opt_err; - opts->fshat = s; + opts->fshat = skp->smk_known; break; case Opt_fsroot: if (opts->fsroot) goto out_opt_err; - opts->fsroot = s; + opts->fsroot = skp->smk_known; break; case Opt_fstransmute: if (opts->fstransmute) goto out_opt_err; - opts->fstransmute = s; + opts->fstransmute = skp->smk_known; break; } return 0; @@ -629,33 +632,14 @@ static int smack_fs_context_dup(struct fs_context *fc, fc->security = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL); if (!fc->security) return -ENOMEM; + dst = fc->security; + dst->fsdefault = src->fsdefault; + dst->fsfloor = src->fsfloor; + dst->fshat = src->fshat; + dst->fsroot = src->fsroot; + dst->fstransmute = src->fstransmute; - if (src->fsdefault) { - dst->fsdefault = kstrdup(src->fsdefault, GFP_KERNEL); - if (!dst->fsdefault) - return -ENOMEM; - } - if (src->fsfloor) { - dst->fsfloor = kstrdup(src->fsfloor, GFP_KERNEL); - if (!dst->fsfloor) - return -ENOMEM; - } - if (src->fshat) { - dst->fshat = kstrdup(src->fshat, GFP_KERNEL); - if (!dst->fshat) - return -ENOMEM; - } - if (src->fsroot) { - dst->fsroot = kstrdup(src->fsroot, GFP_KERNEL); - if (!dst->fsroot) - return -ENOMEM; - } - if (src->fstransmute) { - dst->fstransmute = kstrdup(src->fstransmute, GFP_KERNEL); - if (!dst->fstransmute) - return -ENOMEM; - } return 0; } @@ -712,8 +696,8 @@ static int smack_sb_eat_lsm_opts(char *options, void **mnt_opts) if (token != Opt_error) { arg = kmemdup_nul(arg, from + len - arg, GFP_KERNEL); rc = smack_add_opt(token, arg, mnt_opts); + kfree(arg); if (unlikely(rc)) { - kfree(arg); if (*mnt_opts) smack_free_mnt_opts(*mnt_opts); *mnt_opts = NULL; @@ -1477,7 +1461,7 @@ static int smack_inode_getsecurity(struct mnt_idmap *idmap, struct socket_smack *ssp; struct socket *sock; struct super_block *sbp; - struct inode *ip = (struct inode *)inode; + struct inode *ip = inode; struct smack_known *isp; if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) @@ -4847,7 +4831,7 @@ static int smack_uring_cmd(struct io_uring_cmd *ioucmd) #endif /* CONFIG_IO_URING */ -struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = { +struct lsm_blob_sizes smack_blob_sizes __ro_after_init = { .lbs_cred = sizeof(struct task_smack), .lbs_file = sizeof(struct smack_known *), .lbs_inode = sizeof(struct inode_smack), @@ -4856,7 +4840,7 @@ struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = { .lbs_superblock = sizeof(struct superblock_smack), }; -static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { +static struct security_hook_list smack_hooks[] __ro_after_init = { LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), LSM_HOOK_INIT(syslog, smack_syslog), diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c index 7cf8fdbb29bf..610c1536cf70 100644 --- a/security/tomoyo/audit.c +++ b/security/tomoyo/audit.c @@ -271,7 +271,7 @@ char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt, /* +18 is for " symlink.target=\"%s\"" */ len += 18 + strlen(symlink); } - len = tomoyo_round2(len); + len = kmalloc_size_roundup(len); buf = kzalloc(len, GFP_NOFS); if (!buf) goto out; @@ -382,12 +382,12 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, goto out; } entry->log = buf; - len = tomoyo_round2(strlen(buf) + 1); + len = kmalloc_size_roundup(strlen(buf) + 1); /* * The entry->size is used for memory quota checks. * Don't go beyond strlen(entry->log). */ - entry->size = len + tomoyo_round2(sizeof(*entry)); + entry->size = len + kmalloc_size_roundup(sizeof(*entry)); spin_lock(&tomoyo_log_lock); if (tomoyo_memory_quota[TOMOYO_MEMORY_AUDIT] && tomoyo_memory_used[TOMOYO_MEMORY_AUDIT] + entry->size >= diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index f4cd9b58b205..969d4aa6fd55 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -2094,7 +2094,7 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) tomoyo_add_entry(r->domain, entry.query); goto out; } - len = tomoyo_round2(entry.query_len); + len = kmalloc_size_roundup(entry.query_len); entry.domain = r->domain; spin_lock(&tomoyo_query_list_lock); if (tomoyo_memory_quota[TOMOYO_MEMORY_QUERY] && diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index ca285f362705..a539b2cbb5c4 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -1276,50 +1276,6 @@ static inline struct tomoyo_policy_namespace *tomoyo_current_namespace(void) return tomoyo_domain()->ns; } -#if defined(CONFIG_SLOB) - -/** - * tomoyo_round2 - Round up to power of 2 for calculating memory usage. - * - * @size: Size to be rounded up. - * - * Returns @size. - * - * Since SLOB does not round up, this function simply returns @size. - */ -static inline int tomoyo_round2(size_t size) -{ - return size; -} - -#else - -/** - * tomoyo_round2 - Round up to power of 2 for calculating memory usage. - * - * @size: Size to be rounded up. - * - * Returns rounded size. - * - * Strictly speaking, SLAB may be able to allocate (e.g.) 96 bytes instead of - * (e.g.) 128 bytes. - */ -static inline int tomoyo_round2(size_t size) -{ -#if PAGE_SIZE == 4096 - size_t bsize = 32; -#else - size_t bsize = 64; -#endif - if (!size) - return 0; - while (size > bsize) - bsize <<= 1; - return bsize; -} - -#endif - /** * list_for_each_cookie - iterate over a list with cookie. * @pos: the &struct list_head to use as a loop cursor. diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index af04a7b7eb28..25006fddc964 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -499,7 +499,7 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, return tomoyo_socket_sendmsg_permission(sock, msg, size); } -struct lsm_blob_sizes tomoyo_blob_sizes __lsm_ro_after_init = { +struct lsm_blob_sizes tomoyo_blob_sizes __ro_after_init = { .lbs_task = sizeof(struct tomoyo_task), }; @@ -546,7 +546,7 @@ static void tomoyo_task_free(struct task_struct *task) * tomoyo_security_ops is a "struct security_operations" which is used for * registering TOMOYO. */ -static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = { +static struct security_hook_list tomoyo_hooks[] __ro_after_init = { LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare), LSM_HOOK_INIT(bprm_committed_creds, tomoyo_bprm_committed_creds), LSM_HOOK_INIT(task_alloc, tomoyo_task_alloc), @@ -583,7 +583,7 @@ static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = { /* Lock for GC. */ DEFINE_SRCU(tomoyo_ss); -int tomoyo_enabled __lsm_ro_after_init = 1; +int tomoyo_enabled __ro_after_init = 1; /** * tomoyo_init - Register TOMOYO Linux as a LSM module. diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 06e226166aab..478be269571a 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -421,7 +421,7 @@ static int yama_ptrace_traceme(struct task_struct *parent) return rc; } -static struct security_hook_list yama_hooks[] __lsm_ro_after_init = { +static struct security_hook_list yama_hooks[] __ro_after_init = { LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme), LSM_HOOK_INIT(task_prctl, yama_task_prctl), diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 331380c2438b..5868661d461b 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3521,6 +3521,7 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) unsigned long i; void __user **bufs; snd_pcm_uframes_t frames; + const struct iovec *iov = iter_iov(to); pcm_file = iocb->ki_filp->private_data; substream = pcm_file->substream; @@ -3530,18 +3531,20 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) if (runtime->state == SNDRV_PCM_STATE_OPEN || runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; - if (!iter_is_iovec(to)) + if (!to->user_backed) return -EINVAL; if (to->nr_segs > 1024 || to->nr_segs != runtime->channels) return -EINVAL; - if (!frame_aligned(runtime, to->iov->iov_len)) + if (!frame_aligned(runtime, iov->iov_len)) return -EINVAL; - frames = bytes_to_samples(runtime, to->iov->iov_len); + frames = bytes_to_samples(runtime, iov->iov_len); bufs = kmalloc_array(to->nr_segs, sizeof(void *), GFP_KERNEL); if (bufs == NULL) return -ENOMEM; - for (i = 0; i < to->nr_segs; ++i) - bufs[i] = to->iov[i].iov_base; + for (i = 0; i < to->nr_segs; ++i) { + bufs[i] = iov->iov_base; + iov++; + } result = snd_pcm_lib_readv(substream, bufs, frames); if (result > 0) result = frames_to_bytes(runtime, result); @@ -3558,6 +3561,7 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) unsigned long i; void __user **bufs; snd_pcm_uframes_t frames; + const struct iovec *iov = iter_iov(from); pcm_file = iocb->ki_filp->private_data; substream = pcm_file->substream; @@ -3567,17 +3571,19 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) if (runtime->state == SNDRV_PCM_STATE_OPEN || runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; - if (!iter_is_iovec(from)) + if (!from->user_backed) return -EINVAL; if (from->nr_segs > 128 || from->nr_segs != runtime->channels || - !frame_aligned(runtime, from->iov->iov_len)) + !frame_aligned(runtime, iov->iov_len)) return -EINVAL; - frames = bytes_to_samples(runtime, from->iov->iov_len); + frames = bytes_to_samples(runtime, iov->iov_len); bufs = kmalloc_array(from->nr_segs, sizeof(void *), GFP_KERNEL); if (bufs == NULL) return -ENOMEM; - for (i = 0; i < from->nr_segs; ++i) - bufs[i] = from->iov[i].iov_base; + for (i = 0; i < from->nr_segs; ++i) { + bufs[i] = iov->iov_base; + iov++; + } result = snd_pcm_lib_writev(substream, bufs, frames); if (result > 0) result = frames_to_bytes(runtime, result); diff --git a/tools/objtool/check.c b/tools/objtool/check.c index f937be1afe65..50ed63f701f1 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1284,9 +1284,9 @@ static const char *uaccess_safe_builtin[] = { "copy_mc_fragile_handle_tail", "copy_mc_enhanced_fast_string", "ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */ - "clear_user_erms", - "clear_user_rep_good", - "clear_user_original", + "rep_stos_alternative", + "rep_movs_alternative", + "__copy_user_nocache", NULL }; |