]> granicus.if.org Git - python/commitdiff
Issue #28563: Fixed possible DoS and arbitrary code execution when handle
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 8 Nov 2016 19:20:09 +0000 (21:20 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Tue, 8 Nov 2016 19:20:09 +0000 (21:20 +0200)
plural form selections in the gettext module.  The expression parser now
supports exact syntax supported by GNU gettext.

1  2 
Lib/gettext.py
Lib/test/test_gettext.py
Misc/NEWS

diff --cc Lib/gettext.py
Simple merge
index 2737e8136760a5f471845f0b3695d502aed1b09f,f8df62246e5089f667b85babcab984d27f297bf6..7cd84347fd5aa30d96abcc62182b9a6a9da25cd3
@@@ -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 513989afee0e07ed16cc312f890cf522bfaffc3c,c55dc4a2e015cba0bf73b9ef2e55e7a1930d1a49..07d1b215ba79e92a3c75cf9989c61696e3275d01
+++ 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.