diff options
| author | Christian Göttsche | 2023-12-13 20:37:42 +0100 |
|---|---|---|
| committer | Julien Voisin | 2023-12-13 22:32:49 +0100 |
| commit | 3c720bec3a78775f37839256cfc4b2fea1348550 (patch) | |
| tree | 5231fd396c26896cf4b7eb5657fe504c0444b1bb /src/sp_ini.c | |
| parent | fed8c8f180b275147940b1c6bf8f2c95dfb1ada2 (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.c | 60 |
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 | ||
| 14 | static 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 | |||
| 24 | static 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 | ||
| 15 | static bool /* success */ sp_ini_check(zend_string *const restrict varname, zend_string const *const restrict new_value, sp_ini_entry **sp_entry_p) { | 38 | static 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 | } |
