summaryrefslogtreecommitdiff
path: root/src/sp_ini.c
diff options
context:
space:
mode:
authorChristian Göttsche2023-12-13 20:37:42 +0100
committerJulien Voisin2023-12-13 22:32:49 +0100
commit3c720bec3a78775f37839256cfc4b2fea1348550 (patch)
tree5231fd396c26896cf4b7eb5657fe504c0444b1bb /src/sp_ini.c
parentfed8c8f180b275147940b1c6bf8f2c95dfb1ada2 (diff)
print key and value on INI violations
On violations of INI settings include the key and if appropriate the value in the log message. This helps to locate offenders and fine tune the configuration itself.
Diffstat (limited to 'src/sp_ini.c')
-rw-r--r--src/sp_ini.c60
1 files changed, 55 insertions, 5 deletions
diff --git a/src/sp_ini.c b/src/sp_ini.c
index 7b22012..8860a92 100644
--- a/src/sp_ini.c
+++ b/src/sp_ini.c
@@ -11,6 +11,29 @@
11 sp_log_auto2("ini_protection", simulation, (cfg->policy_drop || (entry && entry->drop)), __VA_ARGS__); \ 11 sp_log_auto2("ini_protection", simulation, (cfg->policy_drop || (entry && entry->drop)), __VA_ARGS__); \
12 } 12 }
13 13
14static const char* check_safe_key(const char* string) {
15 for (const char* p = string; *p != '\0'; p++) {
16 if (!isalnum((unsigned char)*p) && *p != '_' && *p != '.') {
17 return NULL;
18 }
19 }
20
21 return string;
22}
23
24static const char* check_safe_value(const char* string) {
25 for (const char* p = string; *p != '\0'; p++) {
26 if (*p == '\'' || *p == '"') {
27 return NULL;
28 }
29
30 if (!isgraph((unsigned char)*p)) {
31 return NULL;
32 }
33 }
34
35 return string;
36}
14 37
15static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend_string const *const restrict new_value, sp_ini_entry **sp_entry_p) { 38static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend_string const *const restrict new_value, sp_ini_entry **sp_entry_p) {
16 if (!varname || ZSTR_LEN(varname) == 0) { 39 if (!varname || ZSTR_LEN(varname) == 0) {
@@ -27,7 +50,8 @@ static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend
27 if (!entry) { 50 if (!entry) {
28 if (cfg->policy_readonly) { 51 if (cfg->policy_readonly) {
29 if (!cfg->policy_silent_ro) { 52 if (!cfg->policy_silent_ro) {
30 sp_log_ini_check_violation("INI setting is read-only"); 53 sp_log_ini_check_violation("INI setting `%s` is read-only",
54 check_safe_key(ZSTR_VAL(varname)) ? ZSTR_VAL(varname) : "<invalid>");
31 } 55 }
32 return simulation; 56 return simulation;
33 } 57 }
@@ -38,7 +62,11 @@ static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend
38 62
39 if (SP_INI_ACCESS_READONLY_COND(entry, cfg)) { 63 if (SP_INI_ACCESS_READONLY_COND(entry, cfg)) {
40 if (!cfg->policy_silent_ro) { 64 if (!cfg->policy_silent_ro) {
41 sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI setting is read-only")); 65 if (entry->msg) {
66 sp_log_ini_check_violation("%s", ZSTR_VAL(entry->msg));
67 } else {
68 sp_log_ini_check_violation("INI setting `%s` is read-only", ZSTR_VAL(entry->key));
69 }
42 } 70 }
43 return simulation; 71 return simulation;
44 } 72 }
@@ -48,7 +76,7 @@ static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend
48 return true; // allow NULL value and skip other tests 76 return true; // allow NULL value and skip other tests
49 } 77 }
50 if (SP_INI_HAS_CHECKS_COND(entry)) { 78 if (SP_INI_HAS_CHECKS_COND(entry)) {
51 sp_log_ini_check_violation("new INI value must not be NULL or empty"); 79 sp_log_ini_check_violation("new INI value for `%s` must not be NULL or empty", ZSTR_VAL(entry->key));
52 return simulation; 80 return simulation;
53 } 81 }
54 return true; // no new_value, but no checks to perform 82 return true; // no new_value, but no checks to perform
@@ -66,14 +94,36 @@ static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend
66 if ((entry->min && zend_atol(ZSTR_VAL(entry->min), ZSTR_LEN(entry->min)) > lvalue) || 94 if ((entry->min && zend_atol(ZSTR_VAL(entry->min), ZSTR_LEN(entry->min)) > lvalue) ||
67 (entry->max && zend_atol(ZSTR_VAL(entry->max), ZSTR_LEN(entry->max)) < lvalue)) { 95 (entry->max && zend_atol(ZSTR_VAL(entry->max), ZSTR_LEN(entry->max)) < lvalue)) {
68#endif 96#endif
69 sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value out of range")); 97 if (entry->msg) {
98 sp_log_ini_check_violation("%s", ZSTR_VAL(entry->msg));
99 } else {
100 sp_log_ini_check_violation("INI value %lld for `%s` out of range", lvalue, ZSTR_VAL(entry->key));
101 }
70 return simulation; 102 return simulation;
71 } 103 }
72 } 104 }
73 105
74 if (entry->regexp) { 106 if (entry->regexp) {
75 if (!sp_is_regexp_matching_zstr(entry->regexp, new_value)) { 107 if (!sp_is_regexp_matching_zstr(entry->regexp, new_value)) {
76 sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value does not match regex")); 108 if (entry->msg) {
109 sp_log_ini_check_violation("%s", ZSTR_VAL(entry->msg));
110 } else {
111 zend_string *base64_new_val = NULL;
112 const char *safe_new_val = check_safe_value(ZSTR_VAL(new_value));
113 if (!safe_new_val) {
114 base64_new_val = php_base64_encode((const unsigned char*)(ZSTR_VAL(new_value)), ZSTR_LEN(new_value));
115 safe_new_val = base64_new_val ? ZSTR_VAL(base64_new_val) : "<invalid>";
116 }
117
118 sp_log_ini_check_violation("INI value `%s`%s for `%s` does not match regex",
119 safe_new_val,
120 base64_new_val ? "(base64)" : "",
121 ZSTR_VAL(entry->key));
122
123 if (base64_new_val) {
124 zend_string_release(base64_new_val);
125 }
126 }
77 return simulation; 127 return simulation;
78 } 128 }
79 } 129 }