This is an automated email from the ASF dual-hosted git repository. tuhaihe pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/cloudberry.git
commit ee3cfe5b8e576d8a09fc60183ea9a8131377f057 Author: Nathan Bossart <[email protected]> AuthorDate: Mon May 11 05:13:50 2026 -0700 refint: Fix SQL injection and buffer overruns. Maliciously crafted key value updates could achieve SQL injection within check_foreign_key(). To fix, ensure new key values are properly quoted and escaped in the internally generated SQL statements. While at it, avoid potential buffer overruns by replacing the stack buffers for internally generated SQL statements with StringInfo. Reported-by: Nikolay Samokhvalov <[email protected]> Author: Nathan Bossart <[email protected]> Reviewed-by: Noah Misch <[email protected]> Reviewed-by: Tom Lane <[email protected]> Reviewed-by: Fujii Masao <[email protected]> Security: CVE-2026-6637 Backpatch-through: 14 --- contrib/spi/refint.c | 84 ++++++++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 46 deletions(-) diff --git a/contrib/spi/refint.c b/contrib/spi/refint.c index 2c1911f827d..982c74c9047 100644 --- a/contrib/spi/refint.c +++ b/contrib/spi/refint.c @@ -166,21 +166,24 @@ check_primary_key(PG_FUNCTION_ARGS) if (plan->nplans <= 0) { SPIPlanPtr pplan; - char sql[8192]; + StringInfoData sql; + + initStringInfo(&sql); /* * Construct query: SELECT 1 FROM _referenced_relation_ WHERE Pkey1 = * $1 [AND Pkey2 = $2 [...]] */ - snprintf(sql, sizeof(sql), "select 1 from %s where ", relname); - for (i = 0; i < nkeys; i++) + appendStringInfo(&sql, "select 1 from %s where ", relname); + for (i = 1; i <= nkeys; i++) { - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s = $%d %s", - args[i + nkeys + 1], i + 1, (i < nkeys - 1) ? "and " : ""); + appendStringInfo(&sql, "%s = $%d ", args[i + nkeys], i); + if (i < nkeys) + appendStringInfoString(&sql, "and "); } /* Prepare plan for query */ - pplan = SPI_prepare(sql, nkeys, argtypes); + pplan = SPI_prepare(sql.data, nkeys, argtypes); if (pplan == NULL) /* internal error */ elog(ERROR, "check_primary_key: SPI_prepare returned %s", SPI_result_code_string(SPI_result)); @@ -196,6 +199,8 @@ check_primary_key(PG_FUNCTION_ARGS) sizeof(SPIPlanPtr)); *(plan->splan) = pplan; plan->nplans = 1; + + pfree(sql.data); } /* @@ -416,7 +421,6 @@ check_foreign_key(PG_FUNCTION_ARGS) if (plan->nplans <= 0) { SPIPlanPtr pplan; - char sql[8192]; char **args2 = args; plan->splan = (SPIPlanPtr *) MemoryContextAlloc(TopMemoryContext, @@ -424,6 +428,10 @@ check_foreign_key(PG_FUNCTION_ARGS) for (r = 0; r < nrefs; r++) { + StringInfoData sql; + + initStringInfo(&sql); + relname = args2[0]; /*--------- @@ -437,8 +445,7 @@ check_foreign_key(PG_FUNCTION_ARGS) *--------- */ if (action == 'r') - - snprintf(sql, sizeof(sql), "select 1 from %s where ", relname); + appendStringInfo(&sql, "select 1 from %s where ", relname); /*--------- * For 'C'ascade action we construct DELETE query @@ -465,42 +472,23 @@ check_foreign_key(PG_FUNCTION_ARGS) char *nv; int k; - snprintf(sql, sizeof(sql), "update %s set ", relname); + appendStringInfo(&sql, "update %s set ", relname); for (k = 1; k <= nkeys; k++) { - int is_char_type = 0; - char *type; - fn = SPI_fnumber(tupdesc, args_temp[k - 1]); Assert(fn > 0); /* already checked above */ nv = SPI_getvalue(newtuple, tupdesc, fn); - type = SPI_gettype(tupdesc, fn); - - if (strcmp(type, "text") == 0 || - strcmp(type, "varchar") == 0 || - strcmp(type, "char") == 0 || - strcmp(type, "bpchar") == 0 || - strcmp(type, "date") == 0 || - strcmp(type, "timestamp") == 0) - is_char_type = 1; -#ifdef DEBUG_QUERY - elog(DEBUG4, "check_foreign_key Debug value %s type %s %d", - nv, type, is_char_type); -#endif - /* - * is_char_type =1 i set ' ' for define a new value - */ - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), - " %s = %s%s%s %s ", - args2[k], (is_char_type > 0) ? "'" : "", - nv, (is_char_type > 0) ? "'" : "", (k < nkeys) ? ", " : ""); + appendStringInfo(&sql, " %s = %s ", + args2[k], quote_literal_cstr(nv)); + if (k < nkeys) + appendStringInfoString(&sql, ", "); } - strcat(sql, " where "); + appendStringInfoString(&sql, " where "); } else /* DELETE */ - snprintf(sql, sizeof(sql), "delete from %s where ", relname); + appendStringInfo(&sql, "delete from %s where ", relname); } /* @@ -511,25 +499,26 @@ check_foreign_key(PG_FUNCTION_ARGS) */ else if (action == 's') { - snprintf(sql, sizeof(sql), "update %s set ", relname); + appendStringInfo(&sql, "update %s set ", relname); for (i = 1; i <= nkeys; i++) { - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), - "%s = null%s", - args2[i], (i < nkeys) ? ", " : ""); + appendStringInfo(&sql, "%s = null", args2[i]); + if (i < nkeys) + appendStringInfoString(&sql, ", "); } - strcat(sql, " where "); + appendStringInfoString(&sql, " where "); } /* Construct WHERE qual */ for (i = 1; i <= nkeys; i++) { - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s = $%d %s", - args2[i], i, (i < nkeys) ? "and " : ""); + appendStringInfo(&sql, "%s = $%d ", args2[i], i); + if (i < nkeys) + appendStringInfoString(&sql, "and "); } /* Prepare plan for query */ - pplan = SPI_prepare(sql, nkeys, argtypes); + pplan = SPI_prepare(sql.data, nkeys, argtypes); if (pplan == NULL) /* internal error */ elog(ERROR, "check_foreign_key: SPI_prepare returned %s", SPI_result_code_string(SPI_result)); @@ -545,11 +534,14 @@ check_foreign_key(PG_FUNCTION_ARGS) plan->splan[r] = pplan; args2 += nkeys + 1; /* to the next relation */ + +#ifdef DEBUG_QUERY + elog(DEBUG4, "check_foreign_key Debug Query is : %s ", sql.data); +#endif + + pfree(sql.data); } plan->nplans = nrefs; -#ifdef DEBUG_QUERY - elog(DEBUG4, "check_foreign_key Debug Query is : %s ", sql); -#endif } /* --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
