mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-03-16 03:54:10 +00:00
hardening updates for v5.20-rc1
- Fix Sparse warnings with randomizd kstack (GONG, Ruiqi) - Replace uintptr_t with unsigned long in usercopy (Jason A. Donenfeld) - Fix Clang -Wforward warning in LKDTM (Justin Stitt) - Fix comment to correctly refer to STRICT_DEVMEM (Lukas Bulwahn) - Introduce dm-verity binding logic to LoadPin LSM (Matthias Kaehlcke) - Clean up warnings and overflow and KASAN tests (Kees Cook) -----BEGIN PGP SIGNATURE----- iQJKBAABCgA0FiEEpcP2jyKd1g9yPm4TiXL039xtwCYFAmLoEN4WHGtlZXNjb29r QGNocm9taXVtLm9yZwAKCRCJcvTf3G3AJr19D/0fUvHaOui3+ePqKL1CEN2WOYxK Ed/HA0kM7VZnuakS2OoWbHYKurt9wImBkw0EuryNEP4nCBHy5OIyDOmWF7DjWntG 9agKLW5rRgbKe9STbGZpJ92WWosOcJkgkDVES1/NjWt7ujLiefzcZE85hj2Dt1aQ 6nF2LlkdGdtsa07hP5CR5bynQxAAxg1R1pLiJCgZRYn1SEFYtjcnBjUMrPUFJAi2 TNy6ijeG473Oj6V/JiIY88u41KG1fed22SymNj6aQVIjGpH7atn6/ooG076ydAyt QEibSyQP/CwkSbyiqVFOq4v4a+hKEB5j5F+iKZBrCnFWNvt8D3tizBYgm1NymNEZ VBZdg+UhcoVDwiMNzSaAGvt15Qv0INNkQm9PJoeUGSdXz0Yjf4ghOIeaQc3jm6Of tElawmPXxVwRZfNpf5tyPaZFphAPK5EAl35S5mdWinKbAO7Jpz9xqvoyZz9/kygR Kd4qyRPrl0YM8SBKFuYt5rFaYfw9wqF7ox7cMmwR+pbEHt7UDqDvkX2fBbpCyXza 5nJ9PDyvB5SqonIF57RiImXCLKXR6UMJgQvtDGsf+n4hpxL40Nga4pqWY82aQEhj SRdQlkFYhI/izIq1kMJNa8IoOONlJzV6i87D8iOW32bI3/SrykRUTvV3ohpMri7V UFkXzz8pfqfJ4k4zVA== =FRS3 -----END PGP SIGNATURE----- Merge tag 'hardening-v5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux Pull hardening updates from Kees Cook: - Fix Sparse warnings with randomizd kstack (GONG, Ruiqi) - Replace uintptr_t with unsigned long in usercopy (Jason A. Donenfeld) - Fix Clang -Wforward warning in LKDTM (Justin Stitt) - Fix comment to correctly refer to STRICT_DEVMEM (Lukas Bulwahn) - Introduce dm-verity binding logic to LoadPin LSM (Matthias Kaehlcke) - Clean up warnings and overflow and KASAN tests (Kees Cook) * tag 'hardening-v5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: dm: verity-loadpin: Drop use of dm_table_get_num_targets() kasan: test: Silence GCC 12 warnings drivers: lkdtm: fix clang -Wformat warning x86: mm: refer to the intended config STRICT_DEVMEM in a comment dm: verity-loadpin: Use CONFIG_SECURITY_LOADPIN_VERITY for conditional compilation LoadPin: Enable loading from trusted dm-verity devices dm: Add verity helpers for LoadPin stack: Declare {randomize_,}kstack_offset to fix Sparse warnings lib: overflow: Do not define 64-bit tests on 32-bit MAINTAINERS: Add a general "kernel hardening" section usercopy: use unsigned long instead of uintptr_t
This commit is contained in:
commit
6991a564f5
14 changed files with 379 additions and 8 deletions
21
MAINTAINERS
21
MAINTAINERS
|
@ -4998,7 +4998,7 @@ R: Nick Desaulniers <ndesaulniers@google.com>
|
|||
L: llvm@lists.linux.dev
|
||||
S: Supported
|
||||
B: https://github.com/ClangBuiltLinux/linux/issues
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/clang/features
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
|
||||
F: include/linux/cfi.h
|
||||
F: kernel/cfi.c
|
||||
|
||||
|
@ -7909,6 +7909,7 @@ FORTIFY_SOURCE
|
|||
M: Kees Cook <keescook@chromium.org>
|
||||
L: linux-hardening@vger.kernel.org
|
||||
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/test_fortify/*
|
||||
F: scripts/test_fortify.sh
|
||||
|
@ -8351,6 +8352,7 @@ GCC PLUGINS
|
|||
M: Kees Cook <keescook@chromium.org>
|
||||
L: linux-hardening@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
|
||||
F: Documentation/kbuild/gcc-plugins.rst
|
||||
F: scripts/Makefile.gcc-plugins
|
||||
F: scripts/gcc-plugins/
|
||||
|
@ -10878,6 +10880,17 @@ F: scripts/mk*
|
|||
F: scripts/mod/
|
||||
F: scripts/package/
|
||||
|
||||
KERNEL HARDENING (not covered by other areas)
|
||||
M: Kees Cook <keescook@chromium.org>
|
||||
L: linux-hardening@vger.kernel.org
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
|
||||
F: include/linux/overflow.h
|
||||
F: include/linux/randomize_kstack.h
|
||||
F: mm/usercopy.c
|
||||
K: \b(add|choose)_random_kstack_offset\b
|
||||
K: \b__check_(object_size|heap_object)\b
|
||||
|
||||
KERNEL JANITORS
|
||||
L: kernel-janitors@vger.kernel.org
|
||||
S: Odd Fixes
|
||||
|
@ -11688,7 +11701,7 @@ F: drivers/media/usb/dvb-usb-v2/lmedm04*
|
|||
LOADPIN SECURITY MODULE
|
||||
M: Kees Cook <keescook@chromium.org>
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git lsm/loadpin
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
|
||||
F: Documentation/admin-guide/LSM/LoadPin.rst
|
||||
F: security/loadpin/
|
||||
|
||||
|
@ -18026,7 +18039,7 @@ M: Kees Cook <keescook@chromium.org>
|
|||
R: Andy Lutomirski <luto@amacapital.net>
|
||||
R: Will Drewry <wad@chromium.org>
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/seccomp
|
||||
F: Documentation/userspace-api/seccomp_filter.rst
|
||||
F: include/linux/seccomp.h
|
||||
F: include/uapi/linux/seccomp.h
|
||||
|
@ -22174,7 +22187,7 @@ F: include/linux/yam.h
|
|||
YAMA SECURITY MODULE
|
||||
M: Kees Cook <keescook@chromium.org>
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
|
||||
F: Documentation/admin-guide/LSM/Yama.rst
|
||||
F: security/yama/
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ obj-$(CONFIG_DM_LOG_WRITES) += dm-log-writes.o
|
|||
obj-$(CONFIG_DM_INTEGRITY) += dm-integrity.o
|
||||
obj-$(CONFIG_DM_ZONED) += dm-zoned.o
|
||||
obj-$(CONFIG_DM_WRITECACHE) += dm-writecache.o
|
||||
obj-$(CONFIG_SECURITY_LOADPIN_VERITY) += dm-verity-loadpin.o
|
||||
|
||||
ifeq ($(CONFIG_DM_INIT),y)
|
||||
dm-mod-objs += dm-init.o
|
||||
|
|
75
drivers/md/dm-verity-loadpin.c
Normal file
75
drivers/md/dm-verity-loadpin.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/dm-verity-loadpin.h>
|
||||
|
||||
#include "dm.h"
|
||||
#include "dm-core.h"
|
||||
#include "dm-verity.h"
|
||||
|
||||
#define DM_MSG_PREFIX "verity-loadpin"
|
||||
|
||||
LIST_HEAD(dm_verity_loadpin_trusted_root_digests);
|
||||
|
||||
static bool is_trusted_verity_target(struct dm_target *ti)
|
||||
{
|
||||
u8 *root_digest;
|
||||
unsigned int digest_size;
|
||||
struct dm_verity_loadpin_trusted_root_digest *trd;
|
||||
bool trusted = false;
|
||||
|
||||
if (!dm_is_verity_target(ti))
|
||||
return false;
|
||||
|
||||
if (dm_verity_get_root_digest(ti, &root_digest, &digest_size))
|
||||
return false;
|
||||
|
||||
list_for_each_entry(trd, &dm_verity_loadpin_trusted_root_digests, node) {
|
||||
if ((trd->len == digest_size) &&
|
||||
!memcmp(trd->data, root_digest, digest_size)) {
|
||||
trusted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(root_digest);
|
||||
|
||||
return trusted;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines whether the file system of a superblock is located on
|
||||
* a verity device that is trusted by LoadPin.
|
||||
*/
|
||||
bool dm_verity_loadpin_is_bdev_trusted(struct block_device *bdev)
|
||||
{
|
||||
struct mapped_device *md;
|
||||
struct dm_table *table;
|
||||
struct dm_target *ti;
|
||||
int srcu_idx;
|
||||
bool trusted = false;
|
||||
|
||||
if (list_empty(&dm_verity_loadpin_trusted_root_digests))
|
||||
return false;
|
||||
|
||||
md = dm_get_md(bdev->bd_dev);
|
||||
if (!md)
|
||||
return false;
|
||||
|
||||
table = dm_get_live_table(md, &srcu_idx);
|
||||
|
||||
if (table->num_targets != 1)
|
||||
goto out;
|
||||
|
||||
ti = dm_table_get_target(table, 0);
|
||||
|
||||
if (is_trusted_verity_target(ti))
|
||||
trusted = true;
|
||||
|
||||
out:
|
||||
dm_put_live_table(md, srcu_idx);
|
||||
dm_put(md);
|
||||
|
||||
return trusted;
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#define DM_MSG_PREFIX "verity"
|
||||
|
||||
|
@ -1309,10 +1310,40 @@ bad:
|
|||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether a DM target is a verity target.
|
||||
*/
|
||||
bool dm_is_verity_target(struct dm_target *ti)
|
||||
{
|
||||
return ti->type->module == THIS_MODULE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the root digest of a verity target.
|
||||
*
|
||||
* Returns a copy of the root digest, the caller is responsible for
|
||||
* freeing the memory of the digest.
|
||||
*/
|
||||
int dm_verity_get_root_digest(struct dm_target *ti, u8 **root_digest, unsigned int *digest_size)
|
||||
{
|
||||
struct dm_verity *v = ti->private;
|
||||
|
||||
if (!dm_is_verity_target(ti))
|
||||
return -EINVAL;
|
||||
|
||||
*root_digest = kmemdup(v->root_digest, v->digest_size, GFP_KERNEL);
|
||||
if (*root_digest == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
*digest_size = v->digest_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct target_type verity_target = {
|
||||
.name = "verity",
|
||||
.features = DM_TARGET_IMMUTABLE,
|
||||
.version = {1, 8, 0},
|
||||
.version = {1, 8, 1},
|
||||
.module = THIS_MODULE,
|
||||
.ctr = verity_ctr,
|
||||
.dtr = verity_dtr,
|
||||
|
|
|
@ -129,4 +129,8 @@ extern int verity_hash(struct dm_verity *v, struct ahash_request *req,
|
|||
extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
|
||||
sector_t block, u8 *digest, bool *is_zero);
|
||||
|
||||
extern bool dm_is_verity_target(struct dm_target *ti);
|
||||
extern int dm_verity_get_root_digest(struct dm_target *ti, u8 **root_digest,
|
||||
unsigned int *digest_size);
|
||||
|
||||
#endif /* DM_VERITY_H */
|
||||
|
|
|
@ -29,7 +29,7 @@ struct lkdtm_list {
|
|||
#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0)
|
||||
#define REC_STACK_SIZE (_AC(CONFIG_FRAME_WARN, UL) / 2)
|
||||
#else
|
||||
#define REC_STACK_SIZE (THREAD_SIZE / 8)
|
||||
#define REC_STACK_SIZE (THREAD_SIZE / 8UL)
|
||||
#endif
|
||||
#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2)
|
||||
|
||||
|
|
27
include/linux/dm-verity-loadpin.h
Normal file
27
include/linux/dm-verity-loadpin.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef __LINUX_DM_VERITY_LOADPIN_H
|
||||
#define __LINUX_DM_VERITY_LOADPIN_H
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
struct block_device;
|
||||
|
||||
extern struct list_head dm_verity_loadpin_trusted_root_digests;
|
||||
|
||||
struct dm_verity_loadpin_trusted_root_digest {
|
||||
struct list_head node;
|
||||
unsigned int len;
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_SECURITY_LOADPIN_VERITY)
|
||||
bool dm_verity_loadpin_is_bdev_trusted(struct block_device *bdev);
|
||||
#else
|
||||
static inline bool dm_verity_loadpin_is_bdev_trusted(struct block_device *bdev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_DM_VERITY_LOADPIN_H */
|
22
include/uapi/linux/loadpin.h
Normal file
22
include/uapi/linux/loadpin.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2022, Google LLC
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_LINUX_LOOP_LOADPIN_H
|
||||
#define _UAPI_LINUX_LOOP_LOADPIN_H
|
||||
|
||||
#define LOADPIN_IOC_MAGIC 'L'
|
||||
|
||||
/**
|
||||
* LOADPIN_IOC_SET_TRUSTED_VERITY_DIGESTS - Set up the root digests of verity devices
|
||||
* that loadpin should trust.
|
||||
*
|
||||
* Takes a file descriptor from which to read the root digests of trusted verity devices. The file
|
||||
* is expected to contain a list of digests in ASCII format, with one line per digest. The ioctl
|
||||
* must be issued on the securityfs attribute 'loadpin/dm-verity' (which can be typically found
|
||||
* under /sys/kernel/security/loadpin/dm-verity).
|
||||
*/
|
||||
#define LOADPIN_IOC_SET_TRUSTED_VERITY_DIGESTS _IOW(LOADPIN_IOC_MAGIC, 0x00, unsigned int)
|
||||
|
||||
#endif /* _UAPI_LINUX_LOOP_LOADPIN_H */
|
|
@ -99,6 +99,7 @@
|
|||
#include <linux/kcsan.h>
|
||||
#include <linux/init_syscalls.h>
|
||||
#include <linux/stackdepot.h>
|
||||
#include <linux/randomize_kstack.h>
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
|
|
@ -91,6 +91,7 @@ DEFINE_TEST_ARRAY(u32) = {
|
|||
{-4U, 5U, 1U, -9U, -20U, true, false, true},
|
||||
};
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
DEFINE_TEST_ARRAY(u64) = {
|
||||
{0, 0, 0, 0, 0, false, false, false},
|
||||
{1, 1, 2, 0, 1, false, false, false},
|
||||
|
@ -114,6 +115,7 @@ DEFINE_TEST_ARRAY(u64) = {
|
|||
false, true, false},
|
||||
{-15ULL, 10ULL, -5ULL, -25ULL, -150ULL, false, false, true},
|
||||
};
|
||||
#endif
|
||||
|
||||
DEFINE_TEST_ARRAY(s8) = {
|
||||
{0, 0, 0, 0, 0, false, false, false},
|
||||
|
@ -188,6 +190,8 @@ DEFINE_TEST_ARRAY(s32) = {
|
|||
{S32_MIN, S32_MIN, 0, 0, 0, true, false, true},
|
||||
{S32_MAX, S32_MAX, -2, 0, 1, true, false, true},
|
||||
};
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
DEFINE_TEST_ARRAY(s64) = {
|
||||
{0, 0, 0, 0, 0, false, false, false},
|
||||
|
||||
|
@ -216,6 +220,7 @@ DEFINE_TEST_ARRAY(s64) = {
|
|||
{-128, -1, -129, -127, 128, false, false, false},
|
||||
{0, -S64_MAX, -S64_MAX, S64_MAX, 0, false, false, false},
|
||||
};
|
||||
#endif
|
||||
|
||||
#define check_one_op(t, fmt, op, sym, a, b, r, of) do { \
|
||||
t _r; \
|
||||
|
@ -650,6 +655,7 @@ static struct kunit_case overflow_test_cases[] = {
|
|||
KUNIT_CASE(s16_overflow_test),
|
||||
KUNIT_CASE(u32_overflow_test),
|
||||
KUNIT_CASE(s32_overflow_test),
|
||||
/* Clang 13 and earlier generate unwanted libcalls on 32-bit. */
|
||||
#if BITS_PER_LONG == 64
|
||||
KUNIT_CASE(u64_overflow_test),
|
||||
KUNIT_CASE(s64_overflow_test),
|
||||
|
|
|
@ -131,6 +131,7 @@ static void kmalloc_oob_right(struct kunit *test)
|
|||
ptr = kmalloc(size, GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
|
||||
|
||||
OPTIMIZER_HIDE_VAR(ptr);
|
||||
/*
|
||||
* An unaligned access past the requested kmalloc size.
|
||||
* Only generic KASAN can precisely detect these.
|
||||
|
@ -159,6 +160,7 @@ static void kmalloc_oob_left(struct kunit *test)
|
|||
ptr = kmalloc(size, GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
|
||||
|
||||
OPTIMIZER_HIDE_VAR(ptr);
|
||||
KUNIT_EXPECT_KASAN_FAIL(test, *ptr = *(ptr - 1));
|
||||
kfree(ptr);
|
||||
}
|
||||
|
@ -171,6 +173,7 @@ static void kmalloc_node_oob_right(struct kunit *test)
|
|||
ptr = kmalloc_node(size, GFP_KERNEL, 0);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
|
||||
|
||||
OPTIMIZER_HIDE_VAR(ptr);
|
||||
KUNIT_EXPECT_KASAN_FAIL(test, ptr[0] = ptr[size]);
|
||||
kfree(ptr);
|
||||
}
|
||||
|
@ -191,6 +194,7 @@ static void kmalloc_pagealloc_oob_right(struct kunit *test)
|
|||
ptr = kmalloc(size, GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
|
||||
|
||||
OPTIMIZER_HIDE_VAR(ptr);
|
||||
KUNIT_EXPECT_KASAN_FAIL(test, ptr[size + OOB_TAG_OFF] = 0);
|
||||
|
||||
kfree(ptr);
|
||||
|
@ -271,6 +275,7 @@ static void kmalloc_large_oob_right(struct kunit *test)
|
|||
ptr = kmalloc(size, GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
|
||||
|
||||
OPTIMIZER_HIDE_VAR(ptr);
|
||||
KUNIT_EXPECT_KASAN_FAIL(test, ptr[size] = 0);
|
||||
kfree(ptr);
|
||||
}
|
||||
|
@ -410,6 +415,8 @@ static void kmalloc_oob_16(struct kunit *test)
|
|||
ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr2);
|
||||
|
||||
OPTIMIZER_HIDE_VAR(ptr1);
|
||||
OPTIMIZER_HIDE_VAR(ptr2);
|
||||
KUNIT_EXPECT_KASAN_FAIL(test, *ptr1 = *ptr2);
|
||||
kfree(ptr1);
|
||||
kfree(ptr2);
|
||||
|
@ -756,6 +763,8 @@ static void ksize_unpoisons_memory(struct kunit *test)
|
|||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
|
||||
real_size = ksize(ptr);
|
||||
|
||||
OPTIMIZER_HIDE_VAR(ptr);
|
||||
|
||||
/* This access shouldn't trigger a KASAN report. */
|
||||
ptr[size] = 'x';
|
||||
|
||||
|
@ -778,6 +787,7 @@ static void ksize_uaf(struct kunit *test)
|
|||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
|
||||
kfree(ptr);
|
||||
|
||||
OPTIMIZER_HIDE_VAR(ptr);
|
||||
KUNIT_EXPECT_KASAN_FAIL(test, ksize(ptr));
|
||||
KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[0]);
|
||||
KUNIT_EXPECT_KASAN_FAIL(test, ((volatile char *)ptr)[size]);
|
||||
|
|
|
@ -161,7 +161,7 @@ static inline void check_bogus_address(const unsigned long ptr, unsigned long n,
|
|||
static inline void check_heap_object(const void *ptr, unsigned long n,
|
||||
bool to_user)
|
||||
{
|
||||
uintptr_t addr = (uintptr_t)ptr;
|
||||
unsigned long addr = (unsigned long)ptr;
|
||||
unsigned long offset;
|
||||
struct folio *folio;
|
||||
|
||||
|
|
|
@ -18,3 +18,19 @@ config SECURITY_LOADPIN_ENFORCE
|
|||
If selected, LoadPin will enforce pinning at boot. If not
|
||||
selected, it can be enabled at boot with the kernel parameter
|
||||
"loadpin.enforce=1".
|
||||
|
||||
config SECURITY_LOADPIN_VERITY
|
||||
bool "Allow reading files from certain other filesystems that use dm-verity"
|
||||
depends on SECURITY_LOADPIN && DM_VERITY=y && SECURITYFS
|
||||
help
|
||||
If selected LoadPin can allow reading files from filesystems
|
||||
that use dm-verity. LoadPin maintains a list of verity root
|
||||
digests it considers trusted. A verity backed filesystem is
|
||||
considered trusted if its root digest is found in the list
|
||||
of trusted digests.
|
||||
|
||||
The list of trusted verity can be populated through an ioctl
|
||||
on the LoadPin securityfs entry 'dm-verity'. The ioctl
|
||||
expects a file descriptor of a file with verity digests as
|
||||
parameter. The file must be located on the pinned root and
|
||||
contain a comma separated list of digests.
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include <linux/path.h>
|
||||
#include <linux/sched.h> /* current */
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/dm-verity-loadpin.h>
|
||||
#include <uapi/linux/loadpin.h>
|
||||
|
||||
static void report_load(const char *origin, struct file *file, char *operation)
|
||||
{
|
||||
|
@ -43,6 +45,9 @@ static char *exclude_read_files[READING_MAX_ID];
|
|||
static int ignore_read_file_id[READING_MAX_ID] __ro_after_init;
|
||||
static struct super_block *pinned_root;
|
||||
static DEFINE_SPINLOCK(pinned_root_spinlock);
|
||||
#ifdef CONFIG_SECURITY_LOADPIN_VERITY
|
||||
static bool deny_reading_verity_digests;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
|
||||
|
@ -171,7 +176,8 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id,
|
|||
spin_unlock(&pinned_root_spinlock);
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(pinned_root) || load_root != pinned_root) {
|
||||
if (IS_ERR_OR_NULL(pinned_root) ||
|
||||
((load_root != pinned_root) && !dm_verity_loadpin_is_bdev_trusted(load_root->s_bdev))) {
|
||||
if (unlikely(!enforce)) {
|
||||
report_load(origin, file, "pinning-ignored");
|
||||
return 0;
|
||||
|
@ -237,6 +243,7 @@ static int __init loadpin_init(void)
|
|||
enforce ? "" : "not ");
|
||||
parse_exclude();
|
||||
security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -245,6 +252,164 @@ DEFINE_LSM(loadpin) = {
|
|||
.init = loadpin_init,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SECURITY_LOADPIN_VERITY
|
||||
|
||||
enum loadpin_securityfs_interface_index {
|
||||
LOADPIN_DM_VERITY,
|
||||
};
|
||||
|
||||
static int read_trusted_verity_root_digests(unsigned int fd)
|
||||
{
|
||||
struct fd f;
|
||||
void *data;
|
||||
int rc;
|
||||
char *p, *d;
|
||||
|
||||
if (deny_reading_verity_digests)
|
||||
return -EPERM;
|
||||
|
||||
/* The list of trusted root digests can only be set up once */
|
||||
if (!list_empty(&dm_verity_loadpin_trusted_root_digests))
|
||||
return -EPERM;
|
||||
|
||||
f = fdget(fd);
|
||||
if (!f.file)
|
||||
return -EINVAL;
|
||||
|
||||
data = kzalloc(SZ_4K, GFP_KERNEL);
|
||||
if (!data) {
|
||||
rc = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = kernel_read_file(f.file, 0, (void **)&data, SZ_4K - 1, NULL, READING_POLICY);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
|
||||
p = data;
|
||||
p[rc] = '\0';
|
||||
p = strim(p);
|
||||
|
||||
p = strim(data);
|
||||
while ((d = strsep(&p, "\n")) != NULL) {
|
||||
int len = strlen(d);
|
||||
struct dm_verity_loadpin_trusted_root_digest *trd;
|
||||
|
||||
if (len % 2) {
|
||||
rc = -EPROTO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
len /= 2;
|
||||
|
||||
trd = kzalloc(struct_size(trd, data, len), GFP_KERNEL);
|
||||
if (!trd) {
|
||||
rc = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (hex2bin(trd->data, d, len)) {
|
||||
kfree(trd);
|
||||
rc = -EPROTO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
trd->len = len;
|
||||
|
||||
list_add_tail(&trd->node, &dm_verity_loadpin_trusted_root_digests);
|
||||
}
|
||||
|
||||
if (list_empty(&dm_verity_loadpin_trusted_root_digests)) {
|
||||
rc = -EPROTO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
kfree(data);
|
||||
fdput(f);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(data);
|
||||
|
||||
/* any failure in loading/parsing invalidates the entire list */
|
||||
{
|
||||
struct dm_verity_loadpin_trusted_root_digest *trd, *tmp;
|
||||
|
||||
list_for_each_entry_safe(trd, tmp, &dm_verity_loadpin_trusted_root_digests, node) {
|
||||
list_del(&trd->node);
|
||||
kfree(trd);
|
||||
}
|
||||
}
|
||||
|
||||
/* disallow further attempts after reading a corrupt/invalid file */
|
||||
deny_reading_verity_digests = true;
|
||||
|
||||
fdput(f);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/******************************** securityfs ********************************/
|
||||
|
||||
static long dm_verity_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
void __user *uarg = (void __user *)arg;
|
||||
unsigned int fd;
|
||||
int rc;
|
||||
|
||||
switch (cmd) {
|
||||
case LOADPIN_IOC_SET_TRUSTED_VERITY_DIGESTS:
|
||||
rc = copy_from_user(&fd, uarg, sizeof(fd));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return read_trusted_verity_root_digests(fd);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct file_operations loadpin_dm_verity_ops = {
|
||||
.unlocked_ioctl = dm_verity_ioctl,
|
||||
.compat_ioctl = compat_ptr_ioctl,
|
||||
};
|
||||
|
||||
/**
|
||||
* init_loadpin_securityfs - create the securityfs directory for LoadPin
|
||||
*
|
||||
* We can not put this method normally under the loadpin_init() code path since
|
||||
* the security subsystem gets initialized before the vfs caches.
|
||||
*
|
||||
* Returns 0 if the securityfs directory creation was successful.
|
||||
*/
|
||||
static int __init init_loadpin_securityfs(void)
|
||||
{
|
||||
struct dentry *loadpin_dir, *dentry;
|
||||
|
||||
loadpin_dir = securityfs_create_dir("loadpin", NULL);
|
||||
if (IS_ERR(loadpin_dir)) {
|
||||
pr_err("LoadPin: could not create securityfs dir: %ld\n",
|
||||
PTR_ERR(loadpin_dir));
|
||||
return PTR_ERR(loadpin_dir);
|
||||
}
|
||||
|
||||
dentry = securityfs_create_file("dm-verity", 0600, loadpin_dir,
|
||||
(void *)LOADPIN_DM_VERITY, &loadpin_dm_verity_ops);
|
||||
if (IS_ERR(dentry)) {
|
||||
pr_err("LoadPin: could not create securityfs entry 'dm-verity': %ld\n",
|
||||
PTR_ERR(dentry));
|
||||
return PTR_ERR(dentry);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fs_initcall(init_loadpin_securityfs);
|
||||
|
||||
#endif /* CONFIG_SECURITY_LOADPIN_VERITY */
|
||||
|
||||
/* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
|
||||
module_param(enforce, int, 0);
|
||||
MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
|
||||
|
|
Loading…
Add table
Reference in a new issue