Home | History | Annotate | Download | only in soslim
      1 #include <stdio.h>
      2 //#include <common.h>
      3 #include <debug.h>
      4 #include <libelf.h>
      5 #include <libebl.h>
      6 #include <libebl_arm.h>
      7 #include <elf.h>
      8 #include <gelf.h>
      9 #include <string.h>
     10 #include <errno.h>
     11 #include <string.h>
     12 #include <sys/types.h>
     13 #include <sys/stat.h>
     14 #include <fcntl.h>
     15 #include <unistd.h>
     16 #ifdef SUPPORT_ANDROID_PRELINK_TAGS
     17 #include <prelink_info.h>
     18 #endif
     19 
     20 #include <elfcopy.h>
     21 
     22 void clone_elf(Elf *elf, Elf *newelf,
     23                const char *elf_name,
     24                const char *newelf_name,
     25                bool *sym_filter, int num_symbols,
     26                int shady
     27 #ifdef SUPPORT_ANDROID_PRELINK_TAGS
     28                , int *prelinked,
     29                int *elf_little,
     30                long *prelink_addr
     31 #endif
     32                , bool rebuild_shstrtab,
     33                bool strip_debug,
     34                bool dry_run)
     35 {
     36 	GElf_Ehdr ehdr_mem, *ehdr; /* store ELF header of original library */
     37 	size_t shstrndx; /* section-strings-section index */
     38 	size_t shnum; /* number of sections in the original file */
     39 	/* string table for section headers in new file */
     40 	struct Ebl_Strtab *shst = NULL;
     41     int dynamic_idx = -1; /* index in shdr_info[] of .dynamic section */
     42     int dynsym_idx = -1; /* index in shdr_info[] of dynamic symbol table
     43                             section */
     44 
     45     unsigned int cnt;	  /* general-purpose counter */
     46     /* This flag is true when at least one section is dropped or when the
     47        relative order of sections has changed, so that section indices in
     48        the resulting file will be different from those in the original. */
     49     bool sections_dropped_or_rearranged;
     50 	Elf_Scn *scn; /* general-purpose section */
     51 	size_t idx;	  /* general-purporse section index */
     52 
     53 	shdr_info_t *shdr_info = NULL;
     54     unsigned int shdr_info_len = 0;
     55     GElf_Phdr *phdr_info = NULL;
     56 
     57 	/* Get the information from the old file. */
     58 	ehdr = gelf_getehdr (elf, &ehdr_mem);
     59 	FAILIF_LIBELF(NULL == ehdr, gelf_getehdr);
     60 
     61 	/* Create new program header for the elf file */
     62 	FAILIF(gelf_newehdr (newelf, gelf_getclass (elf)) == 0 ||
     63 		   (ehdr->e_type != ET_REL && gelf_newphdr (newelf,
     64 													ehdr->e_phnum) == 0),
     65 		   "Cannot create new file: %s", elf_errmsg (-1));
     66 
     67 #ifdef SUPPORT_ANDROID_PRELINK_TAGS
     68     ASSERT(prelinked);
     69     ASSERT(prelink_addr);
     70     ASSERT(elf_little);
     71     *elf_little = (ehdr->e_ident[EI_DATA] == ELFDATA2LSB);
     72     *prelinked = check_prelinked(elf_name, *elf_little, prelink_addr);
     73 #endif
     74 
     75     INFO("\n\nCALCULATING MODIFICATIONS\n\n");
     76 
     77 	/* Copy out the old program header: notice that if the ELF file does not
     78 	   have a program header, this loop won't execute.
     79 	*/
     80 	INFO("Copying ELF program header...\n");
     81     phdr_info = (GElf_Phdr *)CALLOC(ehdr->e_phnum, sizeof(GElf_Phdr));
     82 	for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) {
     83 		INFO("\tRetrieving entry %d\n", cnt);
     84 		FAILIF_LIBELF(NULL == gelf_getphdr(elf, cnt, phdr_info + cnt),
     85                       gelf_getphdr);
     86         /* -- we update the header at the end
     87         FAILIF_LIBELF(gelf_update_phdr (newelf, cnt, phdr_info + cnt) == 0,
     88                       gelf_update_phdr);
     89         */
     90 	}
     91 
     92     /* Get the section-header strings section.  This section contains the
     93 	   strings used to name the other sections. */
     94 	FAILIF_LIBELF(elf_getshstrndx(elf, &shstrndx) < 0, elf_getshstrndx);
     95 
     96 	/* Get the number of sections. */
     97 	FAILIF_LIBELF(elf_getshnum (elf, &shnum) < 0, elf_getshnum);
     98 	INFO("Original ELF file has %zd sections.\n", shnum);
     99 
    100 	/* Allocate the section-header-info buffer.  We allocate one more entry
    101        for the section-strings section because we regenerate that one and
    102        place it at the very end of the file.  Note that just because we create
    103        an extra entry in the shdr_info array, it does not mean that we create
    104        one more section the header.  We just mark the old section for removal
    105        and create one as the last section.
    106     */
    107 	INFO("Allocating section-header info structure (%zd) bytes...\n",
    108 		 shnum*sizeof (shdr_info_t));
    109     shdr_info_len = rebuild_shstrtab ? shnum + 1 : shnum;
    110 	shdr_info = (shdr_info_t *)CALLOC(shdr_info_len, sizeof (shdr_info_t));
    111 
    112 	/* Iterate over all the sections and initialize the internal section-info
    113 	   array...
    114 	*/
    115 	INFO("Initializing section-header info structure...\n");
    116 	/* Gather information about the sections in this file. */
    117 	scn = NULL;
    118 	cnt = 1;
    119 	while ((scn = elf_nextscn (elf, scn)) != NULL) {
    120 		ASSERT(elf_ndxscn(scn) == cnt);
    121 		shdr_info[cnt].scn = scn;
    122 		FAILIF_LIBELF(NULL == gelf_getshdr(scn, &shdr_info[cnt].shdr),
    123 					  gelf_getshdr);
    124 
    125 		/* Get the name of the section. */
    126 		shdr_info[cnt].name = elf_strptr (elf, shstrndx,
    127 										  shdr_info[cnt].shdr.sh_name);
    128 
    129 		INFO("\tname: %s\n", shdr_info[cnt].name);
    130 		FAILIF(shdr_info[cnt].name == NULL,
    131 			   "Malformed file: section %d name is null\n",
    132 			   cnt);
    133 
    134 		/* Mark them as present but not yet investigated.  By "investigating"
    135 		   sections, we mean that we check to see if by stripping other
    136 		   sections, the sections under investigation will be compromised.  For
    137 		   example, if we are removing a section of code, then we want to make
    138 		   sure that the symbol table does not contain symbols that refer to
    139 		   this code, so we investigate the symbol table.  If we do find such
    140 		   symbols, we will not strip the code section.
    141 		*/
    142 		shdr_info[cnt].idx = 1;
    143 
    144 		/* Remember the shdr.sh_link value.  We need to remember this value
    145 		   for those sections that refer to other sections.  For example,
    146 		   we need to remember it for relocation-entry sections, because if
    147 		   we modify the symbol table that a relocation-entry section is
    148 		   relative to, then we need to patch the relocation section.  By the
    149 		   time we get to deciding whether we need to patch the relocation
    150 		   section, we will have overwritten its header's sh_link field with
    151 		   a new value.
    152 		*/
    153 		shdr_info[cnt].old_shdr = shdr_info[cnt].shdr;
    154         INFO("\t\toriginal sh_link: %08d\n", shdr_info[cnt].old_shdr.sh_link);
    155         INFO("\t\toriginal sh_addr: %lld\n", shdr_info[cnt].old_shdr.sh_addr);
    156         INFO("\t\toriginal sh_offset: %lld\n",
    157              shdr_info[cnt].old_shdr.sh_offset);
    158         INFO("\t\toriginal sh_size: %lld\n", shdr_info[cnt].old_shdr.sh_size);
    159 
    160         if (shdr_info[cnt].shdr.sh_type == SHT_DYNAMIC) {
    161             INFO("\t\tthis is the SHT_DYNAMIC section [%s] at index %d\n",
    162                  shdr_info[cnt].name,
    163                  cnt);
    164             dynamic_idx = cnt;
    165         }
    166         else if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM) {
    167             INFO("\t\tthis is the SHT_DYNSYM section [%s] at index %d\n",
    168                  shdr_info[cnt].name,
    169                  cnt);
    170             dynsym_idx = cnt;
    171         }
    172 
    173 		FAILIF(shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX,
    174 			   "Cannot handle sh_type SHT_SYMTAB_SHNDX!\n");
    175 		FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GROUP,
    176 			   "Cannot handle sh_type SHT_GROUP!\n");
    177 		FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GNU_versym,
    178 			   "Cannot handle sh_type SHT_GNU_versym!\n");
    179 
    180 		/* Increment the counter. */
    181 		++cnt;
    182 	} /* while */
    183 
    184 	/* Get the EBL handling. */
    185 	Ebl *ebl = ebl_openbackend (elf);
    186 	FAILIF_LIBELF(NULL == ebl, ebl_openbackend);
    187     FAILIF_LIBELF(0 != arm_init(elf, ehdr->e_machine, ebl, sizeof(Ebl)),
    188                   arm_init);
    189 
    190     if (strip_debug) {
    191 
    192       /* This will actually strip more than just sections.  It will strip
    193          anything not essential to running the image.
    194       */
    195 
    196       INFO("Finding debug sections to strip.\n");
    197 
    198       /* Now determine which sections can go away.  The general rule is that
    199          all sections which are not used at runtime are stripped out.  But
    200          there are a few exceptions:
    201 
    202          - special sections named ".comment" and ".note" are kept
    203          - OS or architecture specific sections are kept since we might not
    204 		 know how to handle them
    205          - if a section is referred to from a section which is not removed
    206 		 in the sh_link or sh_info element it cannot be removed either
    207       */
    208       for (cnt = 1; cnt < shnum; ++cnt) {
    209 		/* Check whether the section can be removed.  */
    210 		if (SECTION_STRIP_P (ebl, elf, ehdr, &shdr_info[cnt].shdr,
    211 							 shdr_info[cnt].name,
    212 							 1,	 /* remove .comment sections */
    213 							 1	 /* remove all debug sections */) ||
    214             /* The macro above is broken--check for .comment explicitly */
    215             !strcmp(".comment", shdr_info[cnt].name)
    216 #ifdef ARM_SPECIFIC_HACKS
    217             ||
    218             /* We ignore this section, that's why we can remove it. */
    219             !strcmp(".stack", shdr_info[cnt].name)
    220 #endif
    221             )
    222         {
    223           /* For now assume this section will be removed.  */
    224           INFO("Section [%s] will be stripped from image.\n",
    225                shdr_info[cnt].name);
    226           shdr_info[cnt].idx = 0;
    227 		}
    228 #ifdef STRIP_STATIC_SYMBOLS
    229 		else if (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) {
    230           /* Mark the static symbol table for removal */
    231           INFO("Section [%s] (static symbol table) will be stripped from image.\n",
    232                shdr_info[cnt].name);
    233           shdr_info[cnt].idx = 0;
    234           if (shdr_info[shdr_info[cnt].shdr.sh_link].shdr.sh_type ==
    235               SHT_STRTAB)
    236           {
    237             /* Mark the symbol table's string table for removal. */
    238             INFO("Section [%s] (static symbol-string table) will be stripped from image.\n",
    239                  shdr_info[shdr_info[cnt].shdr.sh_link].name);
    240             shdr_info[shdr_info[cnt].shdr.sh_link].idx = 0;
    241           }
    242           else {
    243             ERROR("Expecting the sh_link field of a symbol table to point to"
    244                   " associated symbol-strings table!  This is not mandated by"
    245                   " the standard, but is a common practice and the only way "
    246                   " to know for sure which strings table corresponds to which"
    247                   " symbol table!\n");
    248           }
    249 		}
    250 #endif
    251       }
    252 
    253       /* Mark the SHT_NULL section as handled. */
    254       shdr_info[0].idx = 2;
    255 
    256       /* Handle exceptions: section groups and cross-references.  We might have
    257          to repeat this a few times since the resetting of the flag might
    258          propagate.
    259       */
    260       int exceptions_pass = 0;
    261       bool changes;
    262       do {
    263         changes = false;
    264 		INFO("\nHandling exceptions, pass %d\n\n", exceptions_pass++);
    265 		for (cnt = 1; cnt < shnum; ++cnt) {
    266           if (shdr_info[cnt].idx == 0) {
    267             /* If a relocation section is marked as being removed but the
    268                section it is relocating is not, then do not remove the
    269                relocation section.
    270             */
    271             if ((shdr_info[cnt].shdr.sh_type == SHT_REL
    272                  || shdr_info[cnt].shdr.sh_type == SHT_RELA)
    273                 && shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0) {
    274               PRINT("\tSection [%s] will not be removed because the "
    275                     "section it is relocating (%s) stays.\n",
    276                     shdr_info[cnt].name,
    277                     shdr_info[shdr_info[cnt].shdr.sh_info].name);
    278             }
    279           }
    280           if (shdr_info[cnt].idx == 1) {
    281             INFO("Processing section [%s]...\n", shdr_info[cnt].name);
    282 
    283             /* The content of symbol tables we don't remove must not
    284                reference any section which we do remove.  Otherwise
    285                we cannot remove the referred section.
    286             */
    287             if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM ||
    288                 shdr_info[cnt].shdr.sh_type == SHT_SYMTAB)
    289             {
    290               Elf_Data *symdata;
    291               size_t elsize;
    292 
    293               INFO("\tSection [%s] is a symbol table that's not being"
    294                    " removed.\n\tChecking to make sure that no symbols"
    295                    " refer to sections that are being removed.\n",
    296                    shdr_info[cnt].name);
    297 
    298               /* Make sure the data is loaded.  */
    299               symdata = elf_getdata (shdr_info[cnt].scn, NULL);
    300               FAILIF_LIBELF(NULL == symdata, elf_getdata);
    301 
    302               /* Go through all symbols and make sure the section they
    303                  reference is not removed.  */
    304               elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version);
    305 
    306               /* Check the length of the dynamic-symbol filter. */
    307               FAILIF(sym_filter != NULL &&
    308                      (size_t)num_symbols != symdata->d_size / elsize,
    309                      "Length of dynsym filter (%d) must equal the number"
    310                      " of dynamic symbols (%zd)!\n",
    311                      num_symbols,
    312                      symdata->d_size / elsize);
    313 
    314               size_t inner;
    315               for (inner = 0;
    316                    inner < symdata->d_size / elsize;
    317                    ++inner)
    318               {
    319                 GElf_Sym sym_mem;
    320                 GElf_Sym *sym;
    321                 size_t scnidx;
    322 
    323                 sym = gelf_getsymshndx (symdata, NULL,
    324                                         inner, &sym_mem, NULL);
    325                 FAILIF_LIBELF(sym == NULL, gelf_getsymshndx);
    326 
    327                 scnidx = sym->st_shndx;
    328                 FAILIF(scnidx == SHN_XINDEX,
    329                        "Can't handle SHN_XINDEX!\n");
    330                 if (scnidx == SHN_UNDEF ||
    331                     scnidx >= shnum ||
    332                     (scnidx >= SHN_LORESERVE &&
    333                      scnidx <= SHN_HIRESERVE) ||
    334                     GELF_ST_TYPE (sym->st_info) == STT_SECTION)
    335                 {
    336                   continue;
    337                 }
    338 
    339                 /* If the symbol is going to be thrown and it is a
    340                    global or weak symbol that is defined (not imported),
    341                    then continue.  Since the symbol is going away, we
    342                    do not care  whether it refers to a section that is
    343                    also going away.
    344                 */
    345                 if (sym_filter && !sym_filter[inner])
    346                 {
    347                   bool global_or_weak =
    348                       ELF32_ST_BIND(sym->st_info) == STB_GLOBAL ||
    349                       ELF32_ST_BIND(sym->st_info) == STB_WEAK;
    350                   if (!global_or_weak && sym->st_shndx != SHN_UNDEF)
    351                     continue;
    352                 }
    353 
    354                 /* -- far too much output
    355                    INFO("\t\t\tSymbol [%s] (%d)\n",
    356                    elf_strptr(elf,
    357                    shdr_info[cnt].shdr.sh_link,
    358                    sym->st_name),
    359                    shdr_info[cnt].shdr.sh_info);
    360                 */
    361 
    362                 if (shdr_info[scnidx].idx == 0)
    363                 {
    364                   PRINT("\t\t\tSymbol [%s] refers to section [%s], "
    365                         "which is being removed.  Will keep that "
    366                         "section.\n",
    367                         elf_strptr(elf,
    368                                    shdr_info[cnt].shdr.sh_link,
    369                                    sym->st_name),
    370                         shdr_info[scnidx].name);
    371                   /* Mark this section as used.  */
    372                   shdr_info[scnidx].idx = 1;
    373                   changes |= scnidx < cnt;
    374                 }
    375               } /* for each symbol */
    376             } /* section type is SHT_DYNSYM or SHT_SYMTAB */
    377             /* Cross referencing happens:
    378 			   - for the cases the ELF specification says.  That are
    379 			   + SHT_DYNAMIC in sh_link to string table
    380 			   + SHT_HASH in sh_link to symbol table
    381 			   + SHT_REL and SHT_RELA in sh_link to symbol table
    382 			   + SHT_SYMTAB and SHT_DYNSYM in sh_link to string table
    383 			   + SHT_GROUP in sh_link to symbol table
    384 			   + SHT_SYMTAB_SHNDX in sh_link to symbol table
    385 			   Other (OS or architecture-specific) sections might as
    386 			   well use this field so we process it unconditionally.
    387 			   - references inside section groups
    388 			   - specially marked references in sh_info if the SHF_INFO_LINK
    389 			   flag is set
    390             */
    391 
    392             if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0) {
    393               shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1;
    394               changes |= shdr_info[cnt].shdr.sh_link < cnt;
    395             }
    396 
    397             /* Handle references through sh_info.  */
    398             if (SH_INFO_LINK_P (&shdr_info[cnt].shdr) &&
    399                 shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0) {
    400               PRINT("\tSection [%s] links to section [%s], which was "
    401                     "marked for removal--it will not be removed.\n",
    402                     shdr_info[cnt].name,
    403                     shdr_info[shdr_info[cnt].shdr.sh_info].name);
    404 
    405               shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1;
    406               changes |= shdr_info[cnt].shdr.sh_info < cnt;
    407             }
    408 
    409             /* Mark the section as investigated.  */
    410             shdr_info[cnt].idx = 2;
    411           } /* if (shdr_info[cnt].idx == 1) */
    412 		} /* for (cnt = 1; cnt < shnum; ++cnt) */
    413       } while (changes);
    414     }
    415     else {
    416       INFO("Not stripping sections.\n");
    417       /* Mark the SHT_NULL section as handled. */
    418       shdr_info[0].idx = 2;
    419     }
    420 
    421 	/* Mark the section header string table as unused, we will create
    422 	   a new one as the very last section in the new ELF file.
    423 	*/
    424 	shdr_info[shstrndx].idx = rebuild_shstrtab ? 0 : 2;
    425 
    426 	/* We need a string table for the section headers. */
    427 	FAILIF_LIBELF((shst = ebl_strtabinit (1	/* null-terminated */)) == NULL,
    428 				  ebl_strtabinit);
    429 
    430 	/* Assign new section numbers. */
    431 	INFO("Creating new sections...\n");
    432 	//shdr_info[0].idx = 0;
    433 	for (cnt = idx = 1; cnt < shnum; ++cnt) {
    434 		if (shdr_info[cnt].idx > 0) {
    435 			shdr_info[cnt].idx = idx++;
    436 
    437 			/* Create a new section. */
    438 			FAILIF_LIBELF((shdr_info[cnt].newscn =
    439 						   elf_newscn(newelf)) == NULL, elf_newscn);
    440 			ASSERT(elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
    441 
    442 			/* Add this name to the section header string table. */
    443 			shdr_info[cnt].se = ebl_strtabadd (shst, shdr_info[cnt].name, 0);
    444 
    445 			INFO("\tsection [%s]  (old offset %lld, old size %lld) will have index %d "
    446 				 "(was %zd).\n",
    447 				 shdr_info[cnt].name,
    448 				 shdr_info[cnt].old_shdr.sh_offset,
    449 				 shdr_info[cnt].old_shdr.sh_size,
    450 				 shdr_info[cnt].idx,
    451 				 elf_ndxscn(shdr_info[cnt].scn));
    452 		} else {
    453 			INFO("\tIgnoring section [%s] (offset %lld, size %lld, index %zd), "
    454 				 "it will be discarded.\n",
    455 				 shdr_info[cnt].name,
    456 				 shdr_info[cnt].shdr.sh_offset,
    457 				 shdr_info[cnt].shdr.sh_size,
    458 				 elf_ndxscn(shdr_info[cnt].scn));
    459 		}
    460 	} /* for */
    461 
    462     sections_dropped_or_rearranged = idx != cnt;
    463 
    464     Elf_Data *shstrtab_data = NULL;
    465 
    466 #if 0
    467     /* Fail if sections are being dropped or rearranged (except for moving shstrtab) or the
    468        symbol filter is not empty, AND the file is an executable.
    469     */
    470     FAILIF(((idx != cnt && !(cnt - idx == 1 && rebuild_shstrtab)) || sym_filter != NULL) &&
    471            ehdr->e_type != ET_DYN,
    472            "You may not rearrange sections or strip symbols on an executable file!\n");
    473 #endif
    474 
    475     INFO("\n\nADJUSTING ELF FILE\n\n");
    476 
    477     adjust_elf(elf, elf_name,
    478                newelf, newelf_name,
    479                ebl,
    480                ehdr, /* store ELF header of original library */
    481                sym_filter, num_symbols,
    482                shdr_info, shdr_info_len,
    483                phdr_info,
    484                idx, /* highest_scn_num */
    485                shnum,
    486                shstrndx,
    487                shst,
    488                sections_dropped_or_rearranged,
    489                dynamic_idx, /* index in shdr_info[] of .dynamic section */
    490                dynsym_idx, /* index in shdr_info[] of dynamic symbol table */
    491                shady,
    492                &shstrtab_data,
    493                ehdr->e_type == ET_DYN, /* adjust section ofsets only when the file is a shared library */
    494                rebuild_shstrtab);
    495 
    496     /* We have everything from the old file. */
    497 	FAILIF_LIBELF(elf_cntl(elf, ELF_C_FDDONE) != 0, elf_cntl);
    498 
    499 	/* The ELF library better follows our layout when this is not a
    500 	   relocatable object file. */
    501 	elf_flagelf (newelf,
    502 				 ELF_C_SET,
    503 				 (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0));
    504 
    505 	/* Finally write the file. */
    506     FAILIF_LIBELF(!dry_run && elf_update(newelf, ELF_C_WRITE) == -1, elf_update);
    507 
    508 	if (shdr_info != NULL) {
    509 		/* For some sections we might have created an table to map symbol
    510            table indices. */
    511        for (cnt = 1; cnt < shdr_info_len; ++cnt) {
    512             FREEIF(shdr_info[cnt].newsymidx);
    513             FREEIF(shdr_info[cnt].symse);
    514             if(shdr_info[cnt].dynsymst != NULL)
    515                 ebl_strtabfree (shdr_info[cnt].dynsymst);
    516         }
    517 		/* Free the memory. */
    518 		FREE (shdr_info);
    519 	}
    520     FREEIF(phdr_info);
    521 
    522     ebl_closebackend(ebl);
    523 
    524 	/* Free other resources. */
    525 	if (shst != NULL) ebl_strtabfree (shst);
    526     if (shstrtab_data != NULL)
    527         FREEIF(shstrtab_data->d_buf);
    528 }
    529