8000 Repair insufficiently careful type checking for SQL-language functions: · danielcode/postgres@6be5429 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6be5429

Browse files
committed
Repair insufficiently careful type checking for SQL-language functions:
we should check that the function code returns the claimed result datatype every time we parse the function for execution. Formerly, for simple scalar result types we assumed the creation-time check was sufficient, but this fails if the function selects from a table that's been redefined since then, and even more obviously fails if check_function_bodies had been OFF. This is a significant security hole: not only can one trivially crash the backend, but with appropriate misuse of pass-by-reference datatypes it is possible to read out arbitrary locations in the server process's memory, which could allow retrieving database content the user should not be able to see. Our thanks to Jeff Trout for the initial report. Security: CVE-2007-0555
1 parent cf9ca3d commit 6be5429

File tree

3 files changed

+31
-15
lines changed

3 files changed

+31
-15
lines changed

src/backend/catalog/pg_proc.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.94 2002/09/18 21:35:20 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.94.2.1 2007/02/02 00:04:16 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -33,7 +33,6 @@
3333
#include "utils/syscache.h"
3434

3535

36-
static void checkretval(Oid rettype, char fn_typtype, List *queryTreeList);
3736
Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
3837
Datum fmgr_c_validator(PG_FUNCTION_ARGS);
3938
Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
@@ -294,15 +293,15 @@ ProcedureCreate(const char *procedureName,
294293
}
295294

296295
/*
297-
* checkretval() -- check return value of a list of sql parse trees.
296+
* check_sql_fn_retval() -- check return value of a list of sql parse trees.
298297
*
299298
* The return value of a sql function is the value returned by
300299
* the final query in the function. We do some ad-hoc define-time
301300
* type checking here to be sure that the user is returning the
302301
* type he claims.
303302
*/
304-
static void
305-
checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
303+
void
304+
check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList)
306305
{
307306
Query *parse;
308307
int cmd;
@@ -592,7 +591,7 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
592591
prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
593592

594593
querytree_list = pg_parse_and_rewrite(prosrc, proc->proargtypes, proc->pronargs);
595-
checkretval(proc->prorettype, functyptype, querytree_list);
594+
check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);
596595

597596
ReleaseSysCache(tuple);
598597

src/backend/executor/functions.c

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.57.2.1 2003/06/12 17:29:37 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.57.2.2 2007/02/02 00:04:16 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -24,6 +24,7 @@
2424
#include "tcop/tcopprot.h"
2525
#include "tcop/utility.h"
2626
#include "utils/builtins.h"
27+
#include "utils/lsyscache.h"
2728
#include "utils/syscache.h"
2829

2930

@@ -53,7 +54,7 @@ typedef struct local_es
5354

5455
typedef struct
5556
{
56-
int typlen; /* length of the return type */
57+
int16 typlen; /* length of the return type */
5758
bool typbyval; /* true if return type is pass by value */
5859
bool returnsTuple; /* true if return type is a tuple */
5960
bool shutdown_reg; /* true if registered shutdown callback */
@@ -71,7 +72,8 @@ typedef SQLFunctionCache *SQLFunctionCachePtr;
7172

7273
/* non-export function prototypes */
7374
static execution_state *init_execution_state(char *src,
74-
Oid *argOidVect, int nargs);
75+
Oid *argOidVect, int nargs,
76+
Oid rettype);
7577
static void init_sql_fcache(FmgrInfo *finfo);
7678
static void postquel_start(execution_state *es);
7779
static TupleTableSlot *postquel_getnext(execution_state *es);
@@ -84,7 +86,8 @@ static void ShutdownSQLFunction(Datum arg);
8486

8587

8688
static execution_state *
87-
init_execution_state(char *src, Oid *argOidVect, int nargs)
89+
init_execution_state(char *src, Oid *argOidVect, int nargs,
90+
Oid rettype)
8891
{
8992
execution_state *firstes;
9093
execution_state *preves;
@@ -93,6 +96,14 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
9396

9497
queryTree_list = pg_parse_and_rewrite(src, argOidVect, nargs);
9598

99+
/*
100+
* Check that the function returns the type it claims to. Although
101+
* this was already done when the function was defined,
102+
* we have to recheck because database objects used in the function's
103+
* queries might have changed type.
104+
*/
105+
check_sql_fn_retval(rettype, get_typtype(rettype), queryTree_list);
106+
96107
firstes = NULL;
97108
preves = NULL;
98109

@@ -150,6 +161,7 @@ static void
150161
init_sql_fcache(FmgrInfo *finfo)
151162
{
152163
Oid foid = finfo->fn_oid;
164+
Oid rettype;
153165
HeapTuple procedureTuple;
154166
HeapTuple typeTuple;
155167
Form_pg_proc procedureStruct;
@@ -176,12 +188,14 @@ init_sql_fcache(FmgrInfo *finfo)
176188
/*
177189
* get the return type from the procedure tuple
178190
*/
191+
rettype = procedureStruct->prorettype;
192+
179193
typeTuple = SearchSysCache(TYPEOID,
180-
ObjectIdGetDatum(procedureStruct->prorettype),
194+
ObjectIdGetDatum(rettype),
181195
0, 0, 0);
182196
if (!HeapTupleIsValid(typeTuple))
183197
elog(ERROR, "init_sql_fcache: Cache lookup failed for type %u",
184-
procedureStruct->prorettype);
198+
rettype);
185199

186200
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
187201

@@ -194,7 +208,7 @@ init_sql_fcache(FmgrInfo *finfo)
194208
fcache->typlen = typeStruct->typlen;
195209

196210
if (typeStruct->typtype != 'c' &&
197-
procedureStruct->prorettype != RECORDOID)
211+
rettype != RECORDOID)
198212
{
199213
/* The return type is not a composite type, so just use byval */
200214
fcache->typbyval = typeStruct->typbyval;
@@ -243,7 +257,7 @@ init_sql_fcache(FmgrInfo *finfo)
243257
foid);
244258
src = DatumGetCString(DirectFunctionCall1(textout, tmp));
245259

246-
fcache->func_state = init_execution_state(src, argOidVect, nargs);
260+
fcache->func_state = init_execution_state(src, argOidVect, nargs, rettype);
247261

248262
pfree(src);
249263

src/include/catalog/pg_proc.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: pg_proc.h,v 1.275.2.3 2006/11/28 19:19:25 tgl Exp $
10+
* $Id: pg_proc.h,v 1.275.2.4 2007/02/02 00:04:16 tgl Exp $
1111
*
1212
* NOTES
1313
* The script catalog/genbki.sh reads this file and generates .bki
@@ -3150,4 +3150,7 @@ extern Oid ProcedureCreate(const char *procedureName,
31503150
int parameterCount,
31513151
const Oid *parameterTypes);
31523152

3153+
extern void check_sql_fn_retval(Oid rettype, char fn_typtype,
3154+
List *queryTreeList);
3155+
31533156
#endif /* PG_PROC_H */

0 commit comments

Comments
 (0)
0