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

TOMOYO Linux Cross Reference
Linux/lib/buildid.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 /lib/buildid.c (Version linux-6.12-rc7) and /lib/buildid.c (Version unix-v6-master)


  1 // SPDX-License-Identifier: GPL-2.0                 1 
  2                                                   
  3 #include <linux/buildid.h>                        
  4 #include <linux/cache.h>                          
  5 #include <linux/elf.h>                            
  6 #include <linux/kernel.h>                         
  7 #include <linux/pagemap.h>                        
  8 #include <linux/secretmem.h>                      
  9                                                   
 10 #define BUILD_ID 3                                
 11                                                   
 12 #define MAX_PHDR_CNT 256                          
 13                                                   
 14 struct freader {                                  
 15         void *buf;                                
 16         u32 buf_sz;                               
 17         int err;                                  
 18         union {                                   
 19                 struct {                          
 20                         struct file *file;        
 21                         struct folio *folio;      
 22                         void *addr;               
 23                         loff_t folio_off;         
 24                         bool may_fault;           
 25                 };                                
 26                 struct {                          
 27                         const char *data;         
 28                         u64 data_sz;              
 29                 };                                
 30         };                                        
 31 };                                                
 32                                                   
 33 static void freader_init_from_file(struct frea    
 34                                    struct file    
 35 {                                                 
 36         memset(r, 0, sizeof(*r));                 
 37         r->buf = buf;                             
 38         r->buf_sz = buf_sz;                       
 39         r->file = file;                           
 40         r->may_fault = may_fault;                 
 41 }                                                 
 42                                                   
 43 static void freader_init_from_mem(struct fread    
 44 {                                                 
 45         memset(r, 0, sizeof(*r));                 
 46         r->data = data;                           
 47         r->data_sz = data_sz;                     
 48 }                                                 
 49                                                   
 50 static void freader_put_folio(struct freader *    
 51 {                                                 
 52         if (!r->folio)                            
 53                 return;                           
 54         kunmap_local(r->addr);                    
 55         folio_put(r->folio);                      
 56         r->folio = NULL;                          
 57 }                                                 
 58                                                   
 59 static int freader_get_folio(struct freader *r    
 60 {                                                 
 61         /* check if we can just reuse current     
 62         if (r->folio && file_off >= r->folio_o    
 63             file_off < r->folio_off + folio_si    
 64                 return 0;                         
 65                                                   
 66         freader_put_folio(r);                     
 67                                                   
 68         /* reject secretmem folios created wit    
 69         if (secretmem_mapping(r->file->f_mappi    
 70                 return -EFAULT;                   
 71                                                   
 72         r->folio = filemap_get_folio(r->file->    
 73                                                   
 74         /* if sleeping is allowed, wait for th    
 75         if (r->may_fault && (IS_ERR(r->folio)     
 76                 filemap_invalidate_lock_shared    
 77                 r->folio = read_cache_folio(r-    
 78                                             NU    
 79                 filemap_invalidate_unlock_shar    
 80         }                                         
 81                                                   
 82         if (IS_ERR(r->folio) || !folio_test_up    
 83                 if (!IS_ERR(r->folio))            
 84                         folio_put(r->folio);      
 85                 r->folio = NULL;                  
 86                 return -EFAULT;                   
 87         }                                         
 88                                                   
 89         r->folio_off = folio_pos(r->folio);       
 90         r->addr = kmap_local_folio(r->folio, 0    
 91                                                   
 92         return 0;                                 
 93 }                                                 
 94                                                   
 95 static const void *freader_fetch(struct freade    
 96 {                                                 
 97         size_t folio_sz;                          
 98                                                   
 99         /* provided internal temporary buffer     
100         if (WARN_ON(r->buf && sz > r->buf_sz))    
101                 r->err = -E2BIG;                  
102                 return NULL;                      
103         }                                         
104                                                   
105         if (unlikely(file_off + sz < file_off)    
106                 r->err = -EOVERFLOW;              
107                 return NULL;                      
108         }                                         
109                                                   
110         /* working with memory buffer is much     
111         if (!r->buf) {                            
112                 if (file_off + sz > r->data_sz    
113                         r->err = -ERANGE;         
114                         return NULL;              
115                 }                                 
116                 return r->data + file_off;        
117         }                                         
118                                                   
119         /* fetch or reuse folio for given file    
120         r->err = freader_get_folio(r, file_off    
121         if (r->err)                               
122                 return NULL;                      
123                                                   
124         /* if requested data is crossing folio    
125          * everything into our local buffer to    
126          * access interface                       
127          */                                       
128         folio_sz = folio_size(r->folio);          
129         if (file_off + sz > r->folio_off + fol    
130                 int part_sz = r->folio_off + f    
131                                                   
132                 /* copy the part that resides     
133                 memcpy(r->buf, r->addr + (file    
134                                                   
135                 /* fetch next folio */            
136                 r->err = freader_get_folio(r,     
137                 if (r->err)                       
138                         return NULL;              
139                                                   
140                 /* copy the rest of requested     
141                 memcpy(r->buf + part_sz, r->ad    
142                                                   
143                 return r->buf;                    
144         }                                         
145                                                   
146         /* if data fits in a single folio, jus    
147         return r->addr + (file_off - r->folio_    
148 }                                                 
149                                                   
150 static void freader_cleanup(struct freader *r)    
151 {                                                 
152         if (!r->buf)                              
153                 return; /* non-file-backed mod    
154                                                   
155         freader_put_folio(r);                     
156 }                                                 
157                                                   
158 /*                                                
159  * Parse build id from the note segment. This     
160  * 32-bit and 64-bit system, because Elf32_Nhd    
161  * identical.                                     
162  */                                               
163 static int parse_build_id(struct freader *r, u    
164                           loff_t note_off, Elf    
165 {                                                 
166         const char note_name[] = "GNU";           
167         const size_t note_name_sz = sizeof(not    
168         u32 build_id_off, new_off, note_end, n    
169         const Elf32_Nhdr *nhdr;                   
170         const char *data;                         
171                                                   
172         if (check_add_overflow(note_off, note_    
173                 return -EINVAL;                   
174                                                   
175         while (note_end - note_off > sizeof(El    
176                 nhdr = freader_fetch(r, note_o    
177                 if (!nhdr)                        
178                         return r->err;            
179                                                   
180                 name_sz = READ_ONCE(nhdr->n_na    
181                 desc_sz = READ_ONCE(nhdr->n_de    
182                                                   
183                 new_off = note_off + sizeof(El    
184                 if (check_add_overflow(new_off    
185                     check_add_overflow(new_off    
186                     new_off > note_end)           
187                         break;                    
188                                                   
189                 if (nhdr->n_type == BUILD_ID &    
190                     name_sz == note_name_sz &&    
191                     memcmp(nhdr + 1, note_name    
192                     desc_sz > 0 && desc_sz <=     
193                         build_id_off = note_of    
194                                                   
195                         /* freader_fetch() wil    
196                         data = freader_fetch(r    
197                         if (!data)                
198                                 return r->err;    
199                                                   
200                         memcpy(build_id, data,    
201                         memset(build_id + desc    
202                         if (size)                 
203                                 *size = desc_s    
204                         return 0;                 
205                 }                                 
206                                                   
207                 note_off = new_off;               
208         }                                         
209                                                   
210         return -EINVAL;                           
211 }                                                 
212                                                   
213 /* Parse build ID from 32-bit ELF */              
214 static int get_build_id_32(struct freader *r,     
215 {                                                 
216         const Elf32_Ehdr *ehdr;                   
217         const Elf32_Phdr *phdr;                   
218         __u32 phnum, phoff, i;                    
219                                                   
220         ehdr = freader_fetch(r, 0, sizeof(Elf3    
221         if (!ehdr)                                
222                 return r->err;                    
223                                                   
224         /* subsequent freader_fetch() calls in    
225         phnum = READ_ONCE(ehdr->e_phnum);         
226         phoff = READ_ONCE(ehdr->e_phoff);         
227                                                   
228         /* set upper bound on amount of segmen    
229         if (phnum > MAX_PHDR_CNT)                 
230                 phnum = MAX_PHDR_CNT;             
231                                                   
232         /* check that phoff is not large enoug    
233         if (phoff + phnum * sizeof(Elf32_Phdr)    
234                 return -EINVAL;                   
235                                                   
236         for (i = 0; i < phnum; ++i) {             
237                 phdr = freader_fetch(r, phoff     
238                 if (!phdr)                        
239                         return r->err;            
240                                                   
241                 if (phdr->p_type == PT_NOTE &&    
242                     !parse_build_id(r, build_i    
243                                     READ_ONCE(    
244                         return 0;                 
245         }                                         
246         return -EINVAL;                           
247 }                                                 
248                                                   
249 /* Parse build ID from 64-bit ELF */              
250 static int get_build_id_64(struct freader *r,     
251 {                                                 
252         const Elf64_Ehdr *ehdr;                   
253         const Elf64_Phdr *phdr;                   
254         __u32 phnum, i;                           
255         __u64 phoff;                              
256                                                   
257         ehdr = freader_fetch(r, 0, sizeof(Elf6    
258         if (!ehdr)                                
259                 return r->err;                    
260                                                   
261         /* subsequent freader_fetch() calls in    
262         phnum = READ_ONCE(ehdr->e_phnum);         
263         phoff = READ_ONCE(ehdr->e_phoff);         
264                                                   
265         /* set upper bound on amount of segmen    
266         if (phnum > MAX_PHDR_CNT)                 
267                 phnum = MAX_PHDR_CNT;             
268                                                   
269         /* check that phoff is not large enoug    
270         if (phoff + phnum * sizeof(Elf64_Phdr)    
271                 return -EINVAL;                   
272                                                   
273         for (i = 0; i < phnum; ++i) {             
274                 phdr = freader_fetch(r, phoff     
275                 if (!phdr)                        
276                         return r->err;            
277                                                   
278                 if (phdr->p_type == PT_NOTE &&    
279                     !parse_build_id(r, build_i    
280                                     READ_ONCE(    
281                         return 0;                 
282         }                                         
283                                                   
284         return -EINVAL;                           
285 }                                                 
286                                                   
287 /* enough for Elf64_Ehdr, Elf64_Phdr, and all     
288 #define MAX_FREADER_BUF_SZ 64                     
289                                                   
290 static int __build_id_parse(struct vm_area_str    
291                             __u32 *size, bool     
292 {                                                 
293         const Elf32_Ehdr *ehdr;                   
294         struct freader r;                         
295         char buf[MAX_FREADER_BUF_SZ];             
296         int ret;                                  
297                                                   
298         /* only works for page backed storage     
299         if (!vma->vm_file)                        
300                 return -EINVAL;                   
301                                                   
302         freader_init_from_file(&r, buf, sizeof    
303                                                   
304         /* fetch first 18 bytes of ELF header     
305         ehdr = freader_fetch(&r, 0, offsetofen    
306         if (!ehdr) {                              
307                 ret = r.err;                      
308                 goto out;                         
309         }                                         
310                                                   
311         ret = -EINVAL;                            
312                                                   
313         /* compare magic x7f "ELF" */             
314         if (memcmp(ehdr->e_ident, ELFMAG, SELF    
315                 goto out;                         
316                                                   
317         /* only support executable file and sh    
318         if (ehdr->e_type != ET_EXEC && ehdr->e    
319                 goto out;                         
320                                                   
321         if (ehdr->e_ident[EI_CLASS] == ELFCLAS    
322                 ret = get_build_id_32(&r, buil    
323         else if (ehdr->e_ident[EI_CLASS] == EL    
324                 ret = get_build_id_64(&r, buil    
325 out:                                              
326         freader_cleanup(&r);                      
327         return ret;                               
328 }                                                 
329                                                   
330 /*                                                
331  * Parse build ID of ELF file mapped to vma       
332  * @vma:      vma object                          
333  * @build_id: buffer to store build id, at lea    
334  * @size:     returns actual build id size in     
335  *                                                
336  * Assumes no page fault can be taken, so if r    
337  * not already paged in, fetching of build ID     
338  *                                                
339  * Return: 0 on success; negative error, other    
340  */                                               
341 int build_id_parse_nofault(struct vm_area_stru    
342 {                                                 
343         return __build_id_parse(vma, build_id,    
344 }                                                 
345                                                   
346 /*                                                
347  * Parse build ID of ELF file mapped to VMA       
348  * @vma:      vma object                          
349  * @build_id: buffer to store build id, at lea    
350  * @size:     returns actual build id size in     
351  *                                                
352  * Assumes faultable context and can cause pag    
353  * into page cache.                               
354  *                                                
355  * Return: 0 on success; negative error, other    
356  */                                               
357 int build_id_parse(struct vm_area_struct *vma,    
358 {                                                 
359         return __build_id_parse(vma, build_id,    
360 }                                                 
361                                                   
362 /**                                               
363  * build_id_parse_buf - Get build ID from a bu    
364  * @buf:      ELF note section(s) to parse        
365  * @buf_size: Size of @buf in bytes               
366  * @build_id: Build ID parsed from @buf, at le    
367  *                                                
368  * Return: 0 on success, -EINVAL otherwise        
369  */                                               
370 int build_id_parse_buf(const void *buf, unsign    
371 {                                                 
372         struct freader r;                         
373         int err;                                  
374                                                   
375         freader_init_from_mem(&r, buf, buf_siz    
376                                                   
377         err = parse_build_id(&r, build_id, NUL    
378                                                   
379         freader_cleanup(&r);                      
380         return err;                               
381 }                                                 
382                                                   
383 #if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) ||     
384 unsigned char vmlinux_build_id[BUILD_ID_SIZE_M    
385                                                   
386 /**                                               
387  * init_vmlinux_build_id - Compute and stash t    
388  */                                               
389 void __init init_vmlinux_build_id(void)           
390 {                                                 
391         extern const void __start_notes;          
392         extern const void __stop_notes;           
393         unsigned int size = &__stop_notes - &_    
394                                                   
395         build_id_parse_buf(&__start_notes, vml    
396 }                                                 
397 #endif                                            
398                                                   

~ [ 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