Skip to content

Commit e02bf26

Browse files
Girgiasjorgsowa
authored andcommitted
Check for session name criterias consistently
1 parent dcc29e7 commit e02bf26

File tree

2 files changed

+52
-35
lines changed

2 files changed

+52
-35
lines changed

ext/session/session.c

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,41 @@ static PHP_INI_MH(OnUpdateSaveDir) /* {{{ */
698698
}
699699
/* }}} */
700700

701+
/* If diagnostic_type is 0 then no diagnostic will be emitted */
702+
static bool is_session_name_valid(const zend_string *name, int diagnostic_type)
703+
{
704+
if (ZSTR_LEN(name) == 0) {
705+
if (diagnostic_type) {
706+
php_error_docref(NULL, diagnostic_type, "session.name \"%s\" cannot be empty", ZSTR_VAL(name));
707+
}
708+
return false;
709+
}
710+
/* NUL bytes are not allowed */
711+
if (ZSTR_LEN(name) != strlen(ZSTR_VAL(name))) {
712+
if (diagnostic_type) {
713+
php_error_docref(NULL, diagnostic_type, "session.name \"%s\" cannot contain NUL bytes", ZSTR_VAL(name));
714+
}
715+
return false;
716+
}
717+
/* Numeric session.name won't work at all
718+
* See https://bugs.php.net/bug.php?id=35703
719+
(TL;DR: name is stored in HashTable so numeric string is converted to int key, but lookup looks for string key). */
720+
if (is_numeric_str_function(name, NULL, NULL)) {
721+
if (diagnostic_type) {
722+
php_error_docref(NULL, diagnostic_type, "session.name \"%s\" cannot be numeric", ZSTR_VAL(name));
723+
}
724+
return false;
725+
}
726+
/* Prevent broken Set-Cookie header, because the session_name might be user supplied */
727+
if (strpbrk(ZSTR_VAL(name), "=,; \t\r\n\013\014") != NULL) { /* man isspace for \013 and \014 */
728+
if (diagnostic_type) {
729+
php_error_docref(NULL, diagnostic_type, "session.name \"%s\" cannot contain any of the following "
730+
"'=,; \\t\\r\\n\\013\\014'", ZSTR_VAL(name));
731+
}
732+
return false;
733+
}
734+
return true;
735+
}
701736

702737
static PHP_INI_MH(OnUpdateName) /* {{{ */
703738
{
@@ -708,33 +743,14 @@ static PHP_INI_MH(OnUpdateName) /* {{{ */
708743

709744
if (stage == ZEND_INI_STAGE_RUNTIME || stage == ZEND_INI_STAGE_ACTIVATE || stage == ZEND_INI_STAGE_STARTUP) {
710745
err_type = E_WARNING;
746+
} else if (stage == ZEND_INI_STAGE_DEACTIVATE) {
747+
/* Do not output error when restoring ini options. */
748+
err_type = 0;
711749
} else {
712750
err_type = E_ERROR;
713751
}
714752

715-
if (ZSTR_LEN(new_value) == 0) {
716-
/* Do not output error when restoring ini options. */
717-
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
718-
php_error_docref(NULL, err_type, "session.name \"%s\" cannot be empty", ZSTR_VAL(new_value));
719-
}
720-
return FAILURE;
721-
}
722-
/* NUL bytes are not allowed */
723-
if (ZSTR_LEN(new_value) != strlen(ZSTR_VAL(new_value))) {
724-
/* Do not output error when restoring ini options. */
725-
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
726-
php_error_docref(NULL, err_type, "session.name \"%s\" cannot contain NUL bytes", ZSTR_VAL(new_value));
727-
}
728-
return FAILURE;
729-
}
730-
/* Numeric session.name won't work at all
731-
* See https://bugs.php.net/bug.php?id=35703
732-
(TL;DR: name is stored in HashTable so numeric string is converted to int key, but lookup looks for string key). */
733-
if (is_numeric_str_function(new_value, NULL, NULL)) {
734-
/* Do not output error when restoring ini options. */
735-
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
736-
php_error_docref(NULL, err_type, "session.name \"%s\" cannot be numeric", ZSTR_VAL(new_value));
737-
}
753+
if (!is_session_name_valid(new_value, err_type)) {
738754
return FAILURE;
739755
}
740756

@@ -1413,7 +1429,7 @@ static void php_session_remove_cookie(void) {
14131429
size_t session_cookie_len;
14141430
size_t len = sizeof("Set-Cookie")-1;
14151431

1416-
ZEND_ASSERT(strpbrk(ZSTR_VAL(PS(session_name)), SESSION_FORBIDDEN_CHARS) == NULL);
1432+
ZEND_ASSERT(is_session_name_valid(PS(session_name), 0));
14171433
spprintf(&session_cookie, 0, "Set-Cookie: %s=", ZSTR_VAL(PS(session_name)));
14181434

14191435
// TODO Manually compute from known information?
@@ -1454,10 +1470,8 @@ static zend_result php_session_send_cookie(void) /* {{{ */
14541470
return FAILURE;
14551471
}
14561472

1457-
// TODO need to Check for nul byte?
14581473
/* Prevent broken Set-Cookie header, because the session_name might be user supplied */
1459-
if (strpbrk(ZSTR_VAL(PS(session_name)), SESSION_FORBIDDEN_CHARS) != NULL) { /* man isspace for \013 and \014 */
1460-
php_error_docref(NULL, E_WARNING, "session.name cannot contain any of the following '=,; \\t\\r\\n\\013\\014'");
1474+
if (!is_session_name_valid(PS(session_name), E_WARNING)) {
14611475
return FAILURE;
14621476
}
14631477

ext/session/tests/session_name_variation1.phpt

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,22 @@ string(9) "PHPSESSID"
6767

6868
Warning: session_name(): session.name "10.25" cannot be numeric in %s on line %d
6969
string(9) "PHPSESSID"
70+
bool(true)
71+
string(9) "PHPSESSID"
72+
bool(true)
73+
string(9) "PHPSESSID"
7074

71-
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"
7277
bool(true)
73-
string(1) " "
78+
string(9) "PHPSESSID"
7479
bool(true)
75-
string(1) " "
80+
string(9) "PHPSESSID"
7681

7782
Warning: session_name(): session.name "" cannot be empty in %s on line %d
78-
string(1) " "
79-
80-
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"
8184
bool(true)
82-
string(1) " "
85+
string(9) "PHPSESSID"
8386
bool(true)
84-
string(1) " "
87+
string(9) "PHPSESSID"
8588
Done

0 commit comments

Comments
 (0)