mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
hardening updates for v7.2-rc1
- lkdtm: Add case to provoke a crash in EFI runtime services (Ard Biesheuvel)
- lkdtm: add PPC_RADIX_TLBIEL test and missed isync (Sayali Patil)
- stddef: Document designated initializer semantics for __TRAILING_OVERLAP()
(Gustavo A. R. Silva)
- strarray: drop redundant allocation, add __counted_by_ptr (Thorsten Blum)
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQRSPkdeREjth1dHnSE2KwveOeQkuwUCajBj8AAKCRA2KwveOeQk
u/fjAPwJVWvocviOCGGA6Rq/BAPNJpkrahqtcNAjwvuh+SWDfQD/bHcdXLXi6tl2
fHWCdJ2ScNBqAWVkJNl9F3k+XdSsmws=
=GZAD
-----END PGP SIGNATURE-----
Merge tag 'hardening-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull hardening updates from Kees Cook:
- lkdtm:
- Add case to provoke a crash in EFI runtime services (Ard Biesheuvel)
- add PPC_RADIX_TLBIEL test and missed isync (Sayali Patil)
- stddef: Document designated initializer semantics for
__TRAILING_OVERLAP() (Gustavo A. R. Silva)
- strarray: drop redundant allocation, add __counted_by_ptr (Thorsten
Blum)
* tag 'hardening-v7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
lkdtm/powerpc: add PPC_RADIX_TLBIEL test for radix MCE validation
lkdtm/powerpc: add isync after slbmte to enforce SLB update ordering
lkdtm: Add case to provoke a crash in EFI runtime services
lib/string_helpers: annotate struct strarray with __counted_by_ptr
lib/string_helpers: drop redundant allocation in kasprintf_strarray
MAINTAINERS: add kernel hardening keyword __counted_by_ptr
stddef: Document designated initializer semantics for __TRAILING_OVERLAP()
This commit is contained in:
commit
481329ec5b
|
|
@ -13944,7 +13944,7 @@ F: scripts/Makefile.randstruct
|
|||
F: security/Kconfig.hardening
|
||||
K: \b(add|choose)_random_kstack_offset\b
|
||||
K: \b__check_(object_size|heap_object)\b
|
||||
K: \b__counted_by(_le|_be)?\b
|
||||
K: \b__counted_by(_le|_be|_ptr)?\b
|
||||
|
||||
KERNEL JANITORS
|
||||
L: kernel-janitors@vger.kernel.org
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ lkdtm-$(CONFIG_LKDTM) += usercopy.o
|
|||
lkdtm-$(CONFIG_LKDTM) += kstack_erase.o
|
||||
lkdtm-$(CONFIG_LKDTM) += cfi.o
|
||||
lkdtm-$(CONFIG_LKDTM) += fortify.o
|
||||
lkdtm-$(CONFIG_PPC_64S_HASH_MMU) += powerpc.o
|
||||
lkdtm-$(CONFIG_PPC_BOOK3S_64) += powerpc.o
|
||||
|
||||
KASAN_SANITIZE_stackleak.o := n
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
#include "lkdtm.h"
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/sched.h>
|
||||
|
|
@ -817,6 +818,29 @@ static noinline void lkdtm_CORRUPT_PAC(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void __maybe_unused lkdtm_EFI_RUNTIME_CRASH(void)
|
||||
{
|
||||
static unsigned long size __ro_after_init = sizeof(efi_char16_t);
|
||||
efi_status_t status;
|
||||
|
||||
if (!efi.get_next_variable ||
|
||||
!efi_enabled(EFI_RUNTIME_SERVICES) ||
|
||||
!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME)) {
|
||||
pr_err("FAIL: EFI GetNextVariableName() is not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provoke a fault by asking the firmware to write to a read-only
|
||||
* variable.
|
||||
*/
|
||||
status = efi.get_next_variable(&size, L"", &(efi_guid_t){});
|
||||
|
||||
if (status != EFI_ABORTED || efi_enabled(EFI_RUNTIME_SERVICES))
|
||||
pr_err("FAIL: EFI GetNextVariable() did not abort (%#lx)\n",
|
||||
status);
|
||||
}
|
||||
|
||||
static struct crashtype crashtypes[] = {
|
||||
CRASHTYPE(PANIC),
|
||||
CRASHTYPE(PANIC_STOP_IRQOFF),
|
||||
|
|
@ -850,6 +874,9 @@ static struct crashtype crashtypes[] = {
|
|||
CRASHTYPE(UNSET_SMEP),
|
||||
CRASHTYPE(DOUBLE_FAULT),
|
||||
CRASHTYPE(CORRUPT_PAC),
|
||||
#ifdef CONFIG_EFI
|
||||
CRASHTYPE(EFI_RUNTIME_CRASH),
|
||||
#endif
|
||||
};
|
||||
|
||||
struct crashtype_category bugs_crashtypes = {
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ static const struct crashtype_category *crashtype_categories[] = {
|
|||
&stackleak_crashtypes,
|
||||
&cfi_crashtypes,
|
||||
&fortify_crashtypes,
|
||||
#ifdef CONFIG_PPC_64S_HASH_MMU
|
||||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
&powerpc_crashtypes,
|
||||
#endif
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/vmalloc.h>
|
||||
#include <asm/mmu.h>
|
||||
|
||||
#ifdef CONFIG_PPC_64S_HASH_MMU
|
||||
/* Inserts new slb entries */
|
||||
static void insert_slb_entry(unsigned long p, int ssize, int page_size)
|
||||
{
|
||||
|
|
@ -17,11 +18,14 @@ static void insert_slb_entry(unsigned long p, int ssize, int page_size)
|
|||
: "r" (mk_vsid_data(p, ssize, flags)),
|
||||
"r" (mk_esid_data(p, ssize, SLB_NUM_BOLTED))
|
||||
: "memory");
|
||||
isync();
|
||||
|
||||
asm volatile("slbmte %0,%1" :
|
||||
: "r" (mk_vsid_data(p, ssize, flags)),
|
||||
"r" (mk_esid_data(p, ssize, SLB_NUM_BOLTED + 1))
|
||||
: "memory");
|
||||
isync();
|
||||
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +88,7 @@ static void insert_dup_slb_entry_0(void)
|
|||
: "r" (vsid),
|
||||
"r" (esid | SLB_NUM_BOLTED)
|
||||
: "memory");
|
||||
isync();
|
||||
|
||||
asm volatile("slbmfee %0,%1" : "=r" (esid) : "r" (i));
|
||||
asm volatile("slbmfev %0,%1" : "=r" (vsid) : "r" (i));
|
||||
|
|
@ -93,15 +98,42 @@ static void insert_dup_slb_entry_0(void)
|
|||
: "r" (vsid),
|
||||
"r" (esid | (SLB_NUM_BOLTED + 1))
|
||||
: "memory");
|
||||
isync();
|
||||
|
||||
pr_info("%s accessing test address 0x%lx: 0x%lx\n",
|
||||
__func__, test_address, *test_ptr);
|
||||
|
||||
preempt_enable();
|
||||
}
|
||||
#endif /* CONFIG_PPC_64S_HASH_MMU */
|
||||
|
||||
static __always_inline void tlbiel_va(unsigned long va,
|
||||
unsigned long pid,
|
||||
unsigned long ap,
|
||||
unsigned long ric)
|
||||
{
|
||||
unsigned long rb, rs, prs, r;
|
||||
|
||||
rb = va & ~(PPC_BITMASK(52, 63));
|
||||
rb |= ap << PPC_BITLSHIFT(58);
|
||||
rs = pid << PPC_BITLSHIFT(31);
|
||||
|
||||
prs = 1; /* process scoped */
|
||||
r = 1; /* radix format */
|
||||
|
||||
/*
|
||||
* Trigger an MCE by issuing radix tlbiel with an invalid operand combination.
|
||||
* The combination of RIC = 2 with IS = 0 (Invalidation selector specified
|
||||
* in the RB register) is invalid.
|
||||
* This invalid combination causes hardware to raise a machine check.
|
||||
*/
|
||||
asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
|
||||
: : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
|
||||
}
|
||||
|
||||
static void lkdtm_PPC_SLB_MULTIHIT(void)
|
||||
{
|
||||
#ifdef CONFIG_PPC_64S_HASH_MMU
|
||||
if (!radix_enabled()) {
|
||||
pr_info("Injecting SLB multihit errors\n");
|
||||
/*
|
||||
|
|
@ -117,10 +149,27 @@ static void lkdtm_PPC_SLB_MULTIHIT(void)
|
|||
} else {
|
||||
pr_err("XFAIL: This test is for ppc64 and with hash mode MMU only\n");
|
||||
}
|
||||
#else
|
||||
pr_err("XFAIL: This test requires CONFIG_PPC_64S_HASH_MMU\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void lkdtm_PPC_RADIX_TLBIEL(void)
|
||||
{
|
||||
unsigned long addr = PAGE_OFFSET;
|
||||
|
||||
if (radix_enabled()) {
|
||||
pr_info("Injecting Radix TLB invalidation MCE\n");
|
||||
tlbiel_va(addr, 0, 0, RIC_FLUSH_ALL);
|
||||
pr_info("Recovered from radix tlbiel attempt\n");
|
||||
} else {
|
||||
pr_err("XFAIL: This test is for ppc64 and with radix mode MMU only\n");
|
||||
}
|
||||
}
|
||||
|
||||
static struct crashtype crashtypes[] = {
|
||||
CRASHTYPE(PPC_SLB_MULTIHIT),
|
||||
CRASHTYPE(PPC_RADIX_TLBIEL),
|
||||
};
|
||||
|
||||
struct crashtype_category powerpc_crashtypes = {
|
||||
|
|
|
|||
|
|
@ -100,6 +100,71 @@ enum {
|
|||
* Creates a union between a flexible-array member (FAM) in a struct and a set
|
||||
* of additional members that would otherwise follow it.
|
||||
*
|
||||
* Beware that, as this helper encloses TYPE NAME and MEMBERS in the same
|
||||
* union, designated initializers for MEMBERS may overwrite portions
|
||||
* previously initialized through NAME.
|
||||
*
|
||||
* For example::
|
||||
*
|
||||
* struct flex {
|
||||
* size_t count;
|
||||
* u8 fam[];
|
||||
* };
|
||||
*
|
||||
* struct composite {
|
||||
* ...
|
||||
* __TRAILING_OVERLAP(struct flex, flex, fam, __packed,
|
||||
* u8 data;
|
||||
* );
|
||||
* } __packed;
|
||||
*
|
||||
* static struct composite comp = {
|
||||
* .flex = {
|
||||
* .count = 1,
|
||||
* },
|
||||
* .data = 2,
|
||||
* };
|
||||
*
|
||||
* In the example above, .flex and .data initialize different views of the same
|
||||
* union storage. Since .data is initialized last, it _may_ overwrite portions
|
||||
* previously initialized through .flex, leading to .flex.count being zeroed
|
||||
* out.
|
||||
*
|
||||
* A couple of alternatives are shown below.
|
||||
*
|
||||
* a) Initialize only one view of the overlapped storage and assign the rest
|
||||
* at runtime::
|
||||
*
|
||||
* static struct composite comp = {
|
||||
* .flex = {
|
||||
* .count = 1,
|
||||
* },
|
||||
* };
|
||||
*
|
||||
* static void foo(void)
|
||||
* {
|
||||
* comp.data = 2;
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* b) Alternatively, replace designated initializers with runtime assignments::
|
||||
*
|
||||
* static void foo(void)
|
||||
* {
|
||||
* struct composite comp;
|
||||
*
|
||||
* comp.flex.count = 1;
|
||||
* comp.data = 2;
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* Compiler Explorer test code: https://godbolt.org/z/voM4E36dT
|
||||
*
|
||||
* For another example of the above see commit 5e54510a9389 ("acpi: nfit:
|
||||
* intel: avoid multiple -Wflex-array-member-not-at-end warnings")
|
||||
*
|
||||
* Link: https://git.kernel.org/linus/5e54510a9389caa9
|
||||
*
|
||||
* @TYPE: Flexible structure type name, including "struct" keyword.
|
||||
* @NAME: Name for a variable to define.
|
||||
* @FAM: The flexible-array member within @TYPE
|
||||
|
|
|
|||
|
|
@ -752,7 +752,7 @@ EXPORT_SYMBOL_GPL(kstrdup_and_replace);
|
|||
* kasprintf_strarray - allocate and fill array of sequential strings
|
||||
* @gfp: flags for the slab allocator
|
||||
* @prefix: prefix to be used
|
||||
* @n: amount of lines to be allocated and filled
|
||||
* @n: number of strings to be allocated and filled
|
||||
*
|
||||
* Allocates and fills @n strings using pattern "%s-%zu", where prefix
|
||||
* is provided by caller. The caller is responsible to free them with
|
||||
|
|
@ -765,7 +765,7 @@ char **kasprintf_strarray(gfp_t gfp, const char *prefix, size_t n)
|
|||
char **names;
|
||||
size_t i;
|
||||
|
||||
names = kcalloc(n + 1, sizeof(char *), gfp);
|
||||
names = kcalloc(n, sizeof(char *), gfp);
|
||||
if (!names)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -805,7 +805,7 @@ void kfree_strarray(char **array, size_t n)
|
|||
EXPORT_SYMBOL_GPL(kfree_strarray);
|
||||
|
||||
struct strarray {
|
||||
char **array;
|
||||
char **array __counted_by_ptr(n);
|
||||
size_t n;
|
||||
};
|
||||
|
||||
|
|
@ -824,13 +824,13 @@ char **devm_kasprintf_strarray(struct device *dev, const char *prefix, size_t n)
|
|||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ptr->n = n;
|
||||
ptr->array = kasprintf_strarray(GFP_KERNEL, prefix, n);
|
||||
if (!ptr->array) {
|
||||
devres_free(ptr);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
ptr->n = n;
|
||||
devres_add(dev, ptr);
|
||||
|
||||
return ptr->array;
|
||||
|
|
|
|||
|
|
@ -86,3 +86,4 @@ FORTIFY_STR_MEMBER detected buffer overflow
|
|||
FORTIFY_MEM_OBJECT detected buffer overflow
|
||||
FORTIFY_MEM_MEMBER detected field-spanning write
|
||||
PPC_SLB_MULTIHIT Recovered
|
||||
#PPC_RADIX_TLBIEL Triggers unrecoverable MCE
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user