diff --git a/Lib/ConfigParser.py b/Lib/ConfigParser.py index 65c8ce557db..2902939805e 100644 --- a/Lib/ConfigParser.py +++ b/Lib/ConfigParser.py @@ -594,7 +594,8 @@ class SafeConfigParser(ConfigParser): self._interpolate_some(option, L, rawval, section, vars, 1) return ''.join(L) - _interpvar_match = re.compile(r"%\(([^)]+)\)s").match + _interpvar_re = re.compile(r"%\(([^)]+)\)s") + _badpercent_re = re.compile(r"%[^%]|%$") def _interpolate_some(self, option, accum, rest, section, map, depth): if depth > MAX_INTERPOLATION_DEPTH: @@ -613,7 +614,7 @@ class SafeConfigParser(ConfigParser): accum.append("%") rest = rest[2:] elif c == "(": - m = self._interpvar_match(rest) + m = self._interpvar_re.match(rest) if m is None: raise InterpolationSyntaxError(option, section, "bad interpolation variable reference %r" % rest) @@ -638,4 +639,12 @@ class SafeConfigParser(ConfigParser): """Set an option. Extend ConfigParser.set: check for string values.""" if not isinstance(value, basestring): raise TypeError("option values must be strings") + # check for bad percent signs: + # first, replace all "good" interpolations + tmp_value = self._interpvar_re.sub('', value) + # then, check if there's a lone percent sign left + m = self._badpercent_re.search(tmp_value) + if m: + raise ValueError("invalid interpolation syntax in %r at " + "position %d" % (value, m.start())) ConfigParser.set(self, section, option, value) diff --git a/Lib/test/test_cfgparser.py b/Lib/test/test_cfgparser.py index 9e3b495c5ae..c4df74185e0 100644 --- a/Lib/test/test_cfgparser.py +++ b/Lib/test/test_cfgparser.py @@ -422,6 +422,18 @@ class SafeConfigParserTestCase(ConfigParserTestCase): self.assertEqual(cf.get("section", "ok"), "xxx/%s") self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s") + def test_set_malformatted_interpolation(self): + cf = self.fromstring("[sect]\n" + "option1=foo\n") + + self.assertEqual(cf.get('sect', "option1"), "foo") + + self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo") + self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%") + self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo") + + self.assertEqual(cf.get('sect', "option1"), "foo") + def test_set_nonstring_types(self): cf = self.fromstring("[sect]\n" "option1=foo\n") diff --git a/Misc/NEWS b/Misc/NEWS index bd672453b61..d29fe4e78ba 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -168,6 +168,10 @@ Core and builtins Library ------- +- Patch #1603688: ConfigParser.SafeConfigParser now checks values that + are set for invalid interpolation sequences that would lead to errors + on reading back those values. + - Added support for the POSIX.1-2001 (pax) format to tarfile.py. Extended and cleaned up the test suite. Added a new testtar.tar.