Fix overflow in parsing of positional parameter
authorPeter Eisentraut <[email protected]>
Tue, 2 Jul 2024 07:16:36 +0000 (09:16 +0200)
committerPeter Eisentraut <[email protected]>
Tue, 2 Jul 2024 07:29:26 +0000 (09:29 +0200)
Replace atol with pg_strtoint32_safe in the backend parser and with
strtoint in ECPG to reject overflows when parsing the number of a
positional parameter.  With atol from glibc, parameters $2147483648 and
$4294967297 turn into $-2147483648 and $1, respectively.

Author: Erik Wienhold <[email protected]>
Reviewed-by: Michael Paquier <[email protected]>
Reviewed-by: Peter Eisentraut <[email protected]>
Reviewed-by: Alexander Lakhin <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/5d216d1c-91f6-4cbe-95e2-b4cbd930520c@ewie.name

src/backend/parser/scan.l
src/interfaces/ecpg/preproc/pgc.l
src/test/regress/expected/numerology.out
src/test/regress/sql/numerology.sql

index 3248fb5108058f6282632d41a2b9cfff82c61b35..f74059e7b0be5ab07abb50ac4c957d81d0e3f23b 100644 (file)
@@ -992,8 +992,14 @@ other          .
                }
 
 {param}            {
+                   ErrorSaveContext escontext = {T_ErrorSaveContext};
+                   int32       val;
+
                    SET_YYLLOC();
-                   yylval->ival = atol(yytext + 1);
+                   val = pg_strtoint32_safe(yytext + 1, (Node *) &escontext);
+                   if (escontext.error_occurred)
+                       yyerror("parameter number too large");
+                   yylval->ival = val;
                    return PARAM;
                }
 {param_junk}   {
index f9d68a96e79d9af22f05155cae94553104ec6970..27261f42d8d501ccabbc940bd43485e3881401de 100644 (file)
@@ -938,7 +938,13 @@ cppline            {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
                }
 
 {param}            {
-                   base_yylval.ival = atol(yytext+1);
+                   int         val;
+
+                   errno = 0;
+                   val = strtoint(yytext + 1, NULL, 10);
+                   if (errno == ERANGE)
+                       mmfatal(PARSE_ERROR, "parameter number too large");
+                   base_yylval.ival = val;
                    return PARAM;
                }
 {param_junk}   {
index 8d4a3ba228a1c3b79632cd55ce6e57bd689d0b8f..717a237df98652625817164732b66d1c435d32a3 100644 (file)
@@ -206,6 +206,10 @@ PREPARE p1 AS SELECT $1a;
 ERROR:  trailing junk after parameter at or near "$1a"
 LINE 1: PREPARE p1 AS SELECT $1a;
                              ^
+PREPARE p1 AS SELECT $2147483648;
+ERROR:  parameter number too large at or near "$2147483648"
+LINE 1: PREPARE p1 AS SELECT $2147483648;
+                             ^
 SELECT 0b;
 ERROR:  invalid binary integer at or near "0b"
 LINE 1: SELECT 0b;
index 372e7bf9bc87e372ecb579609b68cd47d98cf0d1..3ae491cc980fa4d7d4450202b96f154c21afe023 100644 (file)
@@ -52,6 +52,7 @@ SELECT 0.0e1a;
 SELECT 0.0e;
 SELECT 0.0e+a;
 PREPARE p1 AS SELECT $1a;
+PREPARE p1 AS SELECT $2147483648;
 
 SELECT 0b;
 SELECT 1b;