linux/drivers/md/dm-verity-target.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2012 Red Hat, Inc.
 *
 * Author: Mikulas Patocka <[email protected]>
 *
 * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
 *
 * In the file "/sys/module/dm_verity/parameters/prefetch_cluster" you can set
 * default prefetch value. Data are read in "prefetch_cluster" chunks from the
 * hash device. Setting this greatly improves performance when data and hash
 * are on the same disk on different partitions on devices with poor random
 * access behavior.
 */

#include "dm-verity.h"
#include "dm-verity-fec.h"
#include "dm-verity-verify-sig.h"
#include "dm-audit.h"
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/scatterlist.h>
#include <linux/string.h>
#include <linux/jump_label.h>

#define DM_MSG_PREFIX

#define DM_VERITY_ENV_LENGTH
#define DM_VERITY_ENV_VAR_NAME

#define DM_VERITY_DEFAULT_PREFETCH_SIZE

#define DM_VERITY_MAX_CORRUPTED_ERRS

#define DM_VERITY_OPT_LOGGING
#define DM_VERITY_OPT_RESTART
#define DM_VERITY_OPT_PANIC
#define DM_VERITY_OPT_IGN_ZEROES
#define DM_VERITY_OPT_AT_MOST_ONCE
#define DM_VERITY_OPT_TASKLET_VERIFY

#define DM_VERITY_OPTS_MAX

static unsigned int dm_verity_prefetch_cluster =;

module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, 0644);

static DEFINE_STATIC_KEY_FALSE(use_bh_wq_enabled);

/* Is at least one dm-verity instance using ahash_tfm instead of shash_tfm? */
static DEFINE_STATIC_KEY_FALSE(ahash_enabled);

struct dm_verity_prefetch_work {};

/*
 * Auxiliary structure appended to each dm-bufio buffer. If the value
 * hash_verified is nonzero, hash of the block has been verified.
 *
 * The variable hash_verified is set to 0 when allocating the buffer, then
 * it can be changed to 1 and it is never reset to 0 again.
 *
 * There is no lock around this value, a race condition can at worst cause
 * that multiple processes verify the hash of the same buffer simultaneously
 * and write 1 to hash_verified simultaneously.
 * This condition is harmless, so we don't need locking.
 */
struct buffer_aux {};

/*
 * Initialize struct buffer_aux for a freshly created buffer.
 */
static void dm_bufio_alloc_callback(struct dm_buffer *buf)
{}

/*
 * Translate input sector number to the sector number on the target device.
 */
static sector_t verity_map_sector(struct dm_verity *v, sector_t bi_sector)
{}

/*
 * Return hash position of a specified block at a specified tree level
 * (0 is the lowest level).
 * The lowest "hash_per_block_bits"-bits of the result denote hash position
 * inside a hash block. The remaining bits denote location of the hash block.
 */
static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
					 int level)
{}

static int verity_ahash_update(struct dm_verity *v, struct ahash_request *req,
				const u8 *data, size_t len,
				struct crypto_wait *wait)
{}

/*
 * Wrapper for crypto_ahash_init, which handles verity salting.
 */
static int verity_ahash_init(struct dm_verity *v, struct ahash_request *req,
				struct crypto_wait *wait, bool may_sleep)
{}

static int verity_ahash_final(struct dm_verity *v, struct ahash_request *req,
			      u8 *digest, struct crypto_wait *wait)
{}

int verity_hash(struct dm_verity *v, struct dm_verity_io *io,
		const u8 *data, size_t len, u8 *digest, bool may_sleep)
{}

static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
				 sector_t *hash_block, unsigned int *offset)
{}

/*
 * Handle verification errors.
 */
static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
			     unsigned long long block)
{}

/*
 * Verify hash of a metadata block pertaining to the specified data block
 * ("block" argument) at a specified level ("level" argument).
 *
 * On successful return, verity_io_want_digest(v, io) contains the hash value
 * for a lower tree level or for the data block (if we're at the lowest level).
 *
 * If "skip_unverified" is true, unverified buffer is skipped and 1 is returned.
 * If "skip_unverified" is false, unverified buffer is hashed and verified
 * against current value of verity_io_want_digest(v, io).
 */
static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
			       sector_t block, int level, bool skip_unverified,
			       u8 *want_digest)
{}

/*
 * Find a hash for a given block, write it to digest and verify the integrity
 * of the hash tree if necessary.
 */
int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
			  sector_t block, u8 *digest, bool *is_zero)
{}

static noinline int verity_recheck(struct dm_verity *v, struct dm_verity_io *io,
				   sector_t cur_block, u8 *dest)
{}

static int verity_handle_data_hash_mismatch(struct dm_verity *v,
					    struct dm_verity_io *io,
					    struct bio *bio, sector_t blkno,
					    u8 *data)
{}

/*
 * Verify one "dm_verity_io" structure.
 */
static int verity_verify_io(struct dm_verity_io *io)
{}

/*
 * Skip verity work in response to I/O error when system is shutting down.
 */
static inline bool verity_is_system_shutting_down(void)
{}

/*
 * End one "io" structure with a given error.
 */
static void verity_finish_io(struct dm_verity_io *io, blk_status_t status)
{}

static void verity_work(struct work_struct *w)
{}

static void verity_bh_work(struct work_struct *w)
{}

static void verity_end_io(struct bio *bio)
{}

/*
 * Prefetch buffers for the specified io.
 * The root buffer is not prefetched, it is assumed that it will be cached
 * all the time.
 */
static void verity_prefetch_io(struct work_struct *work)
{}

static void verity_submit_prefetch(struct dm_verity *v, struct dm_verity_io *io,
				   unsigned short ioprio)
{}

/*
 * Bio map function. It allocates dm_verity_io structure and bio vector and
 * fills them. Then it issues prefetches and the I/O.
 */
static int verity_map(struct dm_target *ti, struct bio *bio)
{}

/*
 * Status: V (valid) or C (corruption found)
 */
static void verity_status(struct dm_target *ti, status_type_t type,
			  unsigned int status_flags, char *result, unsigned int maxlen)
{}

static int verity_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
{}

static int verity_iterate_devices(struct dm_target *ti,
				  iterate_devices_callout_fn fn, void *data)
{}

static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
{}

static void verity_dtr(struct dm_target *ti)
{}

static int verity_alloc_most_once(struct dm_verity *v)
{}

static int verity_alloc_zero_digest(struct dm_verity *v)
{}

static inline bool verity_is_verity_mode(const char *arg_name)
{}

static int verity_parse_verity_mode(struct dm_verity *v, const char *arg_name)
{}

static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
				 struct dm_verity_sig_opts *verify_args,
				 bool only_modifier_opts)
{}

static int verity_setup_hash_alg(struct dm_verity *v, const char *alg_name)
{}

static int verity_setup_salt_and_hashstate(struct dm_verity *v, const char *arg)
{}

/*
 * Target parameters:
 *	<version>	The current format is version 1.
 *			Vsn 0 is compatible with original Chromium OS releases.
 *	<data device>
 *	<hash device>
 *	<data block size>
 *	<hash block size>
 *	<the number of data blocks>
 *	<hash start block>
 *	<algorithm>
 *	<digest>
 *	<salt>		Hex string or "-" if no salt.
 */
static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{}

/*
 * Get the verity mode (error behavior) of a verity target.
 *
 * Returns the verity mode of the target, or -EINVAL if 'ti' is not a verity
 * target.
 */
int dm_verity_get_mode(struct dm_target *ti)
{}

/*
 * 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)
{}

static struct target_type verity_target =;
module_dm(verity);

/*
 * Check whether a DM target is a verity target.
 */
bool dm_is_verity_target(struct dm_target *ti)
{}

MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();