lkml.org 
[lkml]   [2021]   [Oct]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC PATCH v7 10/16] fs|dm-verity: add block_dev LSM blob and submit dm-verity data
    Date
    From: Deven Bowers <deven.desai@linux.microsoft.com>

    dm-verity operates on the block_device level. In order to allow IPE to
    determine if a file is sourced from a dm-verity volume, and how that
    dm-verity volume was created, create an LSM blob with the signature
    data and roothash information, allowing IPE to make decisions about
    controls to a resource based on dm-verity information.

    Co-developed-by: Fan Wu <wufan@linux.microsoft.com>
    Signed-off-by: Fan Wu <wufan@linux.microsoft.com>
    Signed-off-by: Deven Bowers <deven.desai@linux.microsoft.com>
    ---

    Relevant changes since v5:
    * Change if statement condition in security_bdev_setsecurity to be
    more concise, as suggested by Casey Schaufler and Al Viro

    Relevant changes since v6:
    * Squash patch 05/12, 07/12, 09/12 to [10/16]

    ---
    block/bdev.c | 7 ++++
    drivers/md/dm-verity-target.c | 20 ++++++++-
    drivers/md/dm-verity-verify-sig.c | 16 +++++--
    drivers/md/dm-verity-verify-sig.h | 10 +++--
    include/linux/blk_types.h | 1 +
    include/linux/device-mapper.h | 3 ++
    include/linux/lsm_hook_defs.h | 5 +++
    include/linux/lsm_hooks.h | 12 ++++++
    include/linux/security.h | 22 ++++++++++
    security/security.c | 70 +++++++++++++++++++++++++++++++
    10 files changed, 157 insertions(+), 9 deletions(-)

    diff --git a/block/bdev.c b/block/bdev.c
    index 485a258b0ab3..4c0d6aaa1f08 100644
    --- a/block/bdev.c
    +++ b/block/bdev.c
    @@ -23,6 +23,7 @@
    #include <linux/pseudo_fs.h>
    #include <linux/uio.h>
    #include <linux/namei.h>
    +#include <linux/security.h>
    #include <linux/cleancache.h>
    #include <linux/part_stat.h>
    #include <linux/uaccess.h>
    @@ -393,6 +394,11 @@ static struct inode *bdev_alloc_inode(struct super_block *sb)
    if (!ei)
    return NULL;
    memset(&ei->bdev, 0, sizeof(ei->bdev));
    +
    + if (unlikely(security_bdev_alloc(&ei->bdev))) {
    + kmem_cache_free(bdev_cachep, ei);
    + return NULL;
    + }
    return &ei->vfs_inode;
    }

    @@ -402,6 +408,7 @@ static void bdev_free_inode(struct inode *inode)

    free_percpu(bdev->bd_stats);
    kfree(bdev->bd_meta_info);
    + security_bdev_free(bdev);

    if (!bdev_is_partition(bdev)) {
    if (bdev->bd_disk && bdev->bd_disk->bdi)
    diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
    index 22a5ac82446a..e62480803e56 100644
    --- a/drivers/md/dm-verity-target.c
    +++ b/drivers/md/dm-verity-target.c
    @@ -13,11 +13,14 @@
    * access behavior.
    */

    +#include "dm-core.h"
    #include "dm-verity.h"
    #include "dm-verity-fec.h"
    #include "dm-verity-verify-sig.h"
    +#include "dm-core.h"
    #include <linux/module.h>
    #include <linux/reboot.h>
    +#include <linux/security.h>

    #define DM_MSG_PREFIX "verity"

    @@ -1051,6 +1054,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
    sector_t hash_position;
    char dummy;
    char *root_hash_digest_to_validate;
    + struct block_device *bdev;

    v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
    if (!v) {
    @@ -1084,6 +1088,13 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
    }
    v->version = num;

    + bdev = dm_table_get_md(ti->table)->disk->part0;
    + if (!bdev) {
    + ti->error = "Mapped device lookup failed";
    + r = -ENOMEM;
    + goto bad;
    + }
    +
    r = dm_get_device(ti, argv[1], FMODE_READ, &v->data_dev);
    if (r) {
    ti->error = "Data device lookup failed";
    @@ -1216,7 +1227,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
    }

    /* Root hash signature is a optional parameter*/
    - r = verity_verify_root_hash(root_hash_digest_to_validate,
    + r = verity_verify_root_hash(bdev, root_hash_digest_to_validate,
    strlen(root_hash_digest_to_validate),
    verify_args.sig,
    verify_args.sig_size);
    @@ -1289,12 +1300,17 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
    ti->per_io_data_size = roundup(ti->per_io_data_size,
    __alignof__(struct dm_verity_io));

    + r = security_bdev_setsecurity(bdev,
    + DM_VERITY_ROOTHASH_SEC_NAME,
    + v->root_digest, v->digest_size);
    + if (r)
    + goto bad;
    +
    verity_verify_sig_opts_cleanup(&verify_args);

    return 0;

    bad:
    -
    verity_verify_sig_opts_cleanup(&verify_args);
    verity_dtr(ti);

    diff --git a/drivers/md/dm-verity-verify-sig.c b/drivers/md/dm-verity-verify-sig.c
    index db61a1f43ae9..1672a35f292b 100644
    --- a/drivers/md/dm-verity-verify-sig.c
    +++ b/drivers/md/dm-verity-verify-sig.c
    @@ -8,7 +8,10 @@
    #include <linux/device-mapper.h>
    #include <linux/verification.h>
    #include <keys/user-type.h>
    +#include <linux/security.h>
    +#include <linux/list.h>
    #include <linux/module.h>
    +#include "dm-core.h"
    #include "dm-verity.h"
    #include "dm-verity-verify-sig.h"

    @@ -97,14 +100,17 @@ int verity_verify_sig_parse_opt_args(struct dm_arg_set *as,
    * verify_verify_roothash - Verify the root hash of the verity hash device
    * using builtin trusted keys.
    *
    + * @bdev: block_device representing the device-mapper created block device.
    + * Used by the security hook, to set information about the block_device.
    * @root_hash: For verity, the roothash/data to be verified.
    * @root_hash_len: Size of the roothash/data to be verified.
    * @sig_data: The trusted signature that verifies the roothash/data.
    * @sig_len: Size of the signature.
    *
    */
    -int verity_verify_root_hash(const void *root_hash, size_t root_hash_len,
    - const void *sig_data, size_t sig_len)
    +int verity_verify_root_hash(struct block_device *bdev, const void *root_hash,
    + size_t root_hash_len, const void *sig_data,
    + size_t sig_len)
    {
    int ret;

    @@ -126,8 +132,12 @@ int verity_verify_root_hash(const void *root_hash, size_t root_hash_len,
    NULL,
    #endif
    VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL);
    + if (ret)
    + return ret;

    - return ret;
    + return security_bdev_setsecurity(bdev,
    + DM_VERITY_SIGNATURE_SEC_NAME,
    + sig_data, sig_len);
    }

    void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts)
    diff --git a/drivers/md/dm-verity-verify-sig.h b/drivers/md/dm-verity-verify-sig.h
    index 3987c7141f79..31692fff92e4 100644
    --- a/drivers/md/dm-verity-verify-sig.h
    +++ b/drivers/md/dm-verity-verify-sig.h
    @@ -20,8 +20,9 @@ struct dm_verity_sig_opts {

    #define DM_VERITY_ROOT_HASH_VERIFICATION_OPTS 2

    -int verity_verify_root_hash(const void *data, size_t data_len,
    - const void *sig_data, size_t sig_len);
    +int verity_verify_root_hash(struct block_device *bdev, const void *data,
    + size_t data_len, const void *sig_data,
    + size_t sig_len);
    bool verity_verify_is_sig_opt_arg(const char *arg_name);

    int verity_verify_sig_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
    @@ -34,8 +35,9 @@ void verity_verify_sig_opts_cleanup(struct dm_verity_sig_opts *sig_opts);

    #define DM_VERITY_ROOT_HASH_VERIFICATION_OPTS 0

    -static inline int verity_verify_root_hash(const void *data, size_t data_len,
    - const void *sig_data, size_t sig_len)
    +int verity_verify_root_hash(struct block_device *bdev, const void *data,
    + size_t data_len, const void *sig_data,
    + size_t sig_len)
    {
    return 0;
    }
    diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
    index be622b5a21ed..58def70aa653 100644
    --- a/include/linux/blk_types.h
    +++ b/include/linux/blk_types.h
    @@ -49,6 +49,7 @@ struct block_device {
    #ifdef CONFIG_FAIL_MAKE_REQUEST
    bool bd_make_it_fail;
    #endif
    + void *security;
    } __randomize_layout;

    #define bdev_whole(_bdev) \
    diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
    index 114553b487ef..0f5bdcfcf337 100644
    --- a/include/linux/device-mapper.h
    +++ b/include/linux/device-mapper.h
    @@ -665,4 +665,7 @@ static inline unsigned long to_bytes(sector_t n)
    return (n << SECTOR_SHIFT);
    }

    +#define DM_VERITY_SIGNATURE_SEC_NAME DM_NAME ".verity-sig"
    +#define DM_VERITY_ROOTHASH_SEC_NAME DM_NAME ".verity-rh"
    +
    #endif /* _LINUX_DEVICE_MAPPER_H */
    diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
    index 2adeea44c0d5..b148a01b2cef 100644
    --- a/include/linux/lsm_hook_defs.h
    +++ b/include/linux/lsm_hook_defs.h
    @@ -402,3 +402,8 @@ LSM_HOOK(void, LSM_RET_VOID, perf_event_free, struct perf_event *event)
    LSM_HOOK(int, 0, perf_event_read, struct perf_event *event)
    LSM_HOOK(int, 0, perf_event_write, struct perf_event *event)
    #endif /* CONFIG_PERF_EVENTS */
    +
    +LSM_HOOK(int, 0, bdev_alloc_security, struct block_device *bdev)
    +LSM_HOOK(void, LSM_RET_VOID, bdev_free_security, struct block_device *bdev)
    +LSM_HOOK(int, 0, bdev_setsecurity, struct block_device *bdev, const char *name,
    + const void *value, size_t size)
    diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
    index 5c4c5c0602cb..43d357e6ab47 100644
    --- a/include/linux/lsm_hooks.h
    +++ b/include/linux/lsm_hooks.h
    @@ -1545,6 +1545,17 @@
    *
    * @what: kernel feature being accessed
    *
    + * @bdev_alloc_security:
    + * Initialize the security field inside a block_device structure.
    + *
    + * @bdev_free_security:
    + * Cleanup the security information stored inside a block_device structure.
    + *
    + * @bdev_setsecurity:
    + * Set a security property associated with @name for @bdev with
    + * value @value. @size indicates the size of @value in bytes.
    + * If a @name is not implemented, return -ENOSYS.
    + *
    * Security hooks for perf events
    *
    * @perf_event_open:
    @@ -1592,6 +1603,7 @@ struct lsm_blob_sizes {
    int lbs_ipc;
    int lbs_msg_msg;
    int lbs_task;
    + int lbs_bdev;
    };

    /*
    diff --git a/include/linux/security.h b/include/linux/security.h
    index 5b7288521300..98af3f645cb6 100644
    --- a/include/linux/security.h
    +++ b/include/linux/security.h
    @@ -472,6 +472,11 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
    int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
    int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
    int security_locked_down(enum lockdown_reason what);
    +int security_bdev_alloc(struct block_device *bdev);
    +void security_bdev_free(struct block_device *bdev);
    +int security_bdev_setsecurity(struct block_device *bdev,
    + const char *name, const void *value,
    + size_t size);
    #else /* CONFIG_SECURITY */

    static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data)
    @@ -1348,6 +1353,23 @@ static inline int security_locked_down(enum lockdown_reason what)
    {
    return 0;
    }
    +
    +static inline int security_bdev_alloc(struct block_device *bdev)
    +{
    + return 0;
    +}
    +
    +static inline void security_bdev_free(struct block_device *bdev)
    +{
    +}
    +
    +static inline int security_bdev_setsecurity(struct block_device *bdev,
    + const char *name,
    + const void *value, size_t size)
    +{
    + return 0;
    +}
    +
    #endif /* CONFIG_SECURITY */

    #if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE)
    diff --git a/security/security.c b/security/security.c
    index 9ffa9e9c5c55..d7ac9f01500b 100644
    --- a/security/security.c
    +++ b/security/security.c
    @@ -29,6 +29,7 @@
    #include <linux/string.h>
    #include <linux/msg.h>
    #include <net/flow.h>
    +#include <linux/fs.h>

    #define MAX_LSM_EVM_XATTR 2

    @@ -206,6 +207,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
    lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
    lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
    lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
    + lsm_set_blob_size(&needed->lbs_bdev, &blob_sizes.lbs_bdev);
    }

    /* Prepare LSM for initialization. */
    @@ -342,6 +344,7 @@ static void __init ordered_lsm_init(void)
    init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
    init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
    init_debug("task blob size = %d\n", blob_sizes.lbs_task);
    + init_debug("bdev blob size = %d\n", blob_sizes.lbs_bdev);

    /*
    * Create any kmem_caches needed for blobs
    @@ -659,6 +662,28 @@ static int lsm_msg_msg_alloc(struct msg_msg *mp)
    return 0;
    }

    +/**
    + * lsm_bdev_alloc - allocate a composite block_device blob
    + * @bdev: the block_device that needs a blob
    + *
    + * Allocate the block_device blob for all the modules
    + *
    + * Returns 0, or -ENOMEM if memory can't be allocated.
    + */
    +static int lsm_bdev_alloc(struct block_device *bdev)
    +{
    + if (blob_sizes.lbs_bdev == 0) {
    + bdev->security = NULL;
    + return 0;
    + }
    +
    + bdev->security = kzalloc(blob_sizes.lbs_bdev, GFP_KERNEL);
    + if (!bdev->security)
    + return -ENOMEM;
    +
    + return 0;
    +}
    +
    /**
    * lsm_early_task - during initialization allocate a composite task blob
    * @task: the task that needs a blob
    @@ -2599,6 +2624,51 @@ int security_locked_down(enum lockdown_reason what)
    }
    EXPORT_SYMBOL(security_locked_down);

    +int security_bdev_alloc(struct block_device *bdev)
    +{
    + int rc = 0;
    +
    + rc = lsm_bdev_alloc(bdev);
    + if (unlikely(rc))
    + return rc;
    +
    + rc = call_int_hook(bdev_alloc_security, 0, bdev);
    + if (unlikely(rc))
    + security_bdev_free(bdev);
    +
    + return 0;
    +}
    +EXPORT_SYMBOL(security_bdev_alloc);
    +
    +void security_bdev_free(struct block_device *bdev)
    +{
    + if (!bdev->security)
    + return;
    +
    + call_void_hook(bdev_free_security, bdev);
    +
    + kfree(bdev->security);
    + bdev->security = NULL;
    +}
    +EXPORT_SYMBOL(security_bdev_free);
    +
    +int security_bdev_setsecurity(struct block_device *bdev,
    + const char *name, const void *value,
    + size_t size)
    +{
    + int rc = 0;
    + struct security_hook_list *p;
    +
    + hlist_for_each_entry(p, &security_hook_heads.bdev_setsecurity, list) {
    + rc = p->hook.bdev_setsecurity(bdev, name, value, size);
    + if (rc && rc != -ENOSYS)
    + return rc;
    + }
    +
    + return 0;
    +}
    +EXPORT_SYMBOL(security_bdev_setsecurity);
    +
    #ifdef CONFIG_PERF_EVENTS
    int security_perf_event_open(struct perf_event_attr *attr, int type)
    {
    --
    2.33.0
    \
     
     \ /
      Last update: 2021-10-13 21:08    [W:4.245 / U:0.128 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site