Skip to content

Commit 91ec6fe

Browse files
committed
Check for session name criterias consistently
1 parent 4cd856d commit 91ec6fe

File tree

2 files changed

+48
-36
lines changed

2 files changed

+48
-36
lines changed

ext/session/session.c

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,41 @@ static PHP_INI_MH(OnUpdateSaveDir) /* {{{ */
647647
}
648648
/* }}} */
649649

650+
/* If diagnostic_type is 0 then no diagnostic will be emitted */
651+
static bool is_session_name_valid(const zend_string *name, int diagnostic_type)
652+
{
653+
if (ZSTR_LEN(name) == 0) {
654+
if (diagnostic_type) {
655+
php_error_docref(NULL, diagnostic_type, "session.name \"%s\" cannot be empty", ZSTR_VAL(name));
656+
}
657+
return false;
658+
}
659+
/* NUL bytes are not allowed */
660+
if (ZSTR_LEN(name) != strlen(ZSTR_VAL(name))) {
661+
if (diagnostic_type) {
662+
php_error_docref(NULL, diagnostic_type, "session.name \"%s\" cannot contain NUL bytes", ZSTR_VAL(name));
663+
}
664+
return false;
665+
}
666+
/* Numeric session.name won't work at all
667+
* See https://bugs.php.net/bug.php?id=35703
668+
(TL;DR: name is stored in HashTable so numeric string is converted to int key, but lookup looks for string key). */
669+
if (is_numeric_str_function(name, NULL, NULL)) {
670+
if (diagnostic_type) {
671+
php_error_docref(NULL, diagnostic_type, "session.name \"%s\" cannot be numeric", ZSTR_VAL(name));
672+
}
673+
return false;
674+
}
675+
/* Prevent broken Set-Cookie header, because the session_name might be user supplied */
676+
if (strpbrk(ZSTR_VAL(name), "=,; \t\r\n\013\014") != NULL) { /* man isspace for \013 and \014 */
677+
if (diagnostic_type) {
678+
php_error_docref(NULL, diagnostic_type, "session.name \"%s\" cannot contain any of the following "
679+
"'=,; \\t\\r\\n\\013\\014'", ZSTR_VAL(name));
680+
}
681+
return false;
682+
}
683+
return true;
684+
}
650685

651686
static PHP_INI_MH(OnUpdateName) /* {{{ */
652687
{
@@ -657,33 +692,14 @@ static PHP_INI_MH(OnUpdateName) /* {{{ */
657692

658693
if (stage == ZEND_INI_STAGE_RUNTIME || stage == ZEND_INI_STAGE_ACTIVATE || stage == ZEND_INI_STAGE_STARTUP) {
659694
err_type = E_WARNING;
695+
} else if (stage == ZEND_INI_STAGE_DEACTIVATE) {
696+
/* Do not output error when restoring ini options. */
697+
err_type = 0;
660698
} else {
661699
err_type = E_ERROR;
662700
}
663701

664-
if (ZSTR_LEN(new_value) == 0) {
665-
/* Do not output error when restoring ini options. */
666-
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
667-
php_error_docref(NULL, err_type, "session.name \"%s\" cannot be empty", ZSTR_VAL(new_value));
668-
}
669-
return FAILURE;
670-
}
671-
/* NUL bytes are not allowed */
672-
if (ZSTR_LEN(new_value) != strlen(ZSTR_VAL(new_value))) {
673-
/* Do not output error when restoring ini options. */
674-
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
675-
php_error_docref(NULL, err_type, "session.name \"%s\" cannot contain NUL bytes", ZSTR_VAL(new_value));
676-
}
677-
return FAILURE;
678-
}
679-
/* Numeric session.name won't work at all
680-
* See https://bugs.php.net/bug.php?id=35703
681-
(TL;DR: name is stored in HashTable so numeric string is converted to int key, but lookup looks for string key). */
682-
if (is_numeric_str_function(new_value, NULL, NULL)) {
683-
/* Do not output error when restoring ini options. */
684-
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
685-
php_error_docref(NULL, err_type, "session.name \"%s\" cannot be numeric", ZSTR_VAL(new_value));
686-
}
702+
if (!is_session_name_valid(new_value, err_type)) {
687703
return FAILURE;
688704
}
689705

@@ -1277,7 +1293,7 @@ static void php_session_remove_cookie(void) {
12771293
size_t session_cookie_len;
12781294
size_t len = sizeof("Set-Cookie")-1;
12791295

1280-
ZEND_ASSERT(strpbrk(ZSTR_VAL(PS(session_name)), "=,; \t\r\n\013\014") == NULL);
1296+
ZEND_ASSERT(is_session_name_valid(PS(session_name), 0));
12811297
spprintf(&session_cookie, 0, "Set-Cookie: %s=", ZSTR_VAL(PS(session_name)));
12821298

12831299
// TODO Manually compute from known information?
@@ -1325,10 +1341,8 @@ static zend_result php_session_send_cookie(void) /* {{{ */
13251341
return FAILURE;
13261342
}
13271343

1328-
// TODO need to Check for nul byte?
13291344
/* Prevent broken Set-Cookie header, because the session_name might be user supplied */
1330-
if (strpbrk(ZSTR_VAL(PS(session_name)), "=,; \t\r\n\013\014") != NULL) { /* man isspace for \013 and \014 */
1331-
php_error_docref(NULL, E_WARNING, "session.name cannot contain any of the following '=,; \\t\\r\\n\\013\\014'");
1345+
if (!is_session_name_valid(PS(session_name), E_WARNING)) {
13321346
return FAILURE;
13331347
}
13341348

ext/session/tests/session_name_variation1.phpt

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,20 +71,18 @@ bool(true)
7171
string(9) "PHPSESSID"
7272
bool(true)
7373
string(9) "PHPSESSID"
74-
string(9) "PHPSESSID"
7574

76-
Warning: session_start(): session.name cannot contain any of the following '=,; \t\r\n\013\014' in %s on line %d
75+
Warning: session_name(): session.name " " cannot contain any of the following '=,; \t\r\n\013\014' in %s on line %d
76+
string(9) "PHPSESSID"
7777
bool(true)
78-
string(1) " "
78+
string(9) "PHPSESSID"
7979
bool(true)
80-
string(1) " "
80+
string(9) "PHPSESSID"
8181

8282
Warning: session_name(): session.name "" cannot be empty in %s on line %d
83-
string(1) " "
84-
85-
Warning: session_start(): session.name cannot contain any of the following '=,; \t\r\n\013\014' in %s on line %d
83+
string(9) "PHPSESSID"
8684
bool(true)
87-
string(1) " "
85+
string(9) "PHPSESSID"
8886
bool(true)
89-
string(1) " "
87+
string(9) "PHPSESSID"
9088
Done

0 commit comments

Comments
 (0)