1*b13c0e40SEric Biggers // SPDX-License-Identifier: MIT
2*b13c0e40SEric Biggers /*
3*b13c0e40SEric Biggers * Implementation of libfsverity_compute_digest().
4*b13c0e40SEric Biggers *
5*b13c0e40SEric Biggers * Copyright 2018 Google LLC
6*b13c0e40SEric Biggers * Copyright (C) 2020 Facebook
7*b13c0e40SEric Biggers *
8*b13c0e40SEric Biggers * Use of this source code is governed by an MIT-style
9*b13c0e40SEric Biggers * license that can be found in the LICENSE file or at
10*b13c0e40SEric Biggers * https://opensource.org/licenses/MIT.
11*b13c0e40SEric Biggers */
12*b13c0e40SEric Biggers
13*b13c0e40SEric Biggers #include "lib_private.h"
14*b13c0e40SEric Biggers
15*b13c0e40SEric Biggers #include <stdlib.h>
16*b13c0e40SEric Biggers #include <string.h>
17*b13c0e40SEric Biggers
18*b13c0e40SEric Biggers #define FS_VERITY_MAX_LEVELS 64
19*b13c0e40SEric Biggers
20*b13c0e40SEric Biggers struct block_buffer {
21*b13c0e40SEric Biggers u32 filled;
22*b13c0e40SEric Biggers u8 *data;
23*b13c0e40SEric Biggers };
24*b13c0e40SEric Biggers
25*b13c0e40SEric Biggers /*
26*b13c0e40SEric Biggers * Hash a block, writing the result to the next level's pending block buffer.
27*b13c0e40SEric Biggers */
hash_one_block(struct hash_ctx * hash,struct block_buffer * cur,u32 block_size,const u8 * salt,u32 salt_size)28*b13c0e40SEric Biggers static void hash_one_block(struct hash_ctx *hash, struct block_buffer *cur,
29*b13c0e40SEric Biggers u32 block_size, const u8 *salt, u32 salt_size)
30*b13c0e40SEric Biggers {
31*b13c0e40SEric Biggers struct block_buffer *next = cur + 1;
32*b13c0e40SEric Biggers
33*b13c0e40SEric Biggers /* Zero-pad the block if it's shorter than block_size. */
34*b13c0e40SEric Biggers memset(&cur->data[cur->filled], 0, block_size - cur->filled);
35*b13c0e40SEric Biggers
36*b13c0e40SEric Biggers libfsverity_hash_init(hash);
37*b13c0e40SEric Biggers libfsverity_hash_update(hash, salt, salt_size);
38*b13c0e40SEric Biggers libfsverity_hash_update(hash, cur->data, block_size);
39*b13c0e40SEric Biggers libfsverity_hash_final(hash, &next->data[next->filled]);
40*b13c0e40SEric Biggers
41*b13c0e40SEric Biggers next->filled += hash->alg->digest_size;
42*b13c0e40SEric Biggers cur->filled = 0;
43*b13c0e40SEric Biggers }
44*b13c0e40SEric Biggers
block_is_full(const struct block_buffer * block,u32 block_size,struct hash_ctx * hash)45*b13c0e40SEric Biggers static bool block_is_full(const struct block_buffer *block, u32 block_size,
46*b13c0e40SEric Biggers struct hash_ctx *hash)
47*b13c0e40SEric Biggers {
48*b13c0e40SEric Biggers /* Would the next hash put us over the limit? */
49*b13c0e40SEric Biggers return block->filled + hash->alg->digest_size > block_size;
50*b13c0e40SEric Biggers }
51*b13c0e40SEric Biggers
report_merkle_tree_size(const struct libfsverity_metadata_callbacks * cbs,u64 size)52*b13c0e40SEric Biggers static int report_merkle_tree_size(const struct libfsverity_metadata_callbacks *cbs,
53*b13c0e40SEric Biggers u64 size)
54*b13c0e40SEric Biggers {
55*b13c0e40SEric Biggers if (cbs && cbs->merkle_tree_size) {
56*b13c0e40SEric Biggers int err = cbs->merkle_tree_size(cbs->ctx, size);
57*b13c0e40SEric Biggers
58*b13c0e40SEric Biggers if (err) {
59*b13c0e40SEric Biggers libfsverity_error_msg("error processing Merkle tree size");
60*b13c0e40SEric Biggers return err;
61*b13c0e40SEric Biggers }
62*b13c0e40SEric Biggers }
63*b13c0e40SEric Biggers return 0;
64*b13c0e40SEric Biggers }
65*b13c0e40SEric Biggers
report_merkle_tree_block(const struct libfsverity_metadata_callbacks * cbs,const struct block_buffer * block,u32 block_size,u64 * level_offset)66*b13c0e40SEric Biggers static int report_merkle_tree_block(const struct libfsverity_metadata_callbacks *cbs,
67*b13c0e40SEric Biggers const struct block_buffer *block,
68*b13c0e40SEric Biggers u32 block_size, u64 *level_offset)
69*b13c0e40SEric Biggers {
70*b13c0e40SEric Biggers
71*b13c0e40SEric Biggers if (cbs && cbs->merkle_tree_block) {
72*b13c0e40SEric Biggers int err = cbs->merkle_tree_block(cbs->ctx, block->data,
73*b13c0e40SEric Biggers block_size,
74*b13c0e40SEric Biggers *level_offset * block_size);
75*b13c0e40SEric Biggers
76*b13c0e40SEric Biggers if (err) {
77*b13c0e40SEric Biggers libfsverity_error_msg("error processing Merkle tree block");
78*b13c0e40SEric Biggers return err;
79*b13c0e40SEric Biggers }
80*b13c0e40SEric Biggers (*level_offset)++;
81*b13c0e40SEric Biggers }
82*b13c0e40SEric Biggers return 0;
83*b13c0e40SEric Biggers }
84*b13c0e40SEric Biggers
report_descriptor(const struct libfsverity_metadata_callbacks * cbs,const void * descriptor,size_t size)85*b13c0e40SEric Biggers static int report_descriptor(const struct libfsverity_metadata_callbacks *cbs,
86*b13c0e40SEric Biggers const void *descriptor, size_t size)
87*b13c0e40SEric Biggers {
88*b13c0e40SEric Biggers if (cbs && cbs->descriptor) {
89*b13c0e40SEric Biggers int err = cbs->descriptor(cbs->ctx, descriptor, size);
90*b13c0e40SEric Biggers
91*b13c0e40SEric Biggers if (err) {
92*b13c0e40SEric Biggers libfsverity_error_msg("error processing fs-verity descriptor");
93*b13c0e40SEric Biggers return err;
94*b13c0e40SEric Biggers }
95*b13c0e40SEric Biggers }
96*b13c0e40SEric Biggers return 0;
97*b13c0e40SEric Biggers }
98*b13c0e40SEric Biggers
99*b13c0e40SEric Biggers /*
100*b13c0e40SEric Biggers * Compute the file's Merkle tree root hash using the given hash algorithm,
101*b13c0e40SEric Biggers * block size, and salt.
102*b13c0e40SEric Biggers */
compute_root_hash(void * fd,libfsverity_read_fn_t read_fn,u64 file_size,struct hash_ctx * hash,u32 block_size,const u8 * salt,u32 salt_size,const struct libfsverity_metadata_callbacks * metadata_cbs,u8 * root_hash)103*b13c0e40SEric Biggers static int compute_root_hash(void *fd, libfsverity_read_fn_t read_fn,
104*b13c0e40SEric Biggers u64 file_size, struct hash_ctx *hash,
105*b13c0e40SEric Biggers u32 block_size, const u8 *salt, u32 salt_size,
106*b13c0e40SEric Biggers const struct libfsverity_metadata_callbacks *metadata_cbs,
107*b13c0e40SEric Biggers u8 *root_hash)
108*b13c0e40SEric Biggers {
109*b13c0e40SEric Biggers const u32 hashes_per_block = block_size / hash->alg->digest_size;
110*b13c0e40SEric Biggers const u32 padded_salt_size = roundup(salt_size, hash->alg->block_size);
111*b13c0e40SEric Biggers u8 *padded_salt = NULL;
112*b13c0e40SEric Biggers u64 blocks;
113*b13c0e40SEric Biggers int num_levels = 0;
114*b13c0e40SEric Biggers int level;
115*b13c0e40SEric Biggers u64 level_offset[FS_VERITY_MAX_LEVELS];
116*b13c0e40SEric Biggers struct block_buffer _buffers[1 + FS_VERITY_MAX_LEVELS + 1] = {};
117*b13c0e40SEric Biggers struct block_buffer *buffers = &_buffers[1];
118*b13c0e40SEric Biggers u64 offset;
119*b13c0e40SEric Biggers int err = 0;
120*b13c0e40SEric Biggers
121*b13c0e40SEric Biggers /* Root hash of empty file is all 0's */
122*b13c0e40SEric Biggers if (file_size == 0) {
123*b13c0e40SEric Biggers memset(root_hash, 0, hash->alg->digest_size);
124*b13c0e40SEric Biggers return report_merkle_tree_size(metadata_cbs, 0);
125*b13c0e40SEric Biggers }
126*b13c0e40SEric Biggers
127*b13c0e40SEric Biggers if (salt_size != 0) {
128*b13c0e40SEric Biggers padded_salt = libfsverity_zalloc(padded_salt_size);
129*b13c0e40SEric Biggers if (!padded_salt)
130*b13c0e40SEric Biggers return -ENOMEM;
131*b13c0e40SEric Biggers memcpy(padded_salt, salt, salt_size);
132*b13c0e40SEric Biggers }
133*b13c0e40SEric Biggers
134*b13c0e40SEric Biggers /* Compute number of levels and the number of blocks in each level. */
135*b13c0e40SEric Biggers blocks = DIV_ROUND_UP(file_size, block_size);
136*b13c0e40SEric Biggers while (blocks > 1) {
137*b13c0e40SEric Biggers if (WARN_ON(num_levels >= FS_VERITY_MAX_LEVELS)) {
138*b13c0e40SEric Biggers err = -EINVAL;
139*b13c0e40SEric Biggers goto out;
140*b13c0e40SEric Biggers }
141*b13c0e40SEric Biggers blocks = DIV_ROUND_UP(blocks, hashes_per_block);
142*b13c0e40SEric Biggers /*
143*b13c0e40SEric Biggers * Temporarily use level_offset[] to store the number of blocks
144*b13c0e40SEric Biggers * in each level. It will be overwritten later.
145*b13c0e40SEric Biggers */
146*b13c0e40SEric Biggers level_offset[num_levels++] = blocks;
147*b13c0e40SEric Biggers }
148*b13c0e40SEric Biggers
149*b13c0e40SEric Biggers /*
150*b13c0e40SEric Biggers * Compute the starting block of each level, using the convention where
151*b13c0e40SEric Biggers * the root level is first, i.e. the convention used by
152*b13c0e40SEric Biggers * FS_IOC_READ_VERITY_METADATA. At the same time, compute the total
153*b13c0e40SEric Biggers * size of the Merkle tree. These values are only needed for the
154*b13c0e40SEric Biggers * metadata callbacks (if they were given), as the hash computation
155*b13c0e40SEric Biggers * itself doesn't prescribe an ordering of the levels and doesn't
156*b13c0e40SEric Biggers * prescribe any special meaning to the total size of the Merkle tree.
157*b13c0e40SEric Biggers */
158*b13c0e40SEric Biggers offset = 0;
159*b13c0e40SEric Biggers for (level = num_levels - 1; level >= 0; level--) {
160*b13c0e40SEric Biggers blocks = level_offset[level];
161*b13c0e40SEric Biggers level_offset[level] = offset;
162*b13c0e40SEric Biggers offset += blocks;
163*b13c0e40SEric Biggers }
164*b13c0e40SEric Biggers err = report_merkle_tree_size(metadata_cbs, offset * block_size);
165*b13c0e40SEric Biggers if (err)
166*b13c0e40SEric Biggers goto out;
167*b13c0e40SEric Biggers
168*b13c0e40SEric Biggers /*
169*b13c0e40SEric Biggers * Allocate the block buffers. Buffer "-1" is for data blocks.
170*b13c0e40SEric Biggers * Buffers 0 <= level < num_levels are for the actual tree levels.
171*b13c0e40SEric Biggers * Buffer 'num_levels' is for the root hash.
172*b13c0e40SEric Biggers */
173*b13c0e40SEric Biggers for (level = -1; level < num_levels; level++) {
174*b13c0e40SEric Biggers buffers[level].data = libfsverity_zalloc(block_size);
175*b13c0e40SEric Biggers if (!buffers[level].data) {
176*b13c0e40SEric Biggers err = -ENOMEM;
177*b13c0e40SEric Biggers goto out;
178*b13c0e40SEric Biggers }
179*b13c0e40SEric Biggers }
180*b13c0e40SEric Biggers buffers[num_levels].data = root_hash;
181*b13c0e40SEric Biggers
182*b13c0e40SEric Biggers /* Hash each data block, also hashing the tree blocks as they fill up */
183*b13c0e40SEric Biggers for (offset = 0; offset < file_size; offset += block_size) {
184*b13c0e40SEric Biggers buffers[-1].filled = min(block_size, file_size - offset);
185*b13c0e40SEric Biggers
186*b13c0e40SEric Biggers err = read_fn(fd, buffers[-1].data, buffers[-1].filled);
187*b13c0e40SEric Biggers if (err) {
188*b13c0e40SEric Biggers libfsverity_error_msg("error reading file");
189*b13c0e40SEric Biggers goto out;
190*b13c0e40SEric Biggers }
191*b13c0e40SEric Biggers
192*b13c0e40SEric Biggers hash_one_block(hash, &buffers[-1], block_size,
193*b13c0e40SEric Biggers padded_salt, padded_salt_size);
194*b13c0e40SEric Biggers for (level = 0; level < num_levels; level++) {
195*b13c0e40SEric Biggers if (!block_is_full(&buffers[level], block_size, hash))
196*b13c0e40SEric Biggers break;
197*b13c0e40SEric Biggers hash_one_block(hash, &buffers[level], block_size,
198*b13c0e40SEric Biggers padded_salt, padded_salt_size);
199*b13c0e40SEric Biggers err = report_merkle_tree_block(metadata_cbs,
200*b13c0e40SEric Biggers &buffers[level],
201*b13c0e40SEric Biggers block_size,
202*b13c0e40SEric Biggers &level_offset[level]);
203*b13c0e40SEric Biggers if (err)
204*b13c0e40SEric Biggers goto out;
205*b13c0e40SEric Biggers }
206*b13c0e40SEric Biggers }
207*b13c0e40SEric Biggers /* Finish all nonempty pending tree blocks */
208*b13c0e40SEric Biggers for (level = 0; level < num_levels; level++) {
209*b13c0e40SEric Biggers if (buffers[level].filled != 0) {
210*b13c0e40SEric Biggers hash_one_block(hash, &buffers[level], block_size,
211*b13c0e40SEric Biggers padded_salt, padded_salt_size);
212*b13c0e40SEric Biggers err = report_merkle_tree_block(metadata_cbs,
213*b13c0e40SEric Biggers &buffers[level],
214*b13c0e40SEric Biggers block_size,
215*b13c0e40SEric Biggers &level_offset[level]);
216*b13c0e40SEric Biggers if (err)
217*b13c0e40SEric Biggers goto out;
218*b13c0e40SEric Biggers }
219*b13c0e40SEric Biggers }
220*b13c0e40SEric Biggers
221*b13c0e40SEric Biggers /* Root hash was filled by the last call to hash_one_block() */
222*b13c0e40SEric Biggers if (WARN_ON(buffers[num_levels].filled != hash->alg->digest_size)) {
223*b13c0e40SEric Biggers err = -EINVAL;
224*b13c0e40SEric Biggers goto out;
225*b13c0e40SEric Biggers }
226*b13c0e40SEric Biggers err = 0;
227*b13c0e40SEric Biggers out:
228*b13c0e40SEric Biggers for (level = -1; level < num_levels; level++)
229*b13c0e40SEric Biggers free(buffers[level].data);
230*b13c0e40SEric Biggers free(padded_salt);
231*b13c0e40SEric Biggers return err;
232*b13c0e40SEric Biggers }
233*b13c0e40SEric Biggers
234*b13c0e40SEric Biggers LIBEXPORT int
libfsverity_compute_digest(void * fd,libfsverity_read_fn_t read_fn,const struct libfsverity_merkle_tree_params * params,struct libfsverity_digest ** digest_ret)235*b13c0e40SEric Biggers libfsverity_compute_digest(void *fd, libfsverity_read_fn_t read_fn,
236*b13c0e40SEric Biggers const struct libfsverity_merkle_tree_params *params,
237*b13c0e40SEric Biggers struct libfsverity_digest **digest_ret)
238*b13c0e40SEric Biggers {
239*b13c0e40SEric Biggers u32 alg_num;
240*b13c0e40SEric Biggers u32 block_size;
241*b13c0e40SEric Biggers const struct fsverity_hash_alg *hash_alg;
242*b13c0e40SEric Biggers struct hash_ctx *hash = NULL;
243*b13c0e40SEric Biggers struct libfsverity_digest *digest;
244*b13c0e40SEric Biggers struct fsverity_descriptor desc;
245*b13c0e40SEric Biggers int err;
246*b13c0e40SEric Biggers
247*b13c0e40SEric Biggers if (!read_fn || !params || !digest_ret) {
248*b13c0e40SEric Biggers libfsverity_error_msg("missing required parameters for compute_digest");
249*b13c0e40SEric Biggers return -EINVAL;
250*b13c0e40SEric Biggers }
251*b13c0e40SEric Biggers if (params->version != 1) {
252*b13c0e40SEric Biggers libfsverity_error_msg("unsupported version (%u)",
253*b13c0e40SEric Biggers params->version);
254*b13c0e40SEric Biggers return -EINVAL;
255*b13c0e40SEric Biggers }
256*b13c0e40SEric Biggers
257*b13c0e40SEric Biggers alg_num = params->hash_algorithm ?: FS_VERITY_HASH_ALG_DEFAULT;
258*b13c0e40SEric Biggers block_size = params->block_size ?: FS_VERITY_BLOCK_SIZE_DEFAULT;
259*b13c0e40SEric Biggers
260*b13c0e40SEric Biggers if (!is_power_of_2(block_size)) {
261*b13c0e40SEric Biggers libfsverity_error_msg("unsupported block size (%u)",
262*b13c0e40SEric Biggers block_size);
263*b13c0e40SEric Biggers return -EINVAL;
264*b13c0e40SEric Biggers }
265*b13c0e40SEric Biggers if (params->salt_size > sizeof(desc.salt)) {
266*b13c0e40SEric Biggers libfsverity_error_msg("unsupported salt size (%u)",
267*b13c0e40SEric Biggers params->salt_size);
268*b13c0e40SEric Biggers return -EINVAL;
269*b13c0e40SEric Biggers }
270*b13c0e40SEric Biggers if (params->salt_size && !params->salt) {
271*b13c0e40SEric Biggers libfsverity_error_msg("salt_size specified, but salt is NULL");
272*b13c0e40SEric Biggers return -EINVAL;
273*b13c0e40SEric Biggers }
274*b13c0e40SEric Biggers if (!libfsverity_mem_is_zeroed(params->reserved1,
275*b13c0e40SEric Biggers sizeof(params->reserved1)) ||
276*b13c0e40SEric Biggers !libfsverity_mem_is_zeroed(params->reserved2,
277*b13c0e40SEric Biggers sizeof(params->reserved2))) {
278*b13c0e40SEric Biggers libfsverity_error_msg("reserved bits set in merkle_tree_params");
279*b13c0e40SEric Biggers return -EINVAL;
280*b13c0e40SEric Biggers }
281*b13c0e40SEric Biggers
282*b13c0e40SEric Biggers hash_alg = libfsverity_find_hash_alg_by_num(alg_num);
283*b13c0e40SEric Biggers if (!hash_alg) {
284*b13c0e40SEric Biggers libfsverity_error_msg("unknown hash algorithm: %u", alg_num);
285*b13c0e40SEric Biggers return -EINVAL;
286*b13c0e40SEric Biggers }
287*b13c0e40SEric Biggers
288*b13c0e40SEric Biggers if (block_size < 2 * hash_alg->digest_size) {
289*b13c0e40SEric Biggers libfsverity_error_msg("block size (%u) too small for hash algorithm %s",
290*b13c0e40SEric Biggers block_size, hash_alg->name);
291*b13c0e40SEric Biggers return -EINVAL;
292*b13c0e40SEric Biggers }
293*b13c0e40SEric Biggers
294*b13c0e40SEric Biggers hash = hash_alg->create_ctx(hash_alg);
295*b13c0e40SEric Biggers if (!hash)
296*b13c0e40SEric Biggers return -ENOMEM;
297*b13c0e40SEric Biggers
298*b13c0e40SEric Biggers memset(&desc, 0, sizeof(desc));
299*b13c0e40SEric Biggers desc.version = 1;
300*b13c0e40SEric Biggers desc.hash_algorithm = alg_num;
301*b13c0e40SEric Biggers desc.log_blocksize = ilog2(block_size);
302*b13c0e40SEric Biggers desc.data_size = cpu_to_le64(params->file_size);
303*b13c0e40SEric Biggers if (params->salt_size != 0) {
304*b13c0e40SEric Biggers memcpy(desc.salt, params->salt, params->salt_size);
305*b13c0e40SEric Biggers desc.salt_size = params->salt_size;
306*b13c0e40SEric Biggers }
307*b13c0e40SEric Biggers
308*b13c0e40SEric Biggers err = compute_root_hash(fd, read_fn, params->file_size, hash,
309*b13c0e40SEric Biggers block_size, params->salt, params->salt_size,
310*b13c0e40SEric Biggers params->metadata_callbacks, desc.root_hash);
311*b13c0e40SEric Biggers if (err)
312*b13c0e40SEric Biggers goto out;
313*b13c0e40SEric Biggers
314*b13c0e40SEric Biggers err = report_descriptor(params->metadata_callbacks,
315*b13c0e40SEric Biggers &desc, sizeof(desc));
316*b13c0e40SEric Biggers if (err)
317*b13c0e40SEric Biggers goto out;
318*b13c0e40SEric Biggers
319*b13c0e40SEric Biggers digest = libfsverity_zalloc(sizeof(*digest) + hash_alg->digest_size);
320*b13c0e40SEric Biggers if (!digest) {
321*b13c0e40SEric Biggers err = -ENOMEM;
322*b13c0e40SEric Biggers goto out;
323*b13c0e40SEric Biggers }
324*b13c0e40SEric Biggers digest->digest_algorithm = alg_num;
325*b13c0e40SEric Biggers digest->digest_size = hash_alg->digest_size;
326*b13c0e40SEric Biggers libfsverity_hash_full(hash, &desc, sizeof(desc), digest->digest);
327*b13c0e40SEric Biggers *digest_ret = digest;
328*b13c0e40SEric Biggers err = 0;
329*b13c0e40SEric Biggers out:
330*b13c0e40SEric Biggers libfsverity_free_hash_ctx(hash);
331*b13c0e40SEric Biggers return err;
332*b13c0e40SEric Biggers }
333