Skip to content

Commit eefa335

Browse files
committed
Check for session name criterias consistently
1 parent 193ca72 commit eefa335

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
@@ -658,6 +658,41 @@ static PHP_INI_MH(OnUpdateSaveDir) /* {{{ */
658658
}
659659
/* }}} */
660660

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

662697
static PHP_INI_MH(OnUpdateName) /* {{{ */
663698
{
@@ -668,33 +703,14 @@ static PHP_INI_MH(OnUpdateName) /* {{{ */
668703

669704
if (stage == ZEND_INI_STAGE_RUNTIME || stage == ZEND_INI_STAGE_ACTIVATE || stage == ZEND_INI_STAGE_STARTUP) {
670705
err_type = E_WARNING;
706+
} else if (stage == ZEND_INI_STAGE_DEACTIVATE) {
707+
/* Do not output error when restoring ini options. */
708+
err_type = 0;
671709
} else {
672710
err_type = E_ERROR;
673711
}
674712

675-
if (ZSTR_LEN(new_value) == 0) {
676-
/* Do not output error when restoring ini options. */
677-
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
678-
php_error_docref(NULL, err_type, "session.name \"%s\" cannot be empty", ZSTR_VAL(new_value));
679-
}
680-
return FAILURE;
681-
}
682-
/* NUL bytes are not allowed */
683-
if (ZSTR_LEN(new_value) != strlen(ZSTR_VAL(new_value))) {
684-
/* Do not output error when restoring ini options. */
685-
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
686-
php_error_docref(NULL, err_type, "session.name \"%s\" cannot contain NUL bytes", ZSTR_VAL(new_value));
687-
}
688-
return FAILURE;
689-
}
690-
/* Numeric session.name won't work at all
691-
* See https://bugs.php.net/bug.php?id=35703
692-
(TL;DR: name is stored in HashTable so numeric string is converted to int key, but lookup looks for string key). */
693-
if (is_numeric_str_function(new_value, NULL, NULL)) {
694-
/* Do not output error when restoring ini options. */
695-
if (stage != ZEND_INI_STAGE_DEACTIVATE) {
696-
php_error_docref(NULL, err_type, "session.name \"%s\" cannot be numeric", ZSTR_VAL(new_value));
697-
}
713+
if (!is_session_name_valid(new_value, err_type)) {
698714
return FAILURE;
699715
}
700716

@@ -1297,7 +1313,7 @@ static void php_session_remove_cookie(void) {
12971313
size_t session_cookie_len;
12981314
size_t len = sizeof("Set-Cookie")-1;
12991315

1300-
ZEND_ASSERT(strpbrk(ZSTR_VAL(PS(session_name)), "=,; \t\r\n\013\014") == NULL);
1316+
ZEND_ASSERT(is_session_name_valid(PS(session_name), 0));
13011317
spprintf(&session_cookie, 0, "Set-Cookie: %s=", ZSTR_VAL(PS(session_name)));
13021318

13031319
// TODO Manually compute from known information?
@@ -1345,10 +1361,8 @@ static zend_result php_session_send_cookie(void) /* {{{ */
13451361
return FAILURE;
13461362
}
13471363

1348-
// TODO need to Check for nul byte?
13491364
/* Prevent broken Set-Cookie header, because the session_name might be user supplied */
1350-
if (strpbrk(ZSTR_VAL(PS(session_name)), "=,; \t\r\n\013\014") != NULL) { /* man isspace for \013 and \014 */
1351-
php_error_docref(NULL, E_WARNING, "session.name cannot contain any of the following '=,; \\t\\r\\n\\013\\014'");
1365+
if (!is_session_name_valid(PS(session_name), E_WARNING)) {
13521366
return FAILURE;
13531367
}
13541368

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)