Skip to content

Commit 25cb97c

Browse files
committed
Teach --replace-needed to update .gnu.version_r table
If the ELF binary that we're patching is linked to a DSO that uses symbol versioning, then the DSO's SONAME appears in two different places: once as a DT_NEEDED entry, and once in the .gnu.version_r version requirements section. Previously, patchelf --replace-needed would update DT_NEEDED entry, but fail to update the .gnu.version_r table. This resulted in completely broken binaries -- trying to load them would trigger an assertion failure inside the dynamic loader, as it tries to check the version of a library that was never loaded: Inconsistency detected by ld.so: dl-version.c: 224: _dl_check_map_versions: Assertion `needed != ((void *)0)' failed! This commit teaches --replace-needed to update the .gnu.version_r table. Fixes: gh-84
1 parent 44b7f95 commit 25cb97c

File tree

1 file changed

+34
-4
lines changed

1 file changed

+34
-4
lines changed

src/patchelf.cc

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ off_t fileSize, maxSize;
5353
unsigned char * contents = 0;
5454

5555

56-
#define ElfFileParams class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym
57-
#define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym
56+
#define ElfFileParams class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym, class Elf_Verneed
57+
#define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed
5858

5959

6060
static unsigned int getPageSize(){
@@ -1260,6 +1260,8 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(map<string, string>& libs)
12601260

12611261
Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset));
12621262

1263+
unsigned int verNeedNum = 0;
1264+
12631265
unsigned int dynStrAddedBytes = 0;
12641266

12651267
for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) {
@@ -1287,6 +1289,34 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(map<string, string>& libs)
12871289
debug("keeping DT_NEEDED entry `%s'\n", name);
12881290
}
12891291
}
1292+
if (rdi(dyn->d_tag) == DT_VERNEEDNUM) {
1293+
verNeedNum = rdi(dyn->d_un.d_val);
1294+
}
1295+
}
1296+
1297+
// If a replaced library uses symbol versions, then there will also be
1298+
// references to it in the "version needed" table, and these also need to
1299+
// be replaced.
1300+
1301+
if (verNeedNum) {
1302+
Elf_Shdr & shdrVersionR = findSection3(".gnu.version_r");
1303+
// The filename strings in the .gnu.version_r aren't necessarily in
1304+
// .dynstr -- we have to look at ->sh_link to find the section with
1305+
// the strings in it.
1306+
Elf_Shdr & shdrVersionRStrings = *shdrs[rdi(shdrVersionR->sh_link)];
1307+
1308+
Elf_Verneed * need = (Elf_Verneed *) (contents + rdi(shdrVersionR.sh_offset));
1309+
while (verNeedNum > 0) {
1310+
1311+
// XX check need->vn_file, which is an offset into the
1312+
// shdrVersionRStrings section
1313+
// if if matches one of the entries in `libs`, then use
1314+
// replaceSection logic like that above to add the new string to
1315+
// this section and change vn_file
1316+
1317+
need = (Elf_Verneed *) (contents + rdi(need->vn_next));
1318+
verNeedNum--;
1319+
}
12901320
}
12911321
}
12921322

@@ -1474,13 +1504,13 @@ static void patchElf()
14741504
if (contents[EI_CLASS] == ELFCLASS32 &&
14751505
contents[EI_VERSION] == EV_CURRENT)
14761506
{
1477-
ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym> elfFile;
1507+
ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed> elfFile;
14781508
patchElf2(elfFile);
14791509
}
14801510
else if (contents[EI_CLASS] == ELFCLASS64 &&
14811511
contents[EI_VERSION] == EV_CURRENT)
14821512
{
1483-
ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym> elfFile;
1513+
ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed> elfFile;
14841514
patchElf2(elfFile);
14851515
}
14861516
else {

0 commit comments

Comments
 (0)