Home | History | Annotate | Download | only in libelf
      1 /* Compute simple checksum from permanent parts of the ELF file.
      2    Copyright (C) 2002, 2003, 2004, 2005, 2009, 2015 Red Hat, Inc.
      3    This file is part of elfutils.
      4    Written by Ulrich Drepper <drepper (at) redhat.com>, 2002.
      5 
      6    This file is free software; you can redistribute it and/or modify
      7    it under the terms of either
      8 
      9      * the GNU Lesser General Public License as published by the Free
     10        Software Foundation; either version 3 of the License, or (at
     11        your option) any later version
     12 
     13    or
     14 
     15      * the GNU General Public License as published by the Free
     16        Software Foundation; either version 2 of the License, or (at
     17        your option) any later version
     18 
     19    or both in parallel, as here.
     20 
     21    elfutils is distributed in the hope that it will be useful, but
     22    WITHOUT ANY WARRANTY; without even the implied warranty of
     23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     24    General Public License for more details.
     25 
     26    You should have received copies of the GNU General Public License and
     27    the GNU Lesser General Public License along with this program.  If
     28    not, see <http://www.gnu.org/licenses/>.  */
     29 
     30 #ifdef HAVE_CONFIG_H
     31 # include <config.h>
     32 #endif
     33 
     34 #include <assert.h>
     35 #include <endian.h>
     36 #include <stdbool.h>
     37 #include <stddef.h>
     38 #include <string.h>
     39 
     40 #include "gelf.h"
     41 #include "libelfP.h"
     42 #include "elf-knowledge.h"
     43 
     44 #ifndef LIBELFBITS
     45 # define LIBELFBITS 32
     46 #endif
     47 
     48 
     49 #define process_block(crc, data) \
     50   __libelf_crc32 (crc, data->d_buf, data->d_size)
     51 
     52 
     53 long int
     54 elfw2(LIBELFBITS,checksum) (Elf *elf)
     55 {
     56   size_t shstrndx;
     57   Elf_Scn *scn;
     58   long int result = 0;
     59   unsigned char *ident;
     60   bool same_byte_order;
     61 
     62   if (elf == NULL)
     63     return -1l;
     64 
     65   /* Find the section header string table.  */
     66   if  (INTUSE(elf_getshdrstrndx) (elf, &shstrndx) < 0)
     67     {
     68       /* This can only happen if the ELF handle is not for real.  */
     69       __libelf_seterrno (ELF_E_INVALID_HANDLE);
     70       return -1l;
     71     }
     72 
     73   /* Determine whether the byte order of the file and that of the host
     74      is the same.  */
     75   ident = elf->state.ELFW(elf,LIBELFBITS).ehdr->e_ident;
     76   same_byte_order = ((ident[EI_DATA] == ELFDATA2LSB
     77 		      && __BYTE_ORDER == __LITTLE_ENDIAN)
     78 		     || (ident[EI_DATA] == ELFDATA2MSB
     79 			 && __BYTE_ORDER == __BIG_ENDIAN));
     80 
     81   /* If we don't have native byte order, we will likely need to
     82      convert the data with xlate functions.  We do it upfront instead
     83      of relocking mid-iteration. */
     84   if (!likely (same_byte_order))
     85     rwlock_wrlock (elf->lock);
     86   else
     87     rwlock_rdlock (elf->lock);
     88 
     89   /* Iterate over all sections to find those which are not strippable.  */
     90   scn = NULL;
     91   while ((scn = INTUSE(elf_nextscn) (elf, scn)) != NULL)
     92     {
     93       GElf_Shdr shdr_mem;
     94       GElf_Shdr *shdr;
     95       Elf_Data *data;
     96 
     97       /* Get the section header.  */
     98       shdr = INTUSE(gelf_getshdr) (scn, &shdr_mem);
     99       if (shdr == NULL)
    100 	{
    101 	  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
    102 	  result = -1l;
    103 	  goto out;
    104 	}
    105 
    106       if (SECTION_STRIP_P (shdr,
    107 			   INTUSE(elf_strptr) (elf, shstrndx, shdr->sh_name),
    108 			   true))
    109 	/* The section can be stripped.  Don't use it.  */
    110 	continue;
    111 
    112       /* Do not look at NOBITS sections.  */
    113       if (shdr->sh_type == SHT_NOBITS)
    114 	continue;
    115 
    116       /* To compute the checksum we need to get to the data.  For
    117 	 repeatable results we must use the external format.  The data
    118 	 we get with 'elf'getdata' might be changed for endianess
    119 	 reasons.  Therefore we use 'elf_rawdata' if possible.  But
    120 	 this function can fail if the data was constructed by the
    121 	 program.  In this case we have to use 'elf_getdata' and
    122 	 eventually convert the data to the external format.  */
    123       data = INTUSE(elf_rawdata) (scn, NULL);
    124       if (data != NULL)
    125 	{
    126 	  /* The raw data is available.  */
    127 	  result = process_block (result, data);
    128 
    129 	  /* Maybe the user added more data.  These blocks cannot be
    130 	     read using 'elf_rawdata'.  Simply proceed with looking
    131 	     for more data block with 'elf_getdata'.  */
    132 	}
    133 
    134       /* Iterate through the list of data blocks.  */
    135       while ((data = INTUSE(elf_getdata) (scn, data)) != NULL)
    136 	/* If the file byte order is the same as the host byte order
    137 	   process the buffer directly.  If the data is just a stream
    138 	   of bytes which the library will not convert we can use it
    139 	   as well.  */
    140 	if (likely (same_byte_order) || data->d_type == ELF_T_BYTE)
    141 	  result = process_block (result, data);
    142 	else
    143 	  {
    144 	    /* Convert the data to file byte order.  */
    145 	    if (INTUSE(elfw2(LIBELFBITS,xlatetof)) (data, data, ident[EI_DATA])
    146 		== NULL)
    147 	      {
    148 		result = -1l;
    149 		goto out;
    150 	      }
    151 
    152 	    result = process_block (result, data);
    153 
    154 	    /* And convert it back.  */
    155 	    if (INTUSE(elfw2(LIBELFBITS,xlatetom)) (data, data, ident[EI_DATA])
    156 		== NULL)
    157 	      {
    158 		result = -1l;
    159 		goto out;
    160 	      }
    161 	  }
    162     }
    163 
    164  out:
    165   rwlock_unlock (elf->lock);
    166   return result;
    167 }
    168 INTDEF(elfw2(LIBELFBITS,checksum))
    169