From a19f2605ed66ba664389dacae20b3085703991b5 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 22 Oct 2001 19:34:13 +0000 Subject: [PATCH] Add defenses against invalid operator names passed in CREATE OPERATOR arguments (where the parser doesn't check them already). Minor code cleanups too. --- src/backend/catalog/pg_operator.c | 179 ++++++++++++++++++++++---------------- 1 file changed, 106 insertions(+), 73 deletions(-) diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index a72565e970..97e0b87b9c 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.61 2001/08/10 15:49:39 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.62 2001/10/22 19:34:13 tgl Exp $ * * NOTES * these routines moved here from commands/define.c and somewhat cleaned up. @@ -41,11 +41,6 @@ static Oid OperatorGet(char *operatorName, char *rightTypeName, bool *defined); -static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc, - char *operatorName, - Oid leftObjectId, - Oid rightObjectId); - static Oid OperatorShellMake(char *operatorName, char *leftTypeName, char *rightTypeName); @@ -66,6 +61,65 @@ static void OperatorDef(char *operatorName, static void OperatorUpd(Oid baseId, Oid commId, Oid negId); + +/* + * Check whether a proposed operator name is legal + * + * This had better match the behavior of parser/scan.l! + * + * We need this because the parser is not smart enough to check that + * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses + * are operator names rather than some other lexical entity. + */ +static bool +validOperatorName(const char *name) +{ + size_t len = strlen(name); + + /* Can't be empty or too long */ + if (len == 0 || len >= NAMEDATALEN) + return false; + + /* Can't contain any invalid characters */ + /* Test string here should match op_chars in scan.l */ + if (strspn(name, "~!@#^&|`?$+-*/%<>=") != len) + return false; + + /* Can't contain slash-star or dash-dash (comment starts) */ + if (strstr(name, "/*") || strstr(name, "--")) + return false; + + /* + * For SQL92 compatibility, '+' and '-' cannot be the + * last char of a multi-char operator unless the operator + * contains chars that are not in SQL92 operators. + * The idea is to lex '=-' as two operators, but not + * to forbid operator names like '?-' that could not be + * sequences of SQL92 operators. + */ + if (len > 1 && + (name[len-1] == '+' || + name[len-1] == '-')) + { + int ic; + + for (ic = len-2; ic >= 0; ic--) + { + if (strchr("~!@#^&|`?$%", name[ic])) + break; + } + if (ic < 0) + return false; /* nope, not valid */ + } + + /* != isn't valid either, because parser will convert it to <> */ + if (strcmp(name, "!=") == 0) + return false; + + return true; +} + + /* ---------------------------------------------------------------- * OperatorGetWithOpenRelation * @@ -157,7 +211,6 @@ OperatorGet(char *operatorName, bool *defined) { Relation pg_operator_desc; - Oid operatorObjectId; Oid leftObjectId = InvalidOid; Oid rightObjectId = InvalidOid; @@ -215,25 +268,56 @@ OperatorGet(char *operatorName, } /* ---------------------------------------------------------------- - * OperatorShellMakeWithOpenRelation + * OperatorShellMake * + * Specify operator name and left and right type names, + * fill an operator struct with this info and NULL's, + * call heap_insert and return the Oid to the caller. * ---------------------------------------------------------------- */ static Oid -OperatorShellMakeWithOpenRelation(Relation pg_operator_desc, - char *operatorName, - Oid leftObjectId, - Oid rightObjectId) +OperatorShellMake(char *operatorName, + char *leftTypeName, + char *rightTypeName) { + Relation pg_operator_desc; + Oid operatorObjectId; + Oid leftObjectId = InvalidOid; + Oid rightObjectId = InvalidOid; + bool leftDefined = false; + bool rightDefined = false; int i; HeapTuple tup; Datum values[Natts_pg_operator]; char nulls[Natts_pg_operator]; - Oid operatorObjectId; NameData oname; TupleDesc tupDesc; /* + * validate operator name + */ + if (!validOperatorName(operatorName)) + elog(ERROR, "\"%s\" is not a valid operator name", operatorName); + + /* + * get the left and right type oid's for this operator + */ + if (leftTypeName) + leftObjectId = TypeGet(leftTypeName, &leftDefined); + + if (rightTypeName) + rightObjectId = TypeGet(rightTypeName, &rightDefined); + + if (!((OidIsValid(leftObjectId) && leftDefined) || + (OidIsValid(rightObjectId) && rightDefined))) + elog(ERROR, "OperatorShellMake: the operand types are not valid"); + + /* + * open pg_operator + */ + pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock); + + /* * initialize our *nulls and *values arrays */ for (i = 0; i < Natts_pg_operator; ++i) @@ -243,7 +327,7 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc, } /* - * initialize *values with the operator name and input data types. + * initialize values[] with the operator name and input data types. * Note that oprcode is set to InvalidOid, indicating it's a shell. */ i = 0; @@ -270,12 +354,10 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc, */ tupDesc = pg_operator_desc->rd_att; - tup = heap_formtuple(tupDesc, - values, - nulls); + tup = heap_formtuple(tupDesc, values, nulls); /* - * insert our "shell" operator tuple and close the relation + * insert our "shell" operator tuple */ heap_insert(pg_operator_desc, tup); operatorObjectId = tup->t_data->t_oid; @@ -289,63 +371,8 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc, CatalogCloseIndices(Num_pg_operator_indices, idescs); } - /* - * free the tuple and return the operator oid - */ heap_freetuple(tup); - return operatorObjectId; -} - -/* ---------------------------------------------------------------- - * OperatorShellMake - * - * Specify operator name and left and right type names, - * fill an operator struct with this info and NULL's, - * call heap_insert and return the Oid - * to the caller. - * ---------------------------------------------------------------- - */ -static Oid -OperatorShellMake(char *operatorName, - char *leftTypeName, - char *rightTypeName) -{ - Relation pg_operator_desc; - Oid operatorObjectId; - - Oid leftObjectId = InvalidOid; - Oid rightObjectId = InvalidOid; - bool leftDefined = false; - bool rightDefined = false; - - /* - * get the left and right type oid's for this operator - */ - if (leftTypeName) - leftObjectId = TypeGet(leftTypeName, &leftDefined); - - if (rightTypeName) - rightObjectId = TypeGet(rightTypeName, &rightDefined); - - if (!((OidIsValid(leftObjectId) && leftDefined) || - (OidIsValid(rightObjectId) && rightDefined))) - elog(ERROR, "OperatorShellMake: the operand types are not valid"); - - /* - * open pg_operator - */ - pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock); - - /* - * add a "shell" operator tuple to the operator relation and recover - * the shell tuple's oid. - */ - operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc, - operatorName, - leftObjectId, - rightObjectId); - /* * close the operator relation and return the oid. */ @@ -485,6 +512,12 @@ OperatorDef(char *operatorName, */ /* + * validate operator name + */ + if (!validOperatorName(operatorName)) + elog(ERROR, "\"%s\" is not a valid operator name", operatorName); + + /* * look up the operator data types. * * Note: types must be defined before operators -- 2.11.0