Skip to content

Commit 1230672

Browse files
committed
Add system ID entropy API
The `zend_system_id` is a (true global) system ID that fingerprints a process state. When extensions add engine hooks during MINIT/startup, entropy is added the system ID for each hook. This allows extensions to identify that changes have been made to the engine since the last PHP process restart. Closes GH-5871
1 parent 30bb15b commit 1230672

16 files changed

+152
-61
lines changed

UPGRADING.INTERNALS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,10 @@ PHP 8.0 INTERNALS UPGRADE NOTES
369369
- zend_stack_is_empty()
370370
- zend_ts_hash_exists()
371371
- zend_ts_hash_index_exists()
372+
9. Argument void to const char* in Zend Engine 4.0:
373+
- zend_get_op_array_extension_handle()
374+
10. Argument zend_extension to const char* in Zend Engine 4.0:
375+
- zend_get_resource_handle()
372376

373377
u. Instead of overwriting zend_error_cb extensions with debugging, monitoring
374378
use-cases catching Errors/Exceptions are strongly encouraged to use

Zend/zend_execute.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "zend_type_info.h"
4242
#include "zend_smart_str.h"
4343
#include "zend_observer.h"
44+
#include "zend_system_id.h"
4445

4546
/* Virtual current working directory support */
4647
#include "zend_virtual_cwd.h"

Zend/zend_extensions.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919

2020
#include "zend_extensions.h"
21+
#include "zend_system_id.h"
2122

2223
ZEND_API zend_llist zend_extensions;
2324
ZEND_API uint32_t zend_extension_flags = 0;
@@ -247,18 +248,19 @@ ZEND_API void zend_extension_dispatch_message(int message, void *arg)
247248
}
248249

249250

250-
ZEND_API int zend_get_resource_handle(zend_extension *extension)
251+
ZEND_API int zend_get_resource_handle(const char *module_name)
251252
{
252253
if (last_resource_number<ZEND_MAX_RESERVED_RESOURCES) {
253-
extension->resource_number = last_resource_number;
254+
zend_add_system_entropy(module_name, "zend_get_resource_handle", &last_resource_number, sizeof(int));
254255
return last_resource_number++;
255256
} else {
256257
return -1;
257258
}
258259
}
259260

260-
ZEND_API int zend_get_op_array_extension_handle(void)
261+
ZEND_API int zend_get_op_array_extension_handle(const char *module_name)
261262
{
263+
zend_add_system_entropy(module_name, "zend_get_op_array_extension_handle", &zend_op_array_extension_handles, sizeof(int));
262264
return zend_op_array_extension_handles++;
263265
}
264266

Zend/zend_extensions.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ struct _zend_extension {
113113
BEGIN_EXTERN_C()
114114
extern ZEND_API int zend_op_array_extension_handles;
115115

116-
ZEND_API int zend_get_resource_handle(zend_extension *extension);
117-
ZEND_API int zend_get_op_array_extension_handle(void);
116+
ZEND_API int zend_get_resource_handle(const char *module_name);
117+
ZEND_API int zend_get_op_array_extension_handle(const char *module_name);
118118
ZEND_API void zend_extension_dispatch_message(int message, void *arg);
119119
END_EXTERN_C()
120120

Zend/zend_observer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init init) {
5050
/* We don't want to get an extension handle unless an ext installs an observer */
5151
if (!ZEND_OBSERVER_ENABLED) {
5252
zend_observer_fcall_op_array_extension =
53-
zend_get_op_array_extension_handle();
53+
zend_get_op_array_extension_handle("Zend Observer");
5454

5555
/* ZEND_CALL_TRAMPOLINE has SPEC(OBSERVER) but zend_init_call_trampoline_op()
5656
* is called before any extensions have registered as an observer. So we

Zend/zend_system_id.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Copyright (c) The PHP Group |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 3.01 of the PHP license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| http://www.php.net/license/3_01.txt |
9+
| If you did not receive a copy of the PHP license and are unable to |
10+
| obtain it through the world-wide-web, please send a note to |
11+
| [email protected] so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Authors: Sammy Kaye Powers <[email protected]> |
14+
| Dmitry Stogov <[email protected]> |
15+
+----------------------------------------------------------------------+
16+
*/
17+
18+
#include "php.h"
19+
#include "zend_system_id.h"
20+
#include "zend_extensions.h"
21+
#include "ext/standard/md5.h"
22+
#include "ext/hash/php_hash.h"
23+
24+
ZEND_API char zend_system_id[32];
25+
26+
static PHP_MD5_CTX context;
27+
static int finalized = 0;
28+
29+
ZEND_API ZEND_RESULT_CODE zend_add_system_entropy(const char *module_name, const char *hook_name, const void *data, size_t size)
30+
{
31+
if (finalized == 0) {
32+
PHP_MD5Update(&context, module_name, strlen(module_name));
33+
PHP_MD5Update(&context, hook_name, strlen(hook_name));
34+
if (size) {
35+
PHP_MD5Update(&context, data, size);
36+
}
37+
return SUCCESS;
38+
}
39+
return FAILURE;
40+
}
41+
42+
#define ZEND_BIN_ID "BIN_" ZEND_TOSTR(SIZEOF_INT) ZEND_TOSTR(SIZEOF_LONG) ZEND_TOSTR(SIZEOF_SIZE_T) ZEND_TOSTR(SIZEOF_ZEND_LONG) ZEND_TOSTR(ZEND_MM_ALIGNMENT)
43+
44+
void zend_startup_system_id(void)
45+
{
46+
PHP_MD5Init(&context);
47+
PHP_MD5Update(&context, PHP_VERSION, sizeof(PHP_VERSION)-1);
48+
PHP_MD5Update(&context, ZEND_EXTENSION_BUILD_ID, sizeof(ZEND_EXTENSION_BUILD_ID)-1);
49+
PHP_MD5Update(&context, ZEND_BIN_ID, sizeof(ZEND_BIN_ID)-1);
50+
if (strstr(PHP_VERSION, "-dev") != 0) {
51+
/* Development versions may be changed from build to build */
52+
PHP_MD5Update(&context, __DATE__, sizeof(__DATE__)-1);
53+
PHP_MD5Update(&context, __TIME__, sizeof(__TIME__)-1);
54+
}
55+
zend_system_id[0] = '\0';
56+
}
57+
58+
#define ZEND_HOOK_AST_PROCESS (1 << 0)
59+
#define ZEND_HOOK_COMPILE_FILE (1 << 1)
60+
#define ZEND_HOOK_EXECUTE_EX (1 << 2)
61+
#define ZEND_HOOK_EXECUTE_INTERNAL (1 << 3)
62+
63+
void zend_finalize_system_id(void)
64+
{
65+
unsigned char digest[16];
66+
zend_uchar hooks = 0;
67+
68+
if (zend_ast_process) {
69+
hooks |= ZEND_HOOK_AST_PROCESS;
70+
}
71+
if (zend_compile_file != compile_file) {
72+
hooks |= ZEND_HOOK_COMPILE_FILE;
73+
}
74+
if (zend_execute_ex != execute_ex) {
75+
hooks |= ZEND_HOOK_EXECUTE_EX;
76+
}
77+
if (zend_execute_internal) {
78+
hooks |= ZEND_HOOK_EXECUTE_INTERNAL;
79+
}
80+
PHP_MD5Update(&context, &hooks, sizeof hooks);
81+
82+
for (int16_t i = 0; i < 256; i++) {
83+
if (zend_get_user_opcode_handler((zend_uchar) i) != NULL) {
84+
PHP_MD5Update(&context, &i, sizeof i);
85+
}
86+
}
87+
88+
PHP_MD5Final(digest, &context);
89+
php_hash_bin2hex(zend_system_id, digest, sizeof digest);
90+
finalized = 1;
91+
}

Zend/zend_system_id.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Copyright (c) The PHP Group |
4+
+----------------------------------------------------------------------+
5+
| This source file is subject to version 3.01 of the PHP license, |
6+
| that is bundled with this package in the file LICENSE, and is |
7+
| available through the world-wide-web at the following url: |
8+
| http://www.php.net/license/3_01.txt |
9+
| If you did not receive a copy of the PHP license and are unable to |
10+
| obtain it through the world-wide-web, please send a note to |
11+
| [email protected] so we can mail you a copy immediately. |
12+
+----------------------------------------------------------------------+
13+
| Author: Sammy Kaye Powers <[email protected]> |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#ifndef ZEND_SYSTEM_ID_H
18+
#define ZEND_SYSTEM_ID_H
19+
20+
BEGIN_EXTERN_C()
21+
/* True global; Write-only during MINIT/startup */
22+
extern ZEND_API char zend_system_id[32];
23+
24+
ZEND_API ZEND_RESULT_CODE zend_add_system_entropy(const char *module_name, const char *hook_name, const void *data, size_t size);
25+
END_EXTERN_C()
26+
27+
void zend_startup_system_id(void);
28+
void zend_finalize_system_id(void);
29+
30+
#endif /* ZEND_SYSTEM_ID_H */

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1464,7 +1464,7 @@ PHP_ADD_SOURCES(Zend, \
14641464
zend_closures.c zend_weakrefs.c zend_float.c zend_string.c zend_signal.c zend_generators.c \
14651465
zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \
14661466
zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c \
1467-
zend_observer.c, \
1467+
zend_observer.c zend_system_id.c, \
14681468
-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
14691469

14701470
PHP_ADD_BUILD_DIR(main main/streams)

ext/opcache/Optimizer/zend_func_info.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -942,11 +942,10 @@ uint32_t zend_get_func_info(
942942

943943
int zend_func_info_startup(void)
944944
{
945-
zend_extension dummy;
946945
size_t i;
947946

948947
if (zend_func_info_rid == -1) {
949-
zend_func_info_rid = zend_get_resource_handle(&dummy);
948+
zend_func_info_rid = zend_get_resource_handle("Zend Optimizer");
950949
if (zend_func_info_rid < 0) {
951950
return FAILURE;
952951
}

ext/opcache/ZendAccelerator.c

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ ZEND_TSRMLS_CACHE_DEFINE()
106106
zend_accel_shared_globals *accel_shared_globals = NULL;
107107

108108
/* true globals, no need for thread safety */
109-
char accel_system_id[32];
110109
#ifdef ZEND_WIN32
111110
char accel_uname_id[32];
112111
#endif
@@ -126,7 +125,6 @@ static zif_handler orig_chdir = NULL;
126125
static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
127126
static zend_result (*orig_post_startup_cb)(void);
128127

129-
static void accel_gen_system_id(void);
130128
static zend_result accel_post_startup(void);
131129
static int accel_finish_startup(void);
132130

@@ -2709,46 +2707,6 @@ static void accel_globals_ctor(zend_accel_globals *accel_globals)
27092707
memset(accel_globals, 0, sizeof(zend_accel_globals));
27102708
}
27112709

2712-
#define ZEND_BIN_ID "BIN_" ZEND_TOSTR(SIZEOF_INT) ZEND_TOSTR(SIZEOF_LONG) ZEND_TOSTR(SIZEOF_SIZE_T) ZEND_TOSTR(SIZEOF_ZEND_LONG) ZEND_TOSTR(ZEND_MM_ALIGNMENT)
2713-
2714-
static void accel_gen_system_id(void)
2715-
{
2716-
PHP_MD5_CTX context;
2717-
unsigned char digest[16];
2718-
zend_module_entry *module;
2719-
zend_extension *extension;
2720-
zend_llist_position pos;
2721-
2722-
PHP_MD5Init(&context);
2723-
PHP_MD5Update(&context, PHP_VERSION, sizeof(PHP_VERSION)-1);
2724-
PHP_MD5Update(&context, ZEND_EXTENSION_BUILD_ID, sizeof(ZEND_EXTENSION_BUILD_ID)-1);
2725-
PHP_MD5Update(&context, ZEND_BIN_ID, sizeof(ZEND_BIN_ID)-1);
2726-
if (strstr(PHP_VERSION, "-dev") != 0) {
2727-
/* Development versions may be changed from build to build */
2728-
PHP_MD5Update(&context, __DATE__, sizeof(__DATE__)-1);
2729-
PHP_MD5Update(&context, __TIME__, sizeof(__TIME__)-1);
2730-
}
2731-
/* Modules may have changed after restart which can cause dangling pointers from
2732-
* custom opcode handlers in the second-level cache files
2733-
*/
2734-
ZEND_HASH_FOREACH_PTR(&module_registry, module) {
2735-
PHP_MD5Update(&context, module->name, strlen(module->name));
2736-
if (module->version != NULL) {
2737-
PHP_MD5Update(&context, module->version, strlen(module->version));
2738-
}
2739-
} ZEND_HASH_FOREACH_END();
2740-
extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos);
2741-
while (extension) {
2742-
PHP_MD5Update(&context, extension->name, strlen(extension->name));
2743-
if (extension->version != NULL) {
2744-
PHP_MD5Update(&context, extension->version, strlen(extension->version));
2745-
}
2746-
extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos);
2747-
}
2748-
PHP_MD5Final(digest, &context);
2749-
php_hash_bin2hex(accel_system_id, digest, sizeof digest);
2750-
}
2751-
27522710
#ifdef HAVE_HUGE_CODE_PAGES
27532711
# ifndef _WIN32
27542712
# include <sys/mman.h>
@@ -2933,8 +2891,6 @@ static int accel_startup(zend_extension *extension)
29332891
# endif
29342892
#endif
29352893

2936-
accel_gen_system_id();
2937-
29382894
if (start_accel_module() == FAILURE) {
29392895
accel_startup_ok = 0;
29402896
zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": module registration failed!");

0 commit comments

Comments
 (0)