Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3db826b

Browse files
committed
Tighten up allowed names for custom GUC parameters.
Formerly we were pretty lax about what a custom GUC's name couldbe; so long as it had at least one dot in it, we'd take it.However, corner cases such as dashes or equal signs in the namewould cause various bits of functionality to misbehave. Ratherthan trying to make the world perfectly safe for that, let'sjust require that custom names look like "identifier.identifier",where "identifier" means something that scan.l would acceptwithout double quotes.Along the way, this patch refactors things slightly in guc.cso that find_option() is responsible for reporting GUC-not-foundcases, allowing removal of duplicative code from its callers.Per report from Hubert Depesz Lubaczewski. No back-patch,since the consequences of the problem don't seem to warrantchanging behavior in stable branches.Discussion:https://postgr.es/m/951335.1612910077@sss.pgh.pa.us
1 parent23607a8 commit3db826b

File tree

4 files changed

+132
-70
lines changed

4 files changed

+132
-70
lines changed

‎src/backend/utils/misc/guc-file.l

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ ProcessConfigFileInternal(GucContext context, bool applySettings, int elevel)
282282
* Try to find the variable; but do not create a custom placeholder if
283283
* it's not there already.
284284
*/
285-
record =find_option(item->name,false, elevel);
285+
record =find_option(item->name,false,true,elevel);
286286

287287
if (record)
288288
{
@@ -306,7 +306,7 @@ ProcessConfigFileInternal(GucContext context, bool applySettings, int elevel)
306306
/* Now mark it as present in file */
307307
record->status |= GUC_IS_IN_FILE;
308308
}
309-
elseif (strchr(item->name, GUC_QUALIFIER_SEPARATOR) ==NULL)
309+
elseif (!valid_custom_variable_name(item->name))
310310
{
311311
/* Invalid non-custom variable, so complain */
312312
ereport(elevel,

‎src/backend/utils/misc/guc.c

Lines changed: 99 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5334,6 +5334,45 @@ add_guc_variable(struct config_generic *var, int elevel)
53345334
return true;
53355335
}
53365336

5337+
/*
5338+
* Decide whether a proposed custom variable name is allowed.
5339+
*
5340+
* It must be "identifier.identifier", where the rules for what is an
5341+
* identifier agree with scan.l.
5342+
*/
5343+
staticbool
5344+
valid_custom_variable_name(constchar*name)
5345+
{
5346+
intnum_sep=0;
5347+
boolname_start= true;
5348+
5349+
for (constchar*p=name;*p;p++)
5350+
{
5351+
if (*p==GUC_QUALIFIER_SEPARATOR)
5352+
{
5353+
if (name_start)
5354+
return false;/* empty name component */
5355+
num_sep++;
5356+
name_start= true;
5357+
}
5358+
elseif (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
5359+
"abcdefghijklmnopqrstuvwxyz",*p)!=NULL||
5360+
IS_HIGHBIT_SET(*p))
5361+
{
5362+
/* okay as first or non-first character */
5363+
name_start= false;
5364+
}
5365+
elseif (!name_start&&strchr("0123456789_$",*p)!=NULL)
5366+
/* okay as non-first character */ ;
5367+
else
5368+
return false;
5369+
}
5370+
if (name_start)
5371+
return false;/* empty name component */
5372+
/* OK if we had exactly one separator */
5373+
return (num_sep==1);
5374+
}
5375+
53375376
/*
53385377
* Create and add a placeholder variable for a custom variable name.
53395378
*/
@@ -5381,12 +5420,23 @@ add_placeholder_variable(const char *name, int elevel)
53815420
}
53825421

53835422
/*
5384-
* Look up option NAME. If it exists, return a pointer to its record,
5385-
* else return NULL. If create_placeholders is true, we'll create a
5386-
* placeholder record for a valid-looking custom variable name.
5423+
* Look up option "name". If it exists, return a pointer to its record.
5424+
* Otherwise, if create_placeholders is true and name is a valid-looking
5425+
* custom variable name, we'll create and return a placeholder record.
5426+
* Otherwise, if skip_errors is true, then we silently return NULL for
5427+
* an unrecognized or invalid name. Otherwise, the error is reported at
5428+
* error level elevel (and we return NULL if that's less than ERROR).
5429+
*
5430+
* Note: internal errors, primarily out-of-memory, draw an elevel-level
5431+
* report and NULL return regardless of skip_errors. Hence, callers must
5432+
* handle a NULL return whenever elevel < ERROR, but they should not need
5433+
* to emit any additional error message. (In practice, internal errors
5434+
* can only happen when create_placeholders is true, so callers passing
5435+
* false need not think terribly hard about this.)
53875436
*/
53885437
staticstructconfig_generic*
5389-
find_option(constchar*name,boolcreate_placeholders,intelevel)
5438+
find_option(constchar*name,boolcreate_placeholders,boolskip_errors,
5439+
intelevel)
53905440
{
53915441
constchar**key=&name;
53925442
structconfig_generic**res;
@@ -5414,19 +5464,38 @@ find_option(const char *name, bool create_placeholders, int elevel)
54145464
for (i=0;map_old_guc_names[i]!=NULL;i+=2)
54155465
{
54165466
if (guc_name_compare(name,map_old_guc_names[i])==0)
5417-
returnfind_option(map_old_guc_names[i+1], false,elevel);
5467+
returnfind_option(map_old_guc_names[i+1], false,
5468+
skip_errors,elevel);
54185469
}
54195470

54205471
if (create_placeholders)
54215472
{
54225473
/*
5423-
* Check if the name is qualified, and if so, add a placeholder.
5474+
* Check if the name is valid, and if so, add a placeholder. If it
5475+
* doesn't contain a separator, don't assume that it was meant to be a
5476+
* placeholder.
54245477
*/
54255478
if (strchr(name,GUC_QUALIFIER_SEPARATOR)!=NULL)
5426-
returnadd_placeholder_variable(name,elevel);
5479+
{
5480+
if (valid_custom_variable_name(name))
5481+
returnadd_placeholder_variable(name,elevel);
5482+
/* A special error message seems desirable here */
5483+
if (!skip_errors)
5484+
ereport(elevel,
5485+
(errcode(ERRCODE_INVALID_NAME),
5486+
errmsg("invalid configuration parameter name \"%s\"",
5487+
name),
5488+
errdetail("Custom parameter names must be of the form \"identifier.identifier\".")));
5489+
returnNULL;
5490+
}
54275491
}
54285492

54295493
/* Unknown name */
5494+
if (!skip_errors)
5495+
ereport(elevel,
5496+
(errcode(ERRCODE_UNDEFINED_OBJECT),
5497+
errmsg("unrecognized configuration parameter \"%s\"",
5498+
name)));
54305499
returnNULL;
54315500
}
54325501

@@ -6444,7 +6513,7 @@ ReportChangedGUCOptions(void)
64446513
{
64456514
structconfig_generic*record;
64466515

6447-
record=find_option("in_hot_standby", false,ERROR);
6516+
record=find_option("in_hot_standby", false,false,ERROR);
64486517
Assert(record!=NULL);
64496518
record->status |=GUC_NEEDS_REPORT;
64506519
report_needed= true;
@@ -7218,14 +7287,9 @@ set_config_option(const char *name, const char *value,
72187287
(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
72197288
errmsg("cannot set parameters during a parallel operation")));
72207289

7221-
record=find_option(name, true,elevel);
7290+
record=find_option(name, true,false,elevel);
72227291
if (record==NULL)
7223-
{
7224-
ereport(elevel,
7225-
(errcode(ERRCODE_UNDEFINED_OBJECT),
7226-
errmsg("unrecognized configuration parameter \"%s\"",name)));
72277292
return0;
7228-
}
72297293

72307294
/*
72317295
* Check if the option can be set at this time. See guc.h for the precise
@@ -7947,10 +8011,10 @@ set_config_sourcefile(const char *name, char *sourcefile, int sourceline)
79478011
*/
79488012
elevel=IsUnderPostmaster ?DEBUG3 :LOG;
79498013

7950-
record=find_option(name, true,elevel);
8014+
record=find_option(name, true,false,elevel);
79518015
/* should not happen */
79528016
if (record==NULL)
7953-
elog(ERROR,"unrecognized configuration parameter \"%s\"",name);
8017+
return;
79548018

79558019
sourcefile=guc_strdup(elevel,sourcefile);
79568020
if (record->sourcefile)
@@ -7999,16 +8063,9 @@ GetConfigOption(const char *name, bool missing_ok, bool restrict_privileged)
79998063
structconfig_generic*record;
80008064
staticcharbuffer[256];
80018065

8002-
record=find_option(name, false,ERROR);
8066+
record=find_option(name, false,missing_ok,ERROR);
80038067
if (record==NULL)
8004-
{
8005-
if (missing_ok)
8006-
returnNULL;
8007-
ereport(ERROR,
8008-
(errcode(ERRCODE_UNDEFINED_OBJECT),
8009-
errmsg("unrecognized configuration parameter \"%s\"",
8010-
name)));
8011-
}
8068+
returnNULL;
80128069
if (restrict_privileged&&
80138070
(record->flags&GUC_SUPERUSER_ONLY)&&
80148071
!is_member_of_role(GetUserId(),ROLE_PG_READ_ALL_SETTINGS))
@@ -8055,11 +8112,8 @@ GetConfigOptionResetString(const char *name)
80558112
structconfig_generic*record;
80568113
staticcharbuffer[256];
80578114

8058-
record=find_option(name, false,ERROR);
8059-
if (record==NULL)
8060-
ereport(ERROR,
8061-
(errcode(ERRCODE_UNDEFINED_OBJECT),
8062-
errmsg("unrecognized configuration parameter \"%s\"",name)));
8115+
record=find_option(name, false, false,ERROR);
8116+
Assert(record!=NULL);
80638117
if ((record->flags&GUC_SUPERUSER_ONLY)&&
80648118
!is_member_of_role(GetUserId(),ROLE_PG_READ_ALL_SETTINGS))
80658119
ereport(ERROR,
@@ -8103,16 +8157,9 @@ GetConfigOptionFlags(const char *name, bool missing_ok)
81038157
{
81048158
structconfig_generic*record;
81058159

8106-
record=find_option(name, false,WARNING);
8160+
record=find_option(name, false,missing_ok,ERROR);
81078161
if (record==NULL)
8108-
{
8109-
if (missing_ok)
8110-
return0;
8111-
ereport(ERROR,
8112-
(errcode(ERRCODE_UNDEFINED_OBJECT),
8113-
errmsg("unrecognized configuration parameter \"%s\"",
8114-
name)));
8115-
}
8162+
return0;
81168163
returnrecord->flags;
81178164
}
81188165

@@ -8144,7 +8191,7 @@ flatten_set_variable_args(const char *name, List *args)
81448191
* Get flags for the variable; if it's not known, use default flags.
81458192
* (Caller might throw error later, but not our business to do so here.)
81468193
*/
8147-
record=find_option(name, false,WARNING);
8194+
record=find_option(name, false,true,WARNING);
81488195
if (record)
81498196
flags=record->flags;
81508197
else
@@ -8439,12 +8486,8 @@ AlterSystemSetConfigFile(AlterSystemStmt *altersysstmt)
84398486
{
84408487
structconfig_generic*record;
84418488

8442-
record=find_option(name, false,ERROR);
8443-
if (record==NULL)
8444-
ereport(ERROR,
8445-
(errcode(ERRCODE_UNDEFINED_OBJECT),
8446-
errmsg("unrecognized configuration parameter \"%s\"",
8447-
name)));
8489+
record=find_option(name, false, false,ERROR);
8490+
Assert(record!=NULL);
84488491

84498492
/*
84508493
* Don't allow parameters that can't be set in configuration files to
@@ -9460,19 +9503,12 @@ GetConfigOptionByName(const char *name, const char **varname, bool missing_ok)
94609503
{
94619504
structconfig_generic*record;
94629505

9463-
record=find_option(name, false,ERROR);
9506+
record=find_option(name, false,missing_ok,ERROR);
94649507
if (record==NULL)
94659508
{
9466-
if (missing_ok)
9467-
{
9468-
if (varname)
9469-
*varname=NULL;
9470-
returnNULL;
9471-
}
9472-
9473-
ereport(ERROR,
9474-
(errcode(ERRCODE_UNDEFINED_OBJECT),
9475-
errmsg("unrecognized configuration parameter \"%s\"",name)));
9509+
if (varname)
9510+
*varname=NULL;
9511+
returnNULL;
94769512
}
94779513

94789514
if ((record->flags&GUC_SUPERUSER_ONLY)&&
@@ -10318,7 +10354,7 @@ read_nondefault_variables(void)
1031810354
if ((varname=read_string_with_null(fp))==NULL)
1031910355
break;
1032010356

10321-
if ((record=find_option(varname, true,FATAL))==NULL)
10357+
if ((record=find_option(varname, true,false,FATAL))==NULL)
1032210358
elog(FATAL,"failed to locate variable \"%s\" in exec config params file",varname);
1032310359

1032410360
if ((varvalue=read_string_with_null(fp))==NULL)
@@ -11008,7 +11044,7 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value)
1100811044
(void)validate_option_array_item(name,value, false);
1100911045

1101011046
/* normalize name (converts obsolete GUC names to modern spellings) */
11011-
record=find_option(name, false,WARNING);
11047+
record=find_option(name, false,true,WARNING);
1101211048
if (record)
1101311049
name=record->name;
1101411050

@@ -11087,7 +11123,7 @@ GUCArrayDelete(ArrayType *array, const char *name)
1108711123
(void)validate_option_array_item(name,NULL, false);
1108811124

1108911125
/* normalize name (converts obsolete GUC names to modern spellings) */
11090-
record=find_option(name, false,WARNING);
11126+
record=find_option(name, false,true,WARNING);
1109111127
if (record)
1109211128
name=record->name;
1109311129

@@ -11234,7 +11270,7 @@ validate_option_array_item(const char *name, const char *value,
1123411270
* SUSET and user is superuser).
1123511271
*
1123611272
* name is not known, but exists or can be created as a placeholder (i.e.,
11237-
* it has aprefixed name). We allow this case if you're a superuser,
11273+
* it has avalid custom name). We allow this case if you're a superuser,
1123811274
* otherwise not. Superusers are assumed to know what they're doing. We
1123911275
* can't allow it for other users, because when the placeholder is
1124011276
* resolved it might turn out to be a SUSET variable;
@@ -11243,16 +11279,11 @@ validate_option_array_item(const char *name, const char *value,
1124311279
* name is not known and can't be created as a placeholder. Throw error,
1124411280
* unless skipIfNoPermissions is true, in which case return false.
1124511281
*/
11246-
gconf=find_option(name, true,WARNING);
11282+
gconf=find_option(name, true,skipIfNoPermissions,ERROR);
1124711283
if (!gconf)
1124811284
{
1124911285
/* not known, failed to make a placeholder */
11250-
if (skipIfNoPermissions)
11251-
return false;
11252-
ereport(ERROR,
11253-
(errcode(ERRCODE_UNDEFINED_OBJECT),
11254-
errmsg("unrecognized configuration parameter \"%s\"",
11255-
name)));
11286+
return false;
1125611287
}
1125711288

1125811289
if (gconf->flags&GUC_CUSTOM_PLACEHOLDER)

‎src/test/regress/expected/guc.out

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,27 @@ SET seq_page_cost TO 'NaN';
511511
ERROR: invalid value for parameter "seq_page_cost": "NaN"
512512
SET vacuum_cost_delay TO '10s';
513513
ERROR: 10000 ms is outside the valid range for parameter "vacuum_cost_delay" (0 .. 100)
514+
SET no_such_variable TO 42;
515+
ERROR: unrecognized configuration parameter "no_such_variable"
516+
-- Test "custom" GUCs created on the fly (which aren't really an
517+
-- intended feature, but many people use them).
518+
SET custom.my_guc = 42;
519+
SHOW custom.my_guc;
520+
custom.my_guc
521+
---------------
522+
42
523+
(1 row)
524+
525+
SET custom."bad-guc" = 42; -- disallowed because -c cannot set this name
526+
ERROR: invalid configuration parameter name "custom.bad-guc"
527+
DETAIL: Custom parameter names must be of the form "identifier.identifier".
528+
SHOW custom."bad-guc";
529+
ERROR: unrecognized configuration parameter "custom.bad-guc"
530+
SET special."weird name" = 'foo'; -- could be allowed, but we choose not to
531+
ERROR: invalid configuration parameter name "special.weird name"
532+
DETAIL: Custom parameter names must be of the form "identifier.identifier".
533+
SHOW special."weird name";
534+
ERROR: unrecognized configuration parameter "special.weird name"
514535
--
515536
-- Test DISCARD TEMP
516537
--

‎src/test/regress/sql/guc.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,16 @@ SELECT '2006-08-13 12:34:56'::timestamptz;
147147
-- Test some simple error cases
148148
SET seq_page_cost TO'NaN';
149149
SET vacuum_cost_delay TO'10s';
150+
SET no_such_variable TO42;
151+
152+
-- Test "custom" GUCs created on the fly (which aren't really an
153+
-- intended feature, but many people use them).
154+
SETcustom.my_guc=42;
155+
SHOWcustom.my_guc;
156+
SET custom."bad-guc"=42;-- disallowed because -c cannot set this name
157+
SHOW custom."bad-guc";
158+
SET special."weird name"='foo';-- could be allowed, but we choose not to
159+
SHOW special."weird name";
150160

151161
--
152162
-- Test DISCARD TEMP

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp