LCOV - code coverage report
Current view: top level - libpkg - pkg_elf.c (source / functions) Hit Total Coverage
Test: plop Lines: 217 337 64.4 %
Date: 2024-12-30 07:09:03 Functions: 9 10 90.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 148 293 50.5 %

           Branch data     Line data    Source code
       1                 :            : /*-
       2                 :            :  * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
       3                 :            :  * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
       4                 :            :  *
       5                 :            :  * SPDX-License-Identifier: BSD-2-Clause
       6                 :            :  */
       7                 :            : 
       8                 :            : #ifdef HAVE_CONFIG_H
       9                 :            : #include "pkg_config.h"
      10                 :            : #endif
      11                 :            : 
      12                 :            : #ifdef HAVE_SYS_ENDIAN_H
      13                 :            : #include <sys/endian.h>
      14                 :            : #elif HAVE_ENDIAN_H
      15                 :            : #include <endian.h>
      16                 :            : #elif HAVE_MACHINE_ENDIAN_H
      17                 :            : #include <machine/endian.h>
      18                 :            : #endif
      19                 :            : #include <sys/types.h>
      20                 :            : #if defined(HAVE_SYS_ELF_COMMON_H) && !defined(__DragonFly__)
      21                 :            : #include <sys/elf_common.h>
      22                 :            : #endif
      23                 :            : #include <sys/stat.h>
      24                 :            : 
      25                 :            : #include <assert.h>
      26                 :            : #include <dlfcn.h>
      27                 :            : #include <fcntl.h>
      28                 :            : #include <gelf.h>
      29                 :            : #include <libgen.h>
      30                 :            : #if defined(HAVE_LINK_H) && !defined(__DragonFly__) && defined(HAVE_LIBELF)
      31                 :            : #include <link.h>
      32                 :            : #endif
      33                 :            : #include <paths.h>
      34                 :            : #include <stdbool.h>
      35                 :            : #include <string.h>
      36                 :            : #include <unistd.h>
      37                 :            : #ifdef HAVE_LIBELF
      38                 :            : #include <libelf.h>
      39                 :            : #endif
      40                 :            : 
      41                 :            : #include <bsd_compat.h>
      42                 :            : 
      43                 :            : #include "pkg.h"
      44                 :            : #include "private/pkg.h"
      45                 :            : #include "private/pkg_abi.h"
      46                 :            : #include "private/event.h"
      47                 :            : #include "private/binfmt.h"
      48                 :            : 
      49                 :            : #ifndef NT_ABI_TAG
      50                 :            : #define NT_ABI_TAG 1
      51                 :            : #endif
      52                 :            : 
      53                 :            : #define NT_VERSION      1
      54                 :            : #define NT_ARCH         2
      55                 :            : #define NT_GNU_ABI_TAG  1
      56                 :            : 
      57                 :            : #ifndef roundup2
      58                 :            : #define roundup2(x, y)  (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
      59                 :            : #endif
      60                 :            : 
      61                 :            : static void elf_parse_abi(Elf *elf, GElf_Ehdr *ehdr, struct pkg_abi *abi);
      62                 :            : 
      63                 :            : #ifndef HAVE_ELF_NOTE
      64                 :            : typedef Elf32_Nhdr Elf_Note;
      65                 :            : #endif
      66                 :            : 
      67                 :            : static int
      68                 :        250 : analyse_elf(struct pkg *pkg, const char *fpath)
      69                 :            : {
      70                 :        250 :         int ret = EPKG_OK;
      71                 :            : 
      72                 :        250 :         pkg_debug(1, "analysing elf %s", fpath);
      73                 :            : 
      74                 :            :         struct stat sb;
      75         [ +  - ]:        250 :         if (lstat(fpath, &sb) != 0)
      76                 :          0 :                 pkg_emit_errno("fstat() failed for", fpath);
      77                 :            :         /* ignore empty files and non regular files */
      78   [ +  +  +  + ]:        250 :         if (sb.st_size == 0 || !S_ISREG(sb.st_mode))
      79                 :        157 :                 return (EPKG_END); /* Empty file or sym-link: no results */
      80                 :            : 
      81                 :         93 :         int fd = open(fpath, O_RDONLY, 0);
      82         [ +  - ]:         93 :         if (fd < 0) {
      83                 :          0 :                 return (EPKG_FATAL);
      84                 :            :         }
      85                 :            : 
      86         [ +  - ]:         93 :         if (elf_version(EV_CURRENT) == EV_NONE) {
      87                 :          0 :                 pkg_emit_error("ELF library initialization failed: %s",
      88                 :          0 :                     elf_errmsg(-1));
      89                 :          0 :                 return (EPKG_FATAL);
      90                 :            :         }
      91                 :            : 
      92                 :         93 :         Elf *e = elf_begin(fd, ELF_C_READ, NULL);
      93         [ +  - ]:         93 :         if (e == NULL) {
      94                 :          0 :                 ret = EPKG_FATAL;
      95                 :          0 :                 pkg_debug(1, "elf_begin() for %s failed: %s", fpath,
      96                 :          0 :                     elf_errmsg(-1));
      97                 :          0 :                 goto cleanup;
      98                 :            :         }
      99                 :            : 
     100         [ +  + ]:         93 :         if (elf_kind(e) != ELF_K_ELF) {
     101                 :            :                 /* Not an elf file: no results */
     102                 :         68 :                 ret = EPKG_END;
     103                 :         68 :                 pkg_debug(1, "not an elf");
     104                 :         68 :                 goto cleanup;
     105                 :            :         }
     106                 :            : 
     107         [ +  - ]:         25 :         if (ctx.developer_mode)
     108                 :          0 :                 pkg->flags |= PKG_CONTAINS_ELF_OBJECTS;
     109                 :            : 
     110                 :            :         GElf_Ehdr elfhdr;
     111         [ +  - ]:         25 :         if (gelf_getehdr(e, &elfhdr) == NULL) {
     112                 :          0 :                 ret = EPKG_WARN;
     113                 :          0 :                 pkg_debug(1, "getehdr() failed: %s.", elf_errmsg(-1));
     114                 :          0 :                 goto cleanup;
     115                 :            :         }
     116                 :            : 
     117   [ +  +  +  -  :         25 :         if (elfhdr.e_type != ET_DYN && elfhdr.e_type != ET_EXEC &&
                   #  # ]
     118                 :          0 :             elfhdr.e_type != ET_REL) {
     119                 :          0 :                 pkg_debug(1, "not an elf");
     120                 :          0 :                 ret = EPKG_END;
     121                 :          0 :                 goto cleanup;
     122                 :            :         }
     123                 :            : 
     124                 :            :         /* Parse the needed information from the dynamic section header */
     125                 :         25 :         Elf_Scn *scn = NULL;
     126                 :         25 :         Elf_Scn *dynamic = NULL;
     127                 :         25 :         size_t numdyn = 0;
     128                 :         25 :         size_t sh_link = 0;
     129         [ -  + ]:        507 :         while ((scn = elf_nextscn(e, scn)) != NULL) {
     130                 :            :                 GElf_Shdr shdr;
     131         [ +  - ]:        507 :                 if (gelf_getshdr(scn, &shdr) != &shdr) {
     132                 :          0 :                         ret = EPKG_FATAL;
     133                 :          0 :                         pkg_emit_error("getshdr() for %s failed: %s", fpath,
     134                 :          0 :                                         elf_errmsg(-1));
     135                 :          0 :                         goto cleanup;
     136                 :            :                 }
     137         [ +  + ]:        507 :                 if (shdr.sh_type == SHT_DYNAMIC) {
     138                 :         25 :                         dynamic = scn;
     139                 :         25 :                         sh_link = shdr.sh_link;
     140         [ +  - ]:         25 :                         if (shdr.sh_entsize == 0) {
     141                 :          0 :                                 ret = EPKG_END;
     142                 :          0 :                                 goto cleanup;
     143                 :            :                         }
     144                 :         25 :                         numdyn = shdr.sh_size / shdr.sh_entsize;
     145                 :         25 :                         break;
     146                 :            :                 }
     147                 :            :         }
     148                 :            : 
     149         [ +  - ]:         25 :         if (dynamic == NULL) {
     150                 :          0 :                 ret = EPKG_END;
     151                 :          0 :                 goto cleanup; /* not a dynamically linked elf: no results */
     152                 :            :         }
     153                 :            : 
     154                 :            :         struct pkg_abi elf_abi;
     155                 :         25 :         elf_parse_abi(e, &elfhdr, &elf_abi);
     156         [ +  - ]:         25 :         if (elf_abi.arch == PKG_ARCH_UNKNOWN) {
     157                 :          0 :                 ret = EPKG_END;
     158                 :          0 :                 goto cleanup;
     159                 :            :         }
     160                 :            : 
     161         [ +  - ]:         25 :         if (elf_abi.os == PKG_OS_UNKNOWN) {
     162                 :            :                 /* There is no reliable way to identify shared libraries targeting Linux.
     163                 :            :                  * It would be possible to reliably identify Linux executables by checking
     164                 :            :                  * the dynamic linker path in DT_INTERP. Shared libraries however do not
     165                 :            :                  * have DT_INTERP set.
     166                 :            :                  *
     167                 :            :                  * Reading the notes section for NT_GNU_ABI_TAG is not sufficient either
     168                 :            :                  * as this is only required for executables, not shared libraries.
     169                 :            :                  * See https://refspecs.linuxfoundation.org/LSB_1.2.0/gLSB/noteabitag.html
     170                 :            :                  *
     171                 :            :                  * Therefore, if pkg is targeting Linux assume that ELF files with unknown
     172                 :            :                  * target OS are also targeting Linux.
     173                 :            :                  *
     174                 :            :                  * Furthermore, if pkg is targeting FreeBSD also assume that ELF
     175                 :            :                  * files with unknown target OS are targeting Linux. This is consistent
     176                 :            :                  * with the behavior of the FreeBSD kernel, which falls back to Linux by
     177                 :            :                  * default if it is unable to determine the target OS of an ELF file.
     178                 :            :                  * (This behavior can be overridden with a fallback_brand sysctl.)
     179                 :            :                  *
     180                 :            :                  * We could add a pkg option to configure the fallback OS
     181                 :            :                  * in the future if necessary.
     182                 :            :                  */
     183   [ #  #  #  # ]:          0 :                 if (ctx.abi.os == PKG_OS_LINUX || ctx.abi.os == PKG_OS_FREEBSD) {
     184                 :          0 :                         elf_abi.os = PKG_OS_LINUX;
     185                 :          0 :                 } else {
     186                 :          0 :                         ret = EPKG_END;
     187                 :          0 :                         goto cleanup;
     188                 :            :                 }
     189                 :          0 :         }
     190                 :            : 
     191                 :         25 :         enum pkg_shlib_flags flags = pkg_shlib_flags_from_abi(&elf_abi);
     192   [ +  -  +  - ]:         25 :         if ((flags & PKG_SHLIB_FLAGS_COMPAT_LINUX) == 0 && elf_abi.os != ctx.abi.os) {
     193                 :          0 :                 ret = EPKG_END;
     194                 :          0 :                 goto cleanup; /* Incompatible OS */
     195                 :            :         }
     196   [ +  -  +  - ]:         25 :         if ((flags & PKG_SHLIB_FLAGS_COMPAT_32) == 0 && elf_abi.arch != ctx.abi.arch) {
     197                 :          0 :                 ret = EPKG_END;
     198                 :          0 :                 goto cleanup; /* Incompatible architecture */
     199                 :            :         }
     200                 :            : 
     201                 :         25 :         Elf_Data *data = elf_getdata(dynamic, NULL);
     202         [ +  - ]:         25 :         if (data == NULL) {
     203                 :          0 :                 ret = EPKG_END; /* Some error occurred, ignore this file */
     204                 :          0 :                 goto cleanup;
     205                 :            :         }
     206                 :            : 
     207         [ +  + ]:        638 :         for (size_t dynidx = 0; dynidx < numdyn; dynidx++) {
     208                 :            :                 GElf_Dyn *dyn, dyn_mem;
     209         [ -  + ]:        613 :                 if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
     210                 :          0 :                         ret = EPKG_FATAL;
     211                 :          0 :                         pkg_emit_error("getdyn() failed for %s: %s", fpath,
     212                 :          0 :                             elf_errmsg(-1));
     213                 :          0 :                         goto cleanup;
     214                 :            :                 }
     215                 :            : 
     216                 :        613 :                 const char *shlib = elf_strptr(e, sh_link, dyn->d_un.d_val);
     217   [ +  +  +  + ]:        613 :                 if (shlib == NULL || *shlib == '\0') {
     218                 :        393 :                         continue;
     219                 :            :                 }
     220                 :            : 
     221                 :            : 
     222                 :            : 
     223         [ +  + ]:        220 :                 if (dyn->d_tag == DT_SONAME) {
     224                 :         10 :                         pkg_addshlib_provided(pkg, shlib, flags);
     225         [ +  + ]:        220 :                 } else if (dyn->d_tag == DT_NEEDED) {
     226                 :         32 :                         pkg_addshlib_required(pkg, shlib, flags);
     227                 :         32 :                 }
     228                 :        245 :         }
     229                 :            : 
     230                 :            : cleanup:
     231         [ -  + ]:         93 :         if (e != NULL)
     232                 :         93 :                 elf_end(e);
     233                 :         93 :         close(fd);
     234                 :            : 
     235                 :         93 :         return (ret);
     236                 :        250 : }
     237                 :            : 
     238                 :            : static int
     239                 :          0 : analyse_fpath(struct pkg *pkg, const char *fpath)
     240                 :            : {
     241                 :            :         const char *dot;
     242                 :            : 
     243                 :          0 :         dot = strrchr(fpath, '.');
     244                 :            : 
     245         [ #  # ]:          0 :         if (dot == NULL)        /* No extension */
     246                 :          0 :                 return (EPKG_OK);
     247                 :            : 
     248   [ #  #  #  # ]:          0 :         if (dot[1] == 'a' && dot[2] == '\0')
     249                 :          0 :                 pkg->flags |= PKG_CONTAINS_STATIC_LIBS;
     250                 :            : 
     251   [ #  #  #  #  :          0 :         if ((dot[1] == 'l' && dot[2] == 'a' && dot[3] == '\0'))
                   #  # ]
     252                 :          0 :                 pkg->flags |= PKG_CONTAINS_LA;
     253                 :            : 
     254                 :          0 :         return (EPKG_OK);
     255                 :          0 : }
     256                 :            : 
     257                 :            : static enum pkg_arch
     258                 :          8 : aeabi_parse_arm_attributes(void *data, size_t length)
     259                 :            : {
     260                 :            :         uint32_t sect_len;
     261                 :          8 :         uint8_t *section = data;
     262                 :            : 
     263                 :            : #define MOVE(len) do {          \
     264                 :            :         assert(length >= (len)); \
     265                 :            :         section += (len);       \
     266                 :            :         length -= (len);        \
     267                 :            : } while (0)
     268                 :            : 
     269   [ +  -  -  + ]:          8 :         if (length == 0 || *section != 'A')
     270                 :          0 :                 return (PKG_ARCH_UNKNOWN);
     271         [ +  - ]:          8 :         MOVE(1);
     272                 :            : 
     273                 :            :         /* Read the section length */
     274         [ -  + ]:          8 :         if (length < sizeof(sect_len))
     275                 :          0 :                 return (PKG_ARCH_UNKNOWN);
     276                 :          8 :         memcpy(&sect_len, section, sizeof(sect_len));
     277                 :            : 
     278                 :            :         /*
     279                 :            :          * The section length should be no longer than the section it is within
     280                 :            :          */
     281         [ -  + ]:          8 :         if (sect_len > length)
     282                 :          0 :                 return (PKG_ARCH_UNKNOWN);
     283                 :            : 
     284         [ +  - ]:          8 :         MOVE(sizeof(sect_len));
     285                 :            : 
     286                 :            :         /* Skip the vendor name */
     287         [ -  + ]:         48 :         while (length != 0) {
     288         [ +  + ]:         48 :                 if (*section == '\0')
     289                 :          8 :                         break;
     290         [ -  + ]:         40 :                 MOVE(1);
     291                 :            :         }
     292         [ +  - ]:          8 :         if (length == 0)
     293                 :          0 :                 return (PKG_ARCH_UNKNOWN);
     294         [ +  - ]:          8 :         MOVE(1);
     295                 :            : 
     296         [ -  + ]:          8 :         while (length != 0) {
     297                 :            :                 uint32_t tag_length;
     298                 :            : 
     299   [ -  -  +  - ]:          8 :                 switch(*section) {
     300                 :            :                 case 1: /* Tag_File */
     301         [ +  - ]:          8 :                         MOVE(1);
     302         [ -  + ]:          8 :                         if (length < sizeof(tag_length))
     303                 :          0 :                                 return (PKG_ARCH_UNKNOWN);
     304                 :          8 :                         memcpy(&tag_length, section, sizeof(tag_length));
     305                 :          8 :                         break;
     306                 :            :                 case 2: /* Tag_Section */
     307                 :          0 :                 case 3: /* Tag_Symbol */
     308                 :            :                 default:
     309                 :          0 :                         return (PKG_ARCH_UNKNOWN);
     310                 :            :                 }
     311                 :            :                 /* At least space for the tag and size */
     312         [ -  + ]:          8 :                 if (tag_length <= 5)
     313                 :          0 :                         return (PKG_ARCH_UNKNOWN);
     314                 :          8 :                 tag_length--;
     315                 :            :                 /* Check the tag fits */
     316         [ -  + ]:          8 :                 if (tag_length > length)
     317                 :          0 :                         return (PKG_ARCH_UNKNOWN);
     318                 :            : 
     319                 :            : #define MOVE_TAG(len) do {              \
     320                 :            :         assert(tag_length >= (len)); \
     321                 :            :         MOVE(len);                      \
     322                 :            :         tag_length -= (len);            \
     323                 :            : } while(0)
     324                 :            : 
     325         [ +  - ]:          8 :                 MOVE(sizeof(tag_length));
     326                 :          8 :                 tag_length -= sizeof(tag_length);
     327                 :            : 
     328         [ -  + ]:         24 :                 while (tag_length != 0) {
     329                 :            :                         uint8_t tag;
     330                 :            : 
     331         [ +  - ]:         24 :                         assert(tag_length >= length);
     332                 :            : 
     333                 :         24 :                         tag = *section;
     334   [ -  +  +  - ]:         24 :                         MOVE_TAG(1);
     335                 :            : 
     336                 :            :                         /*
     337                 :            :                          * These tag values come from:
     338                 :            :                          *
     339                 :            :                          * Addenda to, and Errata in, the ABI for the
     340                 :            :                          * ARM Architecture. Release 2.08, section 2.3.
     341                 :            :                          */
     342         [ +  + ]:         24 :                         if (tag == 6) { /* == Tag_CPU_arch */
     343                 :            :                                 uint8_t val;
     344                 :            : 
     345                 :          8 :                                 val = *section;
     346                 :            :                                 /*
     347                 :            :                                  * We don't support values that require
     348                 :            :                                  * more than one byte.
     349                 :            :                                  */
     350         [ -  + ]:          8 :                                 if (val & (1 << 7))
     351                 :          0 :                                         return (PKG_ARCH_UNKNOWN);
     352                 :            : 
     353                 :            :                                 /* We have an ARMv4 or ARMv5 */
     354         [ -  + ]:          8 :                                 if (val <= 5)
     355                 :          0 :                                         return (PKG_ARCH_UNKNOWN);
     356         [ +  + ]:          8 :                                 else if (val == 6) /* We have an ARMv6 */
     357                 :          4 :                                         return (PKG_ARCH_ARMV6);
     358                 :            :                                 else /* We have an ARMv7+ */
     359                 :          4 :                                         return (PKG_ARCH_ARMV7);
     360   [ +  -  +  +  :         24 :                         } else if (tag == 4 || tag == 5 || tag == 32 ||
             -  +  +  - ]
     361         [ -  + ]:          8 :                             tag == 65 || tag == 67) {
     362   [ +  +  -  +  :        132 :                                 while (*section != '\0' && length != 0)
                   +  + ]
     363   [ +  -  +  - ]:        116 :                                         MOVE_TAG(1);
     364         [ +  - ]:         16 :                                 if (tag_length == 0)
     365                 :          0 :                                         return (PKG_ARCH_UNKNOWN);
     366                 :            :                                 /* Skip the last byte */
     367   [ +  -  +  - ]:         16 :                                 MOVE_TAG(1);
     368   [ #  #  #  #  :         16 :                         } else if ((tag >= 7 && tag <= 31) || tag == 34 ||
             #  #  #  # ]
     369   [ #  #  #  #  :          0 :                             tag == 36 || tag == 38 || tag == 42 || tag == 44 ||
             #  #  #  # ]
     370   [ #  #  #  #  :          0 :                             tag == 64 || tag == 66 || tag == 68 || tag == 70) {
                   #  # ]
     371                 :            :                                 /* Skip the uleb128 data */
     372   [ #  #  #  #  :          0 :                                 while (*section & (1 << 7) && length != 0)
                   #  # ]
     373   [ #  #  #  # ]:          0 :                                         MOVE_TAG(1);
     374         [ #  # ]:          0 :                                 if (tag_length == 0)
     375                 :          0 :                                         return (PKG_ARCH_UNKNOWN);
     376                 :            :                                 /* Skip the last byte */
     377   [ #  #  #  # ]:          0 :                                 MOVE_TAG(1);
     378                 :          0 :                         } else
     379                 :          0 :                                 return (PKG_ARCH_UNKNOWN);
     380                 :            : #undef MOVE_TAG
     381                 :            :                 }
     382                 :            : 
     383                 :          0 :                 break;
     384                 :            :         }
     385                 :          0 :         return (PKG_ARCH_UNKNOWN);
     386                 :            : #undef MOVE
     387                 :          8 : }
     388                 :            : 
     389                 :            : static enum pkg_arch
     390                 :        913 : elf_parse_arch(Elf *elf, GElf_Ehdr *ehdr)
     391                 :            : {
     392   [ +  +  -  +  :        913 :         switch (ehdr->e_machine) {
             +  +  +  + ]
     393                 :            :         case EM_386:
     394                 :          4 :                 return (PKG_ARCH_I386);
     395                 :            :         case EM_X86_64:
     396                 :        881 :                 return (PKG_ARCH_AMD64);
     397                 :            :         case EM_AARCH64:
     398                 :          4 :                 return (PKG_ARCH_AARCH64);
     399                 :            :         case EM_ARM:
     400                 :            :                 /* Only support EABI */
     401         [ +  - ]:          8 :                 if ((ehdr->e_flags & EF_ARM_EABIMASK) == 0) {
     402                 :          0 :                         return (PKG_ARCH_UNKNOWN);
     403                 :            :                 }
     404                 :            : 
     405                 :            :                 size_t shstrndx;
     406                 :          8 :                 elf_getshdrstrndx(elf, &shstrndx);
     407                 :            : 
     408                 :            :                 GElf_Shdr shdr;
     409                 :          8 :                 Elf_Scn *scn = NULL;
     410         [ -  + ]:        208 :                 while ((scn = elf_nextscn(elf, scn)) != NULL) {
     411         [ -  + ]:        208 :                         if (gelf_getshdr(scn, &shdr) != &shdr) {
     412                 :          0 :                                 break;
     413                 :            :                         }
     414                 :        208 :                         const char *sh_name = elf_strptr(elf, shstrndx, shdr.sh_name);
     415         [ -  + ]:        208 :                         if (sh_name == NULL) {
     416                 :          0 :                                 continue;
     417                 :            :                         }
     418         [ +  + ]:        208 :                         if (STREQ(".ARM.attributes", sh_name)) {
     419                 :          8 :                                 Elf_Data *data = elf_getdata(scn, NULL);
     420                 :          8 :                                 return (aeabi_parse_arm_attributes(data->d_buf, data->d_size));
     421                 :            :                         }
     422                 :            :                 }
     423                 :          0 :                 break;
     424                 :            :         case EM_PPC:
     425                 :          4 :                 return (PKG_ARCH_POWERPC);
     426                 :            :         case EM_PPC64:
     427      [ -  +  + ]:          8 :                 switch (ehdr->e_ident[EI_DATA]) {
     428                 :            :                 case ELFDATA2MSB:
     429                 :          4 :                         return (PKG_ARCH_POWERPC64);
     430                 :            :                 case ELFDATA2LSB:
     431                 :          4 :                         return (PKG_ARCH_POWERPC64LE);
     432                 :            :                 }
     433                 :          0 :                 break;
     434                 :            :         case EM_RISCV:
     435      [ -  -  + ]:          4 :                 switch (ehdr->e_ident[EI_CLASS]) {
     436                 :            :                 case ELFCLASS32:
     437                 :          0 :                         return (PKG_ARCH_RISCV32);
     438                 :            :                 case ELFCLASS64:
     439                 :          4 :                         return (PKG_ARCH_RISCV64);
     440                 :            :                 }
     441                 :          0 :                 break;
     442                 :            :         }
     443                 :            : 
     444                 :          0 :         return (PKG_ARCH_UNKNOWN);
     445                 :        913 : }
     446                 :            : 
     447                 :            : /* Returns true if the OS and version were successfully parsed */
     448                 :            : static bool
     449                 :        925 : elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct pkg_abi *abi)
     450                 :            : {
     451                 :            :         Elf_Note note;
     452                 :            :         char *src;
     453                 :            :         uint32_t gnu_abi_tag[4];
     454                 :        925 :         int note_ost[6] = {
     455                 :            :                 PKG_OS_LINUX,
     456                 :            :                 PKG_OS_UNKNOWN, /* GNU Hurd */
     457                 :            :                 PKG_OS_UNKNOWN, /* Solaris */
     458                 :            :                 PKG_OS_FREEBSD,
     459                 :            :                 PKG_OS_NETBSD,
     460                 :            :                 PKG_OS_UNKNOWN, /* Syllable */
     461                 :            :         };
     462                 :        925 :         uint32_t version = 0;
     463                 :        925 :         int version_style = 1;
     464                 :            : 
     465                 :        925 :         src = data->d_buf;
     466                 :            : 
     467         [ +  + ]:        961 :         while ((uintptr_t)src < ((uintptr_t)data->d_buf + data->d_size)) {
     468                 :        949 :                 memcpy(&note, src, sizeof(Elf_Note));
     469                 :        949 :                 src += sizeof(Elf_Note);
     470   [ +  +  -  + ]:        965 :                 if ((strncmp ((const char *) src, "FreeBSD", note.n_namesz) == 0) ||
     471         [ +  + ]:         20 :                     (strncmp ((const char *) src, "DragonFly", note.n_namesz) == 0) ||
     472         [ +  - ]:         16 :                     (strncmp ((const char *) src, "NetBSD", note.n_namesz) == 0) ||
     473                 :         16 :                     (note.n_namesz == 0)) {
     474         [ +  + ]:        933 :                         if (note.n_type == NT_VERSION) {
     475                 :        909 :                                 version_style = 1;
     476                 :        909 :                                 break;
     477                 :            :                         }
     478                 :         24 :                 }
     479         [ +  + ]:         40 :                 if (strncmp ((const char *) src, "GNU", note.n_namesz) == 0) {
     480         [ +  + ]:         16 :                         if (note.n_type == NT_GNU_ABI_TAG) {
     481                 :          4 :                                 version_style = 2;
     482                 :          4 :                                 break;
     483                 :            :                         }
     484                 :         12 :                 }
     485                 :         36 :                 src += roundup2(note.n_namesz + note.n_descsz, 4);
     486                 :            :         }
     487         [ +  + ]:        925 :         if ((uintptr_t)src >= ((uintptr_t)data->d_buf + data->d_size)) {
     488                 :         12 :                 return (false);
     489                 :            :         }
     490         [ +  + ]:        913 :         if (version_style == 2) {
     491                 :            :                 /*
     492                 :            :                  * NT_GNU_ABI_TAG
     493                 :            :                  * Operating system (OS) ABI information.  The
     494                 :            :                  * desc field contains 4 words:
     495                 :            :                  * word 0: OS descriptor (ELF_NOTE_OS_LINUX, ELF_NOTE_OS_GNU, etc)
     496                 :            :                  * word 1: major version of the ABI
     497                 :            :                  * word 2: minor version of the ABI
     498                 :            :                  * word 3: subminor version of the ABI
     499                 :            :                  */
     500                 :          4 :                 src += roundup2(note.n_namesz, 4);
     501         [ -  + ]:          4 :                 if (elfhdr->e_ident[EI_DATA] == ELFDATA2MSB) {
     502         [ #  # ]:          0 :                         for (int wdndx = 0; wdndx < 4; wdndx++) {
     503                 :          0 :                                 gnu_abi_tag[wdndx] = be32dec(src);
     504                 :          0 :                                 src += 4;
     505                 :          0 :                         }
     506                 :          0 :                 } else {
     507         [ +  + ]:         20 :                         for (int wdndx = 0; wdndx < 4; wdndx++) {
     508                 :         16 :                                 gnu_abi_tag[wdndx] = le32dec(src);
     509                 :         16 :                                 src += 4;
     510                 :         16 :                         }
     511                 :            :                 }
     512         [ +  - ]:          4 :                 if (gnu_abi_tag[0] < 6) {
     513                 :          4 :                         abi->os= note_ost[gnu_abi_tag[0]];
     514                 :          4 :                 } else {
     515                 :          0 :                         abi->os = PKG_OS_UNKNOWN;
     516                 :            :                 }
     517                 :          4 :         } else {
     518         [ +  - ]:        909 :                 if (note.n_namesz == 0) {
     519                 :          0 :                         abi->os = PKG_OS_UNKNOWN;
     520                 :          0 :                 } else {
     521         [ +  + ]:        909 :                         if (STREQ(src, "FreeBSD"))
     522                 :        905 :                                 abi->os = PKG_OS_FREEBSD;
     523         [ -  + ]:          4 :                         else if (STREQ(src, "DragonFly"))
     524                 :          4 :                                 abi->os = PKG_OS_DRAGONFLY;
     525         [ #  # ]:          0 :                         else if (STREQ(src, "NetBSD"))
     526                 :          0 :                                 abi->os = PKG_OS_NETBSD;
     527                 :            :                 }
     528                 :        909 :                 src += roundup2(note.n_namesz, 4);
     529         [ +  + ]:        909 :                 if (elfhdr->e_ident[EI_DATA] == ELFDATA2MSB)
     530                 :          8 :                         version = be32dec(src);
     531                 :            :                 else
     532                 :        901 :                         version = le32dec(src);
     533                 :            :         }
     534                 :            : 
     535         [ +  + ]:        913 :         if (version_style == 2) {
     536         [ +  - ]:          4 :                 if (abi->os == PKG_OS_LINUX) {
     537                 :          4 :                         abi->major = gnu_abi_tag[1];
     538                 :          4 :                         abi->minor = gnu_abi_tag[2];
     539                 :          4 :                 } else {
     540                 :          0 :                         abi->major = gnu_abi_tag[1];
     541                 :          0 :                         abi->minor = gnu_abi_tag[2];
     542                 :          0 :                         abi->patch = gnu_abi_tag[3];
     543                 :            :                 }
     544                 :          4 :         } else {
     545   [ -  +  -  +  :        909 :                 switch (abi->os) {
                      - ]
     546                 :            :                 case PKG_OS_UNKNOWN:
     547                 :          0 :                         break;
     548                 :            :                 case PKG_OS_FREEBSD:
     549                 :        905 :                         pkg_abi_set_freebsd_osversion(abi, version);
     550                 :        905 :                         break;
     551                 :            :                 case PKG_OS_DRAGONFLY:
     552                 :          4 :                         abi->major = version / 100000;
     553                 :          4 :                         abi->minor = (((version / 100 % 1000)+1)/2)*2;
     554                 :          4 :                         break;
     555                 :            :                 case PKG_OS_NETBSD:
     556                 :          0 :                         abi->major = (version + 1000000) / 100000000;
     557                 :          0 :                         break;
     558                 :            :                 default:
     559                 :          0 :                         assert(0);
     560                 :            :                 }
     561                 :            :         }
     562                 :            : 
     563                 :        913 :         return (true);
     564                 :        925 : }
     565                 :            : 
     566                 :            : static void
     567                 :        913 : elf_parse_abi(Elf *elf, GElf_Ehdr *ehdr, struct pkg_abi *abi)
     568                 :            : {
     569                 :        913 :         *abi = (struct pkg_abi){0};
     570                 :            : 
     571                 :        913 :         Elf_Scn *scn = NULL;
     572         [ +  + ]:      28345 :         while ((scn = elf_nextscn(elf, scn)) != NULL) {
     573                 :            :                 GElf_Shdr shdr;
     574         [ -  + ]:      27432 :                 if (gelf_getshdr(scn, &shdr) != &shdr) {
     575                 :          0 :                         pkg_emit_error("getshdr() failed: %s.", elf_errmsg(-1));
     576                 :          0 :                         return;
     577                 :            :                 }
     578                 :            : 
     579         [ +  + ]:      27432 :                 if (shdr.sh_type == SHT_NOTE) {
     580                 :        925 :                         Elf_Data *data = elf_getdata(scn, NULL);
     581                 :            :                         /*
     582                 :            :                          * loop over all the note section and override what
     583                 :            :                          * should be overridden if any
     584                 :            :                          */
     585                 :        925 :                         elf_note_analyse(data, ehdr, abi);
     586                 :        925 :                 }
     587                 :            :         }
     588                 :            : 
     589                 :        913 :         abi->arch = elf_parse_arch(elf, ehdr);
     590                 :        913 : }
     591                 :            : 
     592                 :            : int
     593                 :        925 : pkg_elf_abi_from_fd(int fd, struct pkg_abi *abi)
     594                 :            : {
     595                 :        925 :         Elf *elf = NULL;
     596                 :            :         GElf_Ehdr elfhdr;
     597                 :        925 :         int ret = EPKG_OK;
     598                 :            : 
     599         [ +  - ]:        925 :         if (elf_version(EV_CURRENT) == EV_NONE) {
     600                 :          0 :                 pkg_emit_error("ELF library initialization failed: %s",
     601                 :          0 :                     elf_errmsg(-1));
     602                 :          0 :                 return (EPKG_FATAL);
     603                 :            :         }
     604                 :            : 
     605         [ +  - ]:        925 :         if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
     606                 :          0 :                 ret = EPKG_FATAL;
     607                 :          0 :                 pkg_emit_error("elf_begin() failed: %s.", elf_errmsg(-1));
     608                 :          0 :                 goto cleanup;
     609                 :            :         }
     610                 :            : 
     611         [ +  + ]:        925 :         if (gelf_getehdr(elf, &elfhdr) == NULL) {
     612                 :         37 :                 ret = EPKG_WARN;
     613                 :         37 :                 pkg_debug(1, "getehdr() failed: %s.", elf_errmsg(-1));
     614                 :         37 :                 goto cleanup;
     615                 :            :         }
     616                 :            : 
     617                 :        888 :         elf_parse_abi(elf, &elfhdr, abi);
     618                 :            : 
     619         [ +  - ]:        888 :         if (abi->os == PKG_OS_UNKNOWN) {
     620                 :          0 :                 ret = EPKG_FATAL;
     621                 :          0 :                 pkg_emit_error("failed to determine the operating system");
     622                 :          0 :                 goto cleanup;
     623                 :            :         }
     624                 :            : 
     625         [ +  - ]:        888 :         if (abi->arch == PKG_ARCH_UNKNOWN) {
     626                 :          0 :                 ret = EPKG_FATAL;
     627                 :          0 :                 pkg_emit_error("failed to determine the architecture");
     628                 :          0 :                 goto cleanup;
     629                 :            :         }
     630                 :            : 
     631                 :            : cleanup:
     632         [ -  + ]:        925 :         if (elf != NULL)
     633                 :        925 :                 elf_end(elf);
     634                 :        925 :         return (ret);
     635                 :        925 : }
     636                 :            : 
     637                 :        323 : int pkg_analyse_init_elf(__unused const char* stage) {
     638         [ +  - ]:        323 :         if (elf_version(EV_CURRENT) == EV_NONE)
     639                 :          0 :                 return (EPKG_FATAL);
     640                 :        323 :         return (EPKG_OK);
     641                 :        323 : }
     642                 :            : 
     643                 :        250 : int pkg_analyse_elf(const bool developer_mode, struct pkg *pkg, const char *fpath)
     644                 :            : {
     645                 :        250 :         int ret = analyse_elf(pkg, fpath);
     646         [ +  - ]:        250 :         if (developer_mode) {
     647   [ #  #  #  # ]:          0 :                 if (ret != EPKG_OK && ret != EPKG_END) {
     648                 :          0 :                         return EPKG_WARN;
     649                 :            :                 }
     650                 :          0 :                 analyse_fpath(pkg, fpath);
     651                 :          0 :         }
     652                 :        250 :         return ret;
     653                 :        250 : }
     654                 :            : 
     655                 :        323 : int pkg_analyse_close_elf() {
     656                 :        323 :         return EPKG_OK;
     657                 :            : }

Generated by: LCOV version 1.15