LCOV - code coverage report
Current view: top level - lib - buildid.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 0 63 0.0 %
Date: 2021-04-22 12:43:58 Functions: 0 4 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : 
       3             : #include <linux/buildid.h>
       4             : #include <linux/elf.h>
       5             : #include <linux/pagemap.h>
       6             : 
       7             : #define BUILD_ID 3
       8             : /*
       9             :  * Parse build id from the note segment. This logic can be shared between
      10             :  * 32-bit and 64-bit system, because Elf32_Nhdr and Elf64_Nhdr are
      11             :  * identical.
      12             :  */
      13           0 : static inline int parse_build_id(void *page_addr,
      14             :                                  unsigned char *build_id,
      15             :                                  __u32 *size,
      16             :                                  void *note_start,
      17             :                                  Elf32_Word note_size)
      18             : {
      19           0 :         Elf32_Word note_offs = 0, new_offs;
      20             : 
      21             :         /* check for overflow */
      22           0 :         if (note_start < page_addr || note_start + note_size < note_start)
      23             :                 return -EINVAL;
      24             : 
      25             :         /* only supports note that fits in the first page */
      26           0 :         if (note_start + note_size > page_addr + PAGE_SIZE)
      27             :                 return -EINVAL;
      28             : 
      29           0 :         while (note_offs + sizeof(Elf32_Nhdr) < note_size) {
      30           0 :                 Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs);
      31             : 
      32           0 :                 if (nhdr->n_type == BUILD_ID &&
      33           0 :                     nhdr->n_namesz == sizeof("GNU") &&
      34           0 :                     nhdr->n_descsz > 0 &&
      35             :                     nhdr->n_descsz <= BUILD_ID_SIZE_MAX) {
      36           0 :                         memcpy(build_id,
      37             :                                note_start + note_offs +
      38           0 :                                ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr),
      39             :                                nhdr->n_descsz);
      40           0 :                         memset(build_id + nhdr->n_descsz, 0,
      41           0 :                                BUILD_ID_SIZE_MAX - nhdr->n_descsz);
      42           0 :                         if (size)
      43           0 :                                 *size = nhdr->n_descsz;
      44           0 :                         return 0;
      45             :                 }
      46           0 :                 new_offs = note_offs + sizeof(Elf32_Nhdr) +
      47           0 :                         ALIGN(nhdr->n_namesz, 4) + ALIGN(nhdr->n_descsz, 4);
      48           0 :                 if (new_offs <= note_offs)  /* overflow */
      49             :                         break;
      50             :                 note_offs = new_offs;
      51             :         }
      52             :         return -EINVAL;
      53             : }
      54             : 
      55             : /* Parse build ID from 32-bit ELF */
      56           0 : static int get_build_id_32(void *page_addr, unsigned char *build_id,
      57             :                            __u32 *size)
      58             : {
      59           0 :         Elf32_Ehdr *ehdr = (Elf32_Ehdr *)page_addr;
      60           0 :         Elf32_Phdr *phdr;
      61           0 :         int i;
      62             : 
      63             :         /* only supports phdr that fits in one page */
      64           0 :         if (ehdr->e_phnum >
      65             :             (PAGE_SIZE - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr))
      66             :                 return -EINVAL;
      67             : 
      68           0 :         phdr = (Elf32_Phdr *)(page_addr + sizeof(Elf32_Ehdr));
      69             : 
      70           0 :         for (i = 0; i < ehdr->e_phnum; ++i) {
      71           0 :                 if (phdr[i].p_type == PT_NOTE &&
      72           0 :                     !parse_build_id(page_addr, build_id, size,
      73           0 :                                     page_addr + phdr[i].p_offset,
      74             :                                     phdr[i].p_filesz))
      75             :                         return 0;
      76             :         }
      77             :         return -EINVAL;
      78             : }
      79             : 
      80             : /* Parse build ID from 64-bit ELF */
      81           0 : static int get_build_id_64(void *page_addr, unsigned char *build_id,
      82             :                            __u32 *size)
      83             : {
      84           0 :         Elf64_Ehdr *ehdr = (Elf64_Ehdr *)page_addr;
      85           0 :         Elf64_Phdr *phdr;
      86           0 :         int i;
      87             : 
      88             :         /* only supports phdr that fits in one page */
      89           0 :         if (ehdr->e_phnum >
      90             :             (PAGE_SIZE - sizeof(Elf64_Ehdr)) / sizeof(Elf64_Phdr))
      91             :                 return -EINVAL;
      92             : 
      93           0 :         phdr = (Elf64_Phdr *)(page_addr + sizeof(Elf64_Ehdr));
      94             : 
      95           0 :         for (i = 0; i < ehdr->e_phnum; ++i) {
      96           0 :                 if (phdr[i].p_type == PT_NOTE &&
      97           0 :                     !parse_build_id(page_addr, build_id, size,
      98           0 :                                     page_addr + phdr[i].p_offset,
      99           0 :                                     phdr[i].p_filesz))
     100             :                         return 0;
     101             :         }
     102             :         return -EINVAL;
     103             : }
     104             : 
     105             : /*
     106             :  * Parse build ID of ELF file mapped to vma
     107             :  * @vma:      vma object
     108             :  * @build_id: buffer to store build id, at least BUILD_ID_SIZE long
     109             :  * @size:     returns actual build id size in case of success
     110             :  *
     111             :  * Returns 0 on success, otherwise error (< 0).
     112             :  */
     113           0 : int build_id_parse(struct vm_area_struct *vma, unsigned char *build_id,
     114             :                    __u32 *size)
     115             : {
     116           0 :         Elf32_Ehdr *ehdr;
     117           0 :         struct page *page;
     118           0 :         void *page_addr;
     119           0 :         int ret;
     120             : 
     121             :         /* only works for page backed storage  */
     122           0 :         if (!vma->vm_file)
     123             :                 return -EINVAL;
     124             : 
     125           0 :         page = find_get_page(vma->vm_file->f_mapping, 0);
     126           0 :         if (!page)
     127             :                 return -EFAULT; /* page not mapped */
     128             : 
     129           0 :         ret = -EINVAL;
     130           0 :         page_addr = kmap_atomic(page);
     131           0 :         ehdr = (Elf32_Ehdr *)page_addr;
     132             : 
     133             :         /* compare magic x7f "ELF" */
     134           0 :         if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
     135           0 :                 goto out;
     136             : 
     137             :         /* only support executable file and shared object file */
     138           0 :         if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
     139           0 :                 goto out;
     140             : 
     141           0 :         if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
     142           0 :                 ret = get_build_id_32(page_addr, build_id, size);
     143           0 :         else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
     144           0 :                 ret = get_build_id_64(page_addr, build_id, size);
     145           0 : out:
     146           0 :         kunmap_atomic(page_addr);
     147           0 :         put_page(page);
     148           0 :         return ret;
     149             : }

Generated by: LCOV version 1.14