From a4ea0e7799cc1bb63e5406cd427f09d668cedfae Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 6 Apr 2022 09:17:42 +0000 Subject: [PATCH] *) core: make ap_escape_quotes() work correctly on strings with more than MAX_INT/2 characters, counting quotes double. Credit to for finding this. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1899609 13f79535-47bb-0310-9956-ffa450edef68 --- changes-entries/core_ap_escape_quotes.txt | 4 +++ server/util.c | 13 +++++---- test/unit/util.c | 35 +++++++++++++++++++++++ 3 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 changes-entries/core_ap_escape_quotes.txt diff --git a/changes-entries/core_ap_escape_quotes.txt b/changes-entries/core_ap_escape_quotes.txt new file mode 100644 index 00000000000..f83410a8771 --- /dev/null +++ b/changes-entries/core_ap_escape_quotes.txt @@ -0,0 +1,4 @@ + *) core: make ap_escape_quotes() work correctly on strings + with more than MAX_INT/2 characters, counting quotes double. + Credit to for finding this. + [Stefan Eissing] \ No newline at end of file diff --git a/server/util.c b/server/util.c index 771ba7b16f3..420615a41a5 100644 --- a/server/util.c +++ b/server/util.c @@ -2615,7 +2615,7 @@ AP_DECLARE(void) ap_content_type_tolower(char *str) */ AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring) { - int newlen = 0; + apr_ssize_t extra = 0; const char *inchr = instring; char *outchr, *outstring; @@ -2624,9 +2624,8 @@ AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring) * string up by an extra byte each time we find an unescaped ". */ while (*inchr != '\0') { - newlen++; if (*inchr == '"') { - newlen++; + extra++; } /* * If we find a slosh, and it's not the last byte in the string, @@ -2634,11 +2633,15 @@ AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring) */ else if ((*inchr == '\\') && (inchr[1] != '\0')) { inchr++; - newlen++; } inchr++; } - outstring = apr_palloc(p, newlen + 1); + + if (!extra) { + return apr_pstrdup(p, instring); + } + + outstring = apr_palloc(p, (inchr - instring) + extra + 1); inchr = instring; outchr = outstring; /* diff --git a/test/unit/util.c b/test/unit/util.c index 5cadfd89ba1..c9dec41a18e 100644 --- a/test/unit/util.c +++ b/test/unit/util.c @@ -79,6 +79,41 @@ HTTPD_START_LOOP_TEST(find_token_correctly_parses_token_list, ap_test_token_case } END_TEST + +/* + * ap_escape_quotes() + */ + +struct ap_escape_quotes_case { + const char *input; + const char *expected; +}; + +#define ESCQ "\\\"" + +const struct ap_escape_quotes_case ap_test_escape_quotes_cases[] = { + { "one", "one" }, + { "o\"ne", "o"ESCQ"ne" }, + { "o"ESCQ"ne", "o"ESCQ"ne" }, + { "one\\", "one\\" }, + { "o\\ne", "o\\ne" }, + { "o\\"ESCQ"ne", "o\\\\"ESCQ"ne" }, /* 1st \ escapes 2nd, following '"' needs \ */ +}; + +const size_t ap_test_escape_quotes_cases_len = sizeof(ap_test_escape_quotes_cases) / + sizeof(ap_test_escape_quotes_cases[0]); + +HTTPD_START_LOOP_TEST(check_escape_quotes, ap_test_escape_quotes_cases_len) +{ + const struct ap_escape_quotes_case *c = &ap_test_escape_quotes_cases[_i]; + const char *result; + + result = ap_escape_quotes(g_pool, c->input); + ck_assert_str_eq(result, c->expected); +} +END_TEST + + /* * Test Case Boilerplate */ -- 2.47.2