@@ -664,14 +664,14 @@ template<ElfFileParams>
664664void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
665665 Elf_Addr startAddr, Elf_Off startOffset)
666666{
667- /* Overwrite the old section contents with 'X 's. Do this
667+ /* Overwrite the old section contents with 'Z 's. Do this
668668 *before* writing the new section contents (below) to prevent
669669 clobbering previously written new section contents. */
670670 for (auto & i : replacedSections) {
671671 const std::string & sectionName = i.first ;
672672 const Elf_Shdr & shdr = findSectionHeader (sectionName);
673673 if (rdi (shdr.sh_type ) != SHT_NOBITS)
674- memset (fileContents->data () + rdi (shdr.sh_offset ), ' X ' , rdi (shdr.sh_size ));
674+ memset (fileContents->data () + rdi (shdr.sh_offset ), ' Z ' , rdi (shdr.sh_size ));
675675 }
676676
677677 std::set<unsigned int > noted_phdrs = {};
@@ -1538,7 +1538,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
15381538
15391539 /* !!! We assume that the virtual address in the DT_STRTAB entry
15401540 of the dynamic section corresponds to the .dynstr section. */
1541- auto shdrDynStr = findSectionHeader (" .dynstr" );
1541+ auto & shdrDynStr = findSectionHeader (" .dynstr" );
15421542 char * strTab = (char *) fileContents->data () + rdi (shdrDynStr.sh_offset );
15431543
15441544
@@ -1621,24 +1621,39 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
16211621 }
16221622 changed = true ;
16231623
1624- /* Zero out the previous rpath to prevent retained dependencies in
1625- Nix. */
1624+ bool rpathStrShared = false ;
16261625 size_t rpathSize = 0 ;
16271626 if (rpath) {
1628- rpathSize = strlen (rpath);
1627+ std::string_view rpathView {rpath};
1628+ rpathSize = rpathView.size ();
1629+
1630+ size_t rpathStrReferences = 0 ;
1631+ forAllStringReferences (shdrDynStr, [&] (auto refIdx) {
1632+ if (rpathView.end () == std::string_view (strTab + rdi (refIdx)).end ())
1633+ rpathStrReferences++;
1634+ });
1635+ assert (rpathStrReferences >= 1 );
1636+ debug (" Number of rpath references: %lu\n " , rpathStrReferences);
1637+ rpathStrShared = rpathStrReferences > 1 ;
1638+ }
1639+
1640+ /* Zero out the previous rpath to prevent retained dependencies in
1641+ Nix. */
1642+ if (rpath && !rpathStrShared) {
1643+ debug (" Tainting old rpath with Xs\n " );
16291644 memset (rpath, ' X' , rpathSize);
16301645 }
16311646
16321647 debug (" new rpath is '%s'\n " , newRPath.c_str ());
16331648
16341649
1635- if (newRPath.size () <= rpathSize) {
1650+ if (!rpathStrShared && newRPath.size () <= rpathSize) {
16361651 if (rpath) memcpy (rpath, newRPath.c_str (), newRPath.size () + 1 );
16371652 return ;
16381653 }
16391654
16401655 /* Grow the .dynstr section to make room for the new RPATH. */
1641- debug (" rpath is too long, resizing...\n " );
1656+ debug (" rpath is too long or shared , resizing...\n " );
16421657
16431658 std::string & newDynStr = replaceSection (" .dynstr" ,
16441659 rdi (shdrDynStr.sh_size ) + newRPath.size () + 1 );
@@ -2293,6 +2308,42 @@ void ElfFile<ElfFileParamNames>::modifyExecstack(ExecstackMode op)
22932308 printf (" execstack: %c\n " , result);
22942309}
22952310
2311+ template <ElfFileParams>
2312+ template <class StrIdxCallback >
2313+ void ElfFile<ElfFileParamNames>::forAllStringReferences(const Elf_Shdr& strTabHdr, StrIdxCallback&& fn)
2314+ {
2315+ for (auto & sym : tryGetSectionSpan<Elf_Sym>(" .dynsym" ))
2316+ fn (sym.st_name );
2317+
2318+ for (auto & dyn : tryGetSectionSpan<Elf_Dyn>(" .dynamic" ))
2319+ switch (rdi (dyn.d_tag ))
2320+ {
2321+ case DT_NEEDED:
2322+ case DT_SONAME:
2323+ case DT_RPATH:
2324+ case DT_RUNPATH: fn (dyn.d_un .d_val );
2325+ default :;
2326+ }
2327+
2328+ if (auto verdHdr = tryFindSectionHeader (" .gnu.version_d" ))
2329+ {
2330+ if (&shdrs.at (rdi (verdHdr->get ().sh_link )) == &strTabHdr)
2331+ forAll_ElfVer (getSectionSpan<Elf_Verdef>(*verdHdr),
2332+ [] (auto & /* vd*/ ) {},
2333+ [&] (auto & vda) { fn (vda.vda_name ); }
2334+ );
2335+ }
2336+
2337+ if (auto vernHdr = tryFindSectionHeader (" .gnu.version_r" ))
2338+ {
2339+ if (&shdrs.at (rdi (vernHdr->get ().sh_link )) == &strTabHdr)
2340+ forAll_ElfVer (getSectionSpan<Elf_Verneed>(*vernHdr),
2341+ [&] (auto & vn) { fn (vn.vn_file ); },
2342+ [&] (auto & vna) { fn (vna.vna_name ); }
2343+ );
2344+ }
2345+ }
2346+
22962347static bool printInterpreter = false ;
22972348static bool printOsAbi = false ;
22982349static bool setOsAbi = false ;
@@ -2397,9 +2448,9 @@ static void patchElf()
23972448 const std::string & outputFileName2 = outputFileName.empty () ? fileName : outputFileName;
23982449
23992450 if (getElfType (fileContents).is32Bit )
2400- patchElf2 (ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed, Elf32_Versym , Elf32_Rel, Elf32_Rela, 32 >(fileContents), fileContents, outputFileName2);
2451+ patchElf2 (ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Versym, Elf32_Verdef, Elf32_Verdaux, Elf32_Verneed, Elf32_Vernaux , Elf32_Rel, Elf32_Rela, 32 >(fileContents), fileContents, outputFileName2);
24012452 else
2402- patchElf2 (ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, Elf64_Versym , Elf64_Rel, Elf64_Rela, 64 >(fileContents), fileContents, outputFileName2);
2453+ patchElf2 (ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Versym, Elf64_Verdef, Elf64_Verdaux, Elf64_Verneed, Elf64_Vernaux , Elf64_Rel, Elf64_Rela, 64 >(fileContents), fileContents, outputFileName2);
24032454 }
24042455}
24052456
0 commit comments