1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright 2019 Google LLC
4 */
5 #include <crypto/sha2.h>
6 #include <crypto/hash.h>
7 #include <linux/err.h>
8 #include <linux/version.h>
9
10 #include "integrity.h"
11
incfs_get_hash_alg(enum incfs_hash_tree_algorithm id)12 struct incfs_hash_alg *incfs_get_hash_alg(enum incfs_hash_tree_algorithm id)
13 {
14 static struct incfs_hash_alg sha256 = {
15 .name = "sha256",
16 .digest_size = SHA256_DIGEST_SIZE,
17 .id = INCFS_HASH_TREE_SHA256
18 };
19 struct incfs_hash_alg *result = NULL;
20 struct crypto_shash *shash;
21
22 if (id == INCFS_HASH_TREE_SHA256) {
23 BUILD_BUG_ON(INCFS_MAX_HASH_SIZE < SHA256_DIGEST_SIZE);
24 result = &sha256;
25 }
26
27 if (result == NULL)
28 return ERR_PTR(-ENOENT);
29
30 /* pairs with cmpxchg_release() below */
31 shash = smp_load_acquire(&result->shash);
32 if (shash)
33 return result;
34
35 shash = crypto_alloc_shash(result->name, 0, 0);
36 if (IS_ERR(shash)) {
37 int err = PTR_ERR(shash);
38
39 pr_err("Can't allocate hash alg %s, error code:%d",
40 result->name, err);
41 return ERR_PTR(err);
42 }
43
44 /* pairs with smp_load_acquire() above */
45 if (cmpxchg_release(&result->shash, NULL, shash) != NULL)
46 crypto_free_shash(shash);
47
48 return result;
49 }
50
51 struct signature_info {
52 u32 version;
53 enum incfs_hash_tree_algorithm hash_algorithm;
54 u8 log2_blocksize;
55 struct mem_range salt;
56 struct mem_range root_hash;
57 };
58
read_u32(u8 ** p,u8 * top,u32 * result)59 static bool read_u32(u8 **p, u8 *top, u32 *result)
60 {
61 if (*p + sizeof(u32) > top)
62 return false;
63
64 *result = le32_to_cpu(*(__le32 *)*p);
65 *p += sizeof(u32);
66 return true;
67 }
68
read_u8(u8 ** p,u8 * top,u8 * result)69 static bool read_u8(u8 **p, u8 *top, u8 *result)
70 {
71 if (*p + sizeof(u8) > top)
72 return false;
73
74 *result = *(u8 *)*p;
75 *p += sizeof(u8);
76 return true;
77 }
78
read_mem_range(u8 ** p,u8 * top,struct mem_range * range)79 static bool read_mem_range(u8 **p, u8 *top, struct mem_range *range)
80 {
81 u32 len;
82
83 if (!read_u32(p, top, &len) || *p + len > top)
84 return false;
85
86 range->len = len;
87 range->data = *p;
88 *p += len;
89 return true;
90 }
91
incfs_parse_signature(struct mem_range signature,struct signature_info * si)92 static int incfs_parse_signature(struct mem_range signature,
93 struct signature_info *si)
94 {
95 u8 *p = signature.data;
96 u8 *top = signature.data + signature.len;
97 u32 hash_section_size;
98
99 if (signature.len > INCFS_MAX_SIGNATURE_SIZE)
100 return -EINVAL;
101
102 if (!read_u32(&p, top, &si->version) ||
103 si->version != INCFS_SIGNATURE_VERSION)
104 return -EINVAL;
105
106 if (!read_u32(&p, top, &hash_section_size) ||
107 p + hash_section_size > top)
108 return -EINVAL;
109 top = p + hash_section_size;
110
111 if (!read_u32(&p, top, &si->hash_algorithm) ||
112 si->hash_algorithm != INCFS_HASH_TREE_SHA256)
113 return -EINVAL;
114
115 if (!read_u8(&p, top, &si->log2_blocksize) || si->log2_blocksize != 12)
116 return -EINVAL;
117
118 if (!read_mem_range(&p, top, &si->salt))
119 return -EINVAL;
120
121 if (!read_mem_range(&p, top, &si->root_hash))
122 return -EINVAL;
123
124 if (p != top)
125 return -EINVAL;
126
127 return 0;
128 }
129
incfs_alloc_mtree(struct mem_range signature,int data_block_count)130 struct mtree *incfs_alloc_mtree(struct mem_range signature,
131 int data_block_count)
132 {
133 int error;
134 struct signature_info si;
135 struct mtree *result = NULL;
136 struct incfs_hash_alg *hash_alg = NULL;
137 int hash_per_block;
138 int lvl;
139 int total_blocks = 0;
140 int blocks_in_level[INCFS_MAX_MTREE_LEVELS];
141 int blocks = data_block_count;
142
143 if (data_block_count <= 0)
144 return ERR_PTR(-EINVAL);
145
146 error = incfs_parse_signature(signature, &si);
147 if (error)
148 return ERR_PTR(error);
149
150 hash_alg = incfs_get_hash_alg(si.hash_algorithm);
151 if (IS_ERR(hash_alg))
152 return ERR_PTR(PTR_ERR(hash_alg));
153
154 if (si.root_hash.len < hash_alg->digest_size)
155 return ERR_PTR(-EINVAL);
156
157 result = kzalloc(sizeof(*result), GFP_NOFS);
158 if (!result)
159 return ERR_PTR(-ENOMEM);
160
161 result->alg = hash_alg;
162 hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / result->alg->digest_size;
163
164 /* Calculating tree geometry. */
165 /* First pass: calculate how many blocks in each tree level. */
166 for (lvl = 0; blocks > 1; lvl++) {
167 if (lvl >= INCFS_MAX_MTREE_LEVELS) {
168 pr_err("incfs: too much data in mtree");
169 goto err;
170 }
171
172 blocks = (blocks + hash_per_block - 1) / hash_per_block;
173 blocks_in_level[lvl] = blocks;
174 total_blocks += blocks;
175 }
176 result->depth = lvl;
177 result->hash_tree_area_size = total_blocks * INCFS_DATA_FILE_BLOCK_SIZE;
178 if (result->hash_tree_area_size > INCFS_MAX_HASH_AREA_SIZE)
179 goto err;
180
181 blocks = 0;
182 /* Second pass: calculate offset of each level. 0th level goes last. */
183 for (lvl = 0; lvl < result->depth; lvl++) {
184 u32 suboffset;
185
186 blocks += blocks_in_level[lvl];
187 suboffset = (total_blocks - blocks)
188 * INCFS_DATA_FILE_BLOCK_SIZE;
189
190 result->hash_level_suboffset[lvl] = suboffset;
191 }
192
193 /* Root hash is stored separately from the rest of the tree. */
194 memcpy(result->root_hash, si.root_hash.data, hash_alg->digest_size);
195 return result;
196
197 err:
198 kfree(result);
199 return ERR_PTR(-E2BIG);
200 }
201
incfs_free_mtree(struct mtree * tree)202 void incfs_free_mtree(struct mtree *tree)
203 {
204 kfree(tree);
205 }
206
incfs_calc_digest(struct incfs_hash_alg * alg,struct mem_range data,struct mem_range digest)207 int incfs_calc_digest(struct incfs_hash_alg *alg, struct mem_range data,
208 struct mem_range digest)
209 {
210 SHASH_DESC_ON_STACK(desc, alg->shash);
211
212 if (!alg || !alg->shash || !data.data || !digest.data)
213 return -EFAULT;
214
215 if (alg->digest_size > digest.len)
216 return -EINVAL;
217
218 desc->tfm = alg->shash;
219
220 if (data.len < INCFS_DATA_FILE_BLOCK_SIZE) {
221 int err;
222 void *buf = kzalloc(INCFS_DATA_FILE_BLOCK_SIZE, GFP_NOFS);
223
224 if (!buf)
225 return -ENOMEM;
226
227 memcpy(buf, data.data, data.len);
228 err = crypto_shash_digest(desc, buf, INCFS_DATA_FILE_BLOCK_SIZE,
229 digest.data);
230 kfree(buf);
231 return err;
232 }
233 return crypto_shash_digest(desc, data.data, data.len, digest.data);
234 }
235
236