diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-21 22:07:23 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-02-21 22:07:23 +0300 |
commit | 4a7d37e824f57dbace61abf62f53843800bd245c (patch) | |
tree | 8856c83d630a5cd5befb4dae0a5f8fc01f7aaa42 /security | |
parent | 902d9fcd8dccf6a5ccd009f2ae8fec5b3db7f41b (diff) | |
parent | 78f7a3fd6dc66cb788c21d7705977ed13c879351 (diff) | |
download | linux-4a7d37e824f57dbace61abf62f53843800bd245c.tar.xz |
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
Diffstat (limited to 'security')
-rw-r--r-- | security/Kconfig.hardening | 3 | ||||
-rw-r--r-- | security/loadpin/loadpin.c | 89 |
2 files changed, 55 insertions, 37 deletions
diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening index 53baa95cb644..0f295961e773 100644 --- a/security/Kconfig.hardening +++ b/security/Kconfig.hardening @@ -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" diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index 110a5ab2b46b..d73a281adf86 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -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; |