diff options
58 files changed, 861 insertions, 76 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 944e03e29f65..c7ac2f3ac99f 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt | |||
@@ -2276,6 +2276,15 @@ | |||
2276 | lockd.nlm_udpport=M [NFS] Assign UDP port. | 2276 | lockd.nlm_udpport=M [NFS] Assign UDP port. |
2277 | Format: <integer> | 2277 | Format: <integer> |
2278 | 2278 | ||
2279 | lockdown= [SECURITY] | ||
2280 | { integrity | confidentiality } | ||
2281 | Enable the kernel lockdown feature. If set to | ||
2282 | integrity, kernel features that allow userland to | ||
2283 | modify the running kernel are disabled. If set to | ||
2284 | confidentiality, kernel features that allow userland | ||
2285 | to extract confidential information from the kernel | ||
2286 | are also disabled. | ||
2287 | |||
2279 | locktorture.nreaders_stress= [KNL] | 2288 | locktorture.nreaders_stress= [KNL] |
2280 | Set the number of locking read-acquisition kthreads. | 2289 | Set the number of locking read-acquisition kthreads. |
2281 | Defaults to being automatically set based on the | 2290 | Defaults to being automatically set based on the |
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 866e05882799..41a9b4257b72 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig | |||
@@ -982,7 +982,7 @@ config KEXEC_FILE | |||
982 | for kernel and initramfs as opposed to list of segments as | 982 | for kernel and initramfs as opposed to list of segments as |
983 | accepted by previous system call. | 983 | accepted by previous system call. |
984 | 984 | ||
985 | config KEXEC_VERIFY_SIG | 985 | config KEXEC_SIG |
986 | bool "Verify kernel signature during kexec_file_load() syscall" | 986 | bool "Verify kernel signature during kexec_file_load() syscall" |
987 | depends on KEXEC_FILE | 987 | depends on KEXEC_FILE |
988 | help | 988 | help |
@@ -997,13 +997,13 @@ config KEXEC_VERIFY_SIG | |||
997 | config KEXEC_IMAGE_VERIFY_SIG | 997 | config KEXEC_IMAGE_VERIFY_SIG |
998 | bool "Enable Image signature verification support" | 998 | bool "Enable Image signature verification support" |
999 | default y | 999 | default y |
1000 | depends on KEXEC_VERIFY_SIG | 1000 | depends on KEXEC_SIG |
1001 | depends on EFI && SIGNED_PE_FILE_VERIFICATION | 1001 | depends on EFI && SIGNED_PE_FILE_VERIFICATION |
1002 | help | 1002 | help |
1003 | Enable Image signature verification support. | 1003 | Enable Image signature verification support. |
1004 | 1004 | ||
1005 | comment "Support for PE file signature verification disabled" | 1005 | comment "Support for PE file signature verification disabled" |
1006 | depends on KEXEC_VERIFY_SIG | 1006 | depends on KEXEC_SIG |
1007 | depends on !EFI || !SIGNED_PE_FILE_VERIFICATION | 1007 | depends on !EFI || !SIGNED_PE_FILE_VERIFICATION |
1008 | 1008 | ||
1009 | config CRASH_DUMP | 1009 | config CRASH_DUMP |
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 68f7c2b16ff7..43a81d0ad507 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -554,7 +554,7 @@ config ARCH_HAS_KEXEC_PURGATORY | |||
554 | def_bool y | 554 | def_bool y |
555 | depends on KEXEC_FILE | 555 | depends on KEXEC_FILE |
556 | 556 | ||
557 | config KEXEC_VERIFY_SIG | 557 | config KEXEC_SIG |
558 | bool "Verify kernel signature during kexec_file_load() syscall" | 558 | bool "Verify kernel signature during kexec_file_load() syscall" |
559 | depends on KEXEC_FILE && MODULE_SIG_FORMAT | 559 | depends on KEXEC_FILE && MODULE_SIG_FORMAT |
560 | help | 560 | help |
diff --git a/arch/s390/kernel/kexec_elf.c b/arch/s390/kernel/kexec_elf.c index 6d0635ceddd0..9da6fa30c447 100644 --- a/arch/s390/kernel/kexec_elf.c +++ b/arch/s390/kernel/kexec_elf.c | |||
@@ -130,7 +130,7 @@ static int s390_elf_probe(const char *buf, unsigned long len) | |||
130 | const struct kexec_file_ops s390_kexec_elf_ops = { | 130 | const struct kexec_file_ops s390_kexec_elf_ops = { |
131 | .probe = s390_elf_probe, | 131 | .probe = s390_elf_probe, |
132 | .load = s390_elf_load, | 132 | .load = s390_elf_load, |
133 | #ifdef CONFIG_KEXEC_VERIFY_SIG | 133 | #ifdef CONFIG_KEXEC_SIG |
134 | .verify_sig = s390_verify_sig, | 134 | .verify_sig = s390_verify_sig, |
135 | #endif /* CONFIG_KEXEC_VERIFY_SIG */ | 135 | #endif /* CONFIG_KEXEC_SIG */ |
136 | }; | 136 | }; |
diff --git a/arch/s390/kernel/kexec_image.c b/arch/s390/kernel/kexec_image.c index 58318bf89fd9..af23eff5774d 100644 --- a/arch/s390/kernel/kexec_image.c +++ b/arch/s390/kernel/kexec_image.c | |||
@@ -59,7 +59,7 @@ static int s390_image_probe(const char *buf, unsigned long len) | |||
59 | const struct kexec_file_ops s390_kexec_image_ops = { | 59 | const struct kexec_file_ops s390_kexec_image_ops = { |
60 | .probe = s390_image_probe, | 60 | .probe = s390_image_probe, |
61 | .load = s390_image_load, | 61 | .load = s390_image_load, |
62 | #ifdef CONFIG_KEXEC_VERIFY_SIG | 62 | #ifdef CONFIG_KEXEC_SIG |
63 | .verify_sig = s390_verify_sig, | 63 | .verify_sig = s390_verify_sig, |
64 | #endif /* CONFIG_KEXEC_VERIFY_SIG */ | 64 | #endif /* CONFIG_KEXEC_SIG */ |
65 | }; | 65 | }; |
diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c index 1ac9fbc6e01e..8415ae7d2a23 100644 --- a/arch/s390/kernel/machine_kexec_file.c +++ b/arch/s390/kernel/machine_kexec_file.c | |||
@@ -22,7 +22,7 @@ const struct kexec_file_ops * const kexec_file_loaders[] = { | |||
22 | NULL, | 22 | NULL, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | #ifdef CONFIG_KEXEC_VERIFY_SIG | 25 | #ifdef CONFIG_KEXEC_SIG |
26 | int s390_verify_sig(const char *kernel, unsigned long kernel_len) | 26 | int s390_verify_sig(const char *kernel, unsigned long kernel_len) |
27 | { | 27 | { |
28 | const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1; | 28 | const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1; |
@@ -68,7 +68,7 @@ int s390_verify_sig(const char *kernel, unsigned long kernel_len) | |||
68 | VERIFYING_MODULE_SIGNATURE, | 68 | VERIFYING_MODULE_SIGNATURE, |
69 | NULL, NULL); | 69 | NULL, NULL); |
70 | } | 70 | } |
71 | #endif /* CONFIG_KEXEC_VERIFY_SIG */ | 71 | #endif /* CONFIG_KEXEC_SIG */ |
72 | 72 | ||
73 | static int kexec_file_update_purgatory(struct kimage *image, | 73 | static int kexec_file_update_purgatory(struct kimage *image, |
74 | struct s390_load_data *data) | 74 | struct s390_load_data *data) |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 37ed5f5910d5..d6e1faa28c58 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -2031,20 +2031,30 @@ config KEXEC_FILE | |||
2031 | config ARCH_HAS_KEXEC_PURGATORY | 2031 | config ARCH_HAS_KEXEC_PURGATORY |
2032 | def_bool KEXEC_FILE | 2032 | def_bool KEXEC_FILE |
2033 | 2033 | ||
2034 | config KEXEC_VERIFY_SIG | 2034 | config KEXEC_SIG |
2035 | bool "Verify kernel signature during kexec_file_load() syscall" | 2035 | bool "Verify kernel signature during kexec_file_load() syscall" |
2036 | depends on KEXEC_FILE | 2036 | depends on KEXEC_FILE |
2037 | ---help--- | 2037 | ---help--- |
2038 | This option makes kernel signature verification mandatory for | ||
2039 | the kexec_file_load() syscall. | ||
2040 | 2038 | ||
2041 | In addition to that option, you need to enable signature | 2039 | This option makes the kexec_file_load() syscall check for a valid |
2040 | signature of the kernel image. The image can still be loaded without | ||
2041 | a valid signature unless you also enable KEXEC_SIG_FORCE, though if | ||
2042 | there's a signature that we can check, then it must be valid. | ||
2043 | |||
2044 | In addition to this option, you need to enable signature | ||
2042 | verification for the corresponding kernel image type being | 2045 | verification for the corresponding kernel image type being |
2043 | loaded in order for this to work. | 2046 | loaded in order for this to work. |
2044 | 2047 | ||
2048 | config KEXEC_SIG_FORCE | ||
2049 | bool "Require a valid signature in kexec_file_load() syscall" | ||
2050 | depends on KEXEC_SIG | ||
2051 | ---help--- | ||
2052 | This option makes kernel signature verification mandatory for | ||
2053 | the kexec_file_load() syscall. | ||
2054 | |||
2045 | config KEXEC_BZIMAGE_VERIFY_SIG | 2055 | config KEXEC_BZIMAGE_VERIFY_SIG |
2046 | bool "Enable bzImage signature verification support" | 2056 | bool "Enable bzImage signature verification support" |
2047 | depends on KEXEC_VERIFY_SIG | 2057 | depends on KEXEC_SIG |
2048 | depends on SIGNED_PE_FILE_VERIFICATION | 2058 | depends on SIGNED_PE_FILE_VERIFICATION |
2049 | select SYSTEM_TRUSTED_KEYRING | 2059 | select SYSTEM_TRUSTED_KEYRING |
2050 | ---help--- | 2060 | ---help--- |
diff --git a/arch/x86/boot/compressed/acpi.c b/arch/x86/boot/compressed/acpi.c index 15255f388a85..149795c369f2 100644 --- a/arch/x86/boot/compressed/acpi.c +++ b/arch/x86/boot/compressed/acpi.c | |||
@@ -26,7 +26,7 @@ struct mem_vector immovable_mem[MAX_NUMNODES*2]; | |||
26 | */ | 26 | */ |
27 | #define MAX_ADDR_LEN 19 | 27 | #define MAX_ADDR_LEN 19 |
28 | 28 | ||
29 | static acpi_physical_address get_acpi_rsdp(void) | 29 | static acpi_physical_address get_cmdline_acpi_rsdp(void) |
30 | { | 30 | { |
31 | acpi_physical_address addr = 0; | 31 | acpi_physical_address addr = 0; |
32 | 32 | ||
@@ -278,10 +278,7 @@ acpi_physical_address get_rsdp_addr(void) | |||
278 | { | 278 | { |
279 | acpi_physical_address pa; | 279 | acpi_physical_address pa; |
280 | 280 | ||
281 | pa = get_acpi_rsdp(); | 281 | pa = boot_params->acpi_rsdp_addr; |
282 | |||
283 | if (!pa) | ||
284 | pa = boot_params->acpi_rsdp_addr; | ||
285 | 282 | ||
286 | /* | 283 | /* |
287 | * Try to get EFI data from setup_data. This can happen when we're a | 284 | * Try to get EFI data from setup_data. This can happen when we're a |
@@ -311,7 +308,17 @@ static unsigned long get_acpi_srat_table(void) | |||
311 | char arg[10]; | 308 | char arg[10]; |
312 | u8 *entry; | 309 | u8 *entry; |
313 | 310 | ||
314 | rsdp = (struct acpi_table_rsdp *)(long)boot_params->acpi_rsdp_addr; | 311 | /* |
312 | * Check whether we were given an RSDP on the command line. We don't | ||
313 | * stash this in boot params because the kernel itself may have | ||
314 | * different ideas about whether to trust a command-line parameter. | ||
315 | */ | ||
316 | rsdp = (struct acpi_table_rsdp *)get_cmdline_acpi_rsdp(); | ||
317 | |||
318 | if (!rsdp) | ||
319 | rsdp = (struct acpi_table_rsdp *)(long) | ||
320 | boot_params->acpi_rsdp_addr; | ||
321 | |||
315 | if (!rsdp) | 322 | if (!rsdp) |
316 | return 0; | 323 | return 0; |
317 | 324 | ||
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index aac686e1e005..bc9693c9107e 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h | |||
@@ -117,6 +117,12 @@ static inline bool acpi_has_cpu_in_madt(void) | |||
117 | return !!acpi_lapic; | 117 | return !!acpi_lapic; |
118 | } | 118 | } |
119 | 119 | ||
120 | #define ACPI_HAVE_ARCH_SET_ROOT_POINTER | ||
121 | static inline void acpi_arch_set_root_pointer(u64 addr) | ||
122 | { | ||
123 | x86_init.acpi.set_root_pointer(addr); | ||
124 | } | ||
125 | |||
120 | #define ACPI_HAVE_ARCH_GET_ROOT_POINTER | 126 | #define ACPI_HAVE_ARCH_GET_ROOT_POINTER |
121 | static inline u64 acpi_arch_get_root_pointer(void) | 127 | static inline u64 acpi_arch_get_root_pointer(void) |
122 | { | 128 | { |
@@ -125,6 +131,7 @@ static inline u64 acpi_arch_get_root_pointer(void) | |||
125 | 131 | ||
126 | void acpi_generic_reduced_hw_init(void); | 132 | void acpi_generic_reduced_hw_init(void); |
127 | 133 | ||
134 | void x86_default_set_root_pointer(u64 addr); | ||
128 | u64 x86_default_get_root_pointer(void); | 135 | u64 x86_default_get_root_pointer(void); |
129 | 136 | ||
130 | #else /* !CONFIG_ACPI */ | 137 | #else /* !CONFIG_ACPI */ |
@@ -138,6 +145,8 @@ static inline void disable_acpi(void) { } | |||
138 | 145 | ||
139 | static inline void acpi_generic_reduced_hw_init(void) { } | 146 | static inline void acpi_generic_reduced_hw_init(void) { } |
140 | 147 | ||
148 | static inline void x86_default_set_root_pointer(u64 addr) { } | ||
149 | |||
141 | static inline u64 x86_default_get_root_pointer(void) | 150 | static inline u64 x86_default_get_root_pointer(void) |
142 | { | 151 | { |
143 | return 0; | 152 | return 0; |
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index ac0934189017..19435858df5f 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h | |||
@@ -134,10 +134,12 @@ struct x86_hyper_init { | |||
134 | 134 | ||
135 | /** | 135 | /** |
136 | * struct x86_init_acpi - x86 ACPI init functions | 136 | * struct x86_init_acpi - x86 ACPI init functions |
137 | * @set_root_poitner: set RSDP address | ||
137 | * @get_root_pointer: get RSDP address | 138 | * @get_root_pointer: get RSDP address |
138 | * @reduced_hw_early_init: hardware reduced platform early init | 139 | * @reduced_hw_early_init: hardware reduced platform early init |
139 | */ | 140 | */ |
140 | struct x86_init_acpi { | 141 | struct x86_init_acpi { |
142 | void (*set_root_pointer)(u64 addr); | ||
141 | u64 (*get_root_pointer)(void); | 143 | u64 (*get_root_pointer)(void); |
142 | void (*reduced_hw_early_init)(void); | 144 | void (*reduced_hw_early_init)(void); |
143 | }; | 145 | }; |
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 17b33ef604f3..04205ce127a1 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
@@ -1760,6 +1760,11 @@ void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size) | |||
1760 | e820__update_table_print(); | 1760 | e820__update_table_print(); |
1761 | } | 1761 | } |
1762 | 1762 | ||
1763 | void x86_default_set_root_pointer(u64 addr) | ||
1764 | { | ||
1765 | boot_params.acpi_rsdp_addr = addr; | ||
1766 | } | ||
1767 | |||
1763 | u64 x86_default_get_root_pointer(void) | 1768 | u64 x86_default_get_root_pointer(void) |
1764 | { | 1769 | { |
1765 | return boot_params.acpi_rsdp_addr; | 1770 | return boot_params.acpi_rsdp_addr; |
diff --git a/arch/x86/kernel/ima_arch.c b/arch/x86/kernel/ima_arch.c index 4c407833faca..4d4f5d9faac3 100644 --- a/arch/x86/kernel/ima_arch.c +++ b/arch/x86/kernel/ima_arch.c | |||
@@ -74,9 +74,9 @@ bool arch_ima_get_secureboot(void) | |||
74 | 74 | ||
75 | /* secureboot arch rules */ | 75 | /* secureboot arch rules */ |
76 | static const char * const sb_arch_rules[] = { | 76 | static const char * const sb_arch_rules[] = { |
77 | #if !IS_ENABLED(CONFIG_KEXEC_VERIFY_SIG) | 77 | #if !IS_ENABLED(CONFIG_KEXEC_SIG) |
78 | "appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig", | 78 | "appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig", |
79 | #endif /* CONFIG_KEXEC_VERIFY_SIG */ | 79 | #endif /* CONFIG_KEXEC_SIG */ |
80 | "measure func=KEXEC_KERNEL_CHECK", | 80 | "measure func=KEXEC_KERNEL_CHECK", |
81 | #if !IS_ENABLED(CONFIG_MODULE_SIG) | 81 | #if !IS_ENABLED(CONFIG_MODULE_SIG) |
82 | "appraise func=MODULE_CHECK appraise_type=imasig", | 82 | "appraise func=MODULE_CHECK appraise_type=imasig", |
diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c index 0fe1c8782208..61a89d3c0382 100644 --- a/arch/x86/kernel/ioport.c +++ b/arch/x86/kernel/ioport.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <linux/ioport.h> | 13 | #include <linux/ioport.h> |
14 | #include <linux/security.h> | ||
14 | #include <linux/smp.h> | 15 | #include <linux/smp.h> |
15 | #include <linux/stddef.h> | 16 | #include <linux/stddef.h> |
16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
@@ -31,7 +32,8 @@ long ksys_ioperm(unsigned long from, unsigned long num, int turn_on) | |||
31 | 32 | ||
32 | if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) | 33 | if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) |
33 | return -EINVAL; | 34 | return -EINVAL; |
34 | if (turn_on && !capable(CAP_SYS_RAWIO)) | 35 | if (turn_on && (!capable(CAP_SYS_RAWIO) || |
36 | security_locked_down(LOCKDOWN_IOPORT))) | ||
35 | return -EPERM; | 37 | return -EPERM; |
36 | 38 | ||
37 | /* | 39 | /* |
@@ -126,7 +128,8 @@ SYSCALL_DEFINE1(iopl, unsigned int, level) | |||
126 | return -EINVAL; | 128 | return -EINVAL; |
127 | /* Trying to gain more privileges? */ | 129 | /* Trying to gain more privileges? */ |
128 | if (level > old) { | 130 | if (level > old) { |
129 | if (!capable(CAP_SYS_RAWIO)) | 131 | if (!capable(CAP_SYS_RAWIO) || |
132 | security_locked_down(LOCKDOWN_IOPORT)) | ||
130 | return -EPERM; | 133 | return -EPERM; |
131 | } | 134 | } |
132 | regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | | 135 | regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | |
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index 5ebcd02cbca7..d2f4e706a428 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c | |||
@@ -180,6 +180,7 @@ setup_efi_state(struct boot_params *params, unsigned long params_load_addr, | |||
180 | if (efi_enabled(EFI_OLD_MEMMAP)) | 180 | if (efi_enabled(EFI_OLD_MEMMAP)) |
181 | return 0; | 181 | return 0; |
182 | 182 | ||
183 | params->secure_boot = boot_params.secure_boot; | ||
183 | ei->efi_loader_signature = current_ei->efi_loader_signature; | 184 | ei->efi_loader_signature = current_ei->efi_loader_signature; |
184 | ei->efi_systab = current_ei->efi_systab; | 185 | ei->efi_systab = current_ei->efi_systab; |
185 | ei->efi_systab_hi = current_ei->efi_systab_hi; | 186 | ei->efi_systab_hi = current_ei->efi_systab_hi; |
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index 3db2252b958d..1547be359d7f 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/notifier.h> | 34 | #include <linux/notifier.h> |
35 | #include <linux/uaccess.h> | 35 | #include <linux/uaccess.h> |
36 | #include <linux/gfp.h> | 36 | #include <linux/gfp.h> |
37 | #include <linux/security.h> | ||
37 | 38 | ||
38 | #include <asm/cpufeature.h> | 39 | #include <asm/cpufeature.h> |
39 | #include <asm/msr.h> | 40 | #include <asm/msr.h> |
@@ -79,6 +80,10 @@ static ssize_t msr_write(struct file *file, const char __user *buf, | |||
79 | int err = 0; | 80 | int err = 0; |
80 | ssize_t bytes = 0; | 81 | ssize_t bytes = 0; |
81 | 82 | ||
83 | err = security_locked_down(LOCKDOWN_MSR); | ||
84 | if (err) | ||
85 | return err; | ||
86 | |||
82 | if (count % 8) | 87 | if (count % 8) |
83 | return -EINVAL; /* Invalid chunk size */ | 88 | return -EINVAL; /* Invalid chunk size */ |
84 | 89 | ||
@@ -130,6 +135,9 @@ static long msr_ioctl(struct file *file, unsigned int ioc, unsigned long arg) | |||
130 | err = -EFAULT; | 135 | err = -EFAULT; |
131 | break; | 136 | break; |
132 | } | 137 | } |
138 | err = security_locked_down(LOCKDOWN_MSR); | ||
139 | if (err) | ||
140 | break; | ||
133 | err = wrmsr_safe_regs_on_cpu(cpu, regs); | 141 | err = wrmsr_safe_regs_on_cpu(cpu, regs); |
134 | if (err) | 142 | if (err) |
135 | break; | 143 | break; |
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index 1bef687faf22..18a799c8fa28 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c | |||
@@ -95,6 +95,7 @@ struct x86_init_ops x86_init __initdata = { | |||
95 | }, | 95 | }, |
96 | 96 | ||
97 | .acpi = { | 97 | .acpi = { |
98 | .set_root_pointer = x86_default_set_root_pointer, | ||
98 | .get_root_pointer = x86_default_get_root_pointer, | 99 | .get_root_pointer = x86_default_get_root_pointer, |
99 | .reduced_hw_early_init = acpi_generic_reduced_hw_init, | 100 | .reduced_hw_early_init = acpi_generic_reduced_hw_init, |
100 | }, | 101 | }, |
diff --git a/arch/x86/mm/testmmiotrace.c b/arch/x86/mm/testmmiotrace.c index 0881e1ff1e58..a8bd952e136d 100644 --- a/arch/x86/mm/testmmiotrace.c +++ b/arch/x86/mm/testmmiotrace.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/io.h> | 9 | #include <linux/io.h> |
10 | #include <linux/mmiotrace.h> | 10 | #include <linux/mmiotrace.h> |
11 | #include <linux/security.h> | ||
11 | 12 | ||
12 | static unsigned long mmio_address; | 13 | static unsigned long mmio_address; |
13 | module_param_hw(mmio_address, ulong, iomem, 0); | 14 | module_param_hw(mmio_address, ulong, iomem, 0); |
@@ -115,6 +116,10 @@ static void do_test_bulk_ioremapping(void) | |||
115 | static int __init init(void) | 116 | static int __init init(void) |
116 | { | 117 | { |
117 | unsigned long size = (read_far) ? (8 << 20) : (16 << 10); | 118 | unsigned long size = (read_far) ? (8 << 20) : (16 << 10); |
119 | int ret = security_locked_down(LOCKDOWN_MMIOTRACE); | ||
120 | |||
121 | if (ret) | ||
122 | return ret; | ||
118 | 123 | ||
119 | if (mmio_address == 0) { | 124 | if (mmio_address == 0) { |
120 | pr_err("you have to use the module argument mmio_address.\n"); | 125 | pr_err("you have to use the module argument mmio_address.\n"); |
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c index 3b303fe2f061..cc9dbcecaaca 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c | |||
@@ -96,7 +96,7 @@ static int pefile_parse_binary(const void *pebuf, unsigned int pelen, | |||
96 | 96 | ||
97 | if (!ddir->certs.virtual_address || !ddir->certs.size) { | 97 | if (!ddir->certs.virtual_address || !ddir->certs.size) { |
98 | pr_debug("Unsigned PE binary\n"); | 98 | pr_debug("Unsigned PE binary\n"); |
99 | return -EKEYREJECTED; | 99 | return -ENODATA; |
100 | } | 100 | } |
101 | 101 | ||
102 | chkaddr(ctx->header_size, ddir->certs.virtual_address, | 102 | chkaddr(ctx->header_size, ddir->certs.virtual_address, |
@@ -403,6 +403,8 @@ error_no_desc: | |||
403 | * (*) 0 if at least one signature chain intersects with the keys in the trust | 403 | * (*) 0 if at least one signature chain intersects with the keys in the trust |
404 | * keyring, or: | 404 | * keyring, or: |
405 | * | 405 | * |
406 | * (*) -ENODATA if there is no signature present. | ||
407 | * | ||
406 | * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a | 408 | * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a |
407 | * chain. | 409 | * chain. |
408 | * | 410 | * |
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index fd66a736621c..b097ef209313 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/uaccess.h> | 9 | #include <linux/uaccess.h> |
10 | #include <linux/debugfs.h> | 10 | #include <linux/debugfs.h> |
11 | #include <linux/acpi.h> | 11 | #include <linux/acpi.h> |
12 | #include <linux/security.h> | ||
12 | 13 | ||
13 | #include "internal.h" | 14 | #include "internal.h" |
14 | 15 | ||
@@ -29,6 +30,11 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, | |||
29 | 30 | ||
30 | struct acpi_table_header table; | 31 | struct acpi_table_header table; |
31 | acpi_status status; | 32 | acpi_status status; |
33 | int ret; | ||
34 | |||
35 | ret = security_locked_down(LOCKDOWN_ACPI_TABLES); | ||
36 | if (ret) | ||
37 | return ret; | ||
32 | 38 | ||
33 | if (!(*ppos)) { | 39 | if (!(*ppos)) { |
34 | /* parse the table header to get the table length */ | 40 | /* parse the table header to get the table length */ |
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 2f9d0d20b836..a2e844a8e9ed 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/list.h> | 27 | #include <linux/list.h> |
28 | #include <linux/jiffies.h> | 28 | #include <linux/jiffies.h> |
29 | #include <linux/semaphore.h> | 29 | #include <linux/semaphore.h> |
30 | #include <linux/security.h> | ||
30 | 31 | ||
31 | #include <asm/io.h> | 32 | #include <asm/io.h> |
32 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
@@ -182,8 +183,19 @@ acpi_physical_address __init acpi_os_get_root_pointer(void) | |||
182 | acpi_physical_address pa; | 183 | acpi_physical_address pa; |
183 | 184 | ||
184 | #ifdef CONFIG_KEXEC | 185 | #ifdef CONFIG_KEXEC |
185 | if (acpi_rsdp) | 186 | /* |
187 | * We may have been provided with an RSDP on the command line, | ||
188 | * but if a malicious user has done so they may be pointing us | ||
189 | * at modified ACPI tables that could alter kernel behaviour - | ||
190 | * so, we check the lockdown status before making use of | ||
191 | * it. If we trust it then also stash it in an architecture | ||
192 | * specific location (if appropriate) so it can be carried | ||
193 | * over further kexec()s. | ||
194 | */ | ||
195 | if (acpi_rsdp && !security_locked_down(LOCKDOWN_ACPI_TABLES)) { | ||
196 | acpi_arch_set_root_pointer(acpi_rsdp); | ||
186 | return acpi_rsdp; | 197 | return acpi_rsdp; |
198 | } | ||
187 | #endif | 199 | #endif |
188 | pa = acpi_arch_get_root_pointer(); | 200 | pa = acpi_arch_get_root_pointer(); |
189 | if (pa) | 201 | if (pa) |
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index b32327759380..180ac4329763 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/memblock.h> | 20 | #include <linux/memblock.h> |
21 | #include <linux/earlycpio.h> | 21 | #include <linux/earlycpio.h> |
22 | #include <linux/initrd.h> | 22 | #include <linux/initrd.h> |
23 | #include <linux/security.h> | ||
23 | #include "internal.h" | 24 | #include "internal.h" |
24 | 25 | ||
25 | #ifdef CONFIG_ACPI_CUSTOM_DSDT | 26 | #ifdef CONFIG_ACPI_CUSTOM_DSDT |
@@ -578,6 +579,11 @@ void __init acpi_table_upgrade(void) | |||
578 | if (table_nr == 0) | 579 | if (table_nr == 0) |
579 | return; | 580 | return; |
580 | 581 | ||
582 | if (security_locked_down(LOCKDOWN_ACPI_TABLES)) { | ||
583 | pr_notice("kernel is locked down, ignoring table override\n"); | ||
584 | return; | ||
585 | } | ||
586 | |||
581 | acpi_tables_addr = | 587 | acpi_tables_addr = |
582 | memblock_find_in_range(0, ACPI_TABLE_UPGRADE_MAX_PHYS, | 588 | memblock_find_in_range(0, ACPI_TABLE_UPGRADE_MAX_PHYS, |
583 | all_tables_size, PAGE_SIZE); | 589 | all_tables_size, PAGE_SIZE); |
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 9eb564c002f6..43dd0891ca1e 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -29,8 +29,8 @@ | |||
29 | #include <linux/export.h> | 29 | #include <linux/export.h> |
30 | #include <linux/io.h> | 30 | #include <linux/io.h> |
31 | #include <linux/uio.h> | 31 | #include <linux/uio.h> |
32 | |||
33 | #include <linux/uaccess.h> | 32 | #include <linux/uaccess.h> |
33 | #include <linux/security.h> | ||
34 | 34 | ||
35 | #ifdef CONFIG_IA64 | 35 | #ifdef CONFIG_IA64 |
36 | # include <linux/efi.h> | 36 | # include <linux/efi.h> |
@@ -807,7 +807,10 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig) | |||
807 | 807 | ||
808 | static int open_port(struct inode *inode, struct file *filp) | 808 | static int open_port(struct inode *inode, struct file *filp) |
809 | { | 809 | { |
810 | return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; | 810 | if (!capable(CAP_SYS_RAWIO)) |
811 | return -EPERM; | ||
812 | |||
813 | return security_locked_down(LOCKDOWN_DEV_MEM); | ||
811 | } | 814 | } |
812 | 815 | ||
813 | #define zero_lseek null_lseek | 816 | #define zero_lseek null_lseek |
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 8f1ab04f6743..8d3e778e988b 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/acpi.h> | 30 | #include <linux/acpi.h> |
31 | #include <linux/ucs2_string.h> | 31 | #include <linux/ucs2_string.h> |
32 | #include <linux/memblock.h> | 32 | #include <linux/memblock.h> |
33 | #include <linux/security.h> | ||
33 | 34 | ||
34 | #include <asm/early_ioremap.h> | 35 | #include <asm/early_ioremap.h> |
35 | 36 | ||
@@ -221,6 +222,11 @@ static void generic_ops_unregister(void) | |||
221 | static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata; | 222 | static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata; |
222 | static int __init efivar_ssdt_setup(char *str) | 223 | static int __init efivar_ssdt_setup(char *str) |
223 | { | 224 | { |
225 | int ret = security_locked_down(LOCKDOWN_ACPI_TABLES); | ||
226 | |||
227 | if (ret) | ||
228 | return ret; | ||
229 | |||
224 | if (strlen(str) < sizeof(efivar_ssdt)) | 230 | if (strlen(str) < sizeof(efivar_ssdt)) |
225 | memcpy(efivar_ssdt, str, strlen(str)); | 231 | memcpy(efivar_ssdt, str, strlen(str)); |
226 | else | 232 | else |
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 868e35109284..793412954529 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -755,6 +755,11 @@ static ssize_t pci_write_config(struct file *filp, struct kobject *kobj, | |||
755 | unsigned int size = count; | 755 | unsigned int size = count; |
756 | loff_t init_off = off; | 756 | loff_t init_off = off; |
757 | u8 *data = (u8 *) buf; | 757 | u8 *data = (u8 *) buf; |
758 | int ret; | ||
759 | |||
760 | ret = security_locked_down(LOCKDOWN_PCI_ACCESS); | ||
761 | if (ret) | ||
762 | return ret; | ||
758 | 763 | ||
759 | if (off > dev->cfg_size) | 764 | if (off > dev->cfg_size) |
760 | return 0; | 765 | return 0; |
@@ -1016,6 +1021,11 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, | |||
1016 | int bar = (unsigned long)attr->private; | 1021 | int bar = (unsigned long)attr->private; |
1017 | enum pci_mmap_state mmap_type; | 1022 | enum pci_mmap_state mmap_type; |
1018 | struct resource *res = &pdev->resource[bar]; | 1023 | struct resource *res = &pdev->resource[bar]; |
1024 | int ret; | ||
1025 | |||
1026 | ret = security_locked_down(LOCKDOWN_PCI_ACCESS); | ||
1027 | if (ret) | ||
1028 | return ret; | ||
1019 | 1029 | ||
1020 | if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start)) | 1030 | if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start)) |
1021 | return -EINVAL; | 1031 | return -EINVAL; |
@@ -1092,6 +1102,12 @@ static ssize_t pci_write_resource_io(struct file *filp, struct kobject *kobj, | |||
1092 | struct bin_attribute *attr, char *buf, | 1102 | struct bin_attribute *attr, char *buf, |
1093 | loff_t off, size_t count) | 1103 | loff_t off, size_t count) |
1094 | { | 1104 | { |
1105 | int ret; | ||
1106 | |||
1107 | ret = security_locked_down(LOCKDOWN_PCI_ACCESS); | ||
1108 | if (ret) | ||
1109 | return ret; | ||
1110 | |||
1095 | return pci_resource_io(filp, kobj, attr, buf, off, count, true); | 1111 | return pci_resource_io(filp, kobj, attr, buf, off, count, true); |
1096 | } | 1112 | } |
1097 | 1113 | ||
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index fe7fe678965b..5495537c60c2 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/seq_file.h> | 13 | #include <linux/seq_file.h> |
14 | #include <linux/capability.h> | 14 | #include <linux/capability.h> |
15 | #include <linux/uaccess.h> | 15 | #include <linux/uaccess.h> |
16 | #include <linux/security.h> | ||
16 | #include <asm/byteorder.h> | 17 | #include <asm/byteorder.h> |
17 | #include "pci.h" | 18 | #include "pci.h" |
18 | 19 | ||
@@ -115,7 +116,11 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf, | |||
115 | struct pci_dev *dev = PDE_DATA(ino); | 116 | struct pci_dev *dev = PDE_DATA(ino); |
116 | int pos = *ppos; | 117 | int pos = *ppos; |
117 | int size = dev->cfg_size; | 118 | int size = dev->cfg_size; |
118 | int cnt; | 119 | int cnt, ret; |
120 | |||
121 | ret = security_locked_down(LOCKDOWN_PCI_ACCESS); | ||
122 | if (ret) | ||
123 | return ret; | ||
119 | 124 | ||
120 | if (pos >= size) | 125 | if (pos >= size) |
121 | return 0; | 126 | return 0; |
@@ -196,6 +201,10 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd, | |||
196 | #endif /* HAVE_PCI_MMAP */ | 201 | #endif /* HAVE_PCI_MMAP */ |
197 | int ret = 0; | 202 | int ret = 0; |
198 | 203 | ||
204 | ret = security_locked_down(LOCKDOWN_PCI_ACCESS); | ||
205 | if (ret) | ||
206 | return ret; | ||
207 | |||
199 | switch (cmd) { | 208 | switch (cmd) { |
200 | case PCIIOC_CONTROLLER: | 209 | case PCIIOC_CONTROLLER: |
201 | ret = pci_domain_nr(dev->bus); | 210 | ret = pci_domain_nr(dev->bus); |
@@ -238,7 +247,8 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) | |||
238 | struct pci_filp_private *fpriv = file->private_data; | 247 | struct pci_filp_private *fpriv = file->private_data; |
239 | int i, ret, write_combine = 0, res_bit = IORESOURCE_MEM; | 248 | int i, ret, write_combine = 0, res_bit = IORESOURCE_MEM; |
240 | 249 | ||
241 | if (!capable(CAP_SYS_RAWIO)) | 250 | if (!capable(CAP_SYS_RAWIO) || |
251 | security_locked_down(LOCKDOWN_PCI_ACCESS)) | ||
242 | return -EPERM; | 252 | return -EPERM; |
243 | 253 | ||
244 | if (fpriv->mmap_state == pci_mmap_io) { | 254 | if (fpriv->mmap_state == pci_mmap_io) { |
diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index d96626c614f5..31e39558d49d 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c | |||
@@ -7,6 +7,7 @@ | |||
7 | 7 | ||
8 | #include <linux/errno.h> | 8 | #include <linux/errno.h> |
9 | #include <linux/pci.h> | 9 | #include <linux/pci.h> |
10 | #include <linux/security.h> | ||
10 | #include <linux/syscalls.h> | 11 | #include <linux/syscalls.h> |
11 | #include <linux/uaccess.h> | 12 | #include <linux/uaccess.h> |
12 | #include "pci.h" | 13 | #include "pci.h" |
@@ -90,7 +91,8 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn, | |||
90 | u32 dword; | 91 | u32 dword; |
91 | int err = 0; | 92 | int err = 0; |
92 | 93 | ||
93 | if (!capable(CAP_SYS_ADMIN)) | 94 | if (!capable(CAP_SYS_ADMIN) || |
95 | security_locked_down(LOCKDOWN_PCI_ACCESS)) | ||
94 | return -EPERM; | 96 | return -EPERM; |
95 | 97 | ||
96 | dev = pci_get_domain_bus_and_slot(0, bus, dfn); | 98 | dev = pci_get_domain_bus_and_slot(0, bus, dfn); |
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index abd029945cc8..629359fe3513 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
22 | #include <linux/ioport.h> | 22 | #include <linux/ioport.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/security.h> | ||
24 | #include <asm/byteorder.h> | 25 | #include <asm/byteorder.h> |
25 | #include <asm/unaligned.h> | 26 | #include <asm/unaligned.h> |
26 | 27 | ||
@@ -1575,6 +1576,10 @@ static ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj, | |||
1575 | struct pcmcia_socket *s; | 1576 | struct pcmcia_socket *s; |
1576 | int error; | 1577 | int error; |
1577 | 1578 | ||
1579 | error = security_locked_down(LOCKDOWN_PCMCIA_CIS); | ||
1580 | if (error) | ||
1581 | return error; | ||
1582 | |||
1578 | s = to_socket(container_of(kobj, struct device, kobj)); | 1583 | s = to_socket(container_of(kobj, struct device, kobj)); |
1579 | 1584 | ||
1580 | if (off) | 1585 | if (off) |
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 4223cb496764..6e713be1d4e9 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/serial_core.h> | 22 | #include <linux/serial_core.h> |
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/security.h> | ||
25 | 26 | ||
26 | #include <linux/irq.h> | 27 | #include <linux/irq.h> |
27 | #include <linux/uaccess.h> | 28 | #include <linux/uaccess.h> |
@@ -862,6 +863,10 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, | |||
862 | goto check_and_exit; | 863 | goto check_and_exit; |
863 | } | 864 | } |
864 | 865 | ||
866 | retval = security_locked_down(LOCKDOWN_TIOCSSERIAL); | ||
867 | if (retval && (change_irq || change_port)) | ||
868 | goto exit; | ||
869 | |||
865 | /* | 870 | /* |
866 | * Ask the low level driver to verify the settings. | 871 | * Ask the low level driver to verify the settings. |
867 | */ | 872 | */ |
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 93e4ca6b2ad7..87846aad594b 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/atomic.h> | 19 | #include <linux/atomic.h> |
20 | #include <linux/device.h> | 20 | #include <linux/device.h> |
21 | #include <linux/poll.h> | 21 | #include <linux/poll.h> |
22 | #include <linux/security.h> | ||
22 | 23 | ||
23 | #include "internal.h" | 24 | #include "internal.h" |
24 | 25 | ||
@@ -136,6 +137,25 @@ void debugfs_file_put(struct dentry *dentry) | |||
136 | } | 137 | } |
137 | EXPORT_SYMBOL_GPL(debugfs_file_put); | 138 | EXPORT_SYMBOL_GPL(debugfs_file_put); |
138 | 139 | ||
140 | /* | ||
141 | * Only permit access to world-readable files when the kernel is locked down. | ||
142 | * We also need to exclude any file that has ways to write or alter it as root | ||
143 | * can bypass the permissions check. | ||
144 | */ | ||
145 | static bool debugfs_is_locked_down(struct inode *inode, | ||
146 | struct file *filp, | ||
147 | const struct file_operations *real_fops) | ||
148 | { | ||
149 | if ((inode->i_mode & 07777) == 0444 && | ||
150 | !(filp->f_mode & FMODE_WRITE) && | ||
151 | !real_fops->unlocked_ioctl && | ||
152 | !real_fops->compat_ioctl && | ||
153 | !real_fops->mmap) | ||
154 | return false; | ||
155 | |||
156 | return security_locked_down(LOCKDOWN_DEBUGFS); | ||
157 | } | ||
158 | |||
139 | static int open_proxy_open(struct inode *inode, struct file *filp) | 159 | static int open_proxy_open(struct inode *inode, struct file *filp) |
140 | { | 160 | { |
141 | struct dentry *dentry = F_DENTRY(filp); | 161 | struct dentry *dentry = F_DENTRY(filp); |
@@ -147,6 +167,11 @@ static int open_proxy_open(struct inode *inode, struct file *filp) | |||
147 | return r == -EIO ? -ENOENT : r; | 167 | return r == -EIO ? -ENOENT : r; |
148 | 168 | ||
149 | real_fops = debugfs_real_fops(filp); | 169 | real_fops = debugfs_real_fops(filp); |
170 | |||
171 | r = debugfs_is_locked_down(inode, filp, real_fops); | ||
172 | if (r) | ||
173 | goto out; | ||
174 | |||
150 | real_fops = fops_get(real_fops); | 175 | real_fops = fops_get(real_fops); |
151 | if (!real_fops) { | 176 | if (!real_fops) { |
152 | /* Huh? Module did not clean up after itself at exit? */ | 177 | /* Huh? Module did not clean up after itself at exit? */ |
@@ -272,6 +297,11 @@ static int full_proxy_open(struct inode *inode, struct file *filp) | |||
272 | return r == -EIO ? -ENOENT : r; | 297 | return r == -EIO ? -ENOENT : r; |
273 | 298 | ||
274 | real_fops = debugfs_real_fops(filp); | 299 | real_fops = debugfs_real_fops(filp); |
300 | |||
301 | r = debugfs_is_locked_down(inode, filp, real_fops); | ||
302 | if (r) | ||
303 | goto out; | ||
304 | |||
275 | real_fops = fops_get(real_fops); | 305 | real_fops = fops_get(real_fops); |
276 | if (!real_fops) { | 306 | if (!real_fops) { |
277 | /* Huh? Module did not cleanup after itself at exit? */ | 307 | /* Huh? Module did not cleanup after itself at exit? */ |
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 042b688ed124..7b975dbb2bb4 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/parser.h> | 26 | #include <linux/parser.h> |
27 | #include <linux/magic.h> | 27 | #include <linux/magic.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/security.h> | ||
29 | 30 | ||
30 | #include "internal.h" | 31 | #include "internal.h" |
31 | 32 | ||
@@ -35,6 +36,32 @@ static struct vfsmount *debugfs_mount; | |||
35 | static int debugfs_mount_count; | 36 | static int debugfs_mount_count; |
36 | static bool debugfs_registered; | 37 | static bool debugfs_registered; |
37 | 38 | ||
39 | /* | ||
40 | * Don't allow access attributes to be changed whilst the kernel is locked down | ||
41 | * so that we can use the file mode as part of a heuristic to determine whether | ||
42 | * to lock down individual files. | ||
43 | */ | ||
44 | static int debugfs_setattr(struct dentry *dentry, struct iattr *ia) | ||
45 | { | ||
46 | int ret = security_locked_down(LOCKDOWN_DEBUGFS); | ||
47 | |||
48 | if (ret && (ia->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))) | ||
49 | return ret; | ||
50 | return simple_setattr(dentry, ia); | ||
51 | } | ||
52 | |||
53 | static const struct inode_operations debugfs_file_inode_operations = { | ||
54 | .setattr = debugfs_setattr, | ||
55 | }; | ||
56 | static const struct inode_operations debugfs_dir_inode_operations = { | ||
57 | .lookup = simple_lookup, | ||
58 | .setattr = debugfs_setattr, | ||
59 | }; | ||
60 | static const struct inode_operations debugfs_symlink_inode_operations = { | ||
61 | .get_link = simple_get_link, | ||
62 | .setattr = debugfs_setattr, | ||
63 | }; | ||
64 | |||
38 | static struct inode *debugfs_get_inode(struct super_block *sb) | 65 | static struct inode *debugfs_get_inode(struct super_block *sb) |
39 | { | 66 | { |
40 | struct inode *inode = new_inode(sb); | 67 | struct inode *inode = new_inode(sb); |
@@ -369,6 +396,7 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode, | |||
369 | inode->i_mode = mode; | 396 | inode->i_mode = mode; |
370 | inode->i_private = data; | 397 | inode->i_private = data; |
371 | 398 | ||
399 | inode->i_op = &debugfs_file_inode_operations; | ||
372 | inode->i_fop = proxy_fops; | 400 | inode->i_fop = proxy_fops; |
373 | dentry->d_fsdata = (void *)((unsigned long)real_fops | | 401 | dentry->d_fsdata = (void *)((unsigned long)real_fops | |
374 | DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); | 402 | DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); |
@@ -532,7 +560,7 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) | |||
532 | } | 560 | } |
533 | 561 | ||
534 | inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; | 562 | inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; |
535 | inode->i_op = &simple_dir_inode_operations; | 563 | inode->i_op = &debugfs_dir_inode_operations; |
536 | inode->i_fop = &simple_dir_operations; | 564 | inode->i_fop = &simple_dir_operations; |
537 | 565 | ||
538 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | 566 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ |
@@ -632,7 +660,7 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, | |||
632 | return failed_creating(dentry); | 660 | return failed_creating(dentry); |
633 | } | 661 | } |
634 | inode->i_mode = S_IFLNK | S_IRWXUGO; | 662 | inode->i_mode = S_IFLNK | S_IRWXUGO; |
635 | inode->i_op = &simple_symlink_inode_operations; | 663 | inode->i_op = &debugfs_symlink_inode_operations; |
636 | inode->i_link = link; | 664 | inode->i_link = link; |
637 | d_instantiate(dentry, inode); | 665 | d_instantiate(dentry, inode); |
638 | return end_creating(dentry); | 666 | return end_creating(dentry); |
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index f5834488b67d..e2ed8e08cc7a 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/ioport.h> | 31 | #include <linux/ioport.h> |
32 | #include <linux/memory.h> | 32 | #include <linux/memory.h> |
33 | #include <linux/sched/task.h> | 33 | #include <linux/sched/task.h> |
34 | #include <linux/security.h> | ||
34 | #include <asm/sections.h> | 35 | #include <asm/sections.h> |
35 | #include "internal.h" | 36 | #include "internal.h" |
36 | 37 | ||
@@ -545,9 +546,14 @@ out: | |||
545 | 546 | ||
546 | static int open_kcore(struct inode *inode, struct file *filp) | 547 | static int open_kcore(struct inode *inode, struct file *filp) |
547 | { | 548 | { |
549 | int ret = security_locked_down(LOCKDOWN_KCORE); | ||
550 | |||
548 | if (!capable(CAP_SYS_RAWIO)) | 551 | if (!capable(CAP_SYS_RAWIO)) |
549 | return -EPERM; | 552 | return -EPERM; |
550 | 553 | ||
554 | if (ret) | ||
555 | return ret; | ||
556 | |||
551 | filp->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL); | 557 | filp->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL); |
552 | if (!filp->private_data) | 558 | if (!filp->private_data) |
553 | return -ENOMEM; | 559 | return -ENOMEM; |
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index eeeae0475da9..9fc14e38927f 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/parser.h> | 20 | #include <linux/parser.h> |
21 | #include <linux/magic.h> | 21 | #include <linux/magic.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/security.h> | ||
23 | 24 | ||
24 | #define TRACEFS_DEFAULT_MODE 0700 | 25 | #define TRACEFS_DEFAULT_MODE 0700 |
25 | 26 | ||
@@ -27,6 +28,25 @@ static struct vfsmount *tracefs_mount; | |||
27 | static int tracefs_mount_count; | 28 | static int tracefs_mount_count; |
28 | static bool tracefs_registered; | 29 | static bool tracefs_registered; |
29 | 30 | ||
31 | static int default_open_file(struct inode *inode, struct file *filp) | ||
32 | { | ||
33 | struct dentry *dentry = filp->f_path.dentry; | ||
34 | struct file_operations *real_fops; | ||
35 | int ret; | ||
36 | |||
37 | if (!dentry) | ||
38 | return -EINVAL; | ||
39 | |||
40 | ret = security_locked_down(LOCKDOWN_TRACEFS); | ||
41 | if (ret) | ||
42 | return ret; | ||
43 | |||
44 | real_fops = dentry->d_fsdata; | ||
45 | if (!real_fops->open) | ||
46 | return 0; | ||
47 | return real_fops->open(inode, filp); | ||
48 | } | ||
49 | |||
30 | static ssize_t default_read_file(struct file *file, char __user *buf, | 50 | static ssize_t default_read_file(struct file *file, char __user *buf, |
31 | size_t count, loff_t *ppos) | 51 | size_t count, loff_t *ppos) |
32 | { | 52 | { |
@@ -221,6 +241,12 @@ static int tracefs_apply_options(struct super_block *sb) | |||
221 | return 0; | 241 | return 0; |
222 | } | 242 | } |
223 | 243 | ||
244 | static void tracefs_destroy_inode(struct inode *inode) | ||
245 | { | ||
246 | if (S_ISREG(inode->i_mode)) | ||
247 | kfree(inode->i_fop); | ||
248 | } | ||
249 | |||
224 | static int tracefs_remount(struct super_block *sb, int *flags, char *data) | 250 | static int tracefs_remount(struct super_block *sb, int *flags, char *data) |
225 | { | 251 | { |
226 | int err; | 252 | int err; |
@@ -257,6 +283,7 @@ static int tracefs_show_options(struct seq_file *m, struct dentry *root) | |||
257 | static const struct super_operations tracefs_super_operations = { | 283 | static const struct super_operations tracefs_super_operations = { |
258 | .statfs = simple_statfs, | 284 | .statfs = simple_statfs, |
259 | .remount_fs = tracefs_remount, | 285 | .remount_fs = tracefs_remount, |
286 | .destroy_inode = tracefs_destroy_inode, | ||
260 | .show_options = tracefs_show_options, | 287 | .show_options = tracefs_show_options, |
261 | }; | 288 | }; |
262 | 289 | ||
@@ -387,6 +414,7 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, | |||
387 | struct dentry *parent, void *data, | 414 | struct dentry *parent, void *data, |
388 | const struct file_operations *fops) | 415 | const struct file_operations *fops) |
389 | { | 416 | { |
417 | struct file_operations *proxy_fops; | ||
390 | struct dentry *dentry; | 418 | struct dentry *dentry; |
391 | struct inode *inode; | 419 | struct inode *inode; |
392 | 420 | ||
@@ -402,8 +430,20 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode, | |||
402 | if (unlikely(!inode)) | 430 | if (unlikely(!inode)) |
403 | return failed_creating(dentry); | 431 | return failed_creating(dentry); |
404 | 432 | ||
433 | proxy_fops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); | ||
434 | if (unlikely(!proxy_fops)) { | ||
435 | iput(inode); | ||
436 | return failed_creating(dentry); | ||
437 | } | ||
438 | |||
439 | if (!fops) | ||
440 | fops = &tracefs_file_operations; | ||
441 | |||
442 | dentry->d_fsdata = (void *)fops; | ||
443 | memcpy(proxy_fops, fops, sizeof(*proxy_fops)); | ||
444 | proxy_fops->open = default_open_file; | ||
405 | inode->i_mode = mode; | 445 | inode->i_mode = mode; |
406 | inode->i_fop = fops ? fops : &tracefs_file_operations; | 446 | inode->i_fop = proxy_fops; |
407 | inode->i_private = data; | 447 | inode->i_private = data; |
408 | d_instantiate(dentry, inode); | 448 | d_instantiate(dentry, inode); |
409 | fsnotify_create(dentry->d_parent->d_inode, dentry); | 449 | fsnotify_create(dentry->d_parent->d_inode, dentry); |
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index cd28f63bfbc7..dae64600ccbf 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h | |||
@@ -215,8 +215,13 @@ | |||
215 | __start_lsm_info = .; \ | 215 | __start_lsm_info = .; \ |
216 | KEEP(*(.lsm_info.init)) \ | 216 | KEEP(*(.lsm_info.init)) \ |
217 | __end_lsm_info = .; | 217 | __end_lsm_info = .; |
218 | #define EARLY_LSM_TABLE() . = ALIGN(8); \ | ||
219 | __start_early_lsm_info = .; \ | ||
220 | KEEP(*(.early_lsm_info.init)) \ | ||
221 | __end_early_lsm_info = .; | ||
218 | #else | 222 | #else |
219 | #define LSM_TABLE() | 223 | #define LSM_TABLE() |
224 | #define EARLY_LSM_TABLE() | ||
220 | #endif | 225 | #endif |
221 | 226 | ||
222 | #define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name) | 227 | #define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name) |
@@ -627,7 +632,8 @@ | |||
627 | ACPI_PROBE_TABLE(timer) \ | 632 | ACPI_PROBE_TABLE(timer) \ |
628 | THERMAL_TABLE(governor) \ | 633 | THERMAL_TABLE(governor) \ |
629 | EARLYCON_TABLE() \ | 634 | EARLYCON_TABLE() \ |
630 | LSM_TABLE() | 635 | LSM_TABLE() \ |
636 | EARLY_LSM_TABLE() | ||
631 | 637 | ||
632 | #define INIT_TEXT \ | 638 | #define INIT_TEXT \ |
633 | *(.init.text .init.text.*) \ | 639 | *(.init.text .init.text.*) \ |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 978cc239f23b..8b4e516bac00 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
@@ -643,6 +643,12 @@ bool acpi_gtdt_c3stop(int type); | |||
643 | int acpi_arch_timer_mem_init(struct arch_timer_mem *timer_mem, int *timer_count); | 643 | int acpi_arch_timer_mem_init(struct arch_timer_mem *timer_mem, int *timer_count); |
644 | #endif | 644 | #endif |
645 | 645 | ||
646 | #ifndef ACPI_HAVE_ARCH_SET_ROOT_POINTER | ||
647 | static inline void acpi_arch_set_root_pointer(u64 addr) | ||
648 | { | ||
649 | } | ||
650 | #endif | ||
651 | |||
646 | #ifndef ACPI_HAVE_ARCH_GET_ROOT_POINTER | 652 | #ifndef ACPI_HAVE_ARCH_GET_ROOT_POINTER |
647 | static inline u64 acpi_arch_get_root_pointer(void) | 653 | static inline u64 acpi_arch_get_root_pointer(void) |
648 | { | 654 | { |
diff --git a/include/linux/ima.h b/include/linux/ima.h index a20ad398d260..1c37f17f7203 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h | |||
@@ -131,4 +131,13 @@ static inline int ima_inode_removexattr(struct dentry *dentry, | |||
131 | return 0; | 131 | return 0; |
132 | } | 132 | } |
133 | #endif /* CONFIG_IMA_APPRAISE */ | 133 | #endif /* CONFIG_IMA_APPRAISE */ |
134 | |||
135 | #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING) | ||
136 | extern bool ima_appraise_signature(enum kernel_read_file_id func); | ||
137 | #else | ||
138 | static inline bool ima_appraise_signature(enum kernel_read_file_id func) | ||
139 | { | ||
140 | return false; | ||
141 | } | ||
142 | #endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */ | ||
134 | #endif /* _LINUX_IMA_H */ | 143 | #endif /* _LINUX_IMA_H */ |
diff --git a/include/linux/kexec.h b/include/linux/kexec.h index cc162f3e6461..1776eb2e43a4 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h | |||
@@ -125,7 +125,7 @@ typedef void *(kexec_load_t)(struct kimage *image, char *kernel_buf, | |||
125 | unsigned long cmdline_len); | 125 | unsigned long cmdline_len); |
126 | typedef int (kexec_cleanup_t)(void *loader_data); | 126 | typedef int (kexec_cleanup_t)(void *loader_data); |
127 | 127 | ||
128 | #ifdef CONFIG_KEXEC_VERIFY_SIG | 128 | #ifdef CONFIG_KEXEC_SIG |
129 | typedef int (kexec_verify_sig_t)(const char *kernel_buf, | 129 | typedef int (kexec_verify_sig_t)(const char *kernel_buf, |
130 | unsigned long kernel_len); | 130 | unsigned long kernel_len); |
131 | #endif | 131 | #endif |
@@ -134,7 +134,7 @@ struct kexec_file_ops { | |||
134 | kexec_probe_t *probe; | 134 | kexec_probe_t *probe; |
135 | kexec_load_t *load; | 135 | kexec_load_t *load; |
136 | kexec_cleanup_t *cleanup; | 136 | kexec_cleanup_t *cleanup; |
137 | #ifdef CONFIG_KEXEC_VERIFY_SIG | 137 | #ifdef CONFIG_KEXEC_SIG |
138 | kexec_verify_sig_t *verify_sig; | 138 | kexec_verify_sig_t *verify_sig; |
139 | #endif | 139 | #endif |
140 | }; | 140 | }; |
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 3fced5824aee..a3763247547c 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h | |||
@@ -1449,6 +1449,11 @@ | |||
1449 | * @bpf_prog_free_security: | 1449 | * @bpf_prog_free_security: |
1450 | * Clean up the security information stored inside bpf prog. | 1450 | * Clean up the security information stored inside bpf prog. |
1451 | * | 1451 | * |
1452 | * @locked_down | ||
1453 | * Determine whether a kernel feature that potentially enables arbitrary | ||
1454 | * code execution in kernel space should be permitted. | ||
1455 | * | ||
1456 | * @what: kernel feature being accessed | ||
1452 | */ | 1457 | */ |
1453 | union security_list_options { | 1458 | union security_list_options { |
1454 | int (*binder_set_context_mgr)(struct task_struct *mgr); | 1459 | int (*binder_set_context_mgr)(struct task_struct *mgr); |
@@ -1812,6 +1817,7 @@ union security_list_options { | |||
1812 | int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux); | 1817 | int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux); |
1813 | void (*bpf_prog_free_security)(struct bpf_prog_aux *aux); | 1818 | void (*bpf_prog_free_security)(struct bpf_prog_aux *aux); |
1814 | #endif /* CONFIG_BPF_SYSCALL */ | 1819 | #endif /* CONFIG_BPF_SYSCALL */ |
1820 | int (*locked_down)(enum lockdown_reason what); | ||
1815 | }; | 1821 | }; |
1816 | 1822 | ||
1817 | struct security_hook_heads { | 1823 | struct security_hook_heads { |
@@ -2053,6 +2059,7 @@ struct security_hook_heads { | |||
2053 | struct hlist_head bpf_prog_alloc_security; | 2059 | struct hlist_head bpf_prog_alloc_security; |
2054 | struct hlist_head bpf_prog_free_security; | 2060 | struct hlist_head bpf_prog_free_security; |
2055 | #endif /* CONFIG_BPF_SYSCALL */ | 2061 | #endif /* CONFIG_BPF_SYSCALL */ |
2062 | struct hlist_head locked_down; | ||
2056 | } __randomize_layout; | 2063 | } __randomize_layout; |
2057 | 2064 | ||
2058 | /* | 2065 | /* |
@@ -2111,12 +2118,18 @@ struct lsm_info { | |||
2111 | }; | 2118 | }; |
2112 | 2119 | ||
2113 | extern struct lsm_info __start_lsm_info[], __end_lsm_info[]; | 2120 | extern struct lsm_info __start_lsm_info[], __end_lsm_info[]; |
2121 | extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[]; | ||
2114 | 2122 | ||
2115 | #define DEFINE_LSM(lsm) \ | 2123 | #define DEFINE_LSM(lsm) \ |
2116 | static struct lsm_info __lsm_##lsm \ | 2124 | static struct lsm_info __lsm_##lsm \ |
2117 | __used __section(.lsm_info.init) \ | 2125 | __used __section(.lsm_info.init) \ |
2118 | __aligned(sizeof(unsigned long)) | 2126 | __aligned(sizeof(unsigned long)) |
2119 | 2127 | ||
2128 | #define DEFINE_EARLY_LSM(lsm) \ | ||
2129 | static struct lsm_info __early_lsm_##lsm \ | ||
2130 | __used __section(.early_lsm_info.init) \ | ||
2131 | __aligned(sizeof(unsigned long)) | ||
2132 | |||
2120 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 2133 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
2121 | /* | 2134 | /* |
2122 | * Assuring the safety of deleting a security module is up to | 2135 | * Assuring the safety of deleting a security module is up to |
diff --git a/include/linux/security.h b/include/linux/security.h index ace6fdb604f9..a8d59d612d27 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -77,6 +77,54 @@ enum lsm_event { | |||
77 | LSM_POLICY_CHANGE, | 77 | LSM_POLICY_CHANGE, |
78 | }; | 78 | }; |
79 | 79 | ||
80 | /* | ||
81 | * These are reasons that can be passed to the security_locked_down() | ||
82 | * LSM hook. Lockdown reasons that protect kernel integrity (ie, the | ||
83 | * ability for userland to modify kernel code) are placed before | ||
84 | * LOCKDOWN_INTEGRITY_MAX. Lockdown reasons that protect kernel | ||
85 | * confidentiality (ie, the ability for userland to extract | ||
86 | * information from the running kernel that would otherwise be | ||
87 | * restricted) are placed before LOCKDOWN_CONFIDENTIALITY_MAX. | ||
88 | * | ||
89 | * LSM authors should note that the semantics of any given lockdown | ||
90 | * reason are not guaranteed to be stable - the same reason may block | ||
91 | * one set of features in one kernel release, and a slightly different | ||
92 | * set of features in a later kernel release. LSMs that seek to expose | ||
93 | * lockdown policy at any level of granularity other than "none", | ||
94 | * "integrity" or "confidentiality" are responsible for either | ||
95 | * ensuring that they expose a consistent level of functionality to | ||
96 | * userland, or ensuring that userland is aware that this is | ||
97 | * potentially a moving target. It is easy to misuse this information | ||
98 | * in a way that could break userspace. Please be careful not to do | ||
99 | * so. | ||
100 | * | ||
101 | * If you add to this, remember to extend lockdown_reasons in | ||
102 | * security/lockdown/lockdown.c. | ||
103 | */ | ||
104 | enum lockdown_reason { | ||
105 | LOCKDOWN_NONE, | ||
106 | LOCKDOWN_MODULE_SIGNATURE, | ||
107 | LOCKDOWN_DEV_MEM, | ||
108 | LOCKDOWN_KEXEC, | ||
109 | LOCKDOWN_HIBERNATION, | ||
110 | LOCKDOWN_PCI_ACCESS, | ||
111 | LOCKDOWN_IOPORT, | ||
112 | LOCKDOWN_MSR, | ||
113 | LOCKDOWN_ACPI_TABLES, | ||
114 | LOCKDOWN_PCMCIA_CIS, | ||
115 | LOCKDOWN_TIOCSSERIAL, | ||
116 | LOCKDOWN_MODULE_PARAMETERS, | ||
117 | LOCKDOWN_MMIOTRACE, | ||
118 | LOCKDOWN_DEBUGFS, | ||
119 | LOCKDOWN_INTEGRITY_MAX, | ||
120 | LOCKDOWN_KCORE, | ||
121 | LOCKDOWN_KPROBES, | ||
122 | LOCKDOWN_BPF_READ, | ||
123 | LOCKDOWN_PERF, | ||
124 | LOCKDOWN_TRACEFS, | ||
125 | LOCKDOWN_CONFIDENTIALITY_MAX, | ||
126 | }; | ||
127 | |||
80 | /* These functions are in security/commoncap.c */ | 128 | /* These functions are in security/commoncap.c */ |
81 | extern int cap_capable(const struct cred *cred, struct user_namespace *ns, | 129 | extern int cap_capable(const struct cred *cred, struct user_namespace *ns, |
82 | int cap, unsigned int opts); | 130 | int cap, unsigned int opts); |
@@ -195,6 +243,7 @@ int unregister_blocking_lsm_notifier(struct notifier_block *nb); | |||
195 | 243 | ||
196 | /* prototypes */ | 244 | /* prototypes */ |
197 | extern int security_init(void); | 245 | extern int security_init(void); |
246 | extern int early_security_init(void); | ||
198 | 247 | ||
199 | /* Security operations */ | 248 | /* Security operations */ |
200 | int security_binder_set_context_mgr(struct task_struct *mgr); | 249 | int security_binder_set_context_mgr(struct task_struct *mgr); |
@@ -392,6 +441,7 @@ void security_inode_invalidate_secctx(struct inode *inode); | |||
392 | int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); | 441 | int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); |
393 | int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); | 442 | int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); |
394 | int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); | 443 | int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); |
444 | int security_locked_down(enum lockdown_reason what); | ||
395 | #else /* CONFIG_SECURITY */ | 445 | #else /* CONFIG_SECURITY */ |
396 | 446 | ||
397 | static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data) | 447 | static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data) |
@@ -423,6 +473,11 @@ static inline int security_init(void) | |||
423 | return 0; | 473 | return 0; |
424 | } | 474 | } |
425 | 475 | ||
476 | static inline int early_security_init(void) | ||
477 | { | ||
478 | return 0; | ||
479 | } | ||
480 | |||
426 | static inline int security_binder_set_context_mgr(struct task_struct *mgr) | 481 | static inline int security_binder_set_context_mgr(struct task_struct *mgr) |
427 | { | 482 | { |
428 | return 0; | 483 | return 0; |
@@ -1210,6 +1265,10 @@ static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 | |||
1210 | { | 1265 | { |
1211 | return -EOPNOTSUPP; | 1266 | return -EOPNOTSUPP; |
1212 | } | 1267 | } |
1268 | static inline int security_locked_down(enum lockdown_reason what) | ||
1269 | { | ||
1270 | return 0; | ||
1271 | } | ||
1213 | #endif /* CONFIG_SECURITY */ | 1272 | #endif /* CONFIG_SECURITY */ |
1214 | 1273 | ||
1215 | #ifdef CONFIG_SECURITY_NETWORK | 1274 | #ifdef CONFIG_SECURITY_NETWORK |
diff --git a/init/Kconfig b/init/Kconfig index 92c867e25a29..b4daad2bac23 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -2061,6 +2061,11 @@ config MODULE_SIG | |||
2061 | kernel build dependency so that the signing tool can use its crypto | 2061 | kernel build dependency so that the signing tool can use its crypto |
2062 | library. | 2062 | library. |
2063 | 2063 | ||
2064 | You should enable this option if you wish to use either | ||
2065 | CONFIG_SECURITY_LOCKDOWN_LSM or lockdown functionality imposed via | ||
2066 | another LSM - otherwise unsigned modules will be loadable regardless | ||
2067 | of the lockdown policy. | ||
2068 | |||
2064 | !!!WARNING!!! If you enable this option, you MUST make sure that the | 2069 | !!!WARNING!!! If you enable this option, you MUST make sure that the |
2065 | module DOES NOT get stripped after being signed. This includes the | 2070 | module DOES NOT get stripped after being signed. This includes the |
2066 | debuginfo strip done by some packagers (such as rpmbuild) and | 2071 | debuginfo strip done by some packagers (such as rpmbuild) and |
diff --git a/init/main.c b/init/main.c index 208b8fa1808e..91f6ebb30ef0 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -593,6 +593,7 @@ asmlinkage __visible void __init start_kernel(void) | |||
593 | boot_cpu_init(); | 593 | boot_cpu_init(); |
594 | page_address_init(); | 594 | page_address_init(); |
595 | pr_notice("%s", linux_banner); | 595 | pr_notice("%s", linux_banner); |
596 | early_security_init(); | ||
596 | setup_arch(&command_line); | 597 | setup_arch(&command_line); |
597 | setup_command_line(command_line); | 598 | setup_command_line(command_line); |
598 | setup_nr_cpu_ids(); | 599 | setup_nr_cpu_ids(); |
diff --git a/kernel/events/core.c b/kernel/events/core.c index 275eae05af20..4655adbbae10 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -10917,6 +10917,13 @@ SYSCALL_DEFINE5(perf_event_open, | |||
10917 | perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) | 10917 | perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) |
10918 | return -EACCES; | 10918 | return -EACCES; |
10919 | 10919 | ||
10920 | err = security_locked_down(LOCKDOWN_PERF); | ||
10921 | if (err && (attr.sample_type & PERF_SAMPLE_REGS_INTR)) | ||
10922 | /* REGS_INTR can leak data, lockdown must prevent this */ | ||
10923 | return err; | ||
10924 | |||
10925 | err = 0; | ||
10926 | |||
10920 | /* | 10927 | /* |
10921 | * In cgroup mode, the pid argument is used to pass the fd | 10928 | * In cgroup mode, the pid argument is used to pass the fd |
10922 | * opened to the cgroup directory in cgroupfs. The cpu argument | 10929 | * opened to the cgroup directory in cgroupfs. The cpu argument |
diff --git a/kernel/kexec.c b/kernel/kexec.c index 1b018f1a6e0d..bc933c0db9bf 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -206,6 +206,14 @@ static inline int kexec_load_check(unsigned long nr_segments, | |||
206 | return result; | 206 | return result; |
207 | 207 | ||
208 | /* | 208 | /* |
209 | * kexec can be used to circumvent module loading restrictions, so | ||
210 | * prevent loading in that case | ||
211 | */ | ||
212 | result = security_locked_down(LOCKDOWN_KEXEC); | ||
213 | if (result) | ||
214 | return result; | ||
215 | |||
216 | /* | ||
209 | * Verify we have a legal set of flags | 217 | * Verify we have a legal set of flags |
210 | * This leaves us room for future extensions. | 218 | * This leaves us room for future extensions. |
211 | */ | 219 | */ |
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index b8cc032d5620..79f252af7dee 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c | |||
@@ -88,7 +88,7 @@ int __weak arch_kimage_file_post_load_cleanup(struct kimage *image) | |||
88 | return kexec_image_post_load_cleanup_default(image); | 88 | return kexec_image_post_load_cleanup_default(image); |
89 | } | 89 | } |
90 | 90 | ||
91 | #ifdef CONFIG_KEXEC_VERIFY_SIG | 91 | #ifdef CONFIG_KEXEC_SIG |
92 | static int kexec_image_verify_sig_default(struct kimage *image, void *buf, | 92 | static int kexec_image_verify_sig_default(struct kimage *image, void *buf, |
93 | unsigned long buf_len) | 93 | unsigned long buf_len) |
94 | { | 94 | { |
@@ -177,6 +177,59 @@ void kimage_file_post_load_cleanup(struct kimage *image) | |||
177 | image->image_loader_data = NULL; | 177 | image->image_loader_data = NULL; |
178 | } | 178 | } |
179 | 179 | ||
180 | #ifdef CONFIG_KEXEC_SIG | ||
181 | static int | ||
182 | kimage_validate_signature(struct kimage *image) | ||
183 | { | ||
184 | const char *reason; | ||
185 | int ret; | ||
186 | |||
187 | ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf, | ||
188 | image->kernel_buf_len); | ||
189 | switch (ret) { | ||
190 | case 0: | ||
191 | break; | ||
192 | |||
193 | /* Certain verification errors are non-fatal if we're not | ||
194 | * checking errors, provided we aren't mandating that there | ||
195 | * must be a valid signature. | ||
196 | */ | ||
197 | case -ENODATA: | ||
198 | reason = "kexec of unsigned image"; | ||
199 | goto decide; | ||
200 | case -ENOPKG: | ||
201 | reason = "kexec of image with unsupported crypto"; | ||
202 | goto decide; | ||
203 | case -ENOKEY: | ||
204 | reason = "kexec of image with unavailable key"; | ||
205 | decide: | ||
206 | if (IS_ENABLED(CONFIG_KEXEC_SIG_FORCE)) { | ||
207 | pr_notice("%s rejected\n", reason); | ||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | /* If IMA is guaranteed to appraise a signature on the kexec | ||
212 | * image, permit it even if the kernel is otherwise locked | ||
213 | * down. | ||
214 | */ | ||
215 | if (!ima_appraise_signature(READING_KEXEC_IMAGE) && | ||
216 | security_locked_down(LOCKDOWN_KEXEC)) | ||
217 | return -EPERM; | ||
218 | |||
219 | return 0; | ||
220 | |||
221 | /* All other errors are fatal, including nomem, unparseable | ||
222 | * signatures and signature check failures - even if signatures | ||
223 | * aren't required. | ||
224 | */ | ||
225 | default: | ||
226 | pr_notice("kernel signature verification failed (%d).\n", ret); | ||
227 | } | ||
228 | |||
229 | return ret; | ||
230 | } | ||
231 | #endif | ||
232 | |||
180 | /* | 233 | /* |
181 | * In file mode list of segments is prepared by kernel. Copy relevant | 234 | * In file mode list of segments is prepared by kernel. Copy relevant |
182 | * data from user space, do error checking, prepare segment list | 235 | * data from user space, do error checking, prepare segment list |
@@ -186,7 +239,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, | |||
186 | const char __user *cmdline_ptr, | 239 | const char __user *cmdline_ptr, |
187 | unsigned long cmdline_len, unsigned flags) | 240 | unsigned long cmdline_len, unsigned flags) |
188 | { | 241 | { |
189 | int ret = 0; | 242 | int ret; |
190 | void *ldata; | 243 | void *ldata; |
191 | loff_t size; | 244 | loff_t size; |
192 | 245 | ||
@@ -202,14 +255,11 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, | |||
202 | if (ret) | 255 | if (ret) |
203 | goto out; | 256 | goto out; |
204 | 257 | ||
205 | #ifdef CONFIG_KEXEC_VERIFY_SIG | 258 | #ifdef CONFIG_KEXEC_SIG |
206 | ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf, | 259 | ret = kimage_validate_signature(image); |
207 | image->kernel_buf_len); | 260 | |
208 | if (ret) { | 261 | if (ret) |
209 | pr_debug("kernel signature verification failed.\n"); | ||
210 | goto out; | 262 | goto out; |
211 | } | ||
212 | pr_debug("kernel signature verification successful.\n"); | ||
213 | #endif | 263 | #endif |
214 | /* It is possible that there no initramfs is being loaded */ | 264 | /* It is possible that there no initramfs is being loaded */ |
215 | if (!(flags & KEXEC_FILE_NO_INITRAMFS)) { | 265 | if (!(flags & KEXEC_FILE_NO_INITRAMFS)) { |
diff --git a/kernel/module.c b/kernel/module.c index edbe42755a27..ff2d7359a418 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -2839,8 +2839,9 @@ static inline void kmemleak_load_module(const struct module *mod, | |||
2839 | #ifdef CONFIG_MODULE_SIG | 2839 | #ifdef CONFIG_MODULE_SIG |
2840 | static int module_sig_check(struct load_info *info, int flags) | 2840 | static int module_sig_check(struct load_info *info, int flags) |
2841 | { | 2841 | { |
2842 | int err = -ENOKEY; | 2842 | int err = -ENODATA; |
2843 | const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; | 2843 | const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; |
2844 | const char *reason; | ||
2844 | const void *mod = info->hdr; | 2845 | const void *mod = info->hdr; |
2845 | 2846 | ||
2846 | /* | 2847 | /* |
@@ -2855,16 +2856,38 @@ static int module_sig_check(struct load_info *info, int flags) | |||
2855 | err = mod_verify_sig(mod, info); | 2856 | err = mod_verify_sig(mod, info); |
2856 | } | 2857 | } |
2857 | 2858 | ||
2858 | if (!err) { | 2859 | switch (err) { |
2860 | case 0: | ||
2859 | info->sig_ok = true; | 2861 | info->sig_ok = true; |
2860 | return 0; | 2862 | return 0; |
2861 | } | ||
2862 | 2863 | ||
2863 | /* Not having a signature is only an error if we're strict. */ | 2864 | /* We don't permit modules to be loaded into trusted kernels |
2864 | if (err == -ENOKEY && !is_module_sig_enforced()) | 2865 | * without a valid signature on them, but if we're not |
2865 | err = 0; | 2866 | * enforcing, certain errors are non-fatal. |
2867 | */ | ||
2868 | case -ENODATA: | ||
2869 | reason = "Loading of unsigned module"; | ||
2870 | goto decide; | ||
2871 | case -ENOPKG: | ||
2872 | reason = "Loading of module with unsupported crypto"; | ||
2873 | goto decide; | ||
2874 | case -ENOKEY: | ||
2875 | reason = "Loading of module with unavailable key"; | ||
2876 | decide: | ||
2877 | if (is_module_sig_enforced()) { | ||
2878 | pr_notice("%s is rejected\n", reason); | ||
2879 | return -EKEYREJECTED; | ||
2880 | } | ||
2866 | 2881 | ||
2867 | return err; | 2882 | return security_locked_down(LOCKDOWN_MODULE_SIGNATURE); |
2883 | |||
2884 | /* All other errors are fatal, including nomem, unparseable | ||
2885 | * signatures and signature check failures - even if signatures | ||
2886 | * aren't required. | ||
2887 | */ | ||
2888 | default: | ||
2889 | return err; | ||
2890 | } | ||
2868 | } | 2891 | } |
2869 | #else /* !CONFIG_MODULE_SIG */ | 2892 | #else /* !CONFIG_MODULE_SIG */ |
2870 | static int module_sig_check(struct load_info *info, int flags) | 2893 | static int module_sig_check(struct load_info *info, int flags) |
diff --git a/kernel/params.c b/kernel/params.c index cf448785d058..8e56f8b12d8f 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/err.h> | 12 | #include <linux/err.h> |
13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
14 | #include <linux/ctype.h> | 14 | #include <linux/ctype.h> |
15 | #include <linux/security.h> | ||
15 | 16 | ||
16 | #ifdef CONFIG_SYSFS | 17 | #ifdef CONFIG_SYSFS |
17 | /* Protects all built-in parameters, modules use their own param_lock */ | 18 | /* Protects all built-in parameters, modules use their own param_lock */ |
@@ -96,13 +97,19 @@ bool parameq(const char *a, const char *b) | |||
96 | return parameqn(a, b, strlen(a)+1); | 97 | return parameqn(a, b, strlen(a)+1); |
97 | } | 98 | } |
98 | 99 | ||
99 | static void param_check_unsafe(const struct kernel_param *kp) | 100 | static bool param_check_unsafe(const struct kernel_param *kp) |
100 | { | 101 | { |
102 | if (kp->flags & KERNEL_PARAM_FL_HWPARAM && | ||
103 | security_locked_down(LOCKDOWN_MODULE_PARAMETERS)) | ||
104 | return false; | ||
105 | |||
101 | if (kp->flags & KERNEL_PARAM_FL_UNSAFE) { | 106 | if (kp->flags & KERNEL_PARAM_FL_UNSAFE) { |
102 | pr_notice("Setting dangerous option %s - tainting kernel\n", | 107 | pr_notice("Setting dangerous option %s - tainting kernel\n", |
103 | kp->name); | 108 | kp->name); |
104 | add_taint(TAINT_USER, LOCKDEP_STILL_OK); | 109 | add_taint(TAINT_USER, LOCKDEP_STILL_OK); |
105 | } | 110 | } |
111 | |||
112 | return true; | ||
106 | } | 113 | } |
107 | 114 | ||
108 | static int parse_one(char *param, | 115 | static int parse_one(char *param, |
@@ -132,8 +139,10 @@ static int parse_one(char *param, | |||
132 | pr_debug("handling %s with %p\n", param, | 139 | pr_debug("handling %s with %p\n", param, |
133 | params[i].ops->set); | 140 | params[i].ops->set); |
134 | kernel_param_lock(params[i].mod); | 141 | kernel_param_lock(params[i].mod); |
135 | param_check_unsafe(¶ms[i]); | 142 | if (param_check_unsafe(¶ms[i])) |
136 | err = params[i].ops->set(val, ¶ms[i]); | 143 | err = params[i].ops->set(val, ¶ms[i]); |
144 | else | ||
145 | err = -EPERM; | ||
137 | kernel_param_unlock(params[i].mod); | 146 | kernel_param_unlock(params[i].mod); |
138 | return err; | 147 | return err; |
139 | } | 148 | } |
@@ -553,8 +562,10 @@ static ssize_t param_attr_store(struct module_attribute *mattr, | |||
553 | return -EPERM; | 562 | return -EPERM; |
554 | 563 | ||
555 | kernel_param_lock(mk->mod); | 564 | kernel_param_lock(mk->mod); |
556 | param_check_unsafe(attribute->param); | 565 | if (param_check_unsafe(attribute->param)) |
557 | err = attribute->param->ops->set(buf, attribute->param); | 566 | err = attribute->param->ops->set(buf, attribute->param); |
567 | else | ||
568 | err = -EPERM; | ||
558 | kernel_param_unlock(mk->mod); | 569 | kernel_param_unlock(mk->mod); |
559 | if (!err) | 570 | if (!err) |
560 | return len; | 571 | return len; |
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index cd7434e6000d..3c0a5a8170b0 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/ctype.h> | 30 | #include <linux/ctype.h> |
31 | #include <linux/genhd.h> | 31 | #include <linux/genhd.h> |
32 | #include <linux/ktime.h> | 32 | #include <linux/ktime.h> |
33 | #include <linux/security.h> | ||
33 | #include <trace/events/power.h> | 34 | #include <trace/events/power.h> |
34 | 35 | ||
35 | #include "power.h" | 36 | #include "power.h" |
@@ -68,7 +69,7 @@ static const struct platform_hibernation_ops *hibernation_ops; | |||
68 | 69 | ||
69 | bool hibernation_available(void) | 70 | bool hibernation_available(void) |
70 | { | 71 | { |
71 | return (nohibernate == 0); | 72 | return nohibernate == 0 && !security_locked_down(LOCKDOWN_HIBERNATION); |
72 | } | 73 | } |
73 | 74 | ||
74 | /** | 75 | /** |
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index ca1255d14576..492a8bfaae98 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c | |||
@@ -142,8 +142,13 @@ BPF_CALL_3(bpf_probe_read, void *, dst, u32, size, const void *, unsafe_ptr) | |||
142 | { | 142 | { |
143 | int ret; | 143 | int ret; |
144 | 144 | ||
145 | ret = security_locked_down(LOCKDOWN_BPF_READ); | ||
146 | if (ret < 0) | ||
147 | goto out; | ||
148 | |||
145 | ret = probe_kernel_read(dst, unsafe_ptr, size); | 149 | ret = probe_kernel_read(dst, unsafe_ptr, size); |
146 | if (unlikely(ret < 0)) | 150 | if (unlikely(ret < 0)) |
151 | out: | ||
147 | memset(dst, 0, size); | 152 | memset(dst, 0, size); |
148 | 153 | ||
149 | return ret; | 154 | return ret; |
@@ -569,6 +574,10 @@ BPF_CALL_3(bpf_probe_read_str, void *, dst, u32, size, | |||
569 | { | 574 | { |
570 | int ret; | 575 | int ret; |
571 | 576 | ||
577 | ret = security_locked_down(LOCKDOWN_BPF_READ); | ||
578 | if (ret < 0) | ||
579 | goto out; | ||
580 | |||
572 | /* | 581 | /* |
573 | * The strncpy_from_unsafe() call will likely not fill the entire | 582 | * The strncpy_from_unsafe() call will likely not fill the entire |
574 | * buffer, but that's okay in this circumstance as we're probing | 583 | * buffer, but that's okay in this circumstance as we're probing |
@@ -580,6 +589,7 @@ BPF_CALL_3(bpf_probe_read_str, void *, dst, u32, size, | |||
580 | */ | 589 | */ |
581 | ret = strncpy_from_unsafe(dst, unsafe_ptr, size); | 590 | ret = strncpy_from_unsafe(dst, unsafe_ptr, size); |
582 | if (unlikely(ret < 0)) | 591 | if (unlikely(ret < 0)) |
592 | out: | ||
583 | memset(dst, 0, size); | 593 | memset(dst, 0, size); |
584 | 594 | ||
585 | return ret; | 595 | return ret; |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 402dc3ce88d3..324ffbea3556 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/uaccess.h> | 11 | #include <linux/uaccess.h> |
12 | #include <linux/rculist.h> | 12 | #include <linux/rculist.h> |
13 | #include <linux/error-injection.h> | 13 | #include <linux/error-injection.h> |
14 | #include <linux/security.h> | ||
14 | 15 | ||
15 | #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ | 16 | #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ |
16 | 17 | ||
@@ -460,6 +461,10 @@ static int __register_trace_kprobe(struct trace_kprobe *tk) | |||
460 | { | 461 | { |
461 | int i, ret; | 462 | int i, ret; |
462 | 463 | ||
464 | ret = security_locked_down(LOCKDOWN_KPROBES); | ||
465 | if (ret) | ||
466 | return ret; | ||
467 | |||
463 | if (trace_kprobe_is_registered(tk)) | 468 | if (trace_kprobe_is_registered(tk)) |
464 | return -EINVAL; | 469 | return -EINVAL; |
465 | 470 | ||
diff --git a/security/Kconfig b/security/Kconfig index 0d65594b5196..2a1a2d396228 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -237,6 +237,7 @@ source "security/apparmor/Kconfig" | |||
237 | source "security/loadpin/Kconfig" | 237 | source "security/loadpin/Kconfig" |
238 | source "security/yama/Kconfig" | 238 | source "security/yama/Kconfig" |
239 | source "security/safesetid/Kconfig" | 239 | source "security/safesetid/Kconfig" |
240 | source "security/lockdown/Kconfig" | ||
240 | 241 | ||
241 | source "security/integrity/Kconfig" | 242 | source "security/integrity/Kconfig" |
242 | 243 | ||
@@ -276,11 +277,11 @@ endchoice | |||
276 | 277 | ||
277 | config LSM | 278 | config LSM |
278 | string "Ordered list of enabled LSMs" | 279 | string "Ordered list of enabled LSMs" |
279 | default "yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor" if DEFAULT_SECURITY_SMACK | 280 | default "lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor" if DEFAULT_SECURITY_SMACK |
280 | default "yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR | 281 | default "lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR |
281 | default "yama,loadpin,safesetid,integrity,tomoyo" if DEFAULT_SECURITY_TOMOYO | 282 | default "lockdown,yama,loadpin,safesetid,integrity,tomoyo" if DEFAULT_SECURITY_TOMOYO |
282 | default "yama,loadpin,safesetid,integrity" if DEFAULT_SECURITY_DAC | 283 | default "lockdown,yama,loadpin,safesetid,integrity" if DEFAULT_SECURITY_DAC |
283 | default "yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" | 284 | default "lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" |
284 | help | 285 | help |
285 | A comma-separated list of LSMs, in initialization order. | 286 | A comma-separated list of LSMs, in initialization order. |
286 | Any LSMs left off this list will be ignored. This can be | 287 | Any LSMs left off this list will be ignored. This can be |
diff --git a/security/Makefile b/security/Makefile index c598b904938f..be1dd9d2cb2f 100644 --- a/security/Makefile +++ b/security/Makefile | |||
@@ -11,6 +11,7 @@ subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor | |||
11 | subdir-$(CONFIG_SECURITY_YAMA) += yama | 11 | subdir-$(CONFIG_SECURITY_YAMA) += yama |
12 | subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin | 12 | subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin |
13 | subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid | 13 | subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid |
14 | subdir-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown | ||
14 | 15 | ||
15 | # always enable default capabilities | 16 | # always enable default capabilities |
16 | obj-y += commoncap.o | 17 | obj-y += commoncap.o |
@@ -27,6 +28,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ | |||
27 | obj-$(CONFIG_SECURITY_YAMA) += yama/ | 28 | obj-$(CONFIG_SECURITY_YAMA) += yama/ |
28 | obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ | 29 | obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ |
29 | obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/ | 30 | obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/ |
31 | obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown/ | ||
30 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o | 32 | obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o |
31 | 33 | ||
32 | # Object integrity file lists | 34 | # Object integrity file lists |
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 897bafc59a33..838476d780e5 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
@@ -160,7 +160,7 @@ config IMA_APPRAISE | |||
160 | 160 | ||
161 | config IMA_ARCH_POLICY | 161 | config IMA_ARCH_POLICY |
162 | bool "Enable loading an IMA architecture specific policy" | 162 | bool "Enable loading an IMA architecture specific policy" |
163 | depends on (KEXEC_VERIFY_SIG && IMA) || IMA_APPRAISE \ | 163 | depends on (KEXEC_SIG && IMA) || IMA_APPRAISE \ |
164 | && INTEGRITY_ASYMMETRIC_KEYS | 164 | && INTEGRITY_ASYMMETRIC_KEYS |
165 | default n | 165 | default n |
166 | help | 166 | help |
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 19769bf5f6ab..3689081aaf38 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
@@ -114,6 +114,8 @@ struct ima_kexec_hdr { | |||
114 | u64 count; | 114 | u64 count; |
115 | }; | 115 | }; |
116 | 116 | ||
117 | extern const int read_idmap[]; | ||
118 | |||
117 | #ifdef CONFIG_HAVE_IMA_KEXEC | 119 | #ifdef CONFIG_HAVE_IMA_KEXEC |
118 | void ima_load_kexec_buffer(void); | 120 | void ima_load_kexec_buffer(void); |
119 | #else | 121 | #else |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 79c01516211b..60027c643ecd 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -518,7 +518,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id) | |||
518 | return 0; | 518 | return 0; |
519 | } | 519 | } |
520 | 520 | ||
521 | static const int read_idmap[READING_MAX_ID] = { | 521 | const int read_idmap[READING_MAX_ID] = { |
522 | [READING_FIRMWARE] = FIRMWARE_CHECK, | 522 | [READING_FIRMWARE] = FIRMWARE_CHECK, |
523 | [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK, | 523 | [READING_FIRMWARE_PREALLOC_BUFFER] = FIRMWARE_CHECK, |
524 | [READING_MODULE] = MODULE_CHECK, | 524 | [READING_MODULE] = MODULE_CHECK, |
@@ -590,7 +590,7 @@ int ima_load_data(enum kernel_load_data_id id) | |||
590 | 590 | ||
591 | switch (id) { | 591 | switch (id) { |
592 | case LOADING_KEXEC_IMAGE: | 592 | case LOADING_KEXEC_IMAGE: |
593 | if (IS_ENABLED(CONFIG_KEXEC_VERIFY_SIG) | 593 | if (IS_ENABLED(CONFIG_KEXEC_SIG) |
594 | && arch_ima_get_secureboot()) { | 594 | && arch_ima_get_secureboot()) { |
595 | pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n"); | 595 | pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n"); |
596 | return -EACCES; | 596 | return -EACCES; |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 4badc4fcda98..5380aca2b351 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -1507,3 +1507,53 @@ int ima_policy_show(struct seq_file *m, void *v) | |||
1507 | return 0; | 1507 | return 0; |
1508 | } | 1508 | } |
1509 | #endif /* CONFIG_IMA_READ_POLICY */ | 1509 | #endif /* CONFIG_IMA_READ_POLICY */ |
1510 | |||
1511 | #if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING) | ||
1512 | /* | ||
1513 | * ima_appraise_signature: whether IMA will appraise a given function using | ||
1514 | * an IMA digital signature. This is restricted to cases where the kernel | ||
1515 | * has a set of built-in trusted keys in order to avoid an attacker simply | ||
1516 | * loading additional keys. | ||
1517 | */ | ||
1518 | bool ima_appraise_signature(enum kernel_read_file_id id) | ||
1519 | { | ||
1520 | struct ima_rule_entry *entry; | ||
1521 | bool found = false; | ||
1522 | enum ima_hooks func; | ||
1523 | |||
1524 | if (id >= READING_MAX_ID) | ||
1525 | return false; | ||
1526 | |||
1527 | func = read_idmap[id] ?: FILE_CHECK; | ||
1528 | |||
1529 | rcu_read_lock(); | ||
1530 | list_for_each_entry_rcu(entry, ima_rules, list) { | ||
1531 | if (entry->action != APPRAISE) | ||
1532 | continue; | ||
1533 | |||
1534 | /* | ||
1535 | * A generic entry will match, but otherwise require that it | ||
1536 | * match the func we're looking for | ||
1537 | */ | ||
1538 | if (entry->func && entry->func != func) | ||
1539 | continue; | ||
1540 | |||
1541 | /* | ||
1542 | * We require this to be a digital signature, not a raw IMA | ||
1543 | * hash. | ||
1544 | */ | ||
1545 | if (entry->flags & IMA_DIGSIG_REQUIRED) | ||
1546 | found = true; | ||
1547 | |||
1548 | /* | ||
1549 | * We've found a rule that matches, so break now even if it | ||
1550 | * didn't require a digital signature - a later rule that does | ||
1551 | * won't override it, so would be a false positive. | ||
1552 | */ | ||
1553 | break; | ||
1554 | } | ||
1555 | |||
1556 | rcu_read_unlock(); | ||
1557 | return found; | ||
1558 | } | ||
1559 | #endif /* CONFIG_IMA_APPRAISE && CONFIG_INTEGRITY_TRUSTED_KEYRING */ | ||
diff --git a/security/lockdown/Kconfig b/security/lockdown/Kconfig new file mode 100644 index 000000000000..e84ddf484010 --- /dev/null +++ b/security/lockdown/Kconfig | |||
@@ -0,0 +1,47 @@ | |||
1 | config SECURITY_LOCKDOWN_LSM | ||
2 | bool "Basic module for enforcing kernel lockdown" | ||
3 | depends on SECURITY | ||
4 | select MODULE_SIG if MODULES | ||
5 | help | ||
6 | Build support for an LSM that enforces a coarse kernel lockdown | ||
7 | behaviour. | ||
8 | |||
9 | config SECURITY_LOCKDOWN_LSM_EARLY | ||
10 | bool "Enable lockdown LSM early in init" | ||
11 | depends on SECURITY_LOCKDOWN_LSM | ||
12 | help | ||
13 | Enable the lockdown LSM early in boot. This is necessary in order | ||
14 | to ensure that lockdown enforcement can be carried out on kernel | ||
15 | boot parameters that are otherwise parsed before the security | ||
16 | subsystem is fully initialised. If enabled, lockdown will | ||
17 | unconditionally be called before any other LSMs. | ||
18 | |||
19 | choice | ||
20 | prompt "Kernel default lockdown mode" | ||
21 | default LOCK_DOWN_KERNEL_FORCE_NONE | ||
22 | depends on SECURITY_LOCKDOWN_LSM | ||
23 | help | ||
24 | The kernel can be configured to default to differing levels of | ||
25 | lockdown. | ||
26 | |||
27 | config LOCK_DOWN_KERNEL_FORCE_NONE | ||
28 | bool "None" | ||
29 | help | ||
30 | No lockdown functionality is enabled by default. Lockdown may be | ||
31 | enabled via the kernel commandline or /sys/kernel/security/lockdown. | ||
32 | |||
33 | config LOCK_DOWN_KERNEL_FORCE_INTEGRITY | ||
34 | bool "Integrity" | ||
35 | help | ||
36 | The kernel runs in integrity mode by default. Features that allow | ||
37 | the kernel to be modified at runtime are disabled. | ||
38 | |||
39 | config LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY | ||
40 | bool "Confidentiality" | ||
41 | help | ||
42 | The kernel runs in confidentiality mode by default. Features that | ||
43 | allow the kernel to be modified at runtime or that permit userland | ||
44 | code to read confidential material held inside the kernel are | ||
45 | disabled. | ||
46 | |||
47 | endchoice | ||
diff --git a/security/lockdown/Makefile b/security/lockdown/Makefile new file mode 100644 index 000000000000..e3634b9017e7 --- /dev/null +++ b/security/lockdown/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown.o | |||
diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c new file mode 100644 index 000000000000..8a10b43daf74 --- /dev/null +++ b/security/lockdown/lockdown.c | |||
@@ -0,0 +1,191 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* Lock down the kernel | ||
3 | * | ||
4 | * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. | ||
5 | * Written by David Howells (dhowells@redhat.com) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public Licence | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the Licence, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/security.h> | ||
14 | #include <linux/export.h> | ||
15 | #include <linux/lsm_hooks.h> | ||
16 | |||
17 | static enum lockdown_reason kernel_locked_down; | ||
18 | |||
19 | static const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = { | ||
20 | [LOCKDOWN_NONE] = "none", | ||
21 | [LOCKDOWN_MODULE_SIGNATURE] = "unsigned module loading", | ||
22 | [LOCKDOWN_DEV_MEM] = "/dev/mem,kmem,port", | ||
23 | [LOCKDOWN_KEXEC] = "kexec of unsigned images", | ||
24 | [LOCKDOWN_HIBERNATION] = "hibernation", | ||
25 | [LOCKDOWN_PCI_ACCESS] = "direct PCI access", | ||
26 | [LOCKDOWN_IOPORT] = "raw io port access", | ||
27 | [LOCKDOWN_MSR] = "raw MSR access", | ||
28 | [LOCKDOWN_ACPI_TABLES] = "modifying ACPI tables", | ||
29 | [LOCKDOWN_PCMCIA_CIS] = "direct PCMCIA CIS storage", | ||
30 | [LOCKDOWN_TIOCSSERIAL] = "reconfiguration of serial port IO", | ||
31 | [LOCKDOWN_MODULE_PARAMETERS] = "unsafe module parameters", | ||
32 | [LOCKDOWN_MMIOTRACE] = "unsafe mmio", | ||
33 | [LOCKDOWN_DEBUGFS] = "debugfs access", | ||
34 | [LOCKDOWN_INTEGRITY_MAX] = "integrity", | ||
35 | [LOCKDOWN_KCORE] = "/proc/kcore access", | ||
36 | [LOCKDOWN_KPROBES] = "use of kprobes", | ||
37 | [LOCKDOWN_BPF_READ] = "use of bpf to read kernel RAM", | ||
38 | [LOCKDOWN_PERF] = "unsafe use of perf", | ||
39 | [LOCKDOWN_TRACEFS] = "use of tracefs", | ||
40 | [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality", | ||
41 | }; | ||
42 | |||
43 | static const enum lockdown_reason lockdown_levels[] = {LOCKDOWN_NONE, | ||
44 | LOCKDOWN_INTEGRITY_MAX, | ||
45 | LOCKDOWN_CONFIDENTIALITY_MAX}; | ||
46 | |||
47 | /* | ||
48 | * Put the kernel into lock-down mode. | ||
49 | */ | ||
50 | static int lock_kernel_down(const char *where, enum lockdown_reason level) | ||
51 | { | ||
52 | if (kernel_locked_down >= level) | ||
53 | return -EPERM; | ||
54 | |||
55 | kernel_locked_down = level; | ||
56 | pr_notice("Kernel is locked down from %s; see man kernel_lockdown.7\n", | ||
57 | where); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int __init lockdown_param(char *level) | ||
62 | { | ||
63 | if (!level) | ||
64 | return -EINVAL; | ||
65 | |||
66 | if (strcmp(level, "integrity") == 0) | ||
67 | lock_kernel_down("command line", LOCKDOWN_INTEGRITY_MAX); | ||
68 | else if (strcmp(level, "confidentiality") == 0) | ||
69 | lock_kernel_down("command line", LOCKDOWN_CONFIDENTIALITY_MAX); | ||
70 | else | ||
71 | return -EINVAL; | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | early_param("lockdown", lockdown_param); | ||
77 | |||
78 | /** | ||
79 | * lockdown_is_locked_down - Find out if the kernel is locked down | ||
80 | * @what: Tag to use in notice generated if lockdown is in effect | ||
81 | */ | ||
82 | static int lockdown_is_locked_down(enum lockdown_reason what) | ||
83 | { | ||
84 | if (WARN(what >= LOCKDOWN_CONFIDENTIALITY_MAX, | ||
85 | "Invalid lockdown reason")) | ||
86 | return -EPERM; | ||
87 | |||
88 | if (kernel_locked_down >= what) { | ||
89 | if (lockdown_reasons[what]) | ||
90 | pr_notice("Lockdown: %s: %s is restricted; see man kernel_lockdown.7\n", | ||
91 | current->comm, lockdown_reasons[what]); | ||
92 | return -EPERM; | ||
93 | } | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static struct security_hook_list lockdown_hooks[] __lsm_ro_after_init = { | ||
99 | LSM_HOOK_INIT(locked_down, lockdown_is_locked_down), | ||
100 | }; | ||
101 | |||
102 | static int __init lockdown_lsm_init(void) | ||
103 | { | ||
104 | #if defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY) | ||
105 | lock_kernel_down("Kernel configuration", LOCKDOWN_INTEGRITY_MAX); | ||
106 | #elif defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY) | ||
107 | lock_kernel_down("Kernel configuration", LOCKDOWN_CONFIDENTIALITY_MAX); | ||
108 | #endif | ||
109 | security_add_hooks(lockdown_hooks, ARRAY_SIZE(lockdown_hooks), | ||
110 | "lockdown"); | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static ssize_t lockdown_read(struct file *filp, char __user *buf, size_t count, | ||
115 | loff_t *ppos) | ||
116 | { | ||
117 | char temp[80]; | ||
118 | int i, offset = 0; | ||
119 | |||
120 | for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) { | ||
121 | enum lockdown_reason level = lockdown_levels[i]; | ||
122 | |||
123 | if (lockdown_reasons[level]) { | ||
124 | const char *label = lockdown_reasons[level]; | ||
125 | |||
126 | if (kernel_locked_down == level) | ||
127 | offset += sprintf(temp+offset, "[%s] ", label); | ||
128 | else | ||
129 | offset += sprintf(temp+offset, "%s ", label); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | /* Convert the last space to a newline if needed. */ | ||
134 | if (offset > 0) | ||
135 | temp[offset-1] = '\n'; | ||
136 | |||
137 | return simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); | ||
138 | } | ||
139 | |||
140 | static ssize_t lockdown_write(struct file *file, const char __user *buf, | ||
141 | size_t n, loff_t *ppos) | ||
142 | { | ||
143 | char *state; | ||
144 | int i, len, err = -EINVAL; | ||
145 | |||
146 | state = memdup_user_nul(buf, n); | ||
147 | if (IS_ERR(state)) | ||
148 | return PTR_ERR(state); | ||
149 | |||
150 | len = strlen(state); | ||
151 | if (len && state[len-1] == '\n') { | ||
152 | state[len-1] = '\0'; | ||
153 | len--; | ||
154 | } | ||
155 | |||
156 | for (i = 0; i < ARRAY_SIZE(lockdown_levels); i++) { | ||
157 | enum lockdown_reason level = lockdown_levels[i]; | ||
158 | const char *label = lockdown_reasons[level]; | ||
159 | |||
160 | if (label && !strcmp(state, label)) | ||
161 | err = lock_kernel_down("securityfs", level); | ||
162 | } | ||
163 | |||
164 | kfree(state); | ||
165 | return err ? err : n; | ||
166 | } | ||
167 | |||
168 | static const struct file_operations lockdown_ops = { | ||
169 | .read = lockdown_read, | ||
170 | .write = lockdown_write, | ||
171 | }; | ||
172 | |||
173 | static int __init lockdown_secfs_init(void) | ||
174 | { | ||
175 | struct dentry *dentry; | ||
176 | |||
177 | dentry = securityfs_create_file("lockdown", 0600, NULL, NULL, | ||
178 | &lockdown_ops); | ||
179 | return PTR_ERR_OR_ZERO(dentry); | ||
180 | } | ||
181 | |||
182 | core_initcall(lockdown_secfs_init); | ||
183 | |||
184 | #ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY | ||
185 | DEFINE_EARLY_LSM(lockdown) = { | ||
186 | #else | ||
187 | DEFINE_LSM(lockdown) = { | ||
188 | #endif | ||
189 | .name = "lockdown", | ||
190 | .init = lockdown_lsm_init, | ||
191 | }; | ||
diff --git a/security/security.c b/security/security.c index 25ee5c75551f..1bc000f834e2 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -33,6 +33,7 @@ | |||
33 | 33 | ||
34 | /* How many LSMs were built into the kernel? */ | 34 | /* How many LSMs were built into the kernel? */ |
35 | #define LSM_COUNT (__end_lsm_info - __start_lsm_info) | 35 | #define LSM_COUNT (__end_lsm_info - __start_lsm_info) |
36 | #define EARLY_LSM_COUNT (__end_early_lsm_info - __start_early_lsm_info) | ||
36 | 37 | ||
37 | struct security_hook_heads security_hook_heads __lsm_ro_after_init; | 38 | struct security_hook_heads security_hook_heads __lsm_ro_after_init; |
38 | static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain); | 39 | static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain); |
@@ -277,6 +278,8 @@ static void __init ordered_lsm_parse(const char *order, const char *origin) | |||
277 | static void __init lsm_early_cred(struct cred *cred); | 278 | static void __init lsm_early_cred(struct cred *cred); |
278 | static void __init lsm_early_task(struct task_struct *task); | 279 | static void __init lsm_early_task(struct task_struct *task); |
279 | 280 | ||
281 | static int lsm_append(const char *new, char **result); | ||
282 | |||
280 | static void __init ordered_lsm_init(void) | 283 | static void __init ordered_lsm_init(void) |
281 | { | 284 | { |
282 | struct lsm_info **lsm; | 285 | struct lsm_info **lsm; |
@@ -323,6 +326,26 @@ static void __init ordered_lsm_init(void) | |||
323 | kfree(ordered_lsms); | 326 | kfree(ordered_lsms); |
324 | } | 327 | } |
325 | 328 | ||
329 | int __init early_security_init(void) | ||
330 | { | ||
331 | int i; | ||
332 | struct hlist_head *list = (struct hlist_head *) &security_hook_heads; | ||
333 | struct lsm_info *lsm; | ||
334 | |||
335 | for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct hlist_head); | ||
336 | i++) | ||
337 | INIT_HLIST_HEAD(&list[i]); | ||
338 | |||
339 | for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) { | ||
340 | if (!lsm->enabled) | ||
341 | lsm->enabled = &lsm_enabled_true; | ||
342 | prepare_lsm(lsm); | ||
343 | initialize_lsm(lsm); | ||
344 | } | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
326 | /** | 349 | /** |
327 | * security_init - initializes the security framework | 350 | * security_init - initializes the security framework |
328 | * | 351 | * |
@@ -330,14 +353,18 @@ static void __init ordered_lsm_init(void) | |||
330 | */ | 353 | */ |
331 | int __init security_init(void) | 354 | int __init security_init(void) |
332 | { | 355 | { |
333 | int i; | 356 | struct lsm_info *lsm; |
334 | struct hlist_head *list = (struct hlist_head *) &security_hook_heads; | ||
335 | 357 | ||
336 | pr_info("Security Framework initializing\n"); | 358 | pr_info("Security Framework initializing\n"); |
337 | 359 | ||
338 | for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct hlist_head); | 360 | /* |
339 | i++) | 361 | * Append the names of the early LSM modules now that kmalloc() is |
340 | INIT_HLIST_HEAD(&list[i]); | 362 | * available |
363 | */ | ||
364 | for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) { | ||
365 | if (lsm->enabled) | ||
366 | lsm_append(lsm->name, &lsm_names); | ||
367 | } | ||
341 | 368 | ||
342 | /* Load LSMs in specified order. */ | 369 | /* Load LSMs in specified order. */ |
343 | ordered_lsm_init(); | 370 | ordered_lsm_init(); |
@@ -384,7 +411,7 @@ static bool match_last_lsm(const char *list, const char *lsm) | |||
384 | return !strcmp(last, lsm); | 411 | return !strcmp(last, lsm); |
385 | } | 412 | } |
386 | 413 | ||
387 | static int lsm_append(char *new, char **result) | 414 | static int lsm_append(const char *new, char **result) |
388 | { | 415 | { |
389 | char *cp; | 416 | char *cp; |
390 | 417 | ||
@@ -422,8 +449,15 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count, | |||
422 | hooks[i].lsm = lsm; | 449 | hooks[i].lsm = lsm; |
423 | hlist_add_tail_rcu(&hooks[i].list, hooks[i].head); | 450 | hlist_add_tail_rcu(&hooks[i].list, hooks[i].head); |
424 | } | 451 | } |
425 | if (lsm_append(lsm, &lsm_names) < 0) | 452 | |
426 | panic("%s - Cannot get early memory.\n", __func__); | 453 | /* |
454 | * Don't try to append during early_security_init(), we'll come back | ||
455 | * and fix this up afterwards. | ||
456 | */ | ||
457 | if (slab_is_available()) { | ||
458 | if (lsm_append(lsm, &lsm_names) < 0) | ||
459 | panic("%s - Cannot get early memory.\n", __func__); | ||
460 | } | ||
427 | } | 461 | } |
428 | 462 | ||
429 | int call_blocking_lsm_notifier(enum lsm_event event, void *data) | 463 | int call_blocking_lsm_notifier(enum lsm_event event, void *data) |
@@ -2364,3 +2398,9 @@ void security_bpf_prog_free(struct bpf_prog_aux *aux) | |||
2364 | call_void_hook(bpf_prog_free_security, aux); | 2398 | call_void_hook(bpf_prog_free_security, aux); |
2365 | } | 2399 | } |
2366 | #endif /* CONFIG_BPF_SYSCALL */ | 2400 | #endif /* CONFIG_BPF_SYSCALL */ |
2401 | |||
2402 | int security_locked_down(enum lockdown_reason what) | ||
2403 | { | ||
2404 | return call_int_hook(locked_down, 0, what); | ||
2405 | } | ||
2406 | EXPORT_SYMBOL(security_locked_down); | ||