Open dmik opened 4 years ago
Note that the above commit contains a workaround which is as simple as loading the right DLL with dlopen
before calling dlsym
. This workaround is not perfect as the code will break if the DLL name changes but it's OK for now given this code is not actually called (at least I couldn't see any trace of it at runtime).
We will fix this issue once we discover more use cases so that it turns worth spending time on QS_MTE magic.
I know this is not the way to present code contributions but nonetheless:
// icc -Q -Ti -Ss -Tdp -Gd+ -Ge+ -Gm+ -Fadlsym.cod dlsym.c
// all members of this structure are aligned to 2 bytes !!! // do NOT use the QSEXLREC structure from the OS/2 toolkit header file bsedos.h // as this structure is not packed to 2 bytes !!! / Used for 9th bit (Extended Module Data Summary)/ typedef struct _qsELrec { / qsELrec / struct _qsELrec next; / Pointer to next Extended Module Data / USHORT hndmod; / Module Handle / USHORT pid; / Process ID / USHORT type; / Type of Module / ULONG refcnt; / Size of reference array / ULONG segcnt; / Number of segments in module / VOID reserved; UCHAR FAR name; / Pointer to Module Name / ULONG ModuleVersion; / Module version value / UCHAR FAR ShortModName; / New Pointer to Module short name / ULONG modref; / Start of array of handles of module / } qsELrec;
// some hackarounds, remove for final product
typedef ULONG uintptr_t; int __libc_Back_ldrSymbol(void pvHandle, const char pszSymbol, void **ppfn);
int main(int argc,char argv[]) { int rc = 0; void pfn = NULL;
printf("struct size qsELrec is %u, should be 38 (packed)!\n\n\n",sizeof(qsELrec));
rc = libc_Back_ldrSymbol(LIBC_BACK_LDR_GLOBAL,"XYZ_CERT_CacheOCSPResponseFromSideChannel",&pfn); // wrong function name in nss3.dll printf("returned rc:%u\n",rc);
rc = libc_Back_ldrSymbol(LIBC_BACK_LDR_GLOBAL,"_CERT_CacheOCSPResponseFromSideChannel",&pfn); // in nss3.dll printf("returned rc:%u\n",rc);
return 0; }
int libc_Back_ldrSymbol(void pvHandle, const char pszSymbol, void *ppfn)
{
// LIBCLOG_ENTER("pvHandle=%p pszSymbol=%p:{%s} ppfn=%p\n", pvHandle,
// (void )pszSymbol, (uintptr_t)pszSymbol >= 10000 ? pszSymbol : "
/* NEVER EVER try to load a driver module of any sort, it will hang OS/2 !!! */
/* so, if we find one in the module list, skip it ... */
rc = regcomp(®,"^([^</*?\">|]+)\\.dll$",REG_NOSUB|REG_ICASE|REG_EXTENDED);
rc = ERROR_PROC_NOT_FOUND;
*ppfn = NULL;
if (buf) memset(buf,0,BUFLEN);
/*
* using QS_MODVER instead of QS_MTE as that will avoid the
* shortcomings of QS_MTE (broken module chain)
*/
if (buf && (NO_ERROR == DosQuerySysState(QS_MODVER,0,0,0,buf,BUFLEN))) {
while(pRec) {
/*
* OS/2 is VERY sensitive to loading modules that are not meant to be reloaded dynamically
* that includes ALL sorts of drivers (like .psd, .flt, .add, .sys, .vdd, .ifs etc.)
* but also the pseudo modules MVDM.DLL, KEE.DLD and DOSCALLS.DLL (stuff implemented directly in the kernel
* but exported with a DLL type of extension)
* if any attempt is made to load these, the complete system will first hang, then immediately
* lead to a system reboot (no trap 3 error screen, no trap 0 error screen)
* additionally, WPINET.DLL and WPPRINT.DLL always take an extraordinary amount of time
* to load when DosLoadModule is called. Fortunately, these do not contain any "interesting"
* exports per name (WPINET.DLL contains none,
* WPPRINT.DLL only contains the typical SOM data structure exports for various WPS SOM classes)
* and therefore we also exclude them here
* in general it has to be stated that going through the list of loaded modules and attempting to
* locate a function with DosQueryProcAddr via trial and error in order to find its entry point
* is an extremely costly operation under OS/2
*/
if (0 == regexec(®,(PCSZ)pRec->name,0,NULL,0)
&& !strstr((PCSZ)pRec->name,"DOSCALLS")
&& !strstr((PCSZ)pRec->name,"MVDM")
&& !strstr((PCSZ)pRec->name,"WPINET")
&& !strstr((PCSZ)pRec->name,"WPPRINT")
)
{
rc = DosQueryProcAddr((HMODULE)pRec->hndmod,0,(PCSZ)pszSymbol,&pfn);
if (ERROR_INVALID_HANDLE == rc) {
rc2 = DosLoadModule(errBuf,sizeof(errBuf),(PCSZ)pRec->name,&hModule);
if (NO_ERROR == rc2) {
rc = DosQueryProcAddr(hModule,0,(PCSZ)pszSymbol,&pfn);
if (NO_ERROR == rc) {
/* if we find a match, we better keep the module loaded and
* NOT call DosFreeModule because OS/2 needs to have a module loaded
* into the process in order to use it, even though the module code is
* in shared memory
*/
*ppfn = (void *)pfn;
break;
} /* endif */
rc2 = DosFreeModule(hModule);
} /* endif */
} /* endif */
else if (NO_ERROR == rc) {
*ppfn = (void *)pfn;
break;
}
printf("modhandle: %#x, pid: %#x, modtype: %u, modname:%s\n",(HMODULE)pRec->hndmod,(ULONG)pRec->pid,(ULONG)pRec->type,pRec->name);
}
pRec = pRec->next;
}
free(buf);
regfree(®);
if (NO_ERROR != rc) {
rc = ERROR_PROC_NOT_FOUND;
} /* endif */
} /* endif */
}
else
{
PFN pfn;
// FS_VAR(); // FS_SAVE_LOAD(); if ((uintptr_t)pszSymbol < 10000) rc = DosQueryProcAddr((HMODULE)pvHandle, (uintptr_t)pszSymbol, NULL, &pfn); else rc = DosQueryProcAddr((HMODULE)pvHandle, 0, (PCSZ)pszSymbol, &pfn); // FS_RESTORE(); if (!rc)
Also, "dlsym" (src/emx/src/lib/misc/dlsym.c) needs a change to invoke "libc_Back_ldrSymbol" with handle LIBC_BACK_LDR_GLOBAL if "dlsym" itself is invoked with handle RTLD_DEFAULT.
According to Posix, this flag should cause
dlsym
to look up the symbol not in a specific module loaded bydlopen
but in the global symbol scope of the current process (i.e. among all loaded modules including the executable itself, ifI get it right).Currently we miss this functionality but it can be implemented using
DosQuerySysState
using the QS_MTE request. kLIBC sources even contain a todo in that regard.Needed for Chromium (https://github.com/bitwiseworks/qtwebengine-chromium-os2/issues/19) but postponed since not actually used at runtime.