From patchwork Thu Nov 5 02:02:34 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sami Tolvanen X-Patchwork-Id: 7556651 X-Patchwork-Delegate: snitzer@redhat.com Return-Path: X-Original-To: patchwork-dm-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id D5DD49F2F7 for ; Thu, 5 Nov 2015 02:06:04 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D59912068A for ; Thu, 5 Nov 2015 02:06:03 +0000 (UTC) Received: from mx6-phx2.redhat.com (mx6-phx2.redhat.com [209.132.183.39]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9A3AB20555 for ; Thu, 5 Nov 2015 02:06:02 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by mx6-phx2.redhat.com (8.14.4/8.14.4) with ESMTP id tA523AU4019637; Wed, 4 Nov 2015 21:03:10 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id tA5239mC020867 for ; Wed, 4 Nov 2015 21:03:09 -0500 Received: from mx1.redhat.com (ext-mx04.extmail.prod.ext.phx2.redhat.com [10.5.110.28]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id tA5239sr012882 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Wed, 4 Nov 2015 21:03:09 -0500 Received: from mail-wi0-f176.google.com (mail-wi0-f176.google.com [209.85.212.176]) by mx1.redhat.com (Postfix) with ESMTPS id 2339B2635 for ; Thu, 5 Nov 2015 02:03:08 +0000 (UTC) Received: by wikq8 with SMTP id q8so1478596wik.1 for ; Wed, 04 Nov 2015 18:03:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=7En76EXC4ACzCD18TNXfDgtTHAR35d2WyfmdRX8HjsM=; b=dfDmOfMDHJZ7LlaeGCyV7/xnDq5+ijBGFiqSsks8miRTqrEpfojcxGoxhxhlUA5Ezk yO0K4EBVdT83S9dcCia66LibZQ85HlwFYJWhO+0aYIvRala98So9iWNY7qNdw5cgaVDE p6n1pcV8B90mrD5RyF5eshZBbvsBGaXmyfdsESd+Wr7UXR2vuHJf+dvJNBfmqmQha1NK Z9cIMVnaT8geu4k+ZNQl3ufegCnvVGBsZUBL8Hsjko2X5/ubWIfa8cEAK5OKn4k6pApk Ivss8SLijGqqZ6oyyljhDVzIV7egXCNTPzb7R2NlRCGkIdKDpkGJg5pYxxLtaDArJv5K 57yQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=7En76EXC4ACzCD18TNXfDgtTHAR35d2WyfmdRX8HjsM=; b=i9aHJtkaGf5ftNKroaJEA6efk1AqQA2+G9/hMFj7tZ23pz8sS5/dTjWRQx461IRDys dikShGEIxu4QXDUT6+q9yioGsoXHamrDwC8o/U4UBjU4FyeI+bYAhq3LInnGHdDEnZuQ JEW00yQN5eXgVYFpwjSmGlHY/xlIueFSNbOflcxgDXAG2mbhFJ9M4NUdkCPbncOnGosx R3n1vDluEaqRI6y678OJ/ZWdHYwJB1FN+usB19wc4SUnkk2gm7qk3BBUwPUNxqHP89nz MPQUmc60iNLCd57ShtuM9Lo/9PAoqPvW5cg8+LB4qItmtBvAbv3rBxyR5ZqnDz9P8d9k VEfw== X-Gm-Message-State: ALoCoQktNmALxdrmumhLoG/OzoC9XsRph1MkRweWeG0XHstOr5wDFioSSlTUl8BrSiqjJiLMLdHa X-Received: by 10.194.239.104 with SMTP id vr8mr5097125wjc.64.1446688986799; Wed, 04 Nov 2015 18:03:06 -0800 (PST) Received: from samitolvanen1.lon.corp.google.com ([172.16.12.218]) by smtp.gmail.com with ESMTPSA id bf8sm4337693wjc.22.2015.11.04.18.03.06 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 04 Nov 2015 18:03:06 -0800 (PST) From: Sami Tolvanen To: Mikulas Patocka , Mandeep Baines , Will Drewry Date: Thu, 5 Nov 2015 02:02:34 +0000 Message-Id: <1446688954-29589-5-git-send-email-samitolvanen@google.com> In-Reply-To: <1446688954-29589-1-git-send-email-samitolvanen@google.com> References: <1446688954-29589-1-git-send-email-samitolvanen@google.com> X-RedHat-Spam-Score: -0.431 (BAYES_50, DCC_REPUT_00_12, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_PASS, T_RP_MATCHES_RCVD) 209.85.212.176 mail-wi0-f176.google.com 209.85.212.176 mail-wi0-f176.google.com X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Scanned-By: MIMEDefang 2.75 on 10.5.110.28 X-loop: dm-devel@redhat.com Cc: Kees Cook , Mike Snitzer , linux-kernel@vger.kernel.org, dm-devel@redhat.com, Alasdair Kergon , Sami Tolvanen , Mark Salyzyn Subject: [dm-devel] [PATCH 4/4] dm verity: ignore zero blocks X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk Reply-To: device-mapper development List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,RCVD_IN_DNSWL_MED,T_DKIM_INVALID,T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add ignore_zero_blocks option, which returns zeros for blocks matching a zero hash without validating the content. Signed-off-by: Sami Tolvanen --- Documentation/device-mapper/verity.txt | 5 ++ drivers/md/dm-verity.c | 88 ++++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 10 deletions(-) diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt index 3628d28..1b103b0 100644 --- a/Documentation/device-mapper/verity.txt +++ b/Documentation/device-mapper/verity.txt @@ -79,6 +79,11 @@ restart_on_corruption not compatible with ignore_corruption and requires user space support to avoid restart loops. +ignore_zero_blocks + Do not verify blocks that are expected to contain zeros and always return + zeros instead. This may be useful if the partition contains unused blocks + that are not guaranteed to contain zeros. + use_fec_from_device Use forward error correction (FEC) to recover from corruption if hash verification fails. Use encoding data from the specified device. This diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index 61dec39..485d59e 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -38,6 +38,7 @@ #define DM_VERITY_OPT_LOGGING "ignore_corruption" #define DM_VERITY_OPT_RESTART "restart_on_corruption" +#define DM_VERITY_OPT_IGN_ZEROS "ignore_zero_blocks" #define DM_VERITY_OPT_FEC_DEV "use_fec_from_device" #define DM_VERITY_OPT_FEC_BLOCKS "fec_blocks" @@ -45,7 +46,7 @@ #define DM_VERITY_OPT_FEC_ROOTS "fec_roots" #define DM_VERITY_OPTS_FEC 8 -#define DM_VERITY_OPTS_MAX (1 + DM_VERITY_OPTS_FEC) +#define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC) static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE; @@ -74,6 +75,7 @@ struct dm_verity { struct crypto_shash *tfm; u8 *root_digest; /* digest of the root block */ u8 *salt; /* salt: its size is salt_size */ + u8 *zero_digest; /* digest for a zero block */ unsigned salt_size; sector_t data_start; /* data offset in 512-byte sectors */ sector_t hash_start; /* hash start in blocks */ @@ -422,9 +424,9 @@ release_ret_r: * of the hash tree if necessary. */ static int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io, - sector_t block, u8 *digest) + sector_t block, u8 *digest, bool *is_zero) { - int r, i; + int r = 0, i; if (likely(v->levels)) { /* @@ -436,7 +438,7 @@ static int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io, */ r = verity_verify_level(v, io, block, 0, true, digest); if (likely(r <= 0)) - return r; + goto out; } memcpy(digest, v->root_digest, v->digest_size); @@ -444,10 +446,16 @@ static int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io, for (i = v->levels - 1; i >= 0; i--) { r = verity_verify_level(v, io, block, i, false, digest); if (unlikely(r)) - return r; + goto out; } - return 0; +out: + if (!r && v->zero_digest) + *is_zero = !memcmp(v->zero_digest, digest, v->digest_size); + else + *is_zero = false; + + return r; } /* @@ -496,11 +504,19 @@ static int verity_bv_hash_update(struct dm_verity *v, struct dm_verity_io *io, return verity_hash_update(v, io_hash_desc(v, io), data, len); } +static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io, + u8 *data, size_t len) +{ + memset(data, 0, len); + return 0; +} + /* * Verify one "dm_verity_io" structure. */ static int verity_verify_io(struct dm_verity_io *io) { + bool is_zero; struct dm_verity *v = io->v; struct bvec_iter start; unsigned b; @@ -510,10 +526,23 @@ static int verity_verify_io(struct dm_verity_io *io) struct shash_desc *desc = io_hash_desc(v, io); r = verity_hash_for_block(v, io, io->block + b, - io_want_digest(v, io)); + io_want_digest(v, io), &is_zero); if (unlikely(r < 0)) return r; + if (is_zero) { + /* + * If we expect a zero block, don't validate, just + * return zeros. + */ + r = verity_for_bv_block(v, io, &io->iter, + verity_bv_zero); + if (unlikely(r < 0)) + return r; + + continue; + } + r = verity_hash_init(v, desc); if (unlikely(r < 0)) return r; @@ -674,6 +703,7 @@ static int verity_fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io, static int verity_fec_read_buf(struct dm_verity *v, struct dm_verity_io *io, u64 rsb, u64 target, int *neras) { + bool is_zero; int i, j, target_index = -1; struct dm_buffer *buf; struct dm_bufio_client *bufio; @@ -713,9 +743,13 @@ static int verity_fec_read_buf(struct dm_verity *v, struct dm_verity_io *io, } if (block < v->data_blocks && - verity_hash_for_block(v, io, block, want_digest) == 0) { - if (neras && *neras <= v->fec_roots && - verity_fec_is_erasure(v, io, want_digest, bbuf)) + verity_hash_for_block(v, io, block, want_digest, + &is_zero) == 0) { + if (is_zero) + memset(bbuf, 0, 1 << v->data_dev_block_bits); + else if (neras && *neras <= v->fec_roots && + verity_fec_is_erasure(v, io, want_digest, + bbuf)) io->erasures[(*neras)++] = i; } @@ -1066,6 +1100,8 @@ static void verity_status(struct dm_target *ti, status_type_t type, DMEMIT("%02x", v->salt[x]); if (v->mode != DM_VERITY_MODE_EIO) args++; + if (v->zero_digest) + args++; if (v->fec_dev) args += DM_VERITY_OPTS_FEC; if (!args) @@ -1084,6 +1120,8 @@ static void verity_status(struct dm_target *ti, status_type_t type, BUG(); } } + if (v->zero_digest) + DMEMIT(" " DM_VERITY_OPT_IGN_ZEROS); if (v->fec_dev) DMEMIT(" " DM_VERITY_OPT_FEC_DEV " %s " DM_VERITY_OPT_FEC_BLOCKS " %llu " @@ -1148,6 +1186,7 @@ static void verity_dtr(struct dm_target *ti) kfree(v->salt); kfree(v->root_digest); + kfree(v->zero_digest); if (v->tfm) crypto_free_shash(v->tfm); @@ -1164,6 +1203,29 @@ static void verity_dtr(struct dm_target *ti) kfree(v); } +static int verity_alloc_zero_digest(struct dm_verity *v) +{ + int r; + u8 desc[v->shash_descsize]; + u8 *zero_data; + + v->zero_digest = kmalloc(v->digest_size, GFP_KERNEL); + + if (!v->zero_digest) + return -ENOMEM; + + zero_data = kzalloc(1 << v->data_dev_block_bits, GFP_KERNEL); + + if (!zero_data) + return -ENOMEM; /* verity_dtr will free zero_digest */ + + r = verity_hash(v, (struct shash_desc *)desc, zero_data, + 1 << v->data_dev_block_bits, v->zero_digest); + + kfree(zero_data); + return r; +} + static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v, const char *opt_string) { @@ -1178,6 +1240,12 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v, } else if (!strcasecmp(opt_string, DM_VERITY_OPT_RESTART)) { v->mode = DM_VERITY_MODE_RESTART; return 0; + } else if (!strcasecmp(opt_string, DM_VERITY_OPT_IGN_ZEROS)) { + r = verity_alloc_zero_digest(v); + if (r) + v->ti->error = "Cannot allocate zero digest"; + + return r; } /* Remaining arguments require a value */