Implement stricter extension compatibility check

This hardens the dynamic module loading by checking the linker compatibility
between the core and the dynamic module. This likely should be extended
for the CRT as well, as 2015, 2017 and 2019 versions of Visual Studio
all have same DLL name for the CRT.
This commit is contained in:
Anatol Belski 2019-03-31 14:01:36 +02:00
parent 2733420f82
commit ddce7ada4c
4 changed files with 66 additions and 0 deletions

View file

@ -167,6 +167,16 @@ PHPAPI int php_load_extension(char *filename, int type, int start_now)
efree(err1);
}
#ifdef PHP_WIN32
if (!php_win32_image_compatible(libpath, NULL, &err1)) {
php_error_docref(NULL, error_type, err1);
efree(err1);
efree(libpath);
DL_UNLOAD(handle);
return FAILURE;
}
#endif
efree(libpath);
get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module");

View file

@ -339,6 +339,13 @@ static void php_load_zend_extension_cb(void *arg)
#endif
if (IS_ABSOLUTE_PATH(filename, length)) {
#ifdef PHP_WIN32
char *err;
if (!php_win32_image_compatible(filename, NULL, &err)) {
php_error(E_CORE_WARNING, err);
return FAILURE;
}
#endif
zend_load_extension(filename);
} else {
DL_HANDLE handle;
@ -384,6 +391,16 @@ static void php_load_zend_extension_cb(void *arg)
efree(err1);
}
#ifdef PHP_WIN32
if (!php_win32_image_compatible(libpath, NULL, &err1)) {
php_error(E_CORE_WARNING, err1);
efree(err1);
efree(libpath);
DL_UNLOAD(handle);
return FAILURE;
}
#endif
zend_load_extension_handle(handle, libpath);
efree(libpath);
}

View file

@ -22,6 +22,8 @@
#include "codepage.h"
#include <bcrypt.h>
#include <lmcons.h>
#include <imagehlp.h>
PHP_WINUTIL_API char *php_win32_error_to_msg(HRESULT error)
{/*{{{*/
@ -435,3 +437,38 @@ PHP_WINUTIL_API char *php_win32_get_username(void)
return uname;
}/*}}}*/
PHP_WINUTIL_API BOOL php_win32_image_compatible(const char *name, const char *path, char **err)
{/*{{{*/
PLOADED_IMAGE img = ImageLoad(name, NULL);
if (!img) {
DWORD _err = GetLastError();
char *err_txt = php_win32_error_to_msg(_err);
spprintf(err, 0, "Failed to load %s, %s", name, err_txt);
free(err_txt);
return FALSE;
}
DWORD major = img->FileHeader->OptionalHeader.MajorLinkerVersion;
DWORD minor = img->FileHeader->OptionalHeader.MinorLinkerVersion;
/* VS 2015, 2017 and 2019 are binary compatible, but only forward compatible.
It should be fine, if we load a module linked with an older one into
the core linked with the newer one, but not the otherway round.
Otherwise, if the linker major version is not same, it is an error, as
per the current knowledge.
This check is to be extended as new VS versions come out. */
if (14 == major && PHP_LINKER_MINOR < minor
|| PHP_LINKER_MAJOR != major) {
spprintf(err, 0, "Can't load module '%s' as it's linked with %u.%u, but the core is linked with %d.%d", name, major, minor, PHP_LINKER_MAJOR, PHP_LINKER_MINOR);
ImageUnload(img);
return FALSE;
}
ImageUnload(img);
return TRUE;
}/*}}}*/

View file

@ -55,4 +55,6 @@ PHP_WINUTIL_API int php_win32_code_to_errno(unsigned long w32Err);
PHP_WINUTIL_API char *php_win32_get_username(void);
PHP_WINUTIL_API BOOL php_win32_image_compatible(const char *img, const char *path, char **err);
#endif