Skip to content

Commit

Permalink
implemented ini settings protection
Browse files Browse the repository at this point in the history
  • Loading branch information
bef committed Aug 6, 2021
1 parent 260f17f commit 2392c46
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 13 deletions.
1 change: 1 addition & 0 deletions src/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c"
sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c"
sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c"
sources="$sources sp_pcre_compat.c sp_crypt.c sp_session.c sp_sloppy.c sp_wrapper.c"
sources="$sources sp_ini.c"

PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support,
[ --enable-snuffleupagus Enable snuffleupagus support])
Expand Down
1 change: 1 addition & 0 deletions src/php_snuffleupagus.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ typedef void (*zif_handler)(INTERNAL_FUNCTION_PARAMETERS);
#include "sp_session.h"
#include "sp_sloppy.h"
#include "sp_wrapper.h"
#include "sp_ini.h"

extern zend_module_entry snuffleupagus_module_entry;
#define phpext_snuffleupagus_ptr &snuffleupagus_module_entry
Expand Down
46 changes: 34 additions & 12 deletions src/snuffleupagus.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,6 @@ static PHP_GINIT_FUNCTION(snuffleupagus) {
snuffleupagus_globals->is_config_valid = SP_CONFIG_NONE;
snuffleupagus_globals->in_eval = 0;

#define SP_INIT_HT(F) \
snuffleupagus_globals->F = pemalloc(sizeof(*(snuffleupagus_globals->F)), 1); \
zend_hash_init(snuffleupagus_globals->F, 10, NULL, NULL, 1);
SP_INIT_HT(disabled_functions_hook);
SP_INIT_HT(sp_internal_functions_hook);
SP_INIT_HT(sp_eval_blacklist_functions_hook);
SP_INIT_HT(config.config_disabled_functions);
SP_INIT_HT(config.config_disabled_functions_hooked);
SP_INIT_HT(config.config_disabled_functions_ret);
SP_INIT_HT(config.config_disabled_functions_ret_hooked);
#undef SP_INIT_HT

#define SP_INIT(F) \
snuffleupagus_globals->config.F = \
pecalloc(sizeof(*(snuffleupagus_globals->config.F)), 1, 1);
Expand All @@ -109,10 +97,24 @@ static PHP_GINIT_FUNCTION(snuffleupagus) {
SP_INIT(config_eval);
SP_INIT(config_wrapper);
SP_INIT(config_session);
SP_INIT(config_ini);
SP_INIT(config_disabled_functions_reg);
SP_INIT(config_disabled_functions_reg_ret);
#undef SP_INIT

#define SP_INIT_HT(F) \
snuffleupagus_globals->F = pemalloc(sizeof(*(snuffleupagus_globals->F)), 1); \
zend_hash_init(snuffleupagus_globals->F, 10, NULL, NULL, 1);
SP_INIT_HT(disabled_functions_hook);
SP_INIT_HT(sp_internal_functions_hook);
SP_INIT_HT(sp_eval_blacklist_functions_hook);
SP_INIT_HT(config.config_disabled_functions);
SP_INIT_HT(config.config_disabled_functions_hooked);
SP_INIT_HT(config.config_disabled_functions_ret);
SP_INIT_HT(config.config_disabled_functions_ret_hooked);
SP_INIT_HT(config.config_ini->entries);
#undef SP_INIT_HT

#define SP_INIT_NULL(F) snuffleupagus_globals->config.F = NULL;
SP_INIT_NULL(config_disabled_functions_reg->disabled_functions);
SP_INIT_NULL(config_disabled_functions_reg_ret->disabled_functions);
Expand All @@ -131,6 +133,11 @@ PHP_MINIT_FUNCTION(snuffleupagus) {
}

PHP_MSHUTDOWN_FUNCTION(snuffleupagus) {
sp_log_debug("(MSHUTDOWN)");
unhook_functions(SNUFFLEUPAGUS_G(sp_internal_functions_hook));
unhook_functions(SNUFFLEUPAGUS_G(disabled_functions_hook));
unhook_functions(SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook));
if (SNUFFLEUPAGUS_G(config).config_ini->enable) { sp_unhook_ini(); }
UNREGISTER_INI_ENTRIES();

return SUCCESS;
Expand All @@ -142,6 +149,12 @@ static inline void free_disabled_functions_hashtable(HashTable *const ht) {
ZEND_HASH_FOREACH_END();
}

static inline void free_config_ini_entries(HashTable *const ht) {
void *ptr = NULL;
ZEND_HASH_FOREACH_PTR(ht, ptr) { sp_free_ini_entry(ptr); pefree(ptr, 1); }
ZEND_HASH_FOREACH_END();
}

static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) {
sp_log_debug("(GSHUTDOWN)");
#define FREE_HT(F) \
Expand All @@ -158,6 +171,9 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) {
FREE_HT_LIST(config_disabled_functions_ret);
FREE_HT_LIST(config_disabled_functions_ret_hooked);
#undef FREE_HT_LIST

free_config_ini_entries(snuffleupagus_globals->config.config_ini->entries);
FREE_HT(config.config_ini->entries);
#undef FREE_HT

#define FREE_LST_DISABLE(L) \
Expand All @@ -174,6 +190,7 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) {
FREE_LST(config_wrapper->whitelist);
#undef FREE_LST


#define FREE_CFG(C) pefree(snuffleupagus_globals->config.C, 1);
#define FREE_CFG_ZSTR(C) sp_free_zstr(snuffleupagus_globals->config.C);
FREE_CFG(config_random);
Expand All @@ -194,6 +211,7 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) {
FREE_CFG(config_eval);
FREE_CFG(config_wrapper);
FREE_CFG(config_session);
FREE_CFG(config_ini);
FREE_CFG(config_disabled_functions_reg);
FREE_CFG(config_disabled_functions_reg_ret);
#undef FREE_CFG
Expand Down Expand Up @@ -332,6 +350,10 @@ static PHP_INI_MH(OnUpdateConfiguration) {
hook_execute();
hook_cookies();

if (SNUFFLEUPAGUS_G(config).config_ini->enable) {
sp_hook_ini();
}

if (true == SNUFFLEUPAGUS_G(config).config_global_strict->enable) {
if (!zend_get_extension(PHP_SNUFFLEUPAGUS_EXTNAME)) {
zend_extension_entry.startup = NULL;
Expand Down
13 changes: 13 additions & 0 deletions src/sp_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ static sp_config_tokens const sp_func[] = {
{.func = parse_session, .token = SP_TOKEN_SESSION_ENCRYPTION},
{.func = parse_sloppy_comparison, .token = SP_TOKEN_SLOPPY_COMPARISON},
{.func = parse_wrapper_whitelist, .token = SP_TOKEN_ALLOW_WRAPPERS},
{.func = parse_ini_protection, .token = ".ini_protection"},
{.func = parse_ini_entry, .token = ".ini"},
{NULL, NULL}};

/* Top level keyword parsing */
Expand Down Expand Up @@ -281,3 +283,14 @@ void sp_free_zstr(void *data) {
zend_string_release_ex((zend_string*)data, 1);
}
}

void sp_free_ini_entry(void *data) {
sp_ini_entry *entry = data;

sp_free_zstr(entry->key);
sp_free_zstr(entry->min);
sp_free_zstr(entry->max);
sp_pcre_free(entry->regexp);
sp_free_zstr(entry->msg);
sp_free_zstr(entry->set);
}
26 changes: 25 additions & 1 deletion src/sp_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ typedef enum {

typedef enum { SP_ZEND = 0, SP_SYSLOG = 1 } sp_log_media;

typedef enum { SP_UNSET = 0, SP_READONLY = 1, SP_READWRITE = -1 } sp_ini_permission;

typedef struct {
int ip_version;
union {
Expand Down Expand Up @@ -162,6 +164,26 @@ typedef struct {
bool enable;
} sp_config_upload_validation;

typedef struct {
zend_string *key;
sp_ini_permission access;
zend_string *min;
zend_string *max;
sp_pcre *regexp;
bool simulation;
zend_string *msg;
zend_string *set;
PHP_INI_MH((*orig_onmodify));
} sp_ini_entry;

typedef struct {
bool enable;
bool simulation;
// sp_ini_permission access_policy;
bool policy_readonly;
HashTable *entries; // ht of sp_ini_entry
} sp_config_ini;

typedef struct {
sp_config_random *config_random;
sp_config_sloppy *config_sloppy;
Expand All @@ -176,6 +198,7 @@ typedef struct {
sp_config_eval *config_eval;
sp_config_wrapper *config_wrapper;
sp_config_session *config_session;
sp_config_ini *config_ini;
bool hook_execute;
char log_media;

Expand Down Expand Up @@ -215,6 +238,7 @@ typedef struct {
#define SP_TOKEN_EVAL_WHITELIST ".eval_whitelist"
#define SP_TOKEN_SLOPPY_COMPARISON ".sloppy_comparison"
#define SP_TOKEN_ALLOW_WRAPPERS ".wrappers_whitelist"
#define SP_TOKEN_INI ".ini"

// common tokens
#define SP_TOKEN_ENABLE ".enable("
Expand Down Expand Up @@ -284,6 +308,6 @@ int parse_list(char *restrict, char *restrict, void *);
void sp_free_disabled_function(void *data);
void sp_free_cookie(void *data);
void sp_free_zstr(void *data);

void sp_free_ini_entry(void *data);

#endif /* SP_CONFIG_H */
77 changes: 77 additions & 0 deletions src/sp_config_keywords.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,3 +562,80 @@ int parse_upload_validation(char *line) {

return ret;
}

int parse_ini_protection(char *line) {
bool disable = false, enable = false;
bool rw = false, ro = false; // rw is ignored, but declaring .policy_rw is valid for readability
sp_config_functions sp_config_ini_protection[] = {
{parse_empty, SP_TOKEN_ENABLE, &(enable)},
{parse_empty, SP_TOKEN_DISABLE, &(disable)},
{parse_empty, SP_TOKEN_SIMULATION, &(SNUFFLEUPAGUS_G(config).config_ini->simulation)},
{parse_empty, ".policy_readonly(", &ro},
{parse_empty, ".policy_ro(", &ro},
{parse_empty, ".policy_readwrite(", &rw},
{parse_empty, ".policy_rw(", &rw},
{0, 0, 0}};

int ret = parse_keywords(sp_config_ini_protection, line);
if (ret) { return ret; }

if (enable && disable) {
sp_log_err("config", "A rule can't be enabled and disabled on line %zu",
sp_line_no);
return -1;
}
if (enable || disable) {
SNUFFLEUPAGUS_G(config).config_ini->enable = (enable || !disable);
}

if (ro && rw) {
sp_log_err("config", "rule cannot be both read-write and read-only on line %zu", sp_line_no);
return -1;
}
SNUFFLEUPAGUS_G(config).config_ini->policy_readonly = ro;

return ret;
}

int parse_ini_entry(char *line) {
sp_ini_entry *entry = pecalloc(sizeof(sp_ini_entry), 1, 1);
bool rw = false, ro = false;

sp_config_functions sp_config_ini_protection[] = {
{parse_empty, SP_TOKEN_SIMULATION, &entry->simulation},
{parse_str, ".key(", &entry->key},
{parse_str, ".msg(", &entry->msg},
{parse_str, ".set(", &entry->set},
{parse_str, ".min(", &entry->min},
{parse_str, ".max(", &entry->max},
{parse_regexp, ".regexp(", &entry->regexp},
{parse_empty, ".readonly(", &ro},
{parse_empty, ".ro(", &ro},
{parse_empty, ".readwrite()", &rw},
{parse_empty, ".rw()", &rw},
{0, 0, 0}};

int ret = parse_keywords(sp_config_ini_protection, line);
if (ret) { goto err; }

if (!entry->key) {
sp_log_err("config", "A .key() must be provided on line %zu", sp_line_no);
ret = -1; goto err;
}

if (ro && rw) {
sp_log_err("config", "rule cannot be both read-write and read-only on line %zu", sp_line_no);
ret = -1; goto err;
}
entry->access = ro - rw;

zend_hash_add_ptr(SNUFFLEUPAGUS_G(config).config_ini->entries, entry->key, entry);
return ret;

err:
if (entry) {
sp_free_ini_entry(entry);
pefree(entry, 1);
}
return ret;
}
2 changes: 2 additions & 0 deletions src/sp_config_keywords.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@ int parse_session(char *line);
int parse_sloppy_comparison(char *line);
int parse_wrapper_whitelist(char *line);
int parse_log_media(char *line);
int parse_ini_protection(char *line);
int parse_ini_entry(char *line);

#endif // __SP_CONFIG_KEYWORDS_H
Loading

0 comments on commit 2392c46

Please sign in to comment.