Back to index

glibc  2.9
check-textrel.c
Go to the documentation of this file.
00001 /* Check for text relocations in DSOs.
00002    Copyright (C) 2002, 2003, 2006 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contribute by Ulrich Drepper <drepper@redhat.com>. 2002.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <byteswap.h>
00022 #include <elf.h>
00023 #include <endian.h>
00024 #include <fcntl.h>
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <unistd.h>
00029 
00030 
00031 #ifdef BITS
00032 
00033 # define AB(name) _AB (name, BITS)
00034 # define _AB(name, bits) __AB (name, bits)
00035 # define __AB(name, bits) name##bits
00036 # define E(name) _E (name, BITS)
00037 # define _E(name, bits) __E (name, bits)
00038 # define __E(name, bits) Elf##bits##_##name
00039 # define SWAP(val) \
00040   ({ __typeof (val) __res;                                           \
00041      if (((ehdr.e_ident[EI_DATA] == ELFDATA2MSB                             \
00042           && BYTE_ORDER == LITTLE_ENDIAN)                            \
00043          || (ehdr.e_ident[EI_DATA] == ELFDATA2LSB                           \
00044              && BYTE_ORDER == BIG_ENDIAN))                                  \
00045         && sizeof (val) != 1)                                               \
00046        {                                                             \
00047         if (sizeof (val) == 2)                                              \
00048           __res = bswap_16 (val);                                    \
00049         else if (sizeof (val) == 4)                                         \
00050           __res = bswap_32 (val);                                    \
00051         else                                                         \
00052           __res = bswap_64 (val);                                    \
00053        }                                                             \
00054      else                                                            \
00055        __res = (val);                                                       \
00056      __res; })
00057 
00058 
00059 static int
00060 AB(handle_file) (const char *fname, int fd)
00061 {
00062   E(Ehdr) ehdr;
00063 
00064   if (pread (fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
00065     {
00066     read_error:
00067       printf ("%s: read error: %m\n", fname);
00068       return 1;
00069     }
00070 
00071   const size_t phnum = SWAP (ehdr.e_phnum);
00072   const size_t phentsize = SWAP (ehdr.e_phentsize);
00073 
00074   /* Read the program header.  */
00075   E(Phdr) *phdr = alloca (phentsize * phnum);
00076   if (pread (fd, phdr, phentsize * phnum, SWAP (ehdr.e_phoff))
00077       != phentsize * phnum)
00078     goto read_error;
00079 
00080   /* Search for the PT_DYNAMIC entry.  */
00081   size_t cnt;
00082   E(Phdr) *dynphdr = NULL;
00083   for (cnt = 0; cnt < phnum; ++cnt)
00084     if (SWAP (phdr[cnt].p_type) == PT_DYNAMIC)
00085       dynphdr = &phdr[cnt];
00086     else if (SWAP (phdr[cnt].p_type) == PT_LOAD
00087             && (SWAP (phdr[cnt].p_flags) & (PF_X | PF_W)) == (PF_X | PF_W))
00088       {
00089        printf ("%s: segment %zu is executable and writable\n",
00090               fname, cnt);
00091 #if !defined __sparc__ \
00092     && !defined __alpha__ \
00093     && (!defined __powerpc__ || defined __powerpc64__ || defined HAVE_PPC_SECURE_PLT)
00094        /* sparc, sparc64, alpha and powerpc32 (the last one only when using
00095           -mbss-plt) are expected to have PF_X | PF_W segment containing .plt
00096           section, it is part of their ABI.  It is bad security wise, nevertheless
00097           this test shouldn't fail because of this.  */
00098        return 1;
00099 #endif
00100       }
00101 
00102   if (dynphdr == NULL)
00103     {
00104       printf ("%s: no DYNAMIC segment found\n", fname);
00105       return 1;
00106     }
00107 
00108   /* Read the dynamic segment.  */
00109   size_t pmemsz = SWAP(dynphdr->p_memsz);
00110   E(Dyn) *dyn = alloca (pmemsz);
00111   if (pread (fd, dyn, pmemsz, SWAP(dynphdr->p_offset)) != pmemsz)
00112     goto read_error;
00113 
00114   /* Search for an DT_TEXTREL entry of DT_FLAGS with the DF_TEXTREL
00115      bit set.  */
00116   for (cnt = 0; (cnt + 1) * sizeof (E(Dyn)) - 1 < pmemsz; ++cnt)
00117     {
00118       unsigned int tag = SWAP (dyn[cnt].d_tag);
00119 
00120       if (tag == DT_NULL)
00121        /* We reached the end.  */
00122        break;
00123 
00124       if (tag == DT_TEXTREL
00125          || (tag == DT_FLAGS
00126              && (SWAP (dyn[cnt].d_un.d_val) & DF_TEXTREL) != 0))
00127        {
00128          /* Urgh!  The DSO has text relocations.  */
00129          printf ("%s: text relocations used\n", fname);
00130          return 1;
00131        }
00132     }
00133 
00134   printf ("%s: OK\n", fname);
00135 
00136   return 0;
00137 }
00138 
00139 # undef BITS
00140 #else
00141 
00142 # define BITS 32
00143 # include "check-textrel.c"
00144 
00145 # define BITS 64
00146 # include "check-textrel.c"
00147 
00148 
00149 static int
00150 handle_file (const char *fname)
00151 {
00152   int fd = open (fname, O_RDONLY);
00153   if (fd == -1)
00154     {
00155       printf ("cannot open %s: %m\n", fname);
00156       return 1;
00157     }
00158 
00159   /* Read was is supposed to be the ELF header.  Read the initial
00160      bytes to determine whether this is a 32 or 64 bit file.  */
00161   char ident[EI_NIDENT];
00162   if (read (fd, ident, EI_NIDENT) != EI_NIDENT)
00163     {
00164       printf ("%s: read error: %m\n", fname);
00165       close (fd);
00166       return 1;
00167     }
00168 
00169   if (memcmp (&ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
00170     {
00171       printf ("%s: not an ELF file\n", fname);
00172       close (fd);
00173       return 1;
00174     }
00175 
00176   int result;
00177   if (ident[EI_CLASS] == ELFCLASS64)
00178     result = handle_file64 (fname, fd);
00179   else
00180     result = handle_file32 (fname, fd);
00181 
00182   close (fd);
00183 
00184   return result;
00185 }
00186 
00187 
00188 int
00189 main (int argc, char *argv[])
00190 {
00191   int cnt;
00192   int result = 0;
00193 
00194   for (cnt = 1; cnt < argc; ++cnt)
00195     result |= handle_file (argv[cnt]);
00196 
00197   return result;
00198 }
00199 #endif