Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12:Update
python3-base.35637
CVE-2015-20107-mailcap-unsafe-filenames.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File CVE-2015-20107-mailcap-unsafe-filenames.patch of Package python3-base.35637
--- Doc/library/mailcap.rst | 13 +++++++++++++ Lib/mailcap.py | 28 ++++++++++++++++++++++++++-- Lib/test/test_mailcap.py | 10 +++++++--- 3 files changed, 46 insertions(+), 5 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(r'[^\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 OSError: @@ -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 --- a/Lib/test/test_mailcap.py +++ b/Lib/test/test_mailcap.py @@ -101,8 +101,9 @@ class HelperFunctionTest(unittest.TestCa (["", "audio/*", "foo.txt"], ""), (["echo foo", "audio/*", "foo.txt"], "echo foo"), (["echo %s", "audio/*", "foo.txt"], "echo foo.txt"), - (["echo %t", "audio/*", "foo.txt"], "echo audio/*"), - (["echo \%t", "audio/*", "foo.txt"], "echo %t"), + (["echo %t", "audio/*", "foo.txt"], None), + (["echo %t", "audio/wav", "foo.txt"], "echo audio/wav"), + (["echo \\%t", "audio/*", "foo.txt"], "echo %t"), (["echo foo", "audio/*", "foo.txt", plist], "echo foo"), (["echo %{total}", "audio/*", "foo.txt", plist], "echo 3") ] @@ -183,7 +184,10 @@ class FindmatchTest(unittest.TestCase): ('"An audio fragment"', audio_basic_entry)), ([c, "audio/*"], {"filename": fname}, - ("/usr/local/bin/showaudio audio/*", audio_entry)), + (None, None)), + ([c, "audio/wav"], + {"filename": fname}, + ("/usr/local/bin/showaudio audio/wav", audio_entry)), ([c, "message/external-body"], {"plist": plist}, ("showexternal /dev/null default john python.org /tmp foo bar", message_entry))
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor