hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/fs/verity/open.c
....@@ -89,7 +89,7 @@
8989 */
9090
9191 /* Compute number of levels and the number of blocks in each level */
92
- blocks = (inode->i_size + params->block_size - 1) >> log_blocksize;
92
+ blocks = ((u64)inode->i_size + params->block_size - 1) >> log_blocksize;
9393 pr_debug("Data is %lld bytes (%llu blocks)\n", inode->i_size, blocks);
9494 while (blocks > 1) {
9595 if (params->num_levels >= FS_VERITY_MAX_LEVELS) {
....@@ -142,44 +142,16 @@
142142 }
143143
144144 /*
145
- * Validate the given fsverity_descriptor and create a new fsverity_info from
146
- * it. The signature (if present) is also checked.
145
+ * Create a new fsverity_info from the given fsverity_descriptor (with optional
146
+ * appended signature), and check the signature if present. The
147
+ * fsverity_descriptor must have already undergone basic validation.
147148 */
148149 struct fsverity_info *fsverity_create_info(const struct inode *inode,
149
- void *_desc, size_t desc_size)
150
+ struct fsverity_descriptor *desc,
151
+ size_t desc_size)
150152 {
151
- struct fsverity_descriptor *desc = _desc;
152153 struct fsverity_info *vi;
153154 int err;
154
-
155
- if (desc_size < sizeof(*desc)) {
156
- fsverity_err(inode, "Unrecognized descriptor size: %zu bytes",
157
- desc_size);
158
- return ERR_PTR(-EINVAL);
159
- }
160
-
161
- if (desc->version != 1) {
162
- fsverity_err(inode, "Unrecognized descriptor version: %u",
163
- desc->version);
164
- return ERR_PTR(-EINVAL);
165
- }
166
-
167
- if (memchr_inv(desc->__reserved, 0, sizeof(desc->__reserved))) {
168
- fsverity_err(inode, "Reserved bits set in descriptor");
169
- return ERR_PTR(-EINVAL);
170
- }
171
-
172
- if (desc->salt_size > sizeof(desc->salt)) {
173
- fsverity_err(inode, "Invalid salt_size: %u", desc->salt_size);
174
- return ERR_PTR(-EINVAL);
175
- }
176
-
177
- if (le64_to_cpu(desc->data_size) != inode->i_size) {
178
- fsverity_err(inode,
179
- "Wrong data_size: %llu (desc) != %lld (inode)",
180
- le64_to_cpu(desc->data_size), inode->i_size);
181
- return ERR_PTR(-EINVAL);
182
- }
183155
184156 vi = kmem_cache_zalloc(fsverity_info_cachep, GFP_KERNEL);
185157 if (!vi)
....@@ -209,7 +181,8 @@
209181 vi->tree_params.hash_alg->name,
210182 vi->tree_params.digest_size, vi->file_digest);
211183
212
- err = fsverity_verify_signature(vi, desc, desc_size);
184
+ err = fsverity_verify_signature(vi, desc->signature,
185
+ le32_to_cpu(desc->sig_size));
213186 out:
214187 if (err) {
215188 fsverity_free_info(vi);
....@@ -221,11 +194,20 @@
221194 void fsverity_set_info(struct inode *inode, struct fsverity_info *vi)
222195 {
223196 /*
224
- * Multiple processes may race to set ->i_verity_info, so use cmpxchg.
225
- * This pairs with the READ_ONCE() in fsverity_get_info().
197
+ * Multiple tasks may race to set ->i_verity_info, so use
198
+ * cmpxchg_release(). This pairs with the smp_load_acquire() in
199
+ * fsverity_get_info(). I.e., here we publish ->i_verity_info with a
200
+ * RELEASE barrier so that other tasks can ACQUIRE it.
226201 */
227
- if (cmpxchg(&inode->i_verity_info, NULL, vi) != NULL)
202
+ if (cmpxchg_release(&inode->i_verity_info, NULL, vi) != NULL) {
203
+ /* Lost the race, so free the fsverity_info we allocated. */
228204 fsverity_free_info(vi);
205
+ /*
206
+ * Afterwards, the caller may access ->i_verity_info directly,
207
+ * so make sure to ACQUIRE the winning fsverity_info.
208
+ */
209
+ (void)fsverity_get_info(inode);
210
+ }
229211 }
230212
231213 void fsverity_free_info(struct fsverity_info *vi)
....@@ -236,15 +218,57 @@
236218 kmem_cache_free(fsverity_info_cachep, vi);
237219 }
238220
239
-/* Ensure the inode has an ->i_verity_info */
240
-static int ensure_verity_info(struct inode *inode)
221
+static bool validate_fsverity_descriptor(struct inode *inode,
222
+ const struct fsverity_descriptor *desc,
223
+ size_t desc_size)
241224 {
242
- struct fsverity_info *vi = fsverity_get_info(inode);
243
- struct fsverity_descriptor *desc;
244
- int res;
225
+ if (desc_size < sizeof(*desc)) {
226
+ fsverity_err(inode, "Unrecognized descriptor size: %zu bytes",
227
+ desc_size);
228
+ return false;
229
+ }
245230
246
- if (vi)
247
- return 0;
231
+ if (desc->version != 1) {
232
+ fsverity_err(inode, "Unrecognized descriptor version: %u",
233
+ desc->version);
234
+ return false;
235
+ }
236
+
237
+ if (memchr_inv(desc->__reserved, 0, sizeof(desc->__reserved))) {
238
+ fsverity_err(inode, "Reserved bits set in descriptor");
239
+ return false;
240
+ }
241
+
242
+ if (desc->salt_size > sizeof(desc->salt)) {
243
+ fsverity_err(inode, "Invalid salt_size: %u", desc->salt_size);
244
+ return false;
245
+ }
246
+
247
+ if (le64_to_cpu(desc->data_size) != inode->i_size) {
248
+ fsverity_err(inode,
249
+ "Wrong data_size: %llu (desc) != %lld (inode)",
250
+ le64_to_cpu(desc->data_size), inode->i_size);
251
+ return false;
252
+ }
253
+
254
+ if (le32_to_cpu(desc->sig_size) > desc_size - sizeof(*desc)) {
255
+ fsverity_err(inode, "Signature overflows verity descriptor");
256
+ return false;
257
+ }
258
+
259
+ return true;
260
+}
261
+
262
+/*
263
+ * Read the inode's fsverity_descriptor (with optional appended signature) from
264
+ * the filesystem, and do basic validation of it.
265
+ */
266
+int fsverity_get_descriptor(struct inode *inode,
267
+ struct fsverity_descriptor **desc_ret,
268
+ size_t *desc_size_ret)
269
+{
270
+ int res;
271
+ struct fsverity_descriptor *desc;
248272
249273 res = inode->i_sb->s_vop->get_verity_descriptor(inode, NULL, 0);
250274 if (res < 0) {
....@@ -263,20 +287,46 @@
263287 res = inode->i_sb->s_vop->get_verity_descriptor(inode, desc, res);
264288 if (res < 0) {
265289 fsverity_err(inode, "Error %d reading verity descriptor", res);
266
- goto out_free_desc;
290
+ kfree(desc);
291
+ return res;
267292 }
268293
269
- vi = fsverity_create_info(inode, desc, res);
294
+ if (!validate_fsverity_descriptor(inode, desc, res)) {
295
+ kfree(desc);
296
+ return -EINVAL;
297
+ }
298
+
299
+ *desc_ret = desc;
300
+ *desc_size_ret = res;
301
+ return 0;
302
+}
303
+
304
+/* Ensure the inode has an ->i_verity_info */
305
+static int ensure_verity_info(struct inode *inode)
306
+{
307
+ struct fsverity_info *vi = fsverity_get_info(inode);
308
+ struct fsverity_descriptor *desc;
309
+ size_t desc_size;
310
+ int err;
311
+
312
+ if (vi)
313
+ return 0;
314
+
315
+ err = fsverity_get_descriptor(inode, &desc, &desc_size);
316
+ if (err)
317
+ return err;
318
+
319
+ vi = fsverity_create_info(inode, desc, desc_size);
270320 if (IS_ERR(vi)) {
271
- res = PTR_ERR(vi);
321
+ err = PTR_ERR(vi);
272322 goto out_free_desc;
273323 }
274324
275325 fsverity_set_info(inode, vi);
276
- res = 0;
326
+ err = 0;
277327 out_free_desc:
278328 kfree(desc);
279
- return res;
329
+ return err;
280330 }
281331
282332 /**