Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit a19f260

Browse files
committed
Add defenses against invalid operator names passed in CREATE OPERATOR
arguments (where the parser doesn't check them already). Minor code cleanups too.
1 parent 970a2d1 commit a19f260

File tree

1 file changed

+106
-73
lines changed

1 file changed

+106
-73
lines changed

src/backend/catalog/pg_operator.c

Lines changed: 106 additions & 73 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_operator.c,v 1.61 2001/08/10 15:49:39 petere Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.62 2001/10/22 19:34:13 tgl Exp $
1212
*
1313
* NOTES
1414
* these routines moved here from commands/define.c and somewhat cleaned up.
@@ -41,11 +41,6 @@ static Oid OperatorGet(char *operatorName,
4141
char *rightTypeName,
4242
bool *defined);
4343

44-
static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
45-
char *operatorName,
46-
Oid leftObjectId,
47-
Oid rightObjectId);
48-
4944
static Oid OperatorShellMake(char *operatorName,
5045
char *leftTypeName,
5146
char *rightTypeName);
@@ -66,6 +61,65 @@ static void OperatorDef(char *operatorName,
6661

6762
static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
6863

64+
65+
/*
66+
* Check whether a proposed operator name is legal
67+
*
68+
* This had better match the behavior of parser/scan.l!
69+
*
70+
* We need this because the parser is not smart enough to check that
71+
* the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
72+
* are operator names rather than some other lexical entity.
73+
*/
74+
static bool
75+
validOperatorName(const char *name)
76+
{
77+
size_t len = strlen(name);
78+
79+
/* Can't be empty or too long */
80+
if (len == 0 || len >= NAMEDATALEN)
81+
return false;
82+
83+
/* Can't contain any invalid characters */
84+
/* Test string here should match op_chars in scan.l */
85+
if (strspn(name, "~!@#^&|`?$+-*/%<>=") != len)
86+
return false;
87+
88+
/* Can't contain slash-star or dash-dash (comment starts) */
89+
if (strstr(name, "/*") || strstr(name, "--"))
90+
return false;
91+
92+
/*
93+
* For SQL92 compatibility, '+' and '-' cannot be the
94+
* last char of a multi-char operator unless the operator
95+
* contains chars that are not in SQL92 operators.
96+
* The idea is to lex '=-' as two operators, but not
97+
* to forbid operator names like '?-' that could not be
98+
* sequences of SQL92 operators.
99+
*/
100+
if (len > 1 &&
101+
(name[len-1] == '+' ||
102+
name[len-1] == '-'))
103+
{
104+
int ic;
105+
106+
for (ic = len-2; ic >= 0; ic--)
107+
{
108+
if (strchr("~!@#^&|`?$%", name[ic]))
109+
break;
110+
}
111+
if (ic < 0)
112+
return false; /* nope, not valid */
113+
}
114+
115+
/* != isn't valid either, because parser will convert it to <> */
116+
if (strcmp(name, "!=") == 0)
117+
return false;
118+
119+
return true;
120+
}
121+
122+
69123
/* ----------------------------------------------------------------
70124
* OperatorGetWithOpenRelation
71125
*
@@ -157,7 +211,6 @@ OperatorGet(char *operatorName,
157211
bool *defined)
158212
{
159213
Relation pg_operator_desc;
160-
161214
Oid operatorObjectId;
162215
Oid leftObjectId = InvalidOid;
163216
Oid rightObjectId = InvalidOid;
@@ -215,24 +268,55 @@ OperatorGet(char *operatorName,
215268
}
216269

217270
/* ----------------------------------------------------------------
218-
* OperatorShellMakeWithOpenRelation
271+
* OperatorShellMake
219272
*
273+
* Specify operator name and left and right type names,
274+
* fill an operator struct with this info and NULL's,
275+
* call heap_insert and return the Oid to the caller.
220276
* ----------------------------------------------------------------
221277
*/
222278
static Oid
223-
OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
224-
char *operatorName,
225-
Oid leftObjectId,
226-
Oid rightObjectId)
279+
OperatorShellMake(char *operatorName,
280+
char *leftTypeName,
281+
char *rightTypeName)
227282
{
283+
Relation pg_operator_desc;
284+
Oid operatorObjectId;
285+
Oid leftObjectId = InvalidOid;
286+
Oid rightObjectId = InvalidOid;
287+
bool leftDefined = false;
288+
bool rightDefined = false;
228289
int i;
229290
HeapTuple tup;
230291
Datum values[Natts_pg_operator];
231292
char nulls[Natts_pg_operator];
232-
Oid operatorObjectId;
233293
NameData oname;
234294
TupleDesc tupDesc;
235295

296+
/*
297+
* validate operator name
298+
*/
299+
if (!validOperatorName(operatorName))
300+
elog(ERROR, "\"%s\" is not a valid operator name", operatorName);
301+
302+
/*
303+
* get the left and right type oid's for this operator
304+
*/
305+
if (leftTypeName)
306+
leftObjectId = TypeGet(leftTypeName, &leftDefined);
307+
308+
if (rightTypeName)
309+
rightObjectId = TypeGet(rightTypeName, &rightDefined);
310+
311+
if (!((OidIsValid(leftObjectId) && leftDefined) ||
312+
(OidIsValid(rightObjectId) && rightDefined)))
313+
elog(ERROR, "OperatorShellMake: the operand types are not valid");
314+
315+
/*
316+
* open pg_operator
317+
*/
318+
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
319+
236320
/*
237321
* initialize our *nulls and *values arrays
238322
*/
@@ -243,7 +327,7 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
243327
}
244328

245329
/*
246-
* initialize *values with the operator name and input data types.
330+
* initialize values[] with the operator name and input data types.
247331
* Note that oprcode is set to InvalidOid, indicating it's a shell.
248332
*/
249333
i = 0;
@@ -270,12 +354,10 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
270354
*/
271355
tupDesc = pg_operator_desc->rd_att;
272356

273-
tup = heap_formtuple(tupDesc,
274-
values,
275-
nulls);
357+
tup = heap_formtuple(tupDesc, values, nulls);
276358

277359
/*
278-
* insert our "shell" operator tuple and close the relation
360+
* insert our "shell" operator tuple
279361
*/
280362
heap_insert(pg_operator_desc, tup);
281363
operatorObjectId = tup->t_data->t_oid;
@@ -289,63 +371,8 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
289371
CatalogCloseIndices(Num_pg_operator_indices, idescs);
290372
}
291373

292-
/*
293-
* free the tuple and return the operator oid
294-
*/
295374
heap_freetuple(tup);
296375

297-
return operatorObjectId;
298-
}
299-
300-
/* ----------------------------------------------------------------
301-
* OperatorShellMake
302-
*
303-
* Specify operator name and left and right type names,
304-
* fill an operator struct with this info and NULL's,
305-
* call heap_insert and return the Oid
306-
* to the caller.
307-
* ----------------------------------------------------------------
308-
*/
309-
static Oid
310-
OperatorShellMake(char *operatorName,
311-
char *leftTypeName,
312-
char *rightTypeName)
313-
{
314-
Relation pg_operator_desc;
315-
Oid operatorObjectId;
316-
317-
Oid leftObjectId = InvalidOid;
318-
Oid rightObjectId = InvalidOid;
319-
bool leftDefined = false;
320-
bool rightDefined = false;
321-
322-
/*
323-
* get the left and right type oid's for this operator
324-
*/
325-
if (leftTypeName)
326-
leftObjectId = TypeGet(leftTypeName, &leftDefined);
327-
328-
if (rightTypeName)
329-
rightObjectId = TypeGet(rightTypeName, &rightDefined);
330-
331-
if (!((OidIsValid(leftObjectId) && leftDefined) ||
332-
(OidIsValid(rightObjectId) && rightDefined)))
333-
elog(ERROR, "OperatorShellMake: the operand types are not valid");
334-
335-
/*
336-
* open pg_operator
337-
*/
338-
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
339-
340-
/*
341-
* add a "shell" operator tuple to the operator relation and recover
342-
* the shell tuple's oid.
343-
*/
344-
operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc,
345-
operatorName,
346-
leftObjectId,
347-
rightObjectId);
348-
349376
/*
350377
* close the operator relation and return the oid.
351378
*/
@@ -484,6 +511,12 @@ OperatorDef(char *operatorName,
484511
* filling in a previously-created shell.
485512
*/
486513

514+
/*
515+
* validate operator name
516+
*/
517+
if (!validOperatorName(operatorName))
518+
elog(ERROR, "\"%s\" is not a valid operator name", operatorName);
519+
487520
/*
488521
* look up the operator data types.
489522
*

0 commit comments

Comments
 (0)