Skip to content

Commit

Permalink
Merge tag 'hardening-v6.1-rc1' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/kees/linux

Pull kernel hardening updates from Kees Cook:
 "Most of the collected changes here are fixes across the tree for
  various hardening features (details noted below).

  The most notable new feature here is the addition of the memcpy()
  overflow warning (under CONFIG_FORTIFY_SOURCE), which is the next step
  on the path to killing the common class of "trivially detectable"
  buffer overflow conditions (i.e. on arrays with sizes known at compile
  time) that have resulted in many exploitable vulnerabilities over the
  years (e.g. BleedingTooth).

  This feature is expected to still have some undiscovered false
  positives. It's been in -next for a full development cycle and all the
  reported false positives have been fixed in their respective trees.
  All the known-bad code patterns we could find with Coccinelle are also
  either fixed in their respective trees or in flight.

  The commit message in commit 54d9469 ("fortify: Add run-time WARN
  for cross-field memcpy()") for the feature has extensive details, but
  I'll repeat here that this is a warning _only_, and is not intended to
  actually block overflows (yet). The many patches fixing array sizes
  and struct members have been landing for several years now, and we're
  finally able to turn this on to find any remaining stragglers.

  Summary:

  Various fixes across several hardening areas:

   - loadpin: Fix verity target enforcement (Matthias Kaehlcke).

   - zero-call-used-regs: Add missing clobbers in paravirt (Bill
     Wendling).

   - CFI: clean up sparc function pointer type mismatches (Bart Van
     Assche).

   - Clang: Adjust compiler flag detection for various Clang changes
     (Sami Tolvanen, Kees Cook).

   - fortify: Fix warnings in arch-specific code in sh, ARM, and xen.

  Improvements to existing features:

   - testing: improve overflow KUnit test, introduce fortify KUnit test,
     add more coverage to LKDTM tests (Bart Van Assche, Kees Cook).

   - overflow: Relax overflow type checking for wider utility.

  New features:

   - string: Introduce strtomem() and strtomem_pad() to fill a gap in
     strncpy() replacement needs.

   - um: Enable FORTIFY_SOURCE support.

   - fortify: Enable run-time struct member memcpy() overflow warning"

* tag 'hardening-v6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: (27 commits)
  Makefile.extrawarn: Move -Wcast-function-type-strict to W=1
  hardening: Remove Clang's enable flag for -ftrivial-auto-var-init=zero
  sparc: Unbreak the build
  x86/paravirt: add extra clobbers with ZERO_CALL_USED_REGS enabled
  x86/paravirt: clean up typos and grammaros
  fortify: Convert to struct vs member helpers
  fortify: Explicitly check bounds are compile-time constants
  x86/entry: Work around Clang __bdos() bug
  ARM: decompressor: Include .data.rel.ro.local
  fortify: Adjust KUnit test for modular build
  sh: machvec: Use char[] for section boundaries
  kunit/memcpy: Avoid pathological compile-time string size
  lib: Improve the is_signed_type() kunit test
  LoadPin: Require file with verity root digests to have a header
  dm: verity-loadpin: Only trust verity targets with enforcement
  LoadPin: Fix Kconfig doc about format of file with verity digests
  um: Enable FORTIFY_SOURCE
  lkdtm: Update tests for memcpy() run-time warnings
  fortify: Add run-time WARN for cross-field memcpy()
  fortify: Use SIZE_MAX instead of (size_t)-1
  ...
  • Loading branch information
torvalds committed Oct 4, 2022
2 parents 865dad2 + 2120635 commit d0989d0
Show file tree
Hide file tree
Showing 33 changed files with 815 additions and 240 deletions.
11 changes: 7 additions & 4 deletions Documentation/process/deprecated.rst
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,20 @@ be NUL terminated. This can lead to various linear read overflows and
other misbehavior due to the missing termination. It also NUL-pads
the destination buffer if the source contents are shorter than the
destination buffer size, which may be a needless performance penalty
for callers using only NUL-terminated strings. The safe replacement is
for callers using only NUL-terminated strings.

When the destination is required to be NUL-terminated, the replacement is
strscpy(), though care must be given to any cases where the return value
of strncpy() was used, since strscpy() does not return a pointer to the
destination, but rather a count of non-NUL bytes copied (or negative
errno when it truncates). Any cases still needing NUL-padding should
instead use strscpy_pad().

If a caller is using non-NUL-terminated strings, strncpy() can
still be used, but destinations should be marked with the `__nonstring
If a caller is using non-NUL-terminated strings, strtomem() should be
used, and the destinations should be marked with the `__nonstring
<https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
attribute to avoid future compiler warnings.
attribute to avoid future compiler warnings. For cases still needing
NUL-padding, strtomem_pad() can be used.

strlcpy()
---------
Expand Down
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -8001,6 +8001,7 @@ L: [email protected]
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
F: include/linux/fortify-string.h
F: lib/fortify_kunit.c
F: lib/test_fortify/*
F: scripts/test_fortify.sh
K: \b__NO_FORTIFY\b
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -909,8 +909,8 @@ endif
# Initialize all stack variables with a zero value.
ifdef CONFIG_INIT_STACK_ALL_ZERO
KBUILD_CFLAGS += -ftrivial-auto-var-init=zero
ifdef CONFIG_CC_IS_CLANG
# https://bugs.llvm.org/show_bug.cgi?id=45497
ifdef CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO_ENABLER
# https://github.com/llvm/llvm-project/issues/44842
KBUILD_CFLAGS += -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang
endif
endif
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/boot/compressed/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ SECTIONS
*(.ARM.extab*)
*(.note.*)
*(.rel.*)
*(.printk_index)
/*
* Discard any r/w data - this produces a link error if we have any,
* which is required for PIC decompression. Local data generates
Expand Down Expand Up @@ -57,6 +58,7 @@ SECTIONS
*(.rodata)
*(.rodata.*)
*(.data.rel.ro)
*(.data.rel.ro.*)
}
.piggydata : {
*(.piggydata)
Expand Down
2 changes: 1 addition & 1 deletion arch/sh/include/asm/sections.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include <asm-generic/sections.h>

extern long __machvec_start, __machvec_end;
extern char __machvec_start[], __machvec_end[];
extern char __uncached_start, __uncached_end;
extern char __start_eh_frame[], __stop_eh_frame[];

Expand Down
10 changes: 5 additions & 5 deletions arch/sh/kernel/machvec.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
#define MV_NAME_SIZE 32

#define for_each_mv(mv) \
for ((mv) = (struct sh_machine_vector *)&__machvec_start; \
(mv) && (unsigned long)(mv) < (unsigned long)&__machvec_end; \
for ((mv) = (struct sh_machine_vector *)__machvec_start; \
(mv) && (unsigned long)(mv) < (unsigned long)__machvec_end; \
(mv)++)

static struct sh_machine_vector * __init get_mv_byname(const char *name)
Expand Down Expand Up @@ -87,8 +87,8 @@ void __init sh_mv_setup(void)
if (!machvec_selected) {
unsigned long machvec_size;

machvec_size = ((unsigned long)&__machvec_end -
(unsigned long)&__machvec_start);
machvec_size = ((unsigned long)__machvec_end -
(unsigned long)__machvec_start);

/*
* Sanity check for machvec section alignment. Ensure
Expand All @@ -102,7 +102,7 @@ void __init sh_mv_setup(void)
* vector (usually the only one) from .machvec.init.
*/
if (machvec_size >= sizeof(struct sh_machine_vector))
sh_mv = *(struct sh_machine_vector *)&__machvec_start;
sh_mv = *(struct sh_machine_vector *)__machvec_start;
}

pr_notice("Booting machvec: %s\n", get_system_type());
Expand Down
15 changes: 6 additions & 9 deletions arch/sparc/include/asm/smp_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ extern volatile unsigned long cpu_callin_map[NR_CPUS];
extern cpumask_t smp_commenced_mask;
extern struct linux_prom_registers smp_penguin_ctable;

typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long);

void cpu_panic(void);

/*
Expand All @@ -57,7 +54,7 @@ void smp_bogo(struct seq_file *);
void smp_info(struct seq_file *);

struct sparc32_ipi_ops {
void (*cross_call)(smpfunc_t func, cpumask_t mask, unsigned long arg1,
void (*cross_call)(void *func, cpumask_t mask, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4);
void (*resched)(int cpu);
Expand All @@ -66,28 +63,28 @@ struct sparc32_ipi_ops {
};
extern const struct sparc32_ipi_ops *sparc32_ipi_ops;

static inline void xc0(smpfunc_t func)
static inline void xc0(void *func)
{
sparc32_ipi_ops->cross_call(func, *cpu_online_mask, 0, 0, 0, 0);
}

static inline void xc1(smpfunc_t func, unsigned long arg1)
static inline void xc1(void *func, unsigned long arg1)
{
sparc32_ipi_ops->cross_call(func, *cpu_online_mask, arg1, 0, 0, 0);
}
static inline void xc2(smpfunc_t func, unsigned long arg1, unsigned long arg2)
static inline void xc2(void *func, unsigned long arg1, unsigned long arg2)
{
sparc32_ipi_ops->cross_call(func, *cpu_online_mask, arg1, arg2, 0, 0);
}

static inline void xc3(smpfunc_t func, unsigned long arg1, unsigned long arg2,
static inline void xc3(void *func, unsigned long arg1, unsigned long arg2,
unsigned long arg3)
{
sparc32_ipi_ops->cross_call(func, *cpu_online_mask,
arg1, arg2, arg3, 0);
}

static inline void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2,
static inline void xc4(void *func, unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4)
{
sparc32_ipi_ops->cross_call(func, *cpu_online_mask,
Expand Down
12 changes: 7 additions & 5 deletions arch/sparc/kernel/leon_smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ void leonsmp_ipi_interrupt(void)
}

static struct smp_funcall {
smpfunc_t func;
void *func;
unsigned long arg1;
unsigned long arg2;
unsigned long arg3;
Expand All @@ -372,7 +372,7 @@ static struct smp_funcall {
static DEFINE_SPINLOCK(cross_call_lock);

/* Cross calls must be serialized, at least currently. */
static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
static void leon_cross_call(void *func, cpumask_t mask, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4)
{
Expand All @@ -384,7 +384,7 @@ static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,

{
/* If you make changes here, make sure gcc generates proper code... */
register smpfunc_t f asm("i0") = func;
register void *f asm("i0") = func;
register unsigned long a1 asm("i1") = arg1;
register unsigned long a2 asm("i2") = arg2;
register unsigned long a3 asm("i3") = arg3;
Expand Down Expand Up @@ -444,11 +444,13 @@ static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
/* Running cross calls. */
void leon_cross_call_irq(void)
{
void (*func)(unsigned long, unsigned long, unsigned long, unsigned long,
unsigned long) = ccall_info.func;
int i = smp_processor_id();

ccall_info.processors_in[i] = 1;
ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
ccall_info.arg4, ccall_info.arg5);
func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3, ccall_info.arg4,
ccall_info.arg5);
ccall_info.processors_out[i] = 1;
}

Expand Down
12 changes: 7 additions & 5 deletions arch/sparc/kernel/sun4d_smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ static void sun4d_ipi_resched(int cpu)
}

static struct smp_funcall {
smpfunc_t func;
void *func;
unsigned long arg1;
unsigned long arg2;
unsigned long arg3;
Expand All @@ -281,7 +281,7 @@ static struct smp_funcall {
static DEFINE_SPINLOCK(cross_call_lock);

/* Cross calls must be serialized, at least currently. */
static void sun4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
static void sun4d_cross_call(void *func, cpumask_t mask, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4)
{
Expand All @@ -296,7 +296,7 @@ static void sun4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
* If you make changes here, make sure
* gcc generates proper code...
*/
register smpfunc_t f asm("i0") = func;
register void *f asm("i0") = func;
register unsigned long a1 asm("i1") = arg1;
register unsigned long a2 asm("i2") = arg2;
register unsigned long a3 asm("i3") = arg3;
Expand Down Expand Up @@ -353,11 +353,13 @@ static void sun4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
/* Running cross calls. */
void smp4d_cross_call_irq(void)
{
void (*func)(unsigned long, unsigned long, unsigned long, unsigned long,
unsigned long) = ccall_info.func;
int i = hard_smp_processor_id();

ccall_info.processors_in[i] = 1;
ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
ccall_info.arg4, ccall_info.arg5);
func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3, ccall_info.arg4,
ccall_info.arg5);
ccall_info.processors_out[i] = 1;
}

Expand Down
10 changes: 6 additions & 4 deletions arch/sparc/kernel/sun4m_smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ static void sun4m_ipi_mask_one(int cpu)
}

static struct smp_funcall {
smpfunc_t func;
void *func;
unsigned long arg1;
unsigned long arg2;
unsigned long arg3;
Expand All @@ -170,7 +170,7 @@ static struct smp_funcall {
static DEFINE_SPINLOCK(cross_call_lock);

/* Cross calls must be serialized, at least currently. */
static void sun4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
static void sun4m_cross_call(void *func, cpumask_t mask, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4)
{
Expand Down Expand Up @@ -230,11 +230,13 @@ static void sun4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
/* Running cross calls. */
void smp4m_cross_call_irq(void)
{
void (*func)(unsigned long, unsigned long, unsigned long, unsigned long,
unsigned long) = ccall_info.func;
int i = smp_processor_id();

ccall_info.processors_in[i] = 1;
ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
ccall_info.arg4, ccall_info.arg5);
func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3, ccall_info.arg4,
ccall_info.arg5);
ccall_info.processors_out[i] = 1;
}

Expand Down
29 changes: 13 additions & 16 deletions arch/sparc/mm/srmmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1636,19 +1636,19 @@ static void __init get_srmmu_type(void)
/* Local cross-calls. */
static void smp_flush_page_for_dma(unsigned long page)
{
xc1((smpfunc_t) local_ops->page_for_dma, page);
xc1(local_ops->page_for_dma, page);
local_ops->page_for_dma(page);
}

static void smp_flush_cache_all(void)
{
xc0((smpfunc_t) local_ops->cache_all);
xc0(local_ops->cache_all);
local_ops->cache_all();
}

static void smp_flush_tlb_all(void)
{
xc0((smpfunc_t) local_ops->tlb_all);
xc0(local_ops->tlb_all);
local_ops->tlb_all();
}

Expand All @@ -1659,7 +1659,7 @@ static void smp_flush_cache_mm(struct mm_struct *mm)
cpumask_copy(&cpu_mask, mm_cpumask(mm));
cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
if (!cpumask_empty(&cpu_mask))
xc1((smpfunc_t) local_ops->cache_mm, (unsigned long) mm);
xc1(local_ops->cache_mm, (unsigned long)mm);
local_ops->cache_mm(mm);
}
}
Expand All @@ -1671,7 +1671,7 @@ static void smp_flush_tlb_mm(struct mm_struct *mm)
cpumask_copy(&cpu_mask, mm_cpumask(mm));
cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
if (!cpumask_empty(&cpu_mask)) {
xc1((smpfunc_t) local_ops->tlb_mm, (unsigned long) mm);
xc1(local_ops->tlb_mm, (unsigned long)mm);
if (atomic_read(&mm->mm_users) == 1 && current->active_mm == mm)
cpumask_copy(mm_cpumask(mm),
cpumask_of(smp_processor_id()));
Expand All @@ -1691,8 +1691,8 @@ static void smp_flush_cache_range(struct vm_area_struct *vma,
cpumask_copy(&cpu_mask, mm_cpumask(mm));
cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
if (!cpumask_empty(&cpu_mask))
xc3((smpfunc_t) local_ops->cache_range,
(unsigned long) vma, start, end);
xc3(local_ops->cache_range, (unsigned long)vma, start,
end);
local_ops->cache_range(vma, start, end);
}
}
Expand All @@ -1708,8 +1708,8 @@ static void smp_flush_tlb_range(struct vm_area_struct *vma,
cpumask_copy(&cpu_mask, mm_cpumask(mm));
cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
if (!cpumask_empty(&cpu_mask))
xc3((smpfunc_t) local_ops->tlb_range,
(unsigned long) vma, start, end);
xc3(local_ops->tlb_range, (unsigned long)vma, start,
end);
local_ops->tlb_range(vma, start, end);
}
}
Expand All @@ -1723,8 +1723,7 @@ static void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
cpumask_copy(&cpu_mask, mm_cpumask(mm));
cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
if (!cpumask_empty(&cpu_mask))
xc2((smpfunc_t) local_ops->cache_page,
(unsigned long) vma, page);
xc2(local_ops->cache_page, (unsigned long)vma, page);
local_ops->cache_page(vma, page);
}
}
Expand All @@ -1738,8 +1737,7 @@ static void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
cpumask_copy(&cpu_mask, mm_cpumask(mm));
cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
if (!cpumask_empty(&cpu_mask))
xc2((smpfunc_t) local_ops->tlb_page,
(unsigned long) vma, page);
xc2(local_ops->tlb_page, (unsigned long)vma, page);
local_ops->tlb_page(vma, page);
}
}
Expand All @@ -1753,7 +1751,7 @@ static void smp_flush_page_to_ram(unsigned long page)
* XXX This experiment failed, research further... -DaveM
*/
#if 1
xc1((smpfunc_t) local_ops->page_to_ram, page);
xc1(local_ops->page_to_ram, page);
#endif
local_ops->page_to_ram(page);
}
Expand All @@ -1764,8 +1762,7 @@ static void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
cpumask_copy(&cpu_mask, mm_cpumask(mm));
cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
if (!cpumask_empty(&cpu_mask))
xc2((smpfunc_t) local_ops->sig_insns,
(unsigned long) mm, insn_addr);
xc2(local_ops->sig_insns, (unsigned long)mm, insn_addr);
local_ops->sig_insns(mm, insn_addr);
}

Expand Down
1 change: 1 addition & 0 deletions arch/um/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ config UML
bool
default y
select ARCH_EPHEMERAL_INODES
select ARCH_HAS_FORTIFY_SOURCE
select ARCH_HAS_GCOV_PROFILE_ALL
select ARCH_HAS_KCOV
select ARCH_HAS_STRNCPY_FROM_USER
Expand Down
1 change: 1 addition & 0 deletions arch/um/os-Linux/user_syms.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#define __NO_FORTIFY
#include <linux/types.h>
#include <linux/module.h>

Expand Down
Loading

0 comments on commit d0989d0

Please sign in to comment.