about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-07-09 12:38:48 +0200
committerptitSeb <sebastien.chev@gmail.com>2023-07-09 12:38:48 +0200
commitdabbca767f9de4fc4cf68252037de3061592eae2 (patch)
treebfc1dadad814a82a155c0c374097177b94154beb /src
parentca9bc1361943575724eb5152798aa208ed5eed6c (diff)
downloadbox64-dabbca767f9de4fc4cf68252037de3061592eae2.tar.gz
box64-dabbca767f9de4fc4cf68252037de3061592eae2.zip
[ELFLOADER] Added a check if lib version is compatible with what the elf loading it wants (helps Linux games on Steam)
Diffstat (limited to 'src')
-rwxr-xr-xsrc/elfs/elfloader.c19
-rwxr-xr-xsrc/elfs/elfparser.c52
-rwxr-xr-xsrc/include/elfloader.h3
-rwxr-xr-xsrc/include/librarian.h2
-rwxr-xr-xsrc/include/library.h2
-rwxr-xr-xsrc/librarian/librarian.c16
-rwxr-xr-xsrc/librarian/library.c24
-rwxr-xr-xsrc/main.c5
-rwxr-xr-xsrc/wrapped/wrappedlibdl.c2
9 files changed, 91 insertions, 34 deletions
diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c
index 4caa07ce..7977b592 100755
--- a/src/elfs/elfloader.c
+++ b/src/elfs/elfloader.c
@@ -374,6 +374,23 @@ int LoadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
     return 0;
 }
 
+int isElfHasNeededVer(elfheader_t* head, const char* libname, elfheader_t* verneeded)
+{
+    if(!verneeded || !head)
+        return 1;
+    if(!head->VerDef || !verneeded->VerNeed)
+        return 1;
+    int cnt = GetNeededVersionCnt(verneeded, libname);
+    for (int i=0; i<cnt; ++i) {
+        const char* vername = GetNeededVersionString(verneeded, libname, i);
+        if(vername && !GetVersionIndice(head, vername)) {
+            printf_log(/*LOG_DEBUG*/LOG_INFO, "Discarding %s for missing version %s\n", head->path, vername);
+            return 0;   // missing version
+        }
+    }
+    return 1;
+}
+
 int ReloadElfMemory(FILE* f, box64context_t* context, elfheader_t* head)
 {
     (void)context;
@@ -1201,7 +1218,7 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, int local, int bindnow, box64c
             h->needed->names[j++] = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
 
     // TODO: Add LD_LIBRARY_PATH and RPATH handling
-    if(AddNeededLib(maplib, local, bindnow, h->needed, box64, emu)) {
+    if(AddNeededLib(maplib, local, bindnow, h->needed, h, box64, emu)) {
         printf_log(LOG_INFO, "Error loading one of needed lib\n");
         if(!allow_missing_libs)
             return 1;   //error...
diff --git a/src/elfs/elfparser.c b/src/elfs/elfparser.c
index 7b83e07e..1701378f 100755
--- a/src/elfs/elfparser.c
+++ b/src/elfs/elfparser.c
@@ -416,18 +416,6 @@ int GetVersionIndice(elfheader_t* h, const char* vername)
 {
     if(!vername)
         return 0;
-    if(h->VerNeed) {
-        Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta);
-        while(ver) {
-            Elf64_Vernaux *aux = (Elf64_Vernaux*)((uintptr_t)ver + ver->vn_aux);
-            for(int j=0; j<ver->vn_cnt; ++j) {
-                if(!strcmp(h->DynStr+aux->vna_name, vername)) 
-                    return aux->vna_other;
-                aux = (Elf64_Vernaux*)((uintptr_t)aux + aux->vna_next);
-            }
-            ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
-        }
-    }
     if(h->VerDef) {
         Elf64_Verdef *def = (Elf64_Verdef*)((uintptr_t)h->VerDef + h->delta);
         while(def) {
@@ -438,4 +426,44 @@ int GetVersionIndice(elfheader_t* h, const char* vername)
         }
     }
     return 0;
+}
+
+int GetNeededVersionCnt(elfheader_t* h, const char* libname)
+{
+    if(!libname)
+        return 0;
+    if(h->VerNeed) {
+        Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta);
+        while(ver) {
+            char *filename = h->DynStr + ver->vn_file;
+            Elf64_Vernaux *aux = (Elf64_Vernaux*)((uintptr_t)ver + ver->vn_aux);
+            if(!strcmp(filename, libname))
+                return ver->vn_cnt;
+            ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
+        }
+    }
+    return 0;
+}
+
+const char* GetNeededVersionString(elfheader_t* h, const char* libname, int idx)
+{
+    if(!libname)
+        return 0;
+    if(h->VerNeed) {
+        Elf64_Verneed *ver = (Elf64_Verneed*)((uintptr_t)h->VerNeed + h->delta);
+        while(ver) {
+            char *filename = h->DynStr + ver->vn_file;
+            Elf64_Vernaux *aux = (Elf64_Vernaux*)((uintptr_t)ver + ver->vn_aux);
+            if(!strcmp(filename, libname)) {
+                for(int j=0; j<ver->vn_cnt; ++j) {
+                    if(j==idx) 
+                        return h->DynStr+aux->vna_name;
+                    aux = (Elf64_Vernaux*)((uintptr_t)aux + aux->vna_next);
+                }
+                return NULL;    // idx out of bound, return NULL...
+           }
+            ver = ver->vn_next?((Elf64_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
+        }
+    }
+    return NULL;
 }
\ No newline at end of file
diff --git a/src/include/elfloader.h b/src/include/elfloader.h
index d5b54145..ca8839df 100755
--- a/src/include/elfloader.h
+++ b/src/include/elfloader.h
@@ -25,6 +25,7 @@ int CalcLoadAddr(elfheader_t* head);
 int AllocElfMemory(box64context_t* context, elfheader_t* head, int mainbin);
 void FreeElfMemory(elfheader_t* head);
 int LoadElfMemory(FILE* f, box64context_t* context, elfheader_t* head);
+int isElfHasNeededVer(elfheader_t* head, const char* libname, elfheader_t* verneeded);
 int ReloadElfMemory(FILE* f, box64context_t* context, elfheader_t* head);
 int RelocateElf(lib_t *maplib, lib_t* local_maplib, int bindnow, elfheader_t* head);
 int RelocateElfPlt(lib_t *maplib, lib_t* local_maplib, int bindnow, elfheader_t* head);
@@ -64,6 +65,8 @@ const char* GetParentSymbolVersion(elfheader_t* h, int index);
 const char* VersionedName(const char* name, int ver, const char* vername);
 int SameVersionedSymbol(const char* name1, int ver1, const char* vername1, const char* name2, int ver2, const char* vername2);
 int GetVersionIndice(elfheader_t* h, const char* vername);
+int GetNeededVersionCnt(elfheader_t* h, const char* libname);
+const char* GetNeededVersionString(elfheader_t* h, const char* libname, int idx);
 
 kh_mapsymbols_t* GetMapSymbols(elfheader_t* h);
 kh_mapsymbols_t* GetWeakSymbols(elfheader_t* h);
diff --git a/src/include/librarian.h b/src/include/librarian.h
index c05ce963..80e108ca 100755
--- a/src/include/librarian.h
+++ b/src/include/librarian.h
@@ -21,7 +21,7 @@ void FreeDLPrivate(dlprivate_t **lib);
 
 box64context_t* GetLibrarianContext(lib_t* maplib);
 kh_mapsymbols_t* GetGlobalData(lib_t* maplib);
-int AddNeededLib(lib_t* maplib, int local, int bindnow, needed_libs_t* needed, box64context_t* box64, x64emu_t* emu); // 0=success, 1=error
+int AddNeededLib(lib_t* maplib, int local, int bindnow, needed_libs_t* needed, elfheader_t* verneeded, box64context_t* box64, x64emu_t* emu); // 0=success, 1=error
 void RemoveNeededLib(lib_t* maplib, int local, needed_libs_t* needed, box64context_t* box64, x64emu_t* emu);
 library_t* GetLibMapLib(lib_t* maplib, const char* name);
 library_t* GetLibInternal(const char* name);
diff --git a/src/include/library.h b/src/include/library.h
index ff48b691..b08927e0 100755
--- a/src/include/library.h
+++ b/src/include/library.h
@@ -15,7 +15,7 @@ typedef struct elfheader_s     elfheader_t;
 #define LIB_EMULATED    1
 #define LIB_UNNKNOW     -1
 
-library_t *NewLibrary(const char* path, box64context_t* box64);
+library_t *NewLibrary(const char* path, box64context_t* box64, elfheader_t* verneeded);
 int AddSymbolsLibrary(lib_t* maplib, library_t* lib, x64emu_t* emu);
 int FinalizeLibrary(library_t* lib, lib_t* local_maplib, int bindnow, x64emu_t* emu);
 
diff --git a/src/librarian/librarian.c b/src/librarian/librarian.c
index d9f20a9a..8ed3fe8b 100755
--- a/src/librarian/librarian.c
+++ b/src/librarian/librarian.c
@@ -177,7 +177,7 @@ int isLibLocal(library_t* lib)
     return libraryInMapLib(my_context->local_maplib, lib);
 }
 
-int AddNeededLib_add(lib_t* maplib, int local, needed_libs_t* needed, int n, box64context_t* box64, x64emu_t* emu)
+static int AddNeededLib_add(lib_t* maplib, int local, needed_libs_t* needed, int n, elfheader_t* verneeded, box64context_t* box64, x64emu_t* emu)
 {
     const char* path = needed->names[n];
     printf_log(LOG_DEBUG, "Trying to add \"%s\" to maplib%s\n", path, local?" (local)":"");
@@ -213,7 +213,7 @@ int AddNeededLib_add(lib_t* maplib, int local, needed_libs_t* needed, int n, box
         return 0;
     }
     // load a new one
-    needed->libs[n] = lib = NewLibrary(path, box64);
+    needed->libs[n] = lib = NewLibrary(path, box64, verneeded);
     if(!lib) {
         printf_log(LOG_DEBUG, "Faillure to create lib => fail\n");
         return 1;   //Error
@@ -257,7 +257,7 @@ int AddNeededLib_add(lib_t* maplib, int local, needed_libs_t* needed, int n, box
     return 0;
 }
 
-int AddNeededLib_init(lib_t* maplib, int local, int bindnow, library_t* lib, box64context_t* box64, x64emu_t* emu)
+int AddNeededLib_init(lib_t* maplib, int local, int bindnow, library_t* lib, elfheader_t* verneeded, box64context_t* box64, x64emu_t* emu)
 {
     if(!lib)    // no lib, error is already detected, no need to return a new one
         return 0;
@@ -283,7 +283,7 @@ int AddNeededLib_init(lib_t* maplib, int local, int bindnow, library_t* lib, box
             tmp.size = tmp.cap = 1;
             tmp.names = names;
             tmp.libs = libs;
-            AddNeededLib(maplib, 0, 0, &tmp, box64, emu);
+            AddNeededLib(maplib, 0, 0, &tmp, verneeded, box64, emu);
         }
         if(!strcmp(GetNameLib(lib), "libmss.so.6")) {
             char* names[] = {"libSDL-1.2.so.0", "libdl.so.2"}; // TODO: they will never be uninit...
@@ -292,7 +292,7 @@ int AddNeededLib_init(lib_t* maplib, int local, int bindnow, library_t* lib, box
             tmp.size = tmp.cap = 2;
             tmp.names = names;
             tmp.libs = libs;
-            AddNeededLib(maplib, 0, 0, &tmp, box64, emu);
+            AddNeededLib(maplib, 0, 0, &tmp, verneeded, box64, emu);
         }
 
         // finalize the lib
@@ -318,7 +318,7 @@ void AddNeededLib_remove(lib_t* maplib, int local, library_t** lib, box64context
 }
 
 EXPORTDYN
-int AddNeededLib(lib_t* maplib, int local, int bindnow, needed_libs_t* needed, box64context_t* box64, x64emu_t* emu)
+int AddNeededLib(lib_t* maplib, int local, int bindnow, needed_libs_t* needed, elfheader_t* verneeded, box64context_t* box64, x64emu_t* emu)
 {
     if(!needed) // no needed libs, no problems
         return 0;
@@ -326,7 +326,7 @@ int AddNeededLib(lib_t* maplib, int local, int bindnow, needed_libs_t* needed, b
     int ret = 0;
     // Add libs and symbol
     for(int i=0; i<needed->size; ++i) {
-        if(AddNeededLib_add(maplib, local, needed, i, box64, emu)) {
+        if(AddNeededLib_add(maplib, local, needed, i, verneeded, box64, emu)) {
             printf_log(strchr(needed->names[i],'/')?LOG_DEBUG:LOG_INFO, "Error loading needed lib %s\n", needed->names[i]);
             ret = 1;
         }
@@ -337,7 +337,7 @@ int AddNeededLib(lib_t* maplib, int local, int bindnow, needed_libs_t* needed, b
     }
     // add dependant libs and init them
     for (int i=0; i<needed->size; ++i)
-        if(AddNeededLib_init(maplib, local, bindnow, needed->libs[i], box64, emu)) {
+        if(AddNeededLib_init(maplib, local, bindnow, needed->libs[i], verneeded, box64, emu)) {
             printf_log(LOG_INFO, "Error initializing needed lib %s\n", needed->names[i]);
             if(!allow_missing_libs) ret = 1;
         }
diff --git a/src/librarian/library.c b/src/librarian/library.c
index 9b2bb997..b3bec1b4 100755
--- a/src/librarian/library.c
+++ b/src/librarian/library.c
@@ -217,7 +217,7 @@ static void initWrappedLib(library_t *lib, box64context_t* context) {
             lib->type = LIB_WRAPPED;
             lib->w.refcnt = 1;
             // Call librarian to load all dependant elf
-            if(AddNeededLib(context->maplib, 0, 0, lib->w.needed, context, thread_get_emu())) {
+            if(AddNeededLib(context->maplib, 0, 0, lib->w.needed, NULL, context, thread_get_emu())) {
                 printf_log(LOG_NONE, "Error: loading a needed libs in elf %s\n", lib->name);
                 return;
             }
@@ -240,7 +240,7 @@ static void initWrappedLib(library_t *lib, box64context_t* context) {
     }
 }
 
-static int loadEmulatedLib(const char* libname, library_t *lib, box64context_t* context)
+static int loadEmulatedLib(const char* libname, library_t *lib, box64context_t* context, elfheader_t* verneeded)
 {
     if(FileExist(libname, IS_FILE))
     {
@@ -255,28 +255,36 @@ static int loadEmulatedLib(const char* libname, library_t *lib, box64context_t*
             fclose(f);
             return 0;
         }
-        int mainelf = AddElfHeader(context, elf_header);
 
         if(CalcLoadAddr(elf_header)) {
             printf_log(LOG_NONE, "Error: reading elf header of %s\n", libname);
+            FreeElfHeader(&elf_header);
             fclose(f);
             return 0;
         }
         // allocate memory
         if(AllocElfMemory(context, elf_header, 0)) {
             printf_log(LOG_NONE, "Error: allocating memory for elf %s\n", libname);
+            FreeElfHeader(&elf_header);
             fclose(f);
             return 0;
         }
         // Load elf into memory
         if(LoadElfMemory(f, context, elf_header)) {
             printf_log(LOG_NONE, "Error: loading in memory elf %s\n", libname);
+            FreeElfHeader(&elf_header);
             fclose(f);
             return 0;
         }
         // can close the file now
         fclose(f);
+        if(verneeded && !isElfHasNeededVer(elf_header, lib->name, verneeded)) {
+            // incompatible, discard and continue the search
+            FreeElfHeader(&elf_header);
+            return 0;
+        }
 
+        int mainelf = AddElfHeader(context, elf_header);
         ElfAttachLib(elf_header, lib);
 
         lib->type = LIB_EMULATED;
@@ -316,13 +324,13 @@ static int loadEmulatedLib(const char* libname, library_t *lib, box64context_t*
     return 0;
 }
 
-static void initEmulatedLib(const char* path, library_t *lib, box64context_t* context)
+static void initEmulatedLib(const char* path, library_t *lib, box64context_t* context, elfheader_t* verneeded)
 {
     char libname[MAX_PATH];
     strcpy(libname, path);
     int found = FileIsX64ELF(libname);
     if(found)
-        if(loadEmulatedLib(libname, lib, context))
+        if(loadEmulatedLib(libname, lib, context, verneeded))
             return;
     if(!strchr(path, '/'))
         for(int i=0; i<context->box64_ld_lib.size; ++i)
@@ -330,7 +338,7 @@ static void initEmulatedLib(const char* path, library_t *lib, box64context_t* co
             strcpy(libname, context->box64_ld_lib.paths[i]);
             strcat(libname, path);
             if(FileIsX64ELF(libname))
-                if(loadEmulatedLib(libname, lib, context))
+                if(loadEmulatedLib(libname, lib, context, verneeded))
                     return;
         }
 }
@@ -353,7 +361,7 @@ static int isEssentialLib(const char* name) {
     return 0;
 }
 
-library_t *NewLibrary(const char* path, box64context_t* context)
+library_t *NewLibrary(const char* path, box64context_t* context, elfheader_t* verneeded)
 {
     printf_log(LOG_DEBUG, "Trying to load \"%s\"\n", path);
     library_t *lib = (library_t*)box_calloc(1, sizeof(library_t));
@@ -399,7 +407,7 @@ library_t *NewLibrary(const char* path, box64context_t* context)
         initWrappedLib(lib, context);
     // then look for a native one
     if(lib->type==LIB_UNNKNOW)
-        initEmulatedLib(path, lib, context);
+        initEmulatedLib(path, lib, context, verneeded);
     // still not loaded but notwrapped indicated: use wrapped...
     if(lib->type==LIB_UNNKNOW && notwrapped && !precise)
         initWrappedLib(lib, context);
diff --git a/src/main.c b/src/main.c
index e06cd2ad..00218c3d 100755
--- a/src/main.c
+++ b/src/main.c
@@ -917,7 +917,7 @@ int GatherEnv(char*** dest, char** env, char* prog)
         (*dest)[idx++] = box_strdup("BOX64_PATH=.:bin");
     }
     if(!ld_path) {
-        (*dest)[idx++] = box_strdup("BOX64_LD_LIBRARY_PATH=.:lib:lib64");
+        (*dest)[idx++] = box_strdup("BOX64_LD_LIBRARY_PATH=.:lib:lib64:x86_64:bin64:libs64");
     }
     // add "_=prog" at the end...
     if(prog) {
@@ -1045,6 +1045,7 @@ void LoadEnvVars(box64context_t *context)
     AddPath("libcrypto.so.1", &context->box64_emulated_libs, 0);
     AddPath("libcrypto.so.1.0.0", &context->box64_emulated_libs, 0);
     AddPath("libunwind.so.8", &context->box64_emulated_libs, 0);
+    AddPath("libpng12.so.0", &context->box64_emulated_libs, 0);
 
     if(getenv("BOX64_SSE_FLUSHTO0")) {
         if (strcmp(getenv("BOX64_SSE_FLUSHTO0"), "1")==0) {
@@ -1744,7 +1745,7 @@ int main(int argc, const char **argv, char **env) {
         for(int i=0; i<ld_preload.size; ++i) {
             needed_libs_t* tmp = new_neededlib(1);
             tmp->names[0] = ld_preload.paths[i];
-            if(AddNeededLib(my_context->maplib, 0, 0, tmp, my_context, emu)) {
+            if(AddNeededLib(my_context->maplib, 0, 0, tmp, elf_header, my_context, emu)) {
                 printf_log(LOG_INFO, "Warning, cannot pre-load of %s\n", tmp->names[0]);
                 RemoveNeededLib(my_context->maplib, 0, tmp, my_context, emu);
             } else {
diff --git a/src/wrapped/wrappedlibdl.c b/src/wrapped/wrappedlibdl.c
index c6787525..47c47c6b 100755
--- a/src/wrapped/wrappedlibdl.c
+++ b/src/wrapped/wrappedlibdl.c
@@ -177,7 +177,7 @@ void* my_dlopen(x64emu_t* emu, void *filename, int flag)
         int bindnow = (!box64_musl && (flag&0x2))?1:0;
         needed_libs_t *tmp = new_neededlib(1);
         tmp->names[0] = rfilename;
-        if(AddNeededLib(NULL, is_local, bindnow, tmp, my_context, emu)) {
+        if(AddNeededLib(NULL, is_local, bindnow, tmp, NULL, my_context, emu)) {
             printf_dlsym(strchr(rfilename,'/')?LOG_DEBUG:LOG_INFO, "Warning: Cannot dlopen(\"%s\"/%p, %X)\n", rfilename, filename, flag);
             if(!dl->last_error)
                 dl->last_error = box_malloc(129);