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:
@ -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);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user