Skip to content

Commit 6de4573

Browse files
committed
Check for session name criterias consistently
1 parent 5093327 commit 6de4573

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
@@ -642,6 +642,41 @@ static PHP_INI_MH(OnUpdateSaveDir) /* {{{ */
642642
}
643643
/* }}} */
644644

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

646681
static PHP_INI_MH(OnUpdateName) /* {{{ */
647682
{
@@ -652,33 +687,14 @@ static PHP_INI_MH(OnUpdateName) /* {{{ */
652687

653688
if (stage == ZEND_INI_STAGE_RUNTIME || stage == ZEND_INI_STAGE_ACTIVATE || stage == ZEND_INI_STAGE_STARTUP) {
654689
err_type = E_WARNING;
690+
} else if (stage == ZEND_INI_STAGE_DEACTIVATE) {
691+
/* Do not output error when restoring ini options. */
692+
err_type = 0;
655693
} else {
656694
err_type = E_ERROR;
657695
}
658696

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

@@ -1270,7 +1286,7 @@ static void php_session_remove_cookie(void) {
12701286
size_t session_cookie_len;
12711287
size_t len = sizeof("Set-Cookie")-1;
12721288

1273-
ZEND_ASSERT(strpbrk(ZSTR_VAL(PS(session_name)), "=,; \t\r\n\013\014") == NULL);
1289+
ZEND_ASSERT(is_session_name_valid(PS(session_name), 0));
12741290
spprintf(&session_cookie, 0, "Set-Cookie: %s=", ZSTR_VAL(PS(session_name)));
12751291

12761292
// TODO Manually compute from known information?
@@ -1318,10 +1334,8 @@ static zend_result php_session_send_cookie(void) /* {{{ */
13181334
return FAILURE;
13191335
}
13201336

1321-
// TODO need to Check for nul byte?
13221337
/* Prevent broken Set-Cookie header, because the session_name might be user supplied */
1323-
if (strpbrk(ZSTR_VAL(PS(session_name)), "=,; \t\r\n\013\014") != NULL) { /* man isspace for \013 and \014 */
1324-
php_error_docref(NULL, E_WARNING, "session.name cannot contain any of the following '=,; \\t\\r\\n\\013\\014'");
1338+
if (!is_session_name_valid(PS(session_name), E_WARNING)) {
13251339
return FAILURE;
13261340
}
13271341

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)