summaryrefslogtreecommitdiff
path: root/src/sp_execute.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sp_execute.c')
-rw-r--r--src/sp_execute.c105
1 files changed, 69 insertions, 36 deletions
diff --git a/src/sp_execute.c b/src/sp_execute.c
index 3a474a3..b4e5c6c 100644
--- a/src/sp_execute.c
+++ b/src/sp_execute.c
@@ -11,11 +11,10 @@ static zend_result (*orig_zend_stream_open)(zend_file_handle *handle) = NULL;
11#endif 11#endif
12 12
13// FIXME handle symlink 13// FIXME handle symlink
14ZEND_COLD static inline void terminate_if_writable(const char *filename) { 14ZEND_COLD static inline void terminate_if_writable(char const* const filename) {
15 const sp_config_readonly_exec *config_ro_exec = &(SPCFG(readonly_exec)); 15 sp_config_readonly_exec const* const config_ro_exec = &(SPCFG(readonly_exec));
16 char *errmsg = "unknown access problem"; 16 char const *errmsg = "unknown access problem";
17 17
18 // check write access
19 if (0 == access(filename, W_OK)) { 18 if (0 == access(filename, W_OK)) {
20 errmsg = "Attempted execution of a writable file"; 19 errmsg = "Attempted execution of a writable file";
21 goto violation; 20 goto violation;
@@ -29,21 +28,20 @@ ZEND_COLD static inline void terminate_if_writable(const char *filename) {
29 return; 28 return;
30 } 29 }
31 30
32 // check effective uid
33 struct stat buf; 31 struct stat buf;
34 if (0 != stat(filename, &buf)) { 32 if (0 != stat(filename, &buf)) {
35 goto err; 33 goto err;
36 } 34 }
37 if (buf.st_uid == geteuid()) { 35 if (buf.st_uid == geteuid()) {
38 errmsg = "Attempted execution of file owned by process"; 36 errmsg = "Attempted execution of a file owned by the PHP process";
39 goto violation; 37 goto violation;
40 } 38 }
41 39
42 // check write access on directory 40 char *const dirname = estrndup(filename, strlen(filename));
43 char *dirname = estrndup(filename, strlen(filename));
44 php_dirname(dirname, strlen(dirname)); 41 php_dirname(dirname, strlen(dirname));
45 if (0 == access(dirname, W_OK)) { 42 if (0 == access(dirname, W_OK)) {
46 errmsg = "Attempted execution of file in writable directory"; 43 errmsg = "Attempted execution of a file in a writable directory";
44
47 efree(dirname); 45 efree(dirname);
48 goto violation; 46 goto violation;
49 } 47 }
@@ -52,18 +50,16 @@ ZEND_COLD static inline void terminate_if_writable(const char *filename) {
52 goto err; 50 goto err;
53 } 51 }
54 52
55 // check effecite uid of directory
56 if (0 != stat(dirname, &buf)) { 53 if (0 != stat(dirname, &buf)) {
57 efree(dirname); 54 efree(dirname);
58 goto err; 55 goto err;
59 } 56 }
60 efree(dirname); 57 efree(dirname);
61 if (buf.st_uid == geteuid()) { 58 if (buf.st_uid == geteuid()) {
62 errmsg = "Attempted execution of file in directory owned by process"; 59 errmsg = "Attempted execution of a file in directory owned by the PHP process";
63 goto violation; 60 goto violation;
64 } 61 }
65 62
66 // we would actually need to check all parent directories as well, but that task is left for other tools
67 return; 63 return;
68 64
69violation: 65violation:
@@ -93,8 +89,8 @@ inline static void is_builtin_matching(
93 should_disable_ht(EG(current_execute_data), function_name, param_value, param_name, SPCFG(disabled_functions_reg).disabled_functions, ht); 89 should_disable_ht(EG(current_execute_data), function_name, param_value, param_name, SPCFG(disabled_functions_reg).disabled_functions, ht);
94} 90}
95 91
96static void ZEND_HOT is_in_eval_and_whitelisted(const zend_execute_data *execute_data) { 92static void ZEND_HOT is_in_eval_and_whitelisted(zend_execute_data const* const execute_data) {
97 const sp_config_eval *config_eval = &(SPCFG(eval)); 93 sp_config_eval const* const config_eval = &(SPCFG(eval));
98 94
99 if (EXPECTED(0 == SPG(in_eval))) { 95 if (EXPECTED(0 == SPG(in_eval))) {
100 return; 96 return;
@@ -113,18 +109,18 @@ static void ZEND_HOT is_in_eval_and_whitelisted(const zend_execute_data *execute
113 return; 109 return;
114 } 110 }
115 111
116 if (UNEXPECTED(false == check_is_in_eval_whitelist(function_name))) { 112 if (UNEXPECTED(false == check_is_in_eval_whitelist(function_name))) {
117 if (config_eval->dump) { 113 if (config_eval->dump) {
118 sp_log_request(config_eval->dump, config_eval->textual_representation); 114 sp_log_request(config_eval->dump, config_eval->textual_representation);
119 }
120 if (config_eval->simulation) {
121 sp_log_simulation("Eval_whitelist", "The function '%s' isn't in the eval whitelist, logging its call.", function_name);
122 goto out;
123 } else {
124 sp_log_drop("Eval_whitelist", "The function '%s' isn't in the eval whitelist, dropping its call.", function_name);
125 }
126 } 115 }
127 // } 116 if (config_eval->simulation) {
117 sp_log_simulation("Eval_whitelist", "The function '%s' isn't in the eval whitelist, logging its call.", function_name);
118 goto out;
119 } else {
120 sp_log_drop("Eval_whitelist", "The function '%s' isn't in the eval whitelist, dropping its call.", function_name);
121 }
122 }
123
128out: 124out:
129 efree(function_name); 125 efree(function_name);
130} 126}
@@ -185,11 +181,13 @@ static inline void sp_execute_handler(INTERNAL_FUNCTION_PARAMETERS, bool interna
185 181
186 if (!internal) { 182 if (!internal) {
187 if (UNEXPECTED(EX(func)->op_array.type == ZEND_EVAL_CODE)) { 183 if (UNEXPECTED(EX(func)->op_array.type == ZEND_EVAL_CODE)) {
188 const sp_list_node *config = zend_hash_str_find_ptr(SPCFG(disabled_functions), ZEND_STRL("eval")); 184 sp_list_node const* const config = zend_hash_str_find_ptr(SPCFG(disabled_functions), ZEND_STRL("eval"));
189 185
190 zend_string *filename = get_eval_filename(zend_get_executed_filename()); 186#if PHP_VERSION_ID >= 80000
191 is_builtin_matching(filename, "eval", NULL, config, SPCFG(disabled_functions)); 187 is_builtin_matching(SPG(eval_source_string), "eval", "code", config, SPCFG(disabled_functions));
192 zend_string_release(filename); 188#else
189 is_builtin_matching(Z_STR_P(SPG(eval_source_string)), "eval", "code", config, SPCFG(disabled_functions));
190#endif
193 191
194 SPG(in_eval)++; 192 SPG(in_eval)++;
195 sp_orig_execute(execute_data); 193 sp_orig_execute(execute_data);
@@ -255,10 +253,8 @@ static inline void sp_execute_handler(INTERNAL_FUNCTION_PARAMETERS, bool interna
255 if (EX(return_value) == &ret_val) { 253 if (EX(return_value) == &ret_val) {
256 return_value = EX(return_value) = NULL; 254 return_value = EX(return_value) = NULL;
257 } 255 }
258
259} 256}
260 257
261
262static void sp_execute_ex(zend_execute_data *execute_data) { 258static void sp_execute_ex(zend_execute_data *execute_data) {
263 sp_execute_handler(execute_data, execute_data ? EX(return_value) : NULL, false); 259 sp_execute_handler(execute_data, execute_data ? EX(return_value) : NULL, false);
264} 260}
@@ -275,7 +271,7 @@ static inline void sp_stream_open_checks(zend_string *zend_filename, zend_file_h
275 return; 271 return;
276 } 272 }
277 273
278 const HashTable *disabled_functions_hooked = SPCFG(disabled_functions_hooked); 274 HashTable const* const disabled_functions_hooked = SPCFG(disabled_functions_hooked);
279 275
280 switch (data->opline->opcode) { 276 switch (data->opline->opcode) {
281 case ZEND_INCLUDE_OR_EVAL: 277 case ZEND_INCLUDE_OR_EVAL:
@@ -316,10 +312,6 @@ static inline void sp_stream_open_checks(zend_string *zend_filename, zend_file_h
316 EMPTY_SWITCH_DEFAULT_CASE(); // LCOV_EXCL_LINE 312 EMPTY_SWITCH_DEFAULT_CASE(); // LCOV_EXCL_LINE
317 } 313 }
318 } 314 }
319 // efree(zend_filename);
320
321// end:
322 // return orig_zend_stream_open(filename, handle);
323} 315}
324 316
325#if PHP_VERSION_ID < 80100 317#if PHP_VERSION_ID < 80100
@@ -342,6 +334,36 @@ static zend_result sp_stream_open(zend_file_handle *handle) {
342 334
343#endif 335#endif
344 336
337ZEND_API zend_op_array* (*orig_zend_compile_file)(zend_file_handle* file_handle,
338 int type) = NULL;
339#if PHP_VERSION_ID >= 80000
340ZEND_API zend_op_array* (*orig_zend_compile_string)(
341 zend_string* source_string, const char* filename) = NULL;
342#else
343ZEND_API zend_op_array* (*orig_zend_compile_string)(zval* source_string,
344 char* filename) = NULL;
345#endif
346
347#if PHP_VERSION_ID >= 80000
348ZEND_API zend_op_array* sp_compile_string(zend_string* source_string,
349 const char* filename) {
350#else
351ZEND_API zend_op_array* sp_compile_string(zval* source_string, char* filename) {
352#endif
353 // TODO(jvoisin) handle recursive calls to `eval`
354 SPG(eval_source_string) = source_string;
355 zend_op_array* opline = orig_zend_compile_string(source_string, filename);
356 sp_sloppy_modify_opcode(opline);
357 return opline;
358}
359
360ZEND_API zend_op_array* sp_compile_file(zend_file_handle* file_handle,
361 int type) {
362 zend_op_array* opline = orig_zend_compile_file(file_handle, type);
363 sp_sloppy_modify_opcode(opline);
364 return opline;
365}
366
345int hook_execute(void) { 367int hook_execute(void) {
346 TSRMLS_FETCH(); 368 TSRMLS_FETCH();
347 369
@@ -365,5 +387,16 @@ int hook_execute(void) {
365 } 387 }
366 } 388 }
367 389
390 if (NULL == orig_zend_compile_file && zend_compile_file != sp_compile_file) {
391 orig_zend_compile_file = zend_compile_file;
392 zend_compile_file = sp_compile_file;
393 }
394
395 if (NULL == orig_zend_compile_string &&
396 zend_compile_string != sp_compile_string) {
397 orig_zend_compile_string = zend_compile_string;
398 zend_compile_string = sp_compile_string;
399 }
400
368 return SUCCESS; 401 return SUCCESS;
369} 402}