php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #3991 admin_values (like safe mode) can be overridden
Submitted: 2000-03-30 22:49 UTC Modified: 2005-01-31 23:05 UTC
From: djm at web dot us dot uu dot net Assigned:
Status: Closed Package: Apache related
PHP Version: 4.0 Release Candidate 1 OS: BSD/OS 4.0.1
Private report: No CVE-ID: None
 [2000-03-30 22:49 UTC] djm at web dot us dot uu dot net
Security problem:

PHP4 with apache 1.3.12, built as a DSO, allows "admin" values and flags (those marked PHP_INI_SYSTEM in main.c) to be reset in .htaccess files.  This bug also existed in PHP4b4 with apache 1.3.9.

To demonstrate the problem, in httpd.conf, set something like this: 

php_admin_flag safe_mode On
php_admin_value doc_root "/opt/homes/web/testtest5"
php_admin_value open_basedir "/opt/homes/web/testtest5"
php_admin_value safe_mode_exec_dir "/opt/homes/web/testtest5/bin"

(your textarea made that last line wrap)

Create a phpinfo.php file under the document root containing:
<?php phpinfo()?> 

GET phpinfo.php to verify that the settings above have been made.

Now, create a .htaccess in that directory containing:
php_value open_basedir "/"
php_value doc_root "/"
php_value safe_mode Off

GET phpinfo.php again and note that the values in the .htaccess file have superceded those in the server config file.

BTW, there's a related doc bug:
--- apidoc-zend.txt     2000/03/31 01:55:33     1.1.1.1
+++ apidoc-zend.txt     2000/03/31 03:44:44
@@ -238,7 +238,7 @@
 and "bah" respectively - note that all defaults are always given as
 strings.  That doesn't reduce your ability to use integer values, simply
 specify them as strings.  "foo" is marked so that it can be changed by
-anyone at any time (PHP_INI_ALL), whereas "foo" is marked so it can be
+anyone at any time (PHP_INI_ALL), whereas "bar" is marked so it can be
 changed only at startup in the php3.ini only, presumably, by the system
 administrator (PHP_INI_SYSTEM).
 When "foo" changes, no function is called.  Access to it is done using the




Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2000-03-31 02:14 UTC] djm at web dot us dot uu dot net
After adding some debugging code, I have a better understanding of what's going on.  The values in the .htaccess file are not being used, but they are overwriting in the hash table the values from the httpd.conf, so the compiled-in defaults are taking effect.
In sapi/apache/mod_php4.c, php_apache_alter_ini_entries calls php_alter_ini_entry, which does return -1 for the values that aren't settable from a .htaccess file, because they have modify_type PHP_INI_PERDIR (2).  But the values set in the httpd.conf (with modify_type PHP_INI_SYSTEM (4)) have disappeared.
In the mod_php4.c hash table merging code, php_merge_dir and copy_per_dir_entry shouldn't overwrite a global setting with a disallowed per-directory one.
Better yet, php_apache_value_handler_ex shouldn't enter disallowed values into the per-dir hash table in the first place (it should check mode first).
Here's a diff that seems to fix the problem, and includes some debugging code to help demonstrate it:

--- sapi/apache/mod_php4.c      2000/03/31 01:55:50     1.1.1.1
+++ sapi/apache/mod_php4.c      2000/03/31 07:10:39
@@ -394,7 +394,13 @@

 static int php_apache_alter_ini_entries(php_per_dir_entry *per_dir_entry)
 {
-       php_alter_ini_entry(per_dir_entry->key, per_dir_entry->key_length+1, per_dir_entry->value, per_dir_entry->value_length+1, per_dir_entry->type, PHP_INI_STAGE_ACTIVATE);
+       int i;
+       char msg[8192];
+       snprintf(msg, 8192, "altering ini entry %s=%s type=%d", per_dir_entry->key, per_dir_entry->value, per_dir_entry->type);
+       php_apache_log_message(msg);
+       i = php_alter_ini_entry(per_dir_entry->key, per_dir_entry->key_length+1, per_dir_entry->value, per_dir_entry->value_length+1, per_dir_entry->type, PHP_INI_STAGE_ACTIVATE);
+       snprintf(msg, 8192, " => %d", i);
+       php_apache_log_message(msg);
        return 0;
 }

@@ -560,6 +566,7 @@
 CONST_PREFIX char *php_apache_value_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode)
 {
        php_per_dir_entry per_dir_entry;
+       php_ini_entry *ini_entry;

        if (!apache_php_initialized) {
                sapi_startup(&sapi_module);
@@ -574,6 +581,14 @@

        per_dir_entry.key_length = strlen(arg1);
        per_dir_entry.value_length = strlen(arg2);
+
+       ini_entry = get_ini_entry(arg1, per_dir_entry.key_length + 1);
+       if (ini_entry && !(ini_entry->modifyable & mode)) {
+               char msg[8192];
+               snprintf(msg, 8192, "setting %s to %s in %d is not permitted", arg1, arg2, mode);
+               php_apache_log_message(msg);
+               return NULL;
+       }

        per_dir_entry.key = (char *) malloc(per_dir_entry.key_length+1);
        memcpy(per_dir_entry.key, arg1, per_dir_entry.key_length);

 [2000-03-31 02:27 UTC] djm at web dot us dot uu dot net
Here's a patch wtih a more user-friendly error message:

--- sapi/apache/mod_php4.c      2000/03/31 01:55:50     1.1
+++ sapi/apache/mod_php4.c      2000/03/31 07:24:01     1.2
@@ -560,6 +571,7 @@
 CONST_PREFIX char *php_apache_value_handler_ex(cmd_parms *cmd, HashTable *conf, char *arg1, char *arg2, int mode)
 {
        php_per_dir_entry per_dir_entry;
+       php_ini_entry *ini_entry;
 
        if (!apache_php_initialized) {
                sapi_startup(&sapi_module);
@@ -574,6 +586,20 @@
 
        per_dir_entry.key_length = strlen(arg1);
        per_dir_entry.value_length = strlen(arg2);
+
+       ini_entry = get_ini_entry(arg1, per_dir_entry.key_length + 1);
+       if (ini_entry && !(ini_entry->modifyable & mode)) {
+               char msg[8192], *context;
+               if (mode == PHP_INI_SYSTEM)
+                       context = "system";
+               else if (mode == PHP_INI_PERDIR)
+                       context = "per-directory";
+               else
+                       context = "unknown";
+               snprintf(msg, 8192, "php: not setting %s=\"%s\"; not permitted in %s configuration", arg1, arg2, context);
+               php_apache_log_message(msg);
+               return NULL;
+       }
 
        per_dir_entry.key = (char *) malloc(per_dir_entry.key_length+1);
        memcpy(per_dir_entry.key, arg1, per_dir_entry.key_length);

 [2000-03-31 02:47 UTC] djm at web dot us dot uu dot net
I should mention that I don't know what the best approach is for logging this error; I'm not suggesting using a fixed-length buffer, but I'm not sure what your preferred function call for this would be.  I figure the PHP maintainers know :-).

 [2000-08-16 15:44 UTC] waldschrott@php.net
as far as I can get it, that?s nothing unusual, you can
override values you?ve set in the .conf file via the
.htaccess file if you?ve allowed via .conf...
Maybe I did not understand the bug, comments anyone?
 [2000-08-16 19:10 UTC] rasmus@php.net
Of course it is unusual.  That is the whole point of having the distinction between flag and admin_flag

You definitely should not be able to override admin_flag values in a .htaccess
 [2000-10-12 05:53 UTC] stas@php.net
Fixed, please check.
 [2000-10-18 19:20 UTC] djm at web dot us dot uu dot net
Yes, this is fixed in 4.0.3pl1.  Thanks!

 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Oct 14 09:01:27 2024 UTC