Skip to content

Commit 55230ec

Browse files
Sjordjorgsowa
authored andcommitted
ext/session: validate full length of session ID
Closes GH-24997.
1 parent aec4f50 commit 55230ec

5 files changed

Lines changed: 54 additions & 17 deletions

File tree

‎NEWS‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ PHP NEWS
214214
(David Carlier)
215215

216216
- Session:
217+
. Validate whole session ID instead of stopping at the first NUL byte.
218+
(Sjoerd Langkemper)
217219
. Fixed session data loss in the files save handler when writing the session
218220
file fails after it was already truncated. (Ilia Alshanetsky)
219221

‎ext/session/mod_files.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ static void ps_files_open(ps_files *data, /* const */ zend_string *key)
165165

166166
ps_files_close(data);
167167

168-
if (php_session_valid_key(ZSTR_VAL(key)) == FAILURE) {
168+
if (php_session_valid_key_ex(key) == FAILURE) {
169169
php_error_docref(NULL, E_WARNING, "Session ID is too long or contains illegal characters. Only the A-Z, a-z, 0-9, \"-\", and \",\" characters are allowed");
170170
return;
171171
}

‎ext/session/php_session.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ PHPAPI const ps_module *_php_find_ps_module(const char *name);
274274
PHPAPI const ps_serializer *_php_find_ps_serializer(const char *name);
275275

276276
PHPAPI zend_result php_session_valid_key(const char *key);
277+
zend_result php_session_valid_key_ex(const zend_string *key);
277278
PHPAPI zend_result php_session_reset_id(void);
278279

279280
#define PS_ADD_VARL(name) do { \

‎ext/session/session.c‎

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -355,14 +355,18 @@ PHPAPI zend_string *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */
355355

356356
/* Default session id char validation function allowed by ps_modules.
357357
* If you change the logic here, please also update the error message in
358-
* ps_modules appropriately */
359-
PHPAPI zend_result php_session_valid_key(const char *key) /* {{{ */
358+
* ps_modules appropriately. */
359+
static zend_result php_session_valid_key_len(const char *key, size_t key_len)
360360
{
361-
size_t len;
362-
const char *p;
363-
char c;
361+
/* Somewhat arbitrary length limit here, but should be way more than
362+
anyone needs and avoids file-level warnings later on if we exceed MAX_PATH */
363+
if (key_len == 0 || key_len > PS_MAX_SID_LENGTH) {
364+
return FAILURE;
365+
}
366+
367+
for (size_t i = 0; i < key_len; i++) {
368+
unsigned char c = (unsigned char) key[i];
364369

365-
for (p = key; (c = *p); p++) {
366370
/* valid characters are [a-z], [A-Z], [0-9], - (hyphen) and , (comma) */
367371
if (!((c >= 'a' && c <= 'z')
368372
|| (c >= 'A' && c <= 'Z')
@@ -373,18 +377,21 @@ PHPAPI zend_result php_session_valid_key(const char *key) /* {{{ */
373377
}
374378
}
375379

376-
len = p - key;
377-
378-
/* Somewhat arbitrary length limit here, but should be way more than
379-
anyone needs and avoids file-level warnings later on if we exceed MAX_PATH */
380-
if (len == 0 || len > PS_MAX_SID_LENGTH) {
381-
return FAILURE;
382-
}
383-
384380
return SUCCESS;
385381
}
386-
/* }}} */
387382

383+
/* Validate the full zend_string, including embedded NUL bytes. */
384+
zend_result php_session_valid_key_ex(const zend_string *key)
385+
{
386+
return php_session_valid_key_len(ZSTR_VAL(key), ZSTR_LEN(key));
387+
}
388+
389+
/* C-string compatibility wrapper. Callers that have a zend_string should use
390+
* php_session_valid_key_ex() instead. */
391+
PHPAPI zend_result php_session_valid_key(const char *key)
392+
{
393+
return php_session_valid_key_len(key, strlen(key));
394+
}
388395

389396
static zend_long php_session_gc(bool immediate) /* {{{ */
390397
{
@@ -2527,7 +2534,7 @@ PHP_FUNCTION(session_create_id)
25272534
zend_argument_value_error(1, "cannot be longer than %d characters", PS_MAX_SID_LENGTH);
25282535
RETURN_THROWS();
25292536
}
2530-
if (php_session_valid_key(ZSTR_VAL(prefix)) == FAILURE) {
2537+
if (php_session_valid_key_ex(prefix) == FAILURE) {
25312538
/* E_ERROR raised for security reason. */
25322539
php_error_docref(NULL, E_WARNING, "Prefix cannot contain special characters. Only the A-Z, a-z, 0-9, \"-\", and \",\" characters are allowed");
25332540
RETURN_FALSE;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Session IDs with NUL bytes are rejected as a whole, not truncated
3+
--INI--
4+
session.save_handler=files
5+
session.save_path=
6+
session.use_cookies=0
7+
session.use_strict_mode=0
8+
--EXTENSIONS--
9+
session
10+
--SKIPIF--
11+
<?php include 'skipif.inc'; ?>
12+
--FILE--
13+
<?php
14+
session_id("nulbug\0stillvalid");
15+
$started = session_start();
16+
var_dump($started);
17+
var_dump(session_id());
18+
if ($started) {
19+
session_destroy();
20+
}
21+
?>
22+
--EXPECTF--
23+
Warning: session_start(): Session ID is too long or contains illegal characters. Only the A-Z, a-z, 0-9, "-", and "," characters are allowed in %s on line %d
24+
25+
Warning: session_start(): Failed to read session data: files (path: ) in %s on line %d
26+
bool(false)
27+
string(0) ""

0 commit comments

Comments
 (0)