File CVE-2015-20107-mailcap-unsafe-filenames.patch of Package python (Revision 7c7532457b948cc36e86ff51d95885bc)
Currently displaying revision 7c7532457b948cc36e86ff51d95885bc , Show latest
99
1
---
2
Doc/library/mailcap.rst | 13 +++++++++++++
3
Lib/mailcap.py | 28 ++++++++++++++++++++++++++--
4
2 files changed, 39 insertions(+), 2 deletions(-)
5
6
--- a/Doc/library/mailcap.rst
7
+++ b/Doc/library/mailcap.rst
8
9
will automatically check such conditions and skip the entry if the check fails.
10
11
12
+.. versionchanged:: 3.11
13
+
14
+ To prevent security issues with shell metacharacters (symbols that have
15
+ special effects in a shell command line), ``findmatch`` will refuse
16
+ to inject ASCII characters other than alphanumerics and ``@+=:,./-_``
17
+ into the returned command line.
18
+
19
+ If a disallowed character appears in *filename*, ``findmatch`` will always
20
+ return ``(None, None)`` as if no entry was found.
21
+ If such a character appears elsewhere (a value in *plist* or in *MIMEtype*),
22
+ ``findmatch`` will ignore all mailcap entries which use that value.
23
+ A :mod:`warning <warnings>` will be raised in either case.
24
+
25
.. function:: getcaps()
26
27
Returns a dictionary mapping MIME types to a list of mailcap file entries. This
28
--- a/Lib/mailcap.py
29
+++ b/Lib/mailcap.py
30
31
"""Mailcap file handling. See RFC 1524."""
32
33
import os
34
+import warnings
35
+import re
36
37
__all__ = ["getcaps","findmatch"]
38
39
+_find_unsafe = re.compile(ur'[^\xa1-\U0010FFFF\w@+=:,./-]').search
40
+
41
+class UnsafeMailcapInput(Warning):
42
+ """Warning raised when refusing unsafe input"""
43
+
44
+
45
# Part 1: top-level interface.
46
47
def getcaps():
48
49
"""
50
caps = {}
51
for mailcap in listmailcapfiles():
52
+ if _find_unsafe(mailcap):
53
+ msg = "Refusing to use mailcap with filename %r. Use a safe temporary filename." % (mailcap,)
54
+ warnings.warn(msg, UnsafeMailcapInput)
55
+ return None, None
56
try:
57
fp = open(mailcap, 'r')
58
except IOError:
59
60
for e in entries:
61
if 'test' in e:
62
test = subst(e['test'], filename, plist)
63
+ if test is None:
64
+ continue
65
if test and os.system(test) != 0:
66
continue
67
command = subst(e[key], MIMEtype, filename, plist)
68
- return command, e
69
+ if command is not None:
70
+ return command, e
71
return None, None
72
73
def lookup(caps, MIMEtype, key=None):
74
75
elif c == 's':
76
res = res + filename
77
elif c == 't':
78
+ if _find_unsafe(MIMEtype):
79
+ msg = "Refusing to substitute MIME type %r into a shell command." % (MIMEtype,)
80
+ warnings.warn(msg, UnsafeMailcapInput)
81
+ return None
82
res = res + MIMEtype
83
elif c == '{':
84
start = i
85
86
i = i+1
87
name = field[start:i]
88
i = i+1
89
- res = res + findparam(name, plist)
90
+ param = findparam(name, plist)
91
+ if _find_unsafe(param):
92
+ msg = "Refusing to substitute parameter %r (%s) into a shell command" % (param, name)
93
+ warnings.warn(msg, UnsafeMailcapInput)
94
+ return None
95
+ res = res + param
96
# XXX To do:
97
# %n == number of parts if type is multipart/*
98
# %F == list of alternating type and filename for parts
99