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);

Attachment: pgp00000.pgp
Description: PGP signature

Reply via email to