~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/verity/open.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /fs/verity/open.c (Version linux-6.12-rc7) and /fs/verity/open.c (Version linux-4.4.302)


  1 // SPDX-License-Identifier: GPL-2.0                 1 
  2 /*                                                
  3  * Opening fs-verity files                        
  4  *                                                
  5  * Copyright 2019 Google LLC                      
  6  */                                               
  7                                                   
  8 #include "fsverity_private.h"                     
  9                                                   
 10 #include <linux/mm.h>                             
 11 #include <linux/slab.h>                           
 12                                                   
 13 static struct kmem_cache *fsverity_info_cachep    
 14                                                   
 15 /**                                               
 16  * fsverity_init_merkle_tree_params() - initia    
 17  * @params: the parameters struct to initializ    
 18  * @inode: the inode for which the Merkle tree    
 19  * @hash_algorithm: number of hash algorithm t    
 20  * @log_blocksize: log base 2 of block size to    
 21  * @salt: pointer to salt (optional)              
 22  * @salt_size: size of salt, possibly 0           
 23  *                                                
 24  * Validate the hash algorithm and block size,    
 25  * (num levels, num blocks in each level, etc.    
 26  *                                                
 27  * Return: 0 on success, -errno on failure        
 28  */                                               
 29 int fsverity_init_merkle_tree_params(struct me    
 30                                      const str    
 31                                      unsigned     
 32                                      unsigned     
 33                                      const u8     
 34 {                                                 
 35         const struct fsverity_hash_alg *hash_a    
 36         int err;                                  
 37         u64 blocks;                               
 38         u64 blocks_in_level[FS_VERITY_MAX_LEVE    
 39         u64 offset;                               
 40         int level;                                
 41                                                   
 42         memset(params, 0, sizeof(*params));       
 43                                                   
 44         hash_alg = fsverity_get_hash_alg(inode    
 45         if (IS_ERR(hash_alg))                     
 46                 return PTR_ERR(hash_alg);         
 47         params->hash_alg = hash_alg;              
 48         params->digest_size = hash_alg->digest    
 49                                                   
 50         params->hashstate = fsverity_prepare_h    
 51                                                   
 52         if (IS_ERR(params->hashstate)) {          
 53                 err = PTR_ERR(params->hashstat    
 54                 params->hashstate = NULL;         
 55                 fsverity_err(inode, "Error %d     
 56                 goto out_err;                     
 57         }                                         
 58                                                   
 59         /*                                        
 60          * fs/verity/ directly assumes that th    
 61          * power of 2 less than or equal to PA    
 62          * arises from the interaction between    
 63          * themselves: filesystems expect to b    
 64          * filesystem block of data at a time.    
 65          * size must also be less than or equa    
 66          *                                        
 67          * The above are the only hard limitat    
 68          * block size could be as small as twi    
 69          * that's not useful, and it would res    
 70          * large Merkle trees.  So we currentl    
 71          * block size be at least 1024 bytes.     
 72          * sub-page block case on systems with    
 73          */                                       
 74         if (log_blocksize < 10 || log_blocksiz    
 75             log_blocksize > inode->i_blkbits)     
 76                 fsverity_warn(inode, "Unsuppor    
 77                               log_blocksize);     
 78                 err = -EINVAL;                    
 79                 goto out_err;                     
 80         }                                         
 81         params->log_blocksize = log_blocksize;    
 82         params->block_size = 1 << log_blocksiz    
 83         params->log_blocks_per_page = PAGE_SHI    
 84         params->blocks_per_page = 1 << params-    
 85                                                   
 86         if (WARN_ON_ONCE(!is_power_of_2(params    
 87                 err = -EINVAL;                    
 88                 goto out_err;                     
 89         }                                         
 90         if (params->block_size < 2 * params->d    
 91                 fsverity_warn(inode,              
 92                               "Merkle tree blo    
 93                               params->block_si    
 94                 err = -EINVAL;                    
 95                 goto out_err;                     
 96         }                                         
 97         params->log_digestsize = ilog2(params-    
 98         params->log_arity = log_blocksize - pa    
 99         params->hashes_per_block = 1 << params    
100                                                   
101         /*                                        
102          * Compute the number of levels in the    
103          * level to the starting block of that    
104          * the root and is stored first.  Leve    
105          * the data blocks and is stored last.    
106          */                                       
107                                                   
108         /* Compute number of levels and the nu    
109         blocks = ((u64)inode->i_size + params-    
110         while (blocks > 1) {                      
111                 if (params->num_levels >= FS_V    
112                         fsverity_err(inode, "T    
113                         err = -EFBIG;             
114                         goto out_err;             
115                 }                                 
116                 blocks = (blocks + params->has    
117                          params->log_arity;       
118                 blocks_in_level[params->num_le    
119         }                                         
120                                                   
121         /* Compute the starting block of each     
122         offset = 0;                               
123         for (level = (int)params->num_levels -    
124                 params->level_start[level] = o    
125                 offset += blocks_in_level[leve    
126         }                                         
127                                                   
128         /*                                        
129          * With block_size != PAGE_SIZE, an in    
130          * allocated to track the "verified" s    
131          * this bitmap to get too large.  For     
132          * limits the file size to about 4.4 T    
133          *                                        
134          * Together with the fact that the dat    
135          * cannot have more than ULONG_MAX pag    
136          * indices can always fit in an 'unsig    
137          * explicitly check for that too.  Not    
138          * indices; data block indices might n    
139          */                                       
140         if ((params->block_size != PAGE_SIZE &    
141             offset > ULONG_MAX) {                 
142                 fsverity_err(inode, "Too many     
143                 err = -EFBIG;                     
144                 goto out_err;                     
145         }                                         
146                                                   
147         params->tree_size = offset << log_bloc    
148         params->tree_pages = PAGE_ALIGN(params    
149         return 0;                                 
150                                                   
151 out_err:                                          
152         kfree(params->hashstate);                 
153         memset(params, 0, sizeof(*params));       
154         return err;                               
155 }                                                 
156                                                   
157 /*                                                
158  * Compute the file digest by hashing the fsve    
159  * builtin signature and with the sig_size fie    
160  */                                               
161 static int compute_file_digest(const struct fs    
162                                struct fsverity    
163                                u8 *file_digest    
164 {                                                 
165         __le32 sig_size = desc->sig_size;         
166         int err;                                  
167                                                   
168         desc->sig_size = 0;                       
169         err = fsverity_hash_buffer(hash_alg, d    
170         desc->sig_size = sig_size;                
171                                                   
172         return err;                               
173 }                                                 
174                                                   
175 /*                                                
176  * Create a new fsverity_info from the given f    
177  * appended builtin signature), and check the     
178  * fsverity_descriptor must have already under    
179  */                                               
180 struct fsverity_info *fsverity_create_info(con    
181                                            str    
182 {                                                 
183         struct fsverity_info *vi;                 
184         int err;                                  
185                                                   
186         vi = kmem_cache_zalloc(fsverity_info_c    
187         if (!vi)                                  
188                 return ERR_PTR(-ENOMEM);          
189         vi->inode = inode;                        
190                                                   
191         err = fsverity_init_merkle_tree_params    
192                                                   
193                                                   
194                                                   
195         if (err) {                                
196                 fsverity_err(inode,               
197                              "Error %d initial    
198                              err);                
199                 goto fail;                        
200         }                                         
201                                                   
202         memcpy(vi->root_hash, desc->root_hash,    
203                                                   
204         err = compute_file_digest(vi->tree_par    
205                                   vi->file_dig    
206         if (err) {                                
207                 fsverity_err(inode, "Error %d     
208                 goto fail;                        
209         }                                         
210                                                   
211         err = fsverity_verify_signature(vi, de    
212                                         le32_t    
213         if (err)                                  
214                 goto fail;                        
215                                                   
216         if (vi->tree_params.block_size != PAGE    
217                 /*                                
218                  * When the Merkle tree block     
219                  * a bitmap to keep track of w    
220                  * verified.  This bitmap must    
221                  * including alignment to a pa    
222                  *                                
223                  * Eventually, to support extr    
224                  * way, it might be necessary     
225                  * reclaimable.  But for now,     
226                  * is a simple solution that w    
227                  * fsverity is realistically u    
228                  * blocks, a 100MB file only n    
229                  * bitmap for any file under 1    
230                  */                               
231                 unsigned long num_bits =          
232                         vi->tree_params.tree_p    
233                         vi->tree_params.log_bl    
234                                                   
235                 vi->hash_block_verified = kvca    
236                                                   
237                                                   
238                 if (!vi->hash_block_verified)     
239                         err = -ENOMEM;            
240                         goto fail;                
241                 }                                 
242         }                                         
243                                                   
244         return vi;                                
245                                                   
246 fail:                                             
247         fsverity_free_info(vi);                   
248         return ERR_PTR(err);                      
249 }                                                 
250                                                   
251 void fsverity_set_info(struct inode *inode, st    
252 {                                                 
253         /*                                        
254          * Multiple tasks may race to set ->i_    
255          * cmpxchg_release().  This pairs with    
256          * fsverity_get_info().  I.e., here we    
257          * RELEASE barrier so that other tasks    
258          */                                       
259         if (cmpxchg_release(&inode->i_verity_i    
260                 /* Lost the race, so free the     
261                 fsverity_free_info(vi);           
262                 /*                                
263                  * Afterwards, the caller may     
264                  * so make sure to ACQUIRE the    
265                  */                               
266                 (void)fsverity_get_info(inode)    
267         }                                         
268 }                                                 
269                                                   
270 void fsverity_free_info(struct fsverity_info *    
271 {                                                 
272         if (!vi)                                  
273                 return;                           
274         kfree(vi->tree_params.hashstate);         
275         kvfree(vi->hash_block_verified);          
276         kmem_cache_free(fsverity_info_cachep,     
277 }                                                 
278                                                   
279 static bool validate_fsverity_descriptor(struc    
280                                          const    
281                                          size_    
282 {                                                 
283         if (desc_size < sizeof(*desc)) {          
284                 fsverity_err(inode, "Unrecogni    
285                              desc_size);          
286                 return false;                     
287         }                                         
288                                                   
289         if (desc->version != 1) {                 
290                 fsverity_err(inode, "Unrecogni    
291                              desc->version);      
292                 return false;                     
293         }                                         
294                                                   
295         if (memchr_inv(desc->__reserved, 0, si    
296                 fsverity_err(inode, "Reserved     
297                 return false;                     
298         }                                         
299                                                   
300         if (desc->salt_size > sizeof(desc->sal    
301                 fsverity_err(inode, "Invalid s    
302                 return false;                     
303         }                                         
304                                                   
305         if (le64_to_cpu(desc->data_size) != in    
306                 fsverity_err(inode,               
307                              "Wrong data_size:    
308                              le64_to_cpu(desc-    
309                 return false;                     
310         }                                         
311                                                   
312         if (le32_to_cpu(desc->sig_size) > desc    
313                 fsverity_err(inode, "Signature    
314                 return false;                     
315         }                                         
316                                                   
317         return true;                              
318 }                                                 
319                                                   
320 /*                                                
321  * Read the inode's fsverity_descriptor (with     
322  * signature) from the filesystem, and do basi    
323  */                                               
324 int fsverity_get_descriptor(struct inode *inod    
325                             struct fsverity_de    
326 {                                                 
327         int res;                                  
328         struct fsverity_descriptor *desc;         
329                                                   
330         res = inode->i_sb->s_vop->get_verity_d    
331         if (res < 0) {                            
332                 fsverity_err(inode,               
333                              "Error %d getting    
334                 return res;                       
335         }                                         
336         if (res > FS_VERITY_MAX_DESCRIPTOR_SIZ    
337                 fsverity_err(inode, "Verity de    
338                              res);                
339                 return -EMSGSIZE;                 
340         }                                         
341         desc = kmalloc(res, GFP_KERNEL);          
342         if (!desc)                                
343                 return -ENOMEM;                   
344         res = inode->i_sb->s_vop->get_verity_d    
345         if (res < 0) {                            
346                 fsverity_err(inode, "Error %d     
347                 kfree(desc);                      
348                 return res;                       
349         }                                         
350                                                   
351         if (!validate_fsverity_descriptor(inod    
352                 kfree(desc);                      
353                 return -EINVAL;                   
354         }                                         
355                                                   
356         *desc_ret = desc;                         
357         return 0;                                 
358 }                                                 
359                                                   
360 /* Ensure the inode has an ->i_verity_info */     
361 static int ensure_verity_info(struct inode *in    
362 {                                                 
363         struct fsverity_info *vi = fsverity_ge    
364         struct fsverity_descriptor *desc;         
365         int err;                                  
366                                                   
367         if (vi)                                   
368                 return 0;                         
369                                                   
370         err = fsverity_get_descriptor(inode, &    
371         if (err)                                  
372                 return err;                       
373                                                   
374         vi = fsverity_create_info(inode, desc)    
375         if (IS_ERR(vi)) {                         
376                 err = PTR_ERR(vi);                
377                 goto out_free_desc;               
378         }                                         
379                                                   
380         fsverity_set_info(inode, vi);             
381         err = 0;                                  
382 out_free_desc:                                    
383         kfree(desc);                              
384         return err;                               
385 }                                                 
386                                                   
387 int __fsverity_file_open(struct inode *inode,     
388 {                                                 
389         if (filp->f_mode & FMODE_WRITE)           
390                 return -EPERM;                    
391         return ensure_verity_info(inode);         
392 }                                                 
393 EXPORT_SYMBOL_GPL(__fsverity_file_open);          
394                                                   
395 int __fsverity_prepare_setattr(struct dentry *    
396 {                                                 
397         if (attr->ia_valid & ATTR_SIZE)           
398                 return -EPERM;                    
399         return 0;                                 
400 }                                                 
401 EXPORT_SYMBOL_GPL(__fsverity_prepare_setattr);    
402                                                   
403 void __fsverity_cleanup_inode(struct inode *in    
404 {                                                 
405         fsverity_free_info(inode->i_verity_inf    
406         inode->i_verity_info = NULL;              
407 }                                                 
408 EXPORT_SYMBOL_GPL(__fsverity_cleanup_inode);      
409                                                   
410 void __init fsverity_init_info_cache(void)        
411 {                                                 
412         fsverity_info_cachep = KMEM_CACHE_USER    
413                                         fsveri    
414                                         SLAB_R    
415                                         file_d    
416 }                                                 
417                                                   

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php