Be more wary of false matches in initdb's replace_token().

Do not replace the target string unless the occurrence is surrounded
by whitespace or line start/end.  This avoids potential false match
to a substring of a field.  While we've not had trouble with that
up to now, the next patch creates hazards of false matches to
POSTGRES within an ACL field.

There is one call site that needs adjustment, as it was presuming
it could write "::1" and have that match "::1/128".  For all the
others, this restriction is okay and strictly safer.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Discussion: https://postgr.es/m/183292bb-4891-4c96-a3ca-e78b5e0e1358@dunslane.net
This commit is contained in:
Tom Lane 2026-03-05 17:22:31 -05:00
parent 34cb4254bd
commit 7664319ccb

View file

@ -461,7 +461,8 @@ add_stringlist_item(_stringlist **listhead, const char *str)
/*
* Modify the array of lines, replacing "token" by "replacement"
* the first time it occurs on each line.
* the first time it occurs on each line. To prevent false matches, the
* occurrence of "token" must be surrounded by whitespace or line start/end.
*
* The array must be a malloc'd array of individually malloc'd strings.
* We free any discarded strings.
@ -483,6 +484,7 @@ replace_token(char **lines, const char *token, const char *replacement)
for (int i = 0; lines[i]; i++)
{
char *where;
char *endwhere;
char *newline;
int pre;
@ -490,6 +492,17 @@ replace_token(char **lines, const char *token, const char *replacement)
if ((where = strstr(lines[i], token)) == NULL)
continue;
/*
* Reject false match. Note a blind spot: we don't check for a valid
* match following a false match. That case can't occur at present,
* so not worth complicating this code for it.
*/
if (!(where == lines[i] || isspace((unsigned char) where[-1])))
continue;
endwhere = where + strlen(token);
if (!(*endwhere == '\0' || isspace((unsigned char) *endwhere)))
continue;
/* if we get here a change is needed - set up new line */
newline = (char *) pg_malloc(strlen(lines[i]) + diff + 1);
@ -1501,11 +1514,11 @@ setup_config(void)
getaddrinfo("::1", NULL, &hints, &gai_result) != 0)
{
conflines = replace_token(conflines,
"host all all ::1",
"#host all all ::1");
"host all all ::1/128",
"#host all all ::1/128");
conflines = replace_token(conflines,
"host replication all ::1",
"#host replication all ::1");
"host replication all ::1/128",
"#host replication all ::1/128");
}
}