xref: /aosp_15_r20/external/fsverity-utils/lib/compute_digest.c (revision b13c0e4024008a1f948ee8189745cb3371f4ac04)
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