Skip to content

Commit f4e2e91

Browse files
authored
core: Remove disable_classes INI setting
RFC: https://wiki.php.net/rfc/deprecations_php_8_5#remove_disable_classes_ini_setting This took longer to merge than expected but the initial motivation from 2 years ago still applied: As described in the email to the PHP internals list [1] this feature is fundamentally broken and pointless. Only internal classes can be disable which brings the following observation. On a minimal build of PHP, with only the mandatory extensions enabled, there are 148 classes/interfaces/traits defined. [2] Other than the SPL ones (and even then), disabling any of these classes will cause issues within the engine. Moreover, the SPL ones are not a security concern. Therefore, any other class that can be disabled must come from an extension that can be disabled altogether. And "disabling" a class from an extension without disabling said extension will render it useless anyway. If a hosting provided is concerned about an extension, then it should not enable it in the first place. Not break it ad hoc. Considering the above, I cannot see how this functionality was ever useful. This is in stark contrast to the disable_functions INI setting, which can be used to selectively remove functionality of an extension without breaking it overall. What makes this setting particularly broken is that it does not unregister the class, it only overwrites the create CE handler to emit a warning and purge the properties and function hashtables. This leads to various use after free, segfaults, and broken expectations for the engine and extensions which define said classes. On top of that, it is possible to actually instantiate such a class (and even classes which actually disallow this like ext/imap) in userland, and pass it to function that are typed against said class without raising a TypeError. However, when trying to do anything with said object stuff is going to explode in countless ways. [1] https://news-web.php.net/php.internals/120896 [2] https://gist.github.com/Girgias/63d55ba1e50b580412b004046daed02b
1 parent 5d5305d commit f4e2e91

File tree

12 files changed

+49
-206
lines changed

12 files changed

+49
-206
lines changed

Zend/tests/bug77494.phpt

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Check that warning is emitted when disabling classes
3+
--INI--
4+
disable_classes=Exception
5+
--FILE--
6+
<?php
7+
$o = new Exception();
8+
var_dump($o);
9+
?>
10+
--EXPECTF--
11+
object(Exception)#1 (7) {
12+
["message":protected]=>
13+
string(0) ""
14+
["string":"Exception":private]=>
15+
string(0) ""
16+
["code":protected]=>
17+
int(0)
18+
["file":protected]=>
19+
string(%d) "%s"
20+
["line":protected]=>
21+
int(2)
22+
["trace":"Exception":private]=>
23+
array(0) {
24+
}
25+
["previous":"Exception":private]=>
26+
NULL
27+
}

Zend/tests/errmsg/errmsg_021.phpt

Lines changed: 0 additions & 17 deletions
This file was deleted.

Zend/zend_API.c

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3692,77 +3692,6 @@ ZEND_API void zend_disable_functions(const char *function_list) /* {{{ */
36923692
}
36933693
/* }}} */
36943694

3695-
#ifdef ZEND_WIN32
3696-
#pragma optimize("", off)
3697-
#endif
3698-
static ZEND_COLD zend_object *display_disabled_class(zend_class_entry *class_type) /* {{{ */
3699-
{
3700-
zend_object *intern;
3701-
3702-
intern = zend_objects_new(class_type);
3703-
3704-
/* Initialize default properties */
3705-
if (EXPECTED(class_type->default_properties_count != 0)) {
3706-
zval *p = intern->properties_table;
3707-
zval *end = p + class_type->default_properties_count;
3708-
do {
3709-
ZVAL_UNDEF(p);
3710-
p++;
3711-
} while (p != end);
3712-
}
3713-
3714-
zend_error(E_WARNING, "%s() has been disabled for security reasons", ZSTR_VAL(class_type->name));
3715-
return intern;
3716-
}
3717-
#ifdef ZEND_WIN32
3718-
#pragma optimize("", on)
3719-
#endif
3720-
/* }}} */
3721-
3722-
static const zend_function_entry disabled_class_new[] = {
3723-
ZEND_FE_END
3724-
};
3725-
3726-
ZEND_API zend_result zend_disable_class(const char *class_name, size_t class_name_length) /* {{{ */
3727-
{
3728-
zend_class_entry *disabled_class;
3729-
zend_string *key;
3730-
zend_function *fn;
3731-
zend_property_info *prop;
3732-
3733-
key = zend_string_alloc(class_name_length, 0);
3734-
zend_str_tolower_copy(ZSTR_VAL(key), class_name, class_name_length);
3735-
disabled_class = zend_hash_find_ptr(CG(class_table), key);
3736-
zend_string_release_ex(key, 0);
3737-
if (!disabled_class) {
3738-
return FAILURE;
3739-
}
3740-
3741-
/* Will be reset by INIT_CLASS_ENTRY. */
3742-
free(disabled_class->interfaces);
3743-
3744-
INIT_CLASS_ENTRY_INIT_METHODS((*disabled_class), disabled_class_new);
3745-
disabled_class->create_object = display_disabled_class;
3746-
3747-
ZEND_HASH_MAP_FOREACH_PTR(&disabled_class->function_table, fn) {
3748-
if ((fn->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) &&
3749-
fn->common.scope == disabled_class) {
3750-
zend_free_internal_arg_info(&fn->internal_function);
3751-
}
3752-
} ZEND_HASH_FOREACH_END();
3753-
zend_hash_clean(&disabled_class->function_table);
3754-
ZEND_HASH_MAP_FOREACH_PTR(&disabled_class->properties_info, prop) {
3755-
if (prop->ce == disabled_class) {
3756-
zend_string_release(prop->name);
3757-
zend_type_release(prop->type, /* persistent */ 1);
3758-
free(prop);
3759-
}
3760-
} ZEND_HASH_FOREACH_END();
3761-
zend_hash_clean(&disabled_class->properties_info);
3762-
return SUCCESS;
3763-
}
3764-
/* }}} */
3765-
37663695
static zend_always_inline zend_class_entry *get_scope(zend_execute_data *frame)
37673696
{
37683697
return frame && frame->func ? frame->func->common.scope : NULL;

Zend/zend_API.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,6 @@ static zend_always_inline zend_result zend_register_class_alias(const char *name
405405
zend_register_class_alias_ex(ZEND_NS_NAME(ns, name), sizeof(ZEND_NS_NAME(ns, name))-1, ce, 1)
406406

407407
ZEND_API void zend_disable_functions(const char *function_list);
408-
ZEND_API zend_result zend_disable_class(const char *class_name, size_t class_name_length);
409408

410409
ZEND_API ZEND_COLD void zend_wrong_param_count(void);
411410
ZEND_API ZEND_COLD void zend_wrong_property_read(zval *object, zval *property);

main/main.c

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -413,41 +413,6 @@ static PHP_INI_MH(OnSetLogFilter)
413413
}
414414
/* }}} */
415415

416-
/* {{{ php_disable_classes */
417-
static void php_disable_classes(void)
418-
{
419-
char *s = NULL, *e;
420-
421-
if (!*(INI_STR("disable_classes"))) {
422-
return;
423-
}
424-
425-
e = PG(disable_classes) = strdup(INI_STR("disable_classes"));
426-
427-
while (*e) {
428-
switch (*e) {
429-
case ' ':
430-
case ',':
431-
if (s) {
432-
*e = '\0';
433-
zend_disable_class(s, e-s);
434-
s = NULL;
435-
}
436-
break;
437-
default:
438-
if (!s) {
439-
s = e;
440-
}
441-
break;
442-
}
443-
e++;
444-
}
445-
if (s) {
446-
zend_disable_class(s, e-s);
447-
}
448-
}
449-
/* }}} */
450-
451416
/* {{{ php_binary_init */
452417
static void php_binary_init(void)
453418
{
@@ -872,7 +837,6 @@ PHP_INI_BEGIN()
872837
PHP_INI_ENTRY("sendmail_path", DEFAULT_SENDMAIL_PATH, PHP_INI_SYSTEM, NULL)
873838
PHP_INI_ENTRY("mail.force_extra_parameters",NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnChangeMailForceExtra)
874839
PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL)
875-
PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL)
876840
PHP_INI_ENTRY("max_file_uploads", "20", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL)
877841
PHP_INI_ENTRY("max_multipart_body_parts", "-1", PHP_INI_SYSTEM|PHP_INI_PERDIR, NULL)
878842

@@ -2105,9 +2069,6 @@ static void core_globals_dtor(php_core_globals *core_globals)
21052069
ZEND_ASSERT(!core_globals->last_error_message);
21062070
ZEND_ASSERT(!core_globals->last_error_file);
21072071

2108-
if (core_globals->disable_classes) {
2109-
free(core_globals->disable_classes);
2110-
}
21112072
if (core_globals->php_binary) {
21122073
free(core_globals->php_binary);
21132074
}
@@ -2372,9 +2333,8 @@ zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additi
23722333
}
23732334
}
23742335

2375-
/* disable certain classes and functions as requested by php.ini */
2336+
/* disable certain functions as requested by php.ini */
23762337
zend_disable_functions(INI_STR("disable_functions"));
2377-
php_disable_classes();
23782338

23792339
/* make core report what it should */
23802340
if ((module = zend_hash_str_find_ptr(&module_registry, "core", sizeof("core")-1)) != NULL) {
@@ -2403,7 +2363,7 @@ zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additi
24032363
struct {
24042364
const long error_level;
24052365
const char *phrase;
2406-
const char *directives[18]; /* Remember to change this if the number of directives change */
2366+
const char *directives[19]; /* Remember to change this if the number of directives change */
24072367
} directives[2] = {
24082368
{
24092369
E_DEPRECATED,
@@ -2434,6 +2394,7 @@ zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additi
24342394
"safe_mode_protected_env_vars",
24352395
"zend.ze1_compatibility_mode",
24362396
"track_errors",
2397+
"disable_classes",
24372398
NULL
24382399
}
24392400
}

main/php_globals.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ struct _php_core_globals {
143143

144144
char *php_sys_temp_dir;
145145

146-
char *disable_classes;
147146
zend_long max_input_nesting_level;
148147
zend_long max_input_vars;
149148

php.ini-development

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,6 @@ serialize_precision = -1
327327
; https://php.net/disable-functions
328328
disable_functions =
329329

330-
; This directive allows you to disable certain classes.
331-
; It receives a comma-delimited list of class names.
332-
; https://php.net/disable-classes
333-
disable_classes =
334-
335330
; Colors for Syntax Highlighting mode. Anything that's acceptable in
336331
; <span style="color: ???????"> would work.
337332
; https://php.net/syntax-highlighting

php.ini-production

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,6 @@ serialize_precision = -1
327327
; https://php.net/disable-functions
328328
disable_functions =
329329

330-
; This directive allows you to disable certain classes.
331-
; It receives a comma-delimited list of class names.
332-
; https://php.net/disable-classes
333-
disable_classes =
334-
335330
; Colors for Syntax Highlighting mode. Anything that's acceptable in
336331
; <span style="color: ???????"> would work.
337332
; https://php.net/syntax-highlighting

sapi/fpm/fpm/fpm_php.c

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -48,35 +48,6 @@ static int fpm_php_zend_ini_alter_master(char *name, int name_length, char *new_
4848
}
4949
/* }}} */
5050

51-
static void fpm_php_disable(char *value, int (*zend_disable)(const char *, size_t)) /* {{{ */
52-
{
53-
char *s = 0, *e = value;
54-
55-
while (*e) {
56-
switch (*e) {
57-
case ' ':
58-
case ',':
59-
if (s) {
60-
*e = '\0';
61-
zend_disable(s, e - s);
62-
s = 0;
63-
}
64-
break;
65-
default:
66-
if (!s) {
67-
s = e;
68-
}
69-
break;
70-
}
71-
e++;
72-
}
73-
74-
if (s) {
75-
zend_disable(s, e - s);
76-
}
77-
}
78-
/* }}} */
79-
8051
#define FPM_PHP_INI_ALTERING_ERROR -1
8152
#define FPM_PHP_INI_APPLIED 1
8253
#define FPM_PHP_INI_EXTENSION_FAILED 0
@@ -121,13 +92,6 @@ int fpm_php_apply_defines_ex(struct key_value_s *kv, int mode) /* {{{ */
12192
return FPM_PHP_INI_APPLIED;
12293
}
12394

124-
if (!strcmp(name, "disable_classes") && *value) {
125-
char *v = strdup(value);
126-
PG(disable_classes) = v;
127-
fpm_php_disable(v, zend_disable_class);
128-
return FPM_PHP_INI_APPLIED;
129-
}
130-
13195
return FPM_PHP_INI_APPLIED;
13296
}
13397
/* }}} */

0 commit comments

Comments
 (0)