summaryrefslogtreecommitdiff
path: root/session.c
diff options
context:
space:
mode:
authorStefan2010-02-21 16:53:30 +0100
committerStefan2010-02-21 16:53:30 +0100
commit2a789c5c933496f4d374a73f3b9b42704c4c8502 (patch)
tree115e3e91a3c284aca7cce78f822f4631ab1b0a64 /session.c
parent91b338c3787713c8e26d5676e368b6ef34691b92 (diff)
Added ! protection to PHP session serializer
Diffstat (limited to 'session.c')
-rw-r--r--session.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/session.c b/session.c
index a6eb5db..db1e97a 100644
--- a/session.c
+++ b/session.c
@@ -253,6 +253,93 @@ static php_ps_globals_43_44 *session_globals = NULL;
253#define SESSION_G(v) (session_globals->v) 253#define SESSION_G(v) (session_globals->v)
254#endif 254#endif
255 255
256ps_serializer *_php_find_ps_serializer(char *name TSRMLS_DC);
257
258#define PS_ENCODE_VARS \
259 char *key; \
260 uint key_length; \
261 ulong num_key; \
262 zval **struc;
263
264#define PS_ENCODE_LOOP(code) do { \
265 HashTable *_ht = Z_ARRVAL_P(SESSION_G(http_session_vars)); \
266 int key_type; \
267 \
268 for (zend_hash_internal_pointer_reset(_ht); \
269 (key_type = zend_hash_get_current_key_ex(_ht, &key, &key_length, &num_key, 0, NULL)) != HASH_KEY_NON_EXISTANT; \
270 zend_hash_move_forward(_ht)) { \
271 if (key_type == HASH_KEY_IS_LONG) { \
272 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Skipping numeric key %ld", num_key); \
273 continue; \
274 } \
275 key_length--; \
276 if (suhosin_get_session_var(key, key_length, &struc TSRMLS_CC) == SUCCESS) { \
277 code; \
278 } \
279 } \
280 } while(0)
281
282static int suhosin_get_session_var(char *name, size_t namelen, zval ***state_var TSRMLS_DC) /* {{{ */
283{
284 int ret = FAILURE;
285
286 if (SESSION_G(http_session_vars) && SESSION_G(http_session_vars)->type == IS_ARRAY) {
287 ret = zend_hash_find(Z_ARRVAL_P(SESSION_G(http_session_vars)), name, namelen + 1, (void **) state_var);
288
289 /* If register_globals is enabled, and
290 * if there is an entry for the slot in $_SESSION, and
291 * if that entry is still set to NULL, and
292 * if the global var exists, then
293 * we prefer the same key in the global sym table. */
294
295 if (PG(register_globals) && ret == SUCCESS && Z_TYPE_PP(*state_var) == IS_NULL) {
296 zval **tmp;
297
298 if (zend_hash_find(&EG(symbol_table), name, namelen + 1, (void **) &tmp) == SUCCESS) {
299 *state_var = tmp;
300 }
301 }
302 }
303 return ret;
304}
305
306#define PS_DELIMITER '|'
307#define PS_UNDEF_MARKER '!'
308
309int suhosin_session_encode(char **newstr, int *newlen TSRMLS_DC)
310{
311 smart_str buf = {0};
312 php_serialize_data_t var_hash;
313 PS_ENCODE_VARS;
314
315 PHP_VAR_SERIALIZE_INIT(var_hash);
316
317 PS_ENCODE_LOOP(
318 smart_str_appendl(&buf, key, key_length);
319 if (key[0] == PS_UNDEF_MARKER || memchr(key, PS_DELIMITER, key_length)) {
320 PHP_VAR_SERIALIZE_DESTROY(var_hash);
321 smart_str_free(&buf);
322 return FAILURE;
323 }
324 smart_str_appendc(&buf, PS_DELIMITER);
325
326 php_var_serialize(&buf, struc, &var_hash TSRMLS_CC);
327 } else {
328 smart_str_appendc(&buf, PS_UNDEF_MARKER);
329 smart_str_appendl(&buf, key, key_length);
330 smart_str_appendc(&buf, PS_DELIMITER);
331 );
332
333 if (newlen) {
334 *newlen = buf.len;
335 }
336 smart_str_0(&buf);
337 *newstr = buf.c;
338
339 PHP_VAR_SERIALIZE_DESTROY(var_hash);
340 return SUCCESS;
341}
342
256static void suhosin_send_cookie() 343static void suhosin_send_cookie()
257{ 344{
258 int * session_send_cookie = &SESSION_G(send_cookie); 345 int * session_send_cookie = &SESSION_G(send_cookie);
@@ -697,6 +784,7 @@ static int suhosin_hook_session_RINIT(INIT_FUNC_ARGS)
697 784
698void suhosin_hook_session(TSRMLS_D) 785void suhosin_hook_session(TSRMLS_D)
699{ 786{
787 ps_serializer *serializer;
700 zend_ini_entry *ini_entry; 788 zend_ini_entry *ini_entry;
701 zend_module_entry *module; 789 zend_module_entry *module;
702#ifdef ZTS 790#ifdef ZTS
@@ -762,6 +850,14 @@ void suhosin_hook_session(TSRMLS_D)
762 ini_entry->on_modify = suhosin_OnUpdateSaveHandler; 850 ini_entry->on_modify = suhosin_OnUpdateSaveHandler;
763 851
764 suhosin_hook_session_module(TSRMLS_C); 852 suhosin_hook_session_module(TSRMLS_C);
853
854 /* Protect the PHP serializer from ! attacks */
855# if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 2)
856 serializer = _php_find_ps_serialize("php" TSRMLS_CC);
857 if (serializer != NULL) {
858 serializer->encode = suhosin_session_encode;
859 }
860#endif
765} 861}
766 862
767void suhosin_unhook_session(TSRMLS_D) 863void suhosin_unhook_session(TSRMLS_D)