1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-26 12:21:12 +03:00

Refactor test_escape.c for additional ways of testing.

Start the file with static functions not specific to pe_test_vectors
tests.  This way, new tests can use them without disrupting the file's
layout.  Change report_result() PQExpBuffer arguments to plain strings.
Back-patch to v13 (all supported versions), for the next commit.

Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Backpatch-through: 13
Security: CVE-2025-4207
This commit is contained in:
Noah Misch
2025-05-05 04:52:04 -07:00
parent 954aacaee3
commit 617d34908b

View File

@ -31,6 +31,8 @@ typedef struct pe_test_config
int failure_count; int failure_count;
} pe_test_config; } pe_test_config;
#define NEVER_ACCESS_STR "\xff never-to-be-touched"
/* /*
* An escape function to be tested by this test. * An escape function to be tested by this test.
@ -86,6 +88,82 @@ static const PsqlScanCallbacks test_scan_callbacks = {
}; };
/*
* Print the string into buf, making characters outside of plain ascii
* somewhat easier to recognize.
*
* The output format could stand to be improved significantly, it's not at all
* unambiguous.
*/
static void
escapify(PQExpBuffer buf, const char *str, size_t len)
{
for (size_t i = 0; i < len; i++)
{
char c = *str;
if (c == '\n')
appendPQExpBufferStr(buf, "\\n");
else if (c == '\0')
appendPQExpBufferStr(buf, "\\0");
else if (c < ' ' || c > '~')
appendPQExpBuffer(buf, "\\x%2x", (uint8_t) c);
else
appendPQExpBufferChar(buf, c);
str++;
}
}
static void
report_result(pe_test_config *tc,
bool success,
const char *testname,
const char *details,
const char *subname,
const char *resultdesc)
{
int test_id = ++tc->test_count;
bool print_details = true;
bool print_result = true;
if (success)
{
if (tc->verbosity <= 0)
print_details = false;
if (tc->verbosity < 0)
print_result = false;
}
else
tc->failure_count++;
if (print_details)
printf("%s", details);
if (print_result)
printf("%s %d - %s: %s: %s\n",
success ? "ok" : "not ok",
test_id, testname,
subname,
resultdesc);
}
/*
* Return true for encodings in which bytes in a multi-byte character look
* like valid ascii characters.
*/
static bool
encoding_conflicts_ascii(int encoding)
{
/*
* We don't store this property directly anywhere, but whether an encoding
* is a client-only encoding is a good proxy.
*/
if (encoding > PG_ENCODING_BE_LAST)
return true;
return false;
}
static bool static bool
escape_literal(PGconn *conn, PQExpBuffer target, escape_literal(PGconn *conn, PQExpBuffer target,
const char *unescaped, size_t unescaped_len, const char *unescaped, size_t unescaped_len,
@ -383,81 +461,6 @@ static pe_test_vector pe_test_vectors[] =
}; };
/*
* Print the string into buf, making characters outside of plain ascii
* somewhat easier to recognize.
*
* The output format could stand to be improved significantly, it's not at all
* unambiguous.
*/
static void
escapify(PQExpBuffer buf, const char *str, size_t len)
{
for (size_t i = 0; i < len; i++)
{
char c = *str;
if (c == '\n')
appendPQExpBufferStr(buf, "\\n");
else if (c == '\0')
appendPQExpBufferStr(buf, "\\0");
else if (c < ' ' || c > '~')
appendPQExpBuffer(buf, "\\x%2x", (uint8_t) c);
else
appendPQExpBufferChar(buf, c);
str++;
}
}
static void
report_result(pe_test_config *tc,
bool success,
PQExpBuffer testname,
PQExpBuffer details,
const char *subname,
const char *resultdesc)
{
int test_id = ++tc->test_count;
bool print_details = true;
bool print_result = true;
if (success)
{
if (tc->verbosity <= 0)
print_details = false;
if (tc->verbosity < 0)
print_result = false;
}
else
tc->failure_count++;
if (print_details)
printf("%s", details->data);
if (print_result)
printf("%s %d - %s: %s: %s\n",
success ? "ok" : "not ok",
test_id, testname->data,
subname,
resultdesc);
}
/*
* Return true for encodings in which bytes in a multi-byte character look
* like valid ascii characters.
*/
static bool
encoding_conflicts_ascii(int encoding)
{
/*
* We don't store this property directly anywhere, but whether an encoding
* is a client-only encoding is a good proxy.
*/
if (encoding > PG_ENCODING_BE_LAST)
return true;
return false;
}
static const char * static const char *
scan_res_s(PsqlScanResult res) scan_res_s(PsqlScanResult res)
{ {
@ -532,7 +535,7 @@ test_psql_parse(pe_test_config *tc, PQExpBuffer testname,
else else
resdesc = "ok"; resdesc = "ok";
report_result(tc, !test_fails, testname, details, report_result(tc, !test_fails, testname->data, details->data,
"psql parse", "psql parse",
resdesc); resdesc);
} }
@ -617,7 +620,6 @@ test_one_vector_escape(pe_test_config *tc, const pe_test_vector *tv, const pe_te
*/ */
appendBinaryPQExpBuffer(raw_buf, tv->escape, tv->escape_len); appendBinaryPQExpBuffer(raw_buf, tv->escape, tv->escape_len);
#define NEVER_ACCESS_STR "\xff never-to-be-touched"
if (ef->supports_input_length) if (ef->supports_input_length)
{ {
/* /*
@ -671,7 +673,7 @@ test_one_vector_escape(pe_test_config *tc, const pe_test_vector *tv, const pe_te
* here, but that's not available everywhere. * here, but that's not available everywhere.
*/ */
contains_never = strstr(escape_buf->data, NEVER_ACCESS_STR) == NULL; contains_never = strstr(escape_buf->data, NEVER_ACCESS_STR) == NULL;
report_result(tc, contains_never, testname, details, report_result(tc, contains_never, testname->data, details->data,
"escaped data beyond end of input", "escaped data beyond end of input",
contains_never ? "no" : "all secrets revealed"); contains_never ? "no" : "all secrets revealed");
} }
@ -714,7 +716,7 @@ test_one_vector_escape(pe_test_config *tc, const pe_test_vector *tv, const pe_te
resdesc = "valid input failed to escape, due to zero byte"; resdesc = "valid input failed to escape, due to zero byte";
} }
report_result(tc, ok, testname, details, report_result(tc, ok, testname->data, details->data,
"input validity vs escape success", "input validity vs escape success",
resdesc); resdesc);
} }
@ -744,7 +746,7 @@ test_one_vector_escape(pe_test_config *tc, const pe_test_vector *tv, const pe_te
resdesc = "invalid input produced valid output"; resdesc = "invalid input produced valid output";
} }
report_result(tc, ok, testname, details, report_result(tc, ok, testname->data, details->data,
"input and escaped encoding validity", "input and escaped encoding validity",
resdesc); resdesc);
} }