mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:02:20 +00:00
hardening updates for v6.3-rc1
- Replace 0-length and 1-element arrays with flexible arrays in various subsystems (Paulo Miguel Almeida, Stephen Rothwell, Kees Cook) - randstruct: Disable Clang 15 support (Eric Biggers) - GCC plugins: Drop -std=gnu++11 flag (Sam James) - strpbrk(): Refactor to use strchr() (Andy Shevchenko) - LoadPin LSM: Allow root filesystem switching when non-enforcing - fortify: Use dynamic object size hints when available - ext4: Fix CFI function prototype mismatch - Nouveau: Fix DP buffer size arguments - hisilicon: Wipe entire crypto DMA pool on error - coda: Fully allocate sig_inputArgs - UBSAN: Improve arm64 trap code reporting - copy_struct_from_user(): Add minimum bounds check on kernel buffer size -----BEGIN PGP SIGNATURE----- iQJKBAABCgA0FiEEpcP2jyKd1g9yPm4TiXL039xtwCYFAmPv1Y8WHGtlZXNjb29r QGNocm9taXVtLm9yZwAKCRCJcvTf3G3AJg5UD/9x3Lx0EG3iL4qPtjmohaXd899r AzP1ysoxYnmo/cY0//W3DPCJrUaVlTm7M2xXOpzi7YPVD8Jcofzy6Uxm9BiG/OJ9 bla7uQixlDMA2MBmWzAXhM7337WgEtBcr6kbXk6rHFnzmk8CdAY3wjmLmiefxEWT gkdeJlbkBFynssSF2nejgCvr/ZyiWQr2V9hRdEavLQH/MDS785bmNwbLyUNqK+eo gOtuyjyV90t+cSIN0bF7gOCFGf1ivKA/+GNFrob0jY0Fy2kGx1I2wQMn9yzjzerC o6Majz9r+7Z7xIaz2Pm9nDaWyZDI05RfoRpQZ9dSEJ+zYgbFBFpDpJShcJvSpNa0 POqeR400n/6VWBcbk7UU0s7VCVU13IsOFhBSVMQM5FfzIcUkj0/VBm0Jm0ODrpM9 13/nKyAkvHkH0uSJbQjn79rXvEvqQyi5f28emm2CuhiHHUiDEUdsmMD7fE8UXo4r U8dgfwTOLLQBKmOQJcgiLo8iLDPhatZKYQAZ7LMY9kbHLsJlRVxfzY9PriNCuI5o XuMLJG33TrlUDfqQrKeSJ9srVRiiIBAzoWnIfIVE3Xb46LqFNXVRdJCt4A2678jn gYIzkQ2HbVe2chUhUyjsjGTjmmeX9qZG0UOlhRQ0RvWFxi390wwYqhkSaOEGtDGv QbVh0Lb86m3H/G+M9g== =XnVa -----END PGP SIGNATURE----- Merge tag 'hardening-v6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux Pull hardening updates from Kees Cook: "Beyond some specific LoadPin, UBSAN, and fortify features, there are other fixes scattered around in various subsystems where maintainers were okay with me carrying them in my tree or were non-responsive but the patches were reviewed by others: - Replace 0-length and 1-element arrays with flexible arrays in various subsystems (Paulo Miguel Almeida, Stephen Rothwell, Kees Cook) - randstruct: Disable Clang 15 support (Eric Biggers) - GCC plugins: Drop -std=gnu++11 flag (Sam James) - strpbrk(): Refactor to use strchr() (Andy Shevchenko) - LoadPin LSM: Allow root filesystem switching when non-enforcing - fortify: Use dynamic object size hints when available - ext4: Fix CFI function prototype mismatch - Nouveau: Fix DP buffer size arguments - hisilicon: Wipe entire crypto DMA pool on error - coda: Fully allocate sig_inputArgs - UBSAN: Improve arm64 trap code reporting - copy_struct_from_user(): Add minimum bounds check on kernel buffer size" * tag 'hardening-v6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: randstruct: disable Clang 15 support uaccess: Add minimum bounds check on kernel buffer size arm64: Support Clang UBSAN trap codes for better reporting coda: Avoid partial allocation of sig_inputArgs gcc-plugins: drop -std=gnu++11 to fix GCC 13 build lib/string: Use strchr() in strpbrk() crypto: hisilicon: Wipe entire pool on error net/i40e: Replace 0-length array with flexible array io_uring: Replace 0-length array with flexible array ext4: Fix function prototype mismatch for ext4_feat_ktype i915/gvt: Replace one-element array with flexible-array member drm/nouveau/disp: Fix nvif_outp_acquire_dp() argument size LoadPin: Allow filesystem switch when not enforcing LoadPin: Move pin reporting cleanly out of locking LoadPin: Refactor sysctl initialization LoadPin: Refactor read-only check into a helper ARM: ixp4xx: Replace 0-length arrays with flexible arrays fortify: Use __builtin_dynamic_object_size() when available rxrpc: replace zero-lenth array with DECLARE_FLEX_ARRAY() helper
This commit is contained in:
commit
4a7d37e824
@ -17,6 +17,7 @@
|
||||
* 0x401: for compile time BRK instruction
|
||||
* 0x800: kernel-mode BUG() and WARN() traps
|
||||
* 0x9xx: tag-based KASAN trap (allowed values 0x900 - 0x9ff)
|
||||
* 0x55xx: Undefined Behavior Sanitizer traps ('U' << 8)
|
||||
* 0x8xxx: Control-Flow Integrity traps
|
||||
*/
|
||||
#define KPROBES_BRK_IMM 0x004
|
||||
@ -28,6 +29,8 @@
|
||||
#define BUG_BRK_IMM 0x800
|
||||
#define KASAN_BRK_IMM 0x900
|
||||
#define KASAN_BRK_MASK 0x0ff
|
||||
#define UBSAN_BRK_IMM 0x5500
|
||||
#define UBSAN_BRK_MASK 0x00ff
|
||||
|
||||
#define CFI_BRK_IMM_TARGET GENMASK(4, 0)
|
||||
#define CFI_BRK_IMM_TYPE GENMASK(9, 5)
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/kasan.h>
|
||||
#include <linux/ubsan.h>
|
||||
#include <linux/cfi.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
@ -1074,6 +1075,19 @@ static struct break_hook kasan_break_hook = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UBSAN_TRAP
|
||||
static int ubsan_handler(struct pt_regs *regs, unsigned long esr)
|
||||
{
|
||||
die(report_ubsan_failure(regs, esr & UBSAN_BRK_MASK), regs, esr);
|
||||
return DBG_HOOK_HANDLED;
|
||||
}
|
||||
|
||||
static struct break_hook ubsan_break_hook = {
|
||||
.fn = ubsan_handler,
|
||||
.imm = UBSAN_BRK_IMM,
|
||||
.mask = UBSAN_BRK_MASK,
|
||||
};
|
||||
#endif
|
||||
|
||||
#define esr_comment(esr) ((esr) & ESR_ELx_BRK64_ISS_COMMENT_MASK)
|
||||
|
||||
@ -1091,6 +1105,10 @@ int __init early_brk64(unsigned long addr, unsigned long esr,
|
||||
#ifdef CONFIG_KASAN_SW_TAGS
|
||||
if ((esr_comment(esr) & ~KASAN_BRK_MASK) == KASAN_BRK_IMM)
|
||||
return kasan_handler(regs, esr) != DBG_HOOK_HANDLED;
|
||||
#endif
|
||||
#ifdef CONFIG_UBSAN_TRAP
|
||||
if ((esr_comment(esr) & ~UBSAN_BRK_MASK) == UBSAN_BRK_IMM)
|
||||
return ubsan_handler(regs, esr) != DBG_HOOK_HANDLED;
|
||||
#endif
|
||||
return bug_handler(regs, esr) != DBG_HOOK_HANDLED;
|
||||
}
|
||||
@ -1104,6 +1122,9 @@ void __init trap_init(void)
|
||||
register_kernel_break_hook(&fault_break_hook);
|
||||
#ifdef CONFIG_KASAN_SW_TAGS
|
||||
register_kernel_break_hook(&kasan_break_hook);
|
||||
#endif
|
||||
#ifdef CONFIG_UBSAN_TRAP
|
||||
register_kernel_break_hook(&ubsan_break_hook);
|
||||
#endif
|
||||
debug_traps_init();
|
||||
}
|
||||
|
@ -124,9 +124,8 @@ err_free_mem:
|
||||
for (j = 0; j < i; j++) {
|
||||
dma_free_coherent(dev, block_size, block[j].sgl,
|
||||
block[j].sgl_dma);
|
||||
memset(block + j, 0, sizeof(*block));
|
||||
}
|
||||
kfree(pool);
|
||||
kfree_sensitive(pool);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hisi_acc_create_sgl_pool);
|
||||
|
@ -45,7 +45,7 @@ struct gvt_firmware_header {
|
||||
u64 cfg_space_offset; /* offset in the file */
|
||||
u64 mmio_size;
|
||||
u64 mmio_offset; /* offset in the file */
|
||||
unsigned char data[1];
|
||||
unsigned char data[];
|
||||
};
|
||||
|
||||
#define dev_to_drm_minor(d) dev_get_drvdata((d))
|
||||
@ -77,7 +77,7 @@ static int expose_firmware_sysfs(struct intel_gvt *gvt)
|
||||
unsigned long size, crc32_start;
|
||||
int ret;
|
||||
|
||||
size = sizeof(*h) + info->mmio_size + info->cfg_space_size;
|
||||
size = offsetof(struct gvt_firmware_header, data) + info->mmio_size + info->cfg_space_size;
|
||||
firmware = vzalloc(size);
|
||||
if (!firmware)
|
||||
return -ENOMEM;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#define __NVIF_OUTP_H__
|
||||
#include <nvif/object.h>
|
||||
#include <nvif/if0012.h>
|
||||
#include <drm/display/drm_dp.h>
|
||||
struct nvif_disp;
|
||||
|
||||
struct nvif_outp {
|
||||
@ -21,7 +22,7 @@ int nvif_outp_acquire_rgb_crt(struct nvif_outp *);
|
||||
int nvif_outp_acquire_tmds(struct nvif_outp *, int head,
|
||||
bool hdmi, u8 max_ac_packet, u8 rekey, u8 scdc, bool hda);
|
||||
int nvif_outp_acquire_lvds(struct nvif_outp *, bool dual, bool bpc8);
|
||||
int nvif_outp_acquire_dp(struct nvif_outp *, u8 dpcd[16],
|
||||
int nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
int link_nr, int link_bw, bool hda, bool mst);
|
||||
void nvif_outp_release(struct nvif_outp *);
|
||||
int nvif_outp_infoframe(struct nvif_outp *, u8 type, struct nvif_outp_infoframe_v0 *, u32 size);
|
||||
|
@ -127,7 +127,7 @@ nvif_outp_acquire(struct nvif_outp *outp, u8 proto, struct nvif_outp_acquire_v0
|
||||
}
|
||||
|
||||
int
|
||||
nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[16],
|
||||
nvif_outp_acquire_dp(struct nvif_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
int link_nr, int link_bw, bool hda, bool mst)
|
||||
{
|
||||
struct nvif_outp_acquire_v0 args;
|
||||
|
@ -31,6 +31,7 @@ static void lkdtm_VMALLOC_LINEAR_OVERFLOW(void)
|
||||
char *one, *two;
|
||||
|
||||
one = vzalloc(PAGE_SIZE);
|
||||
OPTIMIZER_HIDE_VAR(one);
|
||||
two = vzalloc(PAGE_SIZE);
|
||||
|
||||
pr_info("Attempting vmalloc linear overflow ...\n");
|
||||
|
@ -176,7 +176,7 @@ enum i40e_interrupt_policy {
|
||||
|
||||
struct i40e_lump_tracking {
|
||||
u16 num_entries;
|
||||
u16 list[0];
|
||||
u16 list[];
|
||||
#define I40E_PILE_VALID_BIT 0x8000
|
||||
#define I40E_IWARP_IRQ_PILE_ID (I40E_PILE_VALID_BIT - 2)
|
||||
};
|
||||
|
@ -519,15 +519,15 @@ int npe_load_firmware(struct npe *npe, const char *name, struct device *dev)
|
||||
u32 id;
|
||||
u32 size;
|
||||
union {
|
||||
u32 data[0];
|
||||
struct dl_block blocks[0];
|
||||
DECLARE_FLEX_ARRAY(u32, data);
|
||||
DECLARE_FLEX_ARRAY(struct dl_block, blocks);
|
||||
};
|
||||
} *image;
|
||||
|
||||
struct dl_codeblock {
|
||||
u32 npe_addr;
|
||||
u32 size;
|
||||
u32 data[0];
|
||||
u32 data[];
|
||||
} *cb;
|
||||
|
||||
int i, j, err, data_size, instr_size, blocks, table_end;
|
||||
|
@ -791,7 +791,7 @@ static int coda_upcall(struct venus_comm *vcp,
|
||||
sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
|
||||
if (!sig_req) goto exit;
|
||||
|
||||
sig_inputArgs = kvzalloc(sizeof(struct coda_in_hdr), GFP_KERNEL);
|
||||
sig_inputArgs = kvzalloc(sizeof(*sig_inputArgs), GFP_KERNEL);
|
||||
if (!sig_inputArgs) {
|
||||
kfree(sig_req);
|
||||
goto exit;
|
||||
|
@ -491,6 +491,11 @@ static void ext4_sb_release(struct kobject *kobj)
|
||||
complete(&sbi->s_kobj_unregister);
|
||||
}
|
||||
|
||||
static void ext4_feat_release(struct kobject *kobj)
|
||||
{
|
||||
kfree(kobj);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops ext4_attr_ops = {
|
||||
.show = ext4_attr_show,
|
||||
.store = ext4_attr_store,
|
||||
@ -505,7 +510,7 @@ static struct kobj_type ext4_sb_ktype = {
|
||||
static struct kobj_type ext4_feat_ktype = {
|
||||
.default_groups = ext4_feat_groups,
|
||||
.sysfs_ops = &ext4_attr_ops,
|
||||
.release = (void (*)(struct kobject *))kfree,
|
||||
.release = ext4_feat_release,
|
||||
};
|
||||
|
||||
void ext4_notify_error_sysfs(struct ext4_sb_info *sbi)
|
||||
|
@ -297,6 +297,11 @@
|
||||
*
|
||||
* clang: https://clang.llvm.org/docs/AttributeReference.html#pass-object-size-pass-dynamic-object-size
|
||||
*/
|
||||
#if __has_attribute(__pass_dynamic_object_size__)
|
||||
# define __pass_dynamic_object_size(type) __attribute__((__pass_dynamic_object_size__(type)))
|
||||
#else
|
||||
# define __pass_dynamic_object_size(type)
|
||||
#endif
|
||||
#if __has_attribute(__pass_object_size__)
|
||||
# define __pass_object_size(type) __attribute__((__pass_object_size__(type)))
|
||||
#else
|
||||
|
@ -90,10 +90,17 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size)
|
||||
* size, rather than struct size), but there remain some stragglers using
|
||||
* type 0 that will be converted in the future.
|
||||
*/
|
||||
#if __has_builtin(__builtin_dynamic_object_size)
|
||||
#define POS __pass_dynamic_object_size(1)
|
||||
#define POS0 __pass_dynamic_object_size(0)
|
||||
#define __struct_size(p) __builtin_dynamic_object_size(p, 0)
|
||||
#define __member_size(p) __builtin_dynamic_object_size(p, 1)
|
||||
#else
|
||||
#define POS __pass_object_size(1)
|
||||
#define POS0 __pass_object_size(0)
|
||||
#define __struct_size(p) __builtin_object_size(p, 0)
|
||||
#define __member_size(p) __builtin_object_size(p, 1)
|
||||
#endif
|
||||
|
||||
#define __compiletime_lessthan(bounds, length) ( \
|
||||
__builtin_constant_p((bounds) < (length)) && \
|
||||
|
@ -329,6 +329,10 @@ copy_struct_from_user(void *dst, size_t ksize, const void __user *src,
|
||||
size_t size = min(ksize, usize);
|
||||
size_t rest = max(ksize, usize) - size;
|
||||
|
||||
/* Double check if ksize is larger than a known object size. */
|
||||
if (WARN_ON_ONCE(ksize > __builtin_object_size(dst, 1)))
|
||||
return -E2BIG;
|
||||
|
||||
/* Deal with trailing bytes. */
|
||||
if (usize < ksize) {
|
||||
memset(dst + size, 0, rest);
|
||||
|
9
include/linux/ubsan.h
Normal file
9
include/linux/ubsan.h
Normal file
@ -0,0 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_UBSAN_H
|
||||
#define _LINUX_UBSAN_H
|
||||
|
||||
#ifdef CONFIG_UBSAN_TRAP
|
||||
const char *report_ubsan_failure(struct pt_regs *regs, u32 check_type);
|
||||
#endif
|
||||
|
||||
#endif
|
@ -631,7 +631,7 @@ struct io_uring_buf_ring {
|
||||
__u16 resv3;
|
||||
__u16 tail;
|
||||
};
|
||||
struct io_uring_buf bufs[0];
|
||||
__DECLARE_FLEX_ARRAY(struct io_uring_buf, bufs);
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -340,9 +340,7 @@ quiet_cmd_build_OID_registry = GEN $@
|
||||
clean-files += oid_registry_data.c
|
||||
|
||||
obj-$(CONFIG_UCS2_STRING) += ucs2_string.o
|
||||
ifneq ($(CONFIG_UBSAN_TRAP),y)
|
||||
obj-$(CONFIG_UBSAN) += ubsan.o
|
||||
endif
|
||||
|
||||
UBSAN_SANITIZE_ubsan.o := n
|
||||
KASAN_SANITIZE_ubsan.o := n
|
||||
|
10
lib/string.c
10
lib/string.c
@ -480,13 +480,11 @@ EXPORT_SYMBOL(strcspn);
|
||||
*/
|
||||
char *strpbrk(const char *cs, const char *ct)
|
||||
{
|
||||
const char *sc1, *sc2;
|
||||
const char *sc;
|
||||
|
||||
for (sc1 = cs; *sc1 != '\0'; ++sc1) {
|
||||
for (sc2 = ct; *sc2 != '\0'; ++sc2) {
|
||||
if (*sc1 == *sc2)
|
||||
return (char *)sc1;
|
||||
}
|
||||
for (sc = cs; *sc != '\0'; ++sc) {
|
||||
if (strchr(ct, *sc))
|
||||
return (char *)sc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
68
lib/ubsan.c
68
lib/ubsan.c
@ -14,10 +14,76 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ubsan.h>
|
||||
#include <kunit/test-bug.h>
|
||||
|
||||
#include "ubsan.h"
|
||||
|
||||
#ifdef CONFIG_UBSAN_TRAP
|
||||
/*
|
||||
* Only include matches for UBSAN checks that are actually compiled in.
|
||||
* The mappings of struct SanitizerKind (the -fsanitize=xxx args) to
|
||||
* enum SanitizerHandler (the traps) in Clang is in clang/lib/CodeGen/.
|
||||
*/
|
||||
const char *report_ubsan_failure(struct pt_regs *regs, u32 check_type)
|
||||
{
|
||||
switch (check_type) {
|
||||
#ifdef CONFIG_UBSAN_BOUNDS
|
||||
/*
|
||||
* SanitizerKind::ArrayBounds and SanitizerKind::LocalBounds
|
||||
* emit SanitizerHandler::OutOfBounds.
|
||||
*/
|
||||
case ubsan_out_of_bounds:
|
||||
return "UBSAN: array index out of bounds";
|
||||
#endif
|
||||
#ifdef CONFIG_UBSAN_SHIFT
|
||||
/*
|
||||
* SanitizerKind::ShiftBase and SanitizerKind::ShiftExponent
|
||||
* emit SanitizerHandler::ShiftOutOfBounds.
|
||||
*/
|
||||
case ubsan_shift_out_of_bounds:
|
||||
return "UBSAN: shift out of bounds";
|
||||
#endif
|
||||
#ifdef CONFIG_UBSAN_DIV_ZERO
|
||||
/*
|
||||
* SanitizerKind::IntegerDivideByZero emits
|
||||
* SanitizerHandler::DivremOverflow.
|
||||
*/
|
||||
case ubsan_divrem_overflow:
|
||||
return "UBSAN: divide/remainder overflow";
|
||||
#endif
|
||||
#ifdef CONFIG_UBSAN_UNREACHABLE
|
||||
/*
|
||||
* SanitizerKind::Unreachable emits
|
||||
* SanitizerHandler::BuiltinUnreachable.
|
||||
*/
|
||||
case ubsan_builtin_unreachable:
|
||||
return "UBSAN: unreachable code";
|
||||
#endif
|
||||
#if defined(CONFIG_UBSAN_BOOL) || defined(CONFIG_UBSAN_ENUM)
|
||||
/*
|
||||
* SanitizerKind::Bool and SanitizerKind::Enum emit
|
||||
* SanitizerHandler::LoadInvalidValue.
|
||||
*/
|
||||
case ubsan_load_invalid_value:
|
||||
return "UBSAN: loading invalid value";
|
||||
#endif
|
||||
#ifdef CONFIG_UBSAN_ALIGNMENT
|
||||
/*
|
||||
* SanitizerKind::Alignment emits SanitizerHandler::TypeMismatch
|
||||
* or SanitizerHandler::AlignmentAssumption.
|
||||
*/
|
||||
case ubsan_alignment_assumption:
|
||||
return "UBSAN: alignment assumption";
|
||||
case ubsan_type_mismatch:
|
||||
return "UBSAN: type mismatch";
|
||||
#endif
|
||||
default:
|
||||
return "UBSAN: unrecognized failure code";
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
static const char * const type_check_kinds[] = {
|
||||
"load of",
|
||||
"store to",
|
||||
@ -387,3 +453,5 @@ void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr,
|
||||
ubsan_epilogue();
|
||||
}
|
||||
EXPORT_SYMBOL(__ubsan_handle_alignment_assumption);
|
||||
|
||||
#endif /* !CONFIG_UBSAN_TRAP */
|
||||
|
32
lib/ubsan.h
32
lib/ubsan.h
@ -2,6 +2,38 @@
|
||||
#ifndef _LIB_UBSAN_H
|
||||
#define _LIB_UBSAN_H
|
||||
|
||||
/*
|
||||
* ABI defined by Clang's UBSAN enum SanitizerHandler:
|
||||
* https://github.com/llvm/llvm-project/blob/release/16.x/clang/lib/CodeGen/CodeGenFunction.h#L113
|
||||
*/
|
||||
enum ubsan_checks {
|
||||
ubsan_add_overflow,
|
||||
ubsan_builtin_unreachable,
|
||||
ubsan_cfi_check_fail,
|
||||
ubsan_divrem_overflow,
|
||||
ubsan_dynamic_type_cache_miss,
|
||||
ubsan_float_cast_overflow,
|
||||
ubsan_function_type_mismatch,
|
||||
ubsan_implicit_conversion,
|
||||
ubsan_invalid_builtin,
|
||||
ubsan_invalid_objc_cast,
|
||||
ubsan_load_invalid_value,
|
||||
ubsan_missing_return,
|
||||
ubsan_mul_overflow,
|
||||
ubsan_negate_overflow,
|
||||
ubsan_nullability_arg,
|
||||
ubsan_nullability_return,
|
||||
ubsan_nonnull_arg,
|
||||
ubsan_nonnull_return,
|
||||
ubsan_out_of_bounds,
|
||||
ubsan_pointer_overflow,
|
||||
ubsan_shift_out_of_bounds,
|
||||
ubsan_sub_overflow,
|
||||
ubsan_type_mismatch,
|
||||
ubsan_alignment_assumption,
|
||||
ubsan_vla_bound_not_positive,
|
||||
};
|
||||
|
||||
enum {
|
||||
type_kind_int = 0,
|
||||
type_kind_float = 1,
|
||||
|
@ -795,7 +795,7 @@ struct rxrpc_txbuf {
|
||||
u8 data[RXRPC_JUMBO_DATALEN]; /* Data packet */
|
||||
struct {
|
||||
struct rxrpc_ackpacket ack;
|
||||
u8 acks[0];
|
||||
DECLARE_FLEX_ARRAY(u8, acks);
|
||||
};
|
||||
};
|
||||
} __aligned(64);
|
||||
|
@ -29,7 +29,7 @@ GCC_PLUGINS_DIR = $(shell $(CC) -print-file-name=plugin)
|
||||
plugin_cxxflags = -Wp,-MMD,$(depfile) $(KBUILD_HOSTCXXFLAGS) -fPIC \
|
||||
-include $(srctree)/include/linux/compiler-version.h \
|
||||
-DPLUGIN_VERSION=$(call stringify,$(KERNELVERSION)) \
|
||||
-I $(GCC_PLUGINS_DIR)/include -I $(obj) -std=gnu++11 \
|
||||
-I $(GCC_PLUGINS_DIR)/include -I $(obj) \
|
||||
-fno-rtti -fno-exceptions -fasynchronous-unwind-tables \
|
||||
-ggdb -Wno-narrowing -Wno-unused-variable \
|
||||
-Wno-format-diag
|
||||
|
@ -281,6 +281,9 @@ endmenu
|
||||
|
||||
config CC_HAS_RANDSTRUCT
|
||||
def_bool $(cc-option,-frandomize-layout-seed-file=/dev/null)
|
||||
# Randstruct was first added in Clang 15, but it isn't safe to use until
|
||||
# Clang 16 due to https://github.com/llvm/llvm-project/issues/60349
|
||||
depends on !CC_IS_CLANG || CLANG_VERSION >= 160000
|
||||
|
||||
choice
|
||||
prompt "Randomize layout of sensitive kernel structures"
|
||||
|
@ -52,7 +52,6 @@ static bool deny_reading_verity_digests;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
|
||||
static struct ctl_path loadpin_sysctl_path[] = {
|
||||
{ .procname = "kernel", },
|
||||
{ .procname = "loadpin", },
|
||||
@ -66,59 +65,70 @@ static struct ctl_table loadpin_sysctl_table[] = {
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
.extra1 = SYSCTL_ZERO,
|
||||
.extra1 = SYSCTL_ONE,
|
||||
.extra2 = SYSCTL_ONE,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* This must be called after early kernel init, since then the rootdev
|
||||
* is available.
|
||||
*/
|
||||
static void check_pinning_enforcement(struct super_block *mnt_sb)
|
||||
static void set_sysctl(bool is_writable)
|
||||
{
|
||||
bool ro = false;
|
||||
|
||||
/*
|
||||
* If load pinning is not enforced via a read-only block
|
||||
* device, allow sysctl to change modes for testing.
|
||||
*/
|
||||
if (is_writable)
|
||||
loadpin_sysctl_table[0].extra1 = SYSCTL_ZERO;
|
||||
else
|
||||
loadpin_sysctl_table[0].extra1 = SYSCTL_ONE;
|
||||
}
|
||||
#else
|
||||
static inline void set_sysctl(bool is_writable) { }
|
||||
#endif
|
||||
|
||||
static void report_writable(struct super_block *mnt_sb, bool writable)
|
||||
{
|
||||
if (mnt_sb->s_bdev) {
|
||||
ro = bdev_read_only(mnt_sb->s_bdev);
|
||||
pr_info("%pg (%u:%u): %s\n", mnt_sb->s_bdev,
|
||||
MAJOR(mnt_sb->s_bdev->bd_dev),
|
||||
MINOR(mnt_sb->s_bdev->bd_dev),
|
||||
ro ? "read-only" : "writable");
|
||||
writable ? "writable" : "read-only");
|
||||
} else
|
||||
pr_info("mnt_sb lacks block device, treating as: writable\n");
|
||||
|
||||
if (!ro) {
|
||||
if (!register_sysctl_paths(loadpin_sysctl_path,
|
||||
loadpin_sysctl_table))
|
||||
pr_notice("sysctl registration failed!\n");
|
||||
else
|
||||
pr_info("enforcement can be disabled.\n");
|
||||
} else
|
||||
if (!writable)
|
||||
pr_info("load pinning engaged.\n");
|
||||
}
|
||||
#else
|
||||
static void check_pinning_enforcement(struct super_block *mnt_sb)
|
||||
|
||||
/*
|
||||
* This must be called after early kernel init, since then the rootdev
|
||||
* is available.
|
||||
*/
|
||||
static bool sb_is_writable(struct super_block *mnt_sb)
|
||||
{
|
||||
pr_info("load pinning engaged.\n");
|
||||
bool writable = true;
|
||||
|
||||
if (mnt_sb->s_bdev)
|
||||
writable = !bdev_read_only(mnt_sb->s_bdev);
|
||||
|
||||
return writable;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void loadpin_sb_free_security(struct super_block *mnt_sb)
|
||||
{
|
||||
/*
|
||||
* When unmounting the filesystem we were using for load
|
||||
* pinning, we acknowledge the superblock release, but make sure
|
||||
* no other modules or firmware can be loaded.
|
||||
* no other modules or firmware can be loaded when we are in
|
||||
* enforcing mode. Otherwise, allow the root to be reestablished.
|
||||
*/
|
||||
if (!IS_ERR_OR_NULL(pinned_root) && mnt_sb == pinned_root) {
|
||||
pinned_root = ERR_PTR(-EIO);
|
||||
pr_info("umount pinned fs: refusing further loads\n");
|
||||
if (enforce) {
|
||||
pinned_root = ERR_PTR(-EIO);
|
||||
pr_info("umount pinned fs: refusing further loads\n");
|
||||
} else {
|
||||
pinned_root = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,6 +136,8 @@ static int loadpin_check(struct file *file, enum kernel_read_file_id id)
|
||||
{
|
||||
struct super_block *load_root;
|
||||
const char *origin = kernel_read_file_id_str(id);
|
||||
bool first_root_pin = false;
|
||||
bool load_root_writable;
|
||||
|
||||
/* If the file id is excluded, ignore the pinning. */
|
||||
if ((unsigned int)id < ARRAY_SIZE(ignore_read_file_id) &&
|
||||
@ -146,26 +158,25 @@ static int loadpin_check(struct file *file, enum kernel_read_file_id id)
|
||||
}
|
||||
|
||||
load_root = file->f_path.mnt->mnt_sb;
|
||||
load_root_writable = sb_is_writable(load_root);
|
||||
|
||||
/* First loaded module/firmware defines the root for all others. */
|
||||
spin_lock(&pinned_root_spinlock);
|
||||
/*
|
||||
* pinned_root is only NULL at startup. Otherwise, it is either
|
||||
* a valid reference, or an ERR_PTR.
|
||||
* pinned_root is only NULL at startup or when the pinned root has
|
||||
* been unmounted while we are not in enforcing mode. Otherwise, it
|
||||
* is either a valid reference, or an ERR_PTR.
|
||||
*/
|
||||
if (!pinned_root) {
|
||||
pinned_root = load_root;
|
||||
/*
|
||||
* Unlock now since it's only pinned_root we care about.
|
||||
* In the worst case, we will (correctly) report pinning
|
||||
* failures before we have announced that pinning is
|
||||
* enforcing. This would be purely cosmetic.
|
||||
*/
|
||||
spin_unlock(&pinned_root_spinlock);
|
||||
check_pinning_enforcement(pinned_root);
|
||||
first_root_pin = true;
|
||||
}
|
||||
spin_unlock(&pinned_root_spinlock);
|
||||
|
||||
if (first_root_pin) {
|
||||
report_writable(pinned_root, load_root_writable);
|
||||
set_sysctl(load_root_writable);
|
||||
report_load(origin, file, "pinned");
|
||||
} else {
|
||||
spin_unlock(&pinned_root_spinlock);
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(pinned_root) ||
|
||||
@ -250,6 +261,10 @@ static int __init loadpin_init(void)
|
||||
pr_info("ready to pin (currently %senforcing)\n",
|
||||
enforce ? "" : "not ");
|
||||
parse_exclude();
|
||||
#ifdef CONFIG_SYSCTL
|
||||
if (!register_sysctl_paths(loadpin_sysctl_path, loadpin_sysctl_table))
|
||||
pr_notice("sysctl registration failed!\n");
|
||||
#endif
|
||||
security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user