Made session save handler abuse much harder than before.
- Session:
. Improved fix for bug #68063 (Empty session IDs do still start sessions). (Yasuo)
+ . Fixed bug #69111 (Crash in SessionHandler::read()). (Yasuo)
. Fixed bug #71122 (Session GC may not remove obsolete session data). (Yasuo)
. Fixed bug #71038 (session_start() returns TRUE on failure).
It's fixed partially on PHP 5.6. It still returns TRUE on session read
SESS_ZVAL_STRING((char*)save_path, args[0]);
SESS_ZVAL_STRING((char*)session_name, args[1]);
- retval = ps_call_handler(PSF(open), 2, args TSRMLS_CC);
+ zend_try {
+ retval = ps_call_handler(PSF(open), 2, args TSRMLS_CC);
+ } zend_catch {
+ PS(session_status) = php_session_none;
+ if (retval) {
+ zval_ptr_dtor(&retval);
+ }
+ zend_bailout();
+ } zend_end_try();
+
PS(mod_user_implemented) = 1;
FINISH;
#include "php_session.h"
#define PS_SANITY_CHECK \
+ if (PS(session_status) != php_session_active) { \
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Session is not active"); \
+ RETURN_FALSE; \
+ } \
if (PS(default_mod) == NULL) { \
php_error_docref(NULL TSRMLS_CC, E_CORE_ERROR, "Cannot call default session handler"); \
RETURN_FALSE; \
PHP_METHOD(SessionHandler, open)
{
char *save_path = NULL, *session_name = NULL;
- int save_path_len, session_name_len;
+ int ret, save_path_len, session_name_len;
PS_SANITY_CHECK;
}
PS(mod_user_is_open) = 1;
- RETVAL_BOOL(SUCCESS == PS(default_mod)->s_open(&PS(mod_data), save_path, session_name TSRMLS_CC));
+ zend_try {
+ ret =PS(default_mod)->s_open(&PS(mod_data), save_path, session_name TSRMLS_CC);
+ } zend_catch {
+ PS(session_status) = php_session_none;
+ zend_bailout();
+ } zend_end_try();
+
+ RETVAL_BOOL(SUCCESS == ret);
}
/* }}} */
Wraps the old close handler */
PHP_METHOD(SessionHandler, close)
{
+ int ret;
+
PS_SANITY_CHECK_IS_OPEN;
// don't return on failure, since not closing the default handler
zend_parse_parameters_none();
PS(mod_user_is_open) = 0;
- RETVAL_BOOL(SUCCESS == PS(default_mod)->s_close(&PS(mod_data) TSRMLS_CC));
+
+ zend_try {
+ ret = PS(default_mod)->s_close(&PS(mod_data) TSRMLS_CC);
+ } zend_catch {
+ PS(session_status) = php_session_none;
+ zend_bailout();
+ } zend_end_try();
+
+ RETVAL_BOOL(SUCCESS == ret);
}
/* }}} */
/* Dispatched by RINIT and by php_session_destroy */
static inline void php_rinit_session_globals(TSRMLS_D) /* {{{ */
{
+ /* Do NOT init PS(mod_user_names) here! */
+
+ /* TODO: These could be moved to MINIT and removed. These should be initialized by php_rshutdown_session_globals() always when execution is finished. */
PS(id) = NULL;
PS(session_status) = php_session_none;
PS(mod_data) = NULL;
PS(mod_user_is_open) = 0;
PS(define_sid) = 1;
- /* Do NOT init PS(mod_user_names) here! */
PS(http_session_vars) = NULL;
}
/* }}} */
efree(PS(id));
PS(id) = NULL;
}
+ /* User save handlers may end up directly here by misuse, bugs in user script, etc. */
+ /* Set session status to prevent error while restoring save handler INI value. */
+ PS(session_status) = php_session_none;
}
/* }}} */
static void php_session_flush(TSRMLS_D) /* {{{ */
{
if (PS(session_status) == php_session_active) {
- PS(session_status) = php_session_none;
php_session_save_current_state(TSRMLS_C);
+ PS(session_status) = php_session_none;
}
}
/* }}} */
static void php_session_abort(TSRMLS_D) /* {{{ */
{
if (PS(session_status) == php_session_active) {
- PS(session_status) = php_session_none;
if (PS(mod_data) || PS(mod_user_implemented)) {
PS(mod)->s_close(&PS(mod_data) TSRMLS_CC);
}
+ PS(session_status) = php_session_none;
}
}
/* }}} */
$x->gc(1);
?>
--EXPECTF--
-Warning: SessionHandler::gc(): Parent session handler is not open in %s on line %d
+Warning: SessionHandler::gc(): Session is not active in %s on line %d
session_write_close();
echo "um, hi\n";
+/*
+FIXME: Since session module try to write/close session data in
+RSHUTDOWN, write() is executed twices. This is caused by undefined
+function error and zend_bailout(). Current session module codes
+depends on this behavior. These codes should be modified to remove
+multiple write().
+*/
+
?>
--EXPECTF--
write: goodbye cruel world
+write: goodbye cruel world
close: goodbye cruel world
session_write_close();
echo "um, hi\n";
+/*
+FIXME: Since session module try to write/close session data in
+RSHUTDOWN, write() is executed twices. This is caused by undefined
+function error and zend_bailout(). Current session module codes
+depends on this behavior. These codes should be modified to remove
+multiple write().
+*/
+
?>
--EXPECTF--
write: goodbye cruel world
+Fatal error: Call to undefined function undefined_function() in %s on line %d
+write: goodbye cruel world
+
Fatal error: Call to undefined function undefined_function() in %s on line %d
close: goodbye cruel world
close: goodbye cruel world
Fatal error: Call to undefined function undefined_function() in %s on line %d
+
+Warning: Unknown: Failed to write session data (user). Please verify that the current setting of session.save_path is correct () in Unknown on line 0
(new SessionHandler)->create_sid();
--EXPECTF--
-Fatal error: SessionHandler::create_sid(): Cannot call default session handler in %s on line %d
+Warning: SessionHandler::create_sid(): Session is not active in %s on line %d
+
--- /dev/null
+--TEST--
+Bug #69111 (Crash in SessionHandler::read())
+--INI--
+session.save_path=
+session.save_handler=files
+session.name=PHPSESSID
+--SKIPIF--
+<?php include('skipif.inc'); ?>
+--FILE--
+<?php
+$sh = new SessionHandler;
+session_set_save_handler($sh);
+
+$savePath = ini_get('session.save_path');
+$sessionName = ini_get('session.name');
+
+// session_start(); // Uncommenting this makes it not crash when reading the session (see below), but it will not return any data.
+
+$sh->open($savePath, $sessionName);
+$sh->write("foo", "bar");
+$sh->read($id);
+$sh->gc(1245);
+$sh->close();
+?>
+--EXPECTF--
+Warning: SessionHandler::open(): Session is not active in %s on line 10
+
+Warning: SessionHandler::write(): Session is not active in %s on line 11
+
+Notice: Undefined variable: id in %s on line 12
+
+Warning: SessionHandler::read(): Session is not active in %s on line 12
+
+Warning: SessionHandler::gc(): Session is not active in %s on line 13
+
+Warning: SessionHandler::close(): Session is not active in %s on line 14
\ No newline at end of file
?>
--EXPECTF--
+Warning: SessionHandler::open(): Session is not active in %s on line 5
+
+Warning: SessionHandler::open(): Session is not active in %s on line 6
+
+Warning: SessionHandler::open(): Session is not active in %s on line 7
+
+Warning: SessionHandler::open(): Session is not active in %s on line 8
Done!