The attached patch changes dl() so that, instead of outright refusing to run under safe mode, it performs additional security checks on the value of extension_dir and accepts a filename-only argument (no directories) from the caller. In addition, if the provided argument doesn't return a handle, dl will append the value of PHP_SHLIB_SUFFIX to the filename and try again.
Rationale: Most Linux distributions that include PHP ship the majority of extensions as shared objects, to make it easier for the user to get just those features they need. In addition, there are many extensions not provided by Linux distributors that a user may wish to add locally. Unfortunately, current PHP programmer culture leads to all extensions being loaded via php.ini, which -- contrary to some claims made in the past on this list -- often causes instability when used with apache 1.3. Simply put, the current state of libraries on Linux isn't good enough to cope with all possible libraries being loaded into a single apache process at once; and SSL-using extensions seem to have problems of their very own when it comes to Apache's load-unload-load-rinse-spindry handling of DSOs at start time. Supporting a reasonable dl() function under safe mode is the first step toward being able to wean users off of this fragile configuration. -- Steve Langasek postmodern programmer
Index: ext/standard/dl.c =================================================================== RCS file: /repository/php-src/ext/standard/dl.c,v retrieving revision 1.83 diff -u -w -u -r1.83 dl.c --- ext/standard/dl.c 10 Jun 2003 20:03:37 -0000 1.83 +++ ext/standard/dl.c 17 Aug 2003 02:30:55 -0000 @@ -78,8 +78,6 @@ if (!PG(enable_dl)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Dynamically loaded extentions aren't enabled"); - } else if (PG(safe_mode)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Dynamically loaded extensions aren't allowed when running in Safe Mode"); } else { php_dl(*file, MODULE_TEMPORARY, return_value TSRMLS_CC); EG(full_tables_cleanup) = 1; @@ -107,6 +105,8 @@ zend_module_entry *(*get_module)(void); int error_type; char *extension_dir; + char *file_name; + int file_len; if (type==MODULE_PERSISTENT) { /* Use the configuration hash directly, the INI mechanism is not yet initialized */ @@ -123,22 +123,58 @@ error_type = E_CORE_WARNING; } + if (PG(safe_mode) && (!extension_dir || !extension_dir[0] + || !IS_ABSOLUTE_PATH(extension_dir,strlen(extension_dir)))) + { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Dynamically loaded extensions aren't allowed when running in Safe Mode unless an absolute extension_dir is set"); + RETURN_FALSE; + } + + file_len = Z_STRLEN_P(file); + file_name = estrndup(Z_STRVAL_P(file), file_len); + if (extension_dir && extension_dir[0]){ + char *fp; int extension_dir_len = strlen(extension_dir); - libpath = emalloc(extension_dir_len+Z_STRLEN_P(file)+2); + /* If we're running in safe mode, only accept a relative + filename -- no directories. */ + if (PG(safe_mode)) { + fp = file_name + file_len - 1; + while (fp > file_name && !IS_SLASH(*(fp-1))) + fp--; + } else { + fp = file_name; + } + libpath = emalloc(extension_dir_len+strlen(fp)+2); if (IS_SLASH(extension_dir[extension_dir_len-1])) { - sprintf(libpath, "%s%s", extension_dir, Z_STRVAL_P(file)); /* SAFE */ + sprintf(libpath, "%s%s", extension_dir, fp); /* SAFE */ } else { - sprintf(libpath, "%s%c%s", extension_dir, DEFAULT_SLASH, Z_STRVAL_P(file)); /* SAFE */ + sprintf(libpath, "%s%c%s", extension_dir, DEFAULT_SLASH, fp); /* SAFE */ } + efree(file_name); } else { - libpath = estrndup(Z_STRVAL_P(file), Z_STRLEN_P(file)); + libpath = file_name; } /* load dynamic symbol */ handle = DL_LOAD(libpath); +#ifdef PHP_SHLIB_SUFFIX + /* On error, try again using the PHP_SHLIB_SUFFIX */ + if (!handle) { + char *libpath_ext = emalloc(strlen(libpath)+1+sizeof(PHP_SHLIB_SUFFIX)); + + snprintf(libpath_ext, + strlen(libpath)+1+sizeof(PHP_SHLIB_SUFFIX), + "%s." PHP_SHLIB_SUFFIX, libpath); + + handle = DL_LOAD(libpath_ext); + + efree(libpath_ext); + } +#endif + if (!handle) { php_error_docref(NULL TSRMLS_CC, error_type, "Unable to load dynamic library '%s' - %s", libpath, GET_DL_ERROR()); efree(libpath);
pgp00000.pgp
Description: PGP signature