From: Serhiy Storchaka Date: Tue, 8 Nov 2016 19:20:09 +0000 (+0200) Subject: Issue #28563: Fixed possible DoS and arbitrary code execution when handle X-Git-Tag: v3.4.6rc1~7 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1c3fdd900d102cf993fb787dfc65fb01d987945d;p=python Issue #28563: Fixed possible DoS and arbitrary code execution when handle plural form selections in the gettext module. The expression parser now supports exact syntax supported by GNU gettext. --- 1c3fdd900d102cf993fb787dfc65fb01d987945d diff --cc Lib/test/test_gettext.py index 2737e81367,f8df62246e..7cd84347fd --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@@ -295,15 -315,64 +321,72 @@@ class PluralFormsTestCase(GettextBaseTe raises = self.assertRaises # Test for a dangerous expression raises(ValueError, gettext.c2py, "os.chmod('/etc/passwd',0777)") + # issue28563 + raises(ValueError, gettext.c2py, '"(eval(foo) && ""') + raises(ValueError, gettext.c2py, 'f"{os.system(\'sh\')}"') + # Maximum recursion depth exceeded during compilation + raises(ValueError, gettext.c2py, 'n+'*10000 + 'n') + self.assertEqual(gettext.c2py('n+'*100 + 'n')(1), 101) + # MemoryError during compilation + raises(ValueError, gettext.c2py, '('*100 + 'n' + ')'*100) + # Maximum recursion depth exceeded in C to Python translator + raises(ValueError, gettext.c2py, '('*10000 + 'n' + ')'*10000) + self.assertEqual(gettext.c2py('('*20 + 'n' + ')'*20)(1), 1) + + def test_chained_comparison(self): + # C doesn't chain comparison as Python so 2 == 2 == 2 gets different results + f = gettext.c2py('n == n == n') + self.assertEqual(''.join(str(f(x)) for x in range(3)), '010') + f = gettext.c2py('1 < n == n') + self.assertEqual(''.join(str(f(x)) for x in range(3)), '100') + f = gettext.c2py('n == n < 2') + self.assertEqual(''.join(str(f(x)) for x in range(3)), '010') + f = gettext.c2py('0 < n < 2') + self.assertEqual(''.join(str(f(x)) for x in range(3)), '111') + + def test_decimal_number(self): + self.assertEqual(gettext.c2py('0123')(1), 123) + + def test_invalid_syntax(self): + invalid_expressions = [ + 'x>1', '(n>1', 'n>1)', '42**42**42', '0xa', '1.0', '1e2', + 'n>0x1', '+n', '-n', 'n()', 'n(1)', '1+', 'nn', 'n n', + ] + for expr in invalid_expressions: + with self.assertRaises(ValueError): + gettext.c2py(expr) + + def test_nested_condition_operator(self): + self.assertEqual(gettext.c2py('n?1?2:3:4')(0), 4) + self.assertEqual(gettext.c2py('n?1?2:3:4')(1), 2) + self.assertEqual(gettext.c2py('n?1:3?4:5')(0), 4) + self.assertEqual(gettext.c2py('n?1:3?4:5')(1), 1) + + def test_division(self): + f = gettext.c2py('2/n*3') + self.assertEqual(f(1), 6) + self.assertEqual(f(2), 3) + self.assertEqual(f(3), 0) + self.assertEqual(f(-1), -6) + self.assertRaises(ZeroDivisionError, f, 0) + + def test_plural_number(self): + f = gettext.c2py('1') + self.assertEqual(f(1), 1) + self.assertRaises(ValueError, f, 1.0) + self.assertRaises(ValueError, f, '1') + self.assertRaises(ValueError, f, []) + self.assertRaises(ValueError, f, object()) + +class GNUTranslationParsingTest(GettextBaseTest): + def test_plural_form_error_issue17898(self): + with open(MOFILE, 'wb') as fp: + fp.write(base64.decodebytes(GNU_MO_DATA_ISSUE_17898)) + with open(MOFILE, 'rb') as fp: + # If this runs cleanly, the bug is fixed. + t = gettext.GNUTranslations(fp) + class UnicodeTranslationsTest(GettextBaseTest): def setUp(self): diff --cc Misc/NEWS index 513989afee,c55dc4a2e0..07d1b215ba --- a/Misc/NEWS +++ b/Misc/NEWS @@@ -16,9 -32,10 +16,13 @@@ Core and Builtin Library ------- + - Issue #28563: Fixed possible DoS and arbitrary code execution when handle + plural form selections in the gettext module. The expression parser now + supports exact syntax supported by GNU gettext. + +- In the curses module, raise an error if window.getstr() or window.instr() is + passed a negative value. + - Issue #27783: Fix possible usage of uninitialized memory in operator.methodcaller. - Issue #27774: Fix possible Py_DECREF on unowned object in _sre.