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.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/sp_execute.c b/src/sp_execute.c
new file mode 100644
index 0000000..faf126c
--- /dev/null
+++ b/src/sp_execute.c
@@ -0,0 +1,100 @@
1#include "php_snuffleupagus.h"
2
3#include <errno.h>
4#include <string.h>
5
6ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus);
7
8static void (*orig_execute_ex)(zend_execute_data *execute_data);
9static int (*orig_zend_stream_open)(const char *filename,
10 zend_file_handle *handle);
11
12// FIXME handle symlink
13ZEND_COLD static inline void terminate_if_writable(const char *filename) {
14 if (0 == access(filename, W_OK)) {
15 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->simulation) {
16 sp_log_msg("readonly_exec", LOG_NOTICE,
17 "Attempted execution of a writable file (%s).", filename);
18 } else {
19 sp_log_msg("readonly_exec", LOG_DROP,
20 "Attempted execution of a writable file (%s).", filename);
21 sp_terminate();
22 }
23 } else {
24 if (EACCES != errno) {
25 sp_log_err("Writable execution", "Error while accessing %s: %s", filename,
26 strerror(errno));
27 }
28 }
29}
30
31static void check_inclusion_regexp(const char * const filename) {
32 if (SNUFFLEUPAGUS_G(config).config_regexp_inclusion->regexp_inclusion) {
33 const sp_node_t* config = SNUFFLEUPAGUS_G(config).config_regexp_inclusion->regexp_inclusion;
34 if (!config || !config->data) {
35 return;
36 }
37 while (config) {
38 pcre *config_node = (pcre*)(config->data);
39 if (false == is_regexp_matching(config_node, filename)) {
40 sp_log_msg("include", LOG_DROP, "Inclusion of a forbidden file (%s).", filename);
41 sp_terminate();
42 }
43 config = config->next;
44 }
45 }
46}
47
48static void sp_execute_ex(zend_execute_data *execute_data) {
49 if (NULL == execute_data->func->common.function_name) {
50 goto execute;
51 }
52
53 if (true == should_disable(execute_data)) {
54 return;
55 }
56
57 if (execute_data->func->op_array.type == ZEND_EVAL_CODE) {
58 sp_log_debug("Currently in an eval\n");
59 }
60
61 if (NULL != execute_data->func->op_array.filename) {
62 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) {
63 terminate_if_writable(ZSTR_VAL(execute_data->func->op_array.filename));
64 }
65}
66
67execute:
68 orig_execute_ex(execute_data);
69}
70
71static int sp_stream_open(const char *filename,
72 zend_file_handle *handle) {
73 const zend_execute_data *data = EG(current_execute_data);
74
75 if ((NULL != data) && (NULL != data->opline) &&
76 (ZEND_INCLUDE_OR_EVAL == data->opline->opcode)) {
77 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) {
78 terminate_if_writable(filename);
79 }
80 check_inclusion_regexp(filename);
81 }
82 return orig_zend_stream_open(filename, handle);
83}
84
85int hook_execute(void) {
86 TSRMLS_FETCH();
87
88 /* zend_execute_ex is used for "classic" function calls */
89 orig_execute_ex = zend_execute_ex;
90 zend_execute_ex = sp_execute_ex;
91
92 /* zend_stream_open_function is used FIXME */
93 orig_zend_stream_open = zend_stream_open_function;
94 zend_stream_open_function = sp_stream_open;
95
96 /* zend_execute_internal is used for "indirect" functions call,
97 * like array_map or call_user_func. */
98
99 return SUCCESS;
100}