File CVE-2015-20107-mailcap-unsafe-filenames.patch of Package python.32348

---
 Doc/library/mailcap.rst |   13 +++++++++++++
 Lib/mailcap.py          |   28 ++++++++++++++++++++++++++--
 2 files changed, 39 insertions(+), 2 deletions(-)

--- a/Doc/library/mailcap.rst
+++ b/Doc/library/mailcap.rst
@@ -55,6 +55,19 @@ standard.  However, mailcap files are su
    will automatically check such conditions and skip the entry if the check fails.
 
 
+.. versionchanged:: 3.11
+
+   To prevent security issues with shell metacharacters (symbols that have
+   special effects in a shell command line), ``findmatch`` will refuse
+   to inject ASCII characters other than alphanumerics and ``@+=:,./-_``
+   into the returned command line.
+
+   If a disallowed character appears in *filename*, ``findmatch`` will always
+   return ``(None, None)`` as if no entry was found.
+   If such a character appears elsewhere (a value in *plist* or in *MIMEtype*),
+   ``findmatch`` will ignore all mailcap entries which use that value.
+   A :mod:`warning <warnings>` will be raised in either case.
+
 .. function:: getcaps()
 
    Returns a dictionary mapping MIME types to a list of mailcap file entries. This
--- a/Lib/mailcap.py
+++ b/Lib/mailcap.py
@@ -1,9 +1,17 @@
 """Mailcap file handling.  See RFC 1524."""
 
 import os
+import warnings
+import re
 
 __all__ = ["getcaps","findmatch"]
 
+_find_unsafe = re.compile(ur'[^\xa1-\U0010FFFF\w@+=:,./-]').search
+
+class UnsafeMailcapInput(Warning):
+    """Warning raised when refusing unsafe input"""
+
+
 # Part 1: top-level interface.
 
 def getcaps():
@@ -18,6 +26,10 @@ def getcaps():
     """
     caps = {}
     for mailcap in listmailcapfiles():
+        if _find_unsafe(mailcap):
+            msg = "Refusing to use mailcap with filename %r. Use a safe temporary filename." % (mailcap,)
+            warnings.warn(msg, UnsafeMailcapInput)
+            return None, None
         try:
             fp = open(mailcap, 'r')
         except IOError:
@@ -149,10 +161,13 @@ def findmatch(caps, MIMEtype, key='view'
     for e in entries:
         if 'test' in e:
             test = subst(e['test'], filename, plist)
+            if test is None:
+                continue
             if test and os.system(test) != 0:
                 continue
         command = subst(e[key], MIMEtype, filename, plist)
-        return command, e
+        if command is not None:
+            return command, e
     return None, None
 
 def lookup(caps, MIMEtype, key=None):
@@ -184,6 +199,10 @@ def subst(field, MIMEtype, filename, pli
             elif c == 's':
                 res = res + filename
             elif c == 't':
+                if _find_unsafe(MIMEtype):
+                    msg = "Refusing to substitute MIME type %r into a shell command." % (MIMEtype,)
+                    warnings.warn(msg, UnsafeMailcapInput)
+                    return None
                 res = res + MIMEtype
             elif c == '{':
                 start = i
@@ -191,7 +210,12 @@ def subst(field, MIMEtype, filename, pli
                     i = i+1
                 name = field[start:i]
                 i = i+1
-                res = res + findparam(name, plist)
+                param = findparam(name, plist)
+                if _find_unsafe(param):
+                    msg = "Refusing to substitute parameter %r (%s) into a shell command" % (param, name)
+                    warnings.warn(msg, UnsafeMailcapInput)
+                    return None
+                res = res + param
             # XXX To do:
             # %n == number of parts if type is multipart/*
             # %F == list of alternating type and filename for parts
openSUSE Build Service is sponsored by