Ubuntu

Merge lp:~jtaylor/ubuntu/oneiric/gajim/multiple-CVE into lp:ubuntu/oneiric/gajim

Proposed by Julian Taylor on 2012-05-01
Status: Merged
Merge reported by: Julian Taylor
Merged at revision: not available
Proposed branch: lp:~jtaylor/ubuntu/oneiric/gajim/multiple-CVE
Merge into: lp:ubuntu/oneiric/gajim
Diff against target: 373 lines (+343/-0) 5 files modified
To merge this branch: bzr merge lp:~jtaylor/ubuntu/oneiric/gajim/multiple-CVE
Reviewer Review Type Date Requested Status
Ubuntu branches 2012-05-01 Pending
Review via email: mp+104266@code.launchpad.net
To post a comment you must log in.
55. By Julian Taylor on 2012-05-10

fix missing wait on process end

56. By Julian Taylor on 2012-05-10

change version to ubuntu2

Marc Deslauriers (mdeslaur) wrote :

Julian, could you please update the status of this merge request so it gets removed from the sponsors list? Thanks.

Preview Diff

1=== modified file 'debian/changelog'
2--- debian/changelog 2011-05-19 12:14:37 +0000
3+++ debian/changelog 2012-05-10 20:00:24 +0000
4@@ -1,3 +1,22 @@
5+gajim (0.14.1-1ubuntu2) oneiric-security; urgency=low
6+
7+ * SECURITY UPDATE: assisted code execution (LP: #992618)
8+ - debian/patches/CVE-2012-2085.dpatch: fix subprocess call to prevent
9+ shell escape from via crafted messages
10+ https://trac.gajim.org/changeset/bc296e96ac10
11+ - CVE-2012-2085
12+ * SECURITY UPDATE: sql injection in logging code (LP: #992618)
13+ - debian/patches/CVE-2012-2086.dpatch: use a prepated statement
14+ https://trac.gajim.org/changeset/bfd5f94489d8
15+ - CVE-2012-2086
16+ * SECURITY UPDATE: insecure tmpfile creation (LP: #992613)
17+ - debian/patches/CVE-2012-2093.dpatch: use safe tmpfile functions
18+ when convering LaTeX IM messages to png images
19+ Thanks to Nico Golde
20+ - CVE-2012-2093
21+
22+ -- Julian Taylor <jtaylor@ubuntu.com> Tue, 01 May 2012 15:21:25 +0200
23+
24 gajim (0.14.1-1ubuntu1) oneiric; urgency=low
25
26 * Merge from debian unstable(LP: #630876). Remaining changes:
27
28=== added file 'debian/patches/CVE-2012-2085.patch'
29--- debian/patches/CVE-2012-2085.patch 1970-01-01 00:00:00 +0000
30+++ debian/patches/CVE-2012-2085.patch 2012-05-10 20:00:24 +0000
31@@ -0,0 +1,47 @@
32+Description: prevent assisted code execution CVE-2012-2085
33+Origin: https://trac.gajim.org/changeset/bc296e96ac10
34+Bug: https://trac.gajim.org/ticket/7031
35+Author: Yann Leboulange
36+
37+--- a/src/common/helpers.py
38++++ b/src/common/helpers.py
39+@@ -40,6 +40,7 @@
40+ import base64
41+ import hashlib
42+ import caps_cache
43++import shlex
44+
45+ from encodings.punycode import punycode_encode
46+ from string import Template
47+@@ -372,8 +373,18 @@
48+ pass
49+ return False
50+
51+-def exec_command(command):
52+- subprocess.Popen('%s &' % command, shell=True).wait()
53++def exec_command(command, use_shell=False):
54++ """
55++ execute a command. if use_shell is True, we run the command as is it was
56++ typed in a console. So it may be dangerous if you are not sure about what
57++ is executed.
58++ """
59++ if use_shell:
60++ subprocess.Popen('%s &' % command, shell=True).wait()
61++ else:
62++ args = shlex.split(command.encode('utf-8'))
63++ p = subprocess.Popen(args)
64++ gajim.thread_interface(p.wait)
65+
66+ def build_command(executable, parameter):
67+ # we add to the parameter (can hold path with spaces)
68+--- a/src/notify.py
69++++ b/src/notify.py
70+@@ -311,7 +311,7 @@
71+ command = gajim.config.get_per('notifications', str(advanced_notif_num),
72+ 'command')
73+ try:
74+- helpers.exec_command(command)
75++ helpers.exec_command(command, use_shell=True)
76+ except Exception:
77+ pass
78+
79
80=== added file 'debian/patches/CVE-2012-2086.patch'
81--- debian/patches/CVE-2012-2086.patch 1970-01-01 00:00:00 +0000
82+++ debian/patches/CVE-2012-2086.patch 2012-05-10 20:00:24 +0000
83@@ -0,0 +1,167 @@
84+Description: prevent sql injections CVE-2012-2086
85+Origin: https://trac.gajim.org/changeset/988e38ce0e0c
86+Bug: https://trac.gajim.org/ticket/7031
87+Author: Yann Leboulanger
88+
89+--- a/src/common/logger.py
90++++ b/src/common/logger.py
91+@@ -563,7 +563,7 @@
92+ except exceptions.PysqliteOperationalError, e:
93+ # Error trying to create a new jid_id. This means there is no log
94+ return []
95+- where_sql = self._build_contact_where(account, jid)
96++ where_sql, jid_tuple = self._build_contact_where(account, jid)
97+
98+ now = int(float(time.time()))
99+ timed_out = now - (timeout * 60) # before that they are too old
100+@@ -571,14 +571,13 @@
101+ # 3 - 8 (we avoid the last 2 lines but we still return 5 asked)
102+ try:
103+ self.cur.execute('''
104+- SELECT time, kind, message FROM logs
105+- WHERE (%s) AND kind IN (%d, %d, %d, %d, %d) AND time > %d
106+- ORDER BY time DESC LIMIT %d OFFSET %d
107+- ''' % (where_sql, constants.KIND_SINGLE_MSG_RECV,
108+- constants.KIND_CHAT_MSG_RECV, constants.KIND_SINGLE_MSG_SENT,
109+- constants.KIND_CHAT_MSG_SENT, constants.KIND_ERROR,
110+- timed_out, restore_how_many_rows, pending_how_many)
111+- )
112++ SELECT time, kind, message FROM logs
113++ WHERE (%s) AND kind IN (%d, %d, %d, %d, %d) AND time > %d
114++ ORDER BY time DESC LIMIT %d OFFSET %d
115++ ''' % (where_sql, constants.KIND_SINGLE_MSG_RECV,
116++ constants.KIND_CHAT_MSG_RECV, constants.KIND_SINGLE_MSG_SENT,
117++ constants.KIND_CHAT_MSG_SENT, constants.KIND_ERROR, timed_out,
118++ restore_how_many_rows, pending_how_many), jid_tuple)
119+
120+ results = self.cur.fetchall()
121+ except sqlite.DatabaseError:
122+@@ -608,18 +607,18 @@
123+ except exceptions.PysqliteOperationalError, e:
124+ # Error trying to create a new jid_id. This means there is no log
125+ return []
126+- where_sql = self._build_contact_where(account, jid)
127++ where_sql, jid_tuple = self._build_contact_where(account, jid)
128+
129+ start_of_day = self.get_unix_time_from_date(year, month, day)
130+ seconds_in_a_day = 86400 # 60 * 60 * 24
131+ last_second_of_day = start_of_day + seconds_in_a_day - 1
132+
133+ self.cur.execute('''
134+- SELECT contact_name, time, kind, show, message, subject FROM logs
135+- WHERE (%s)
136+- AND time BETWEEN %d AND %d
137+- ORDER BY time
138+- ''' % (where_sql, start_of_day, last_second_of_day))
139++ SELECT contact_name, time, kind, show, message, subject FROM logs
140++ WHERE (%s)
141++ AND time BETWEEN %d AND %d
142++ ORDER BY time
143++ ''' % (where_sql, start_of_day, last_second_of_day), jid_tuple)
144+
145+ results = self.cur.fetchall()
146+ return results
147+@@ -645,13 +644,13 @@
148+ return results
149+
150+ else: # user just typed something, we search in message column
151+- where_sql = self._build_contact_where(account, jid)
152++ where_sql, jid_tuple = self._build_contact_where(account, jid)
153+ like_sql = '%' + query.replace("'", "''") + '%'
154+ self.cur.execute('''
155+- SELECT contact_name, time, kind, show, message, subject FROM logs
156+- WHERE (%s) AND message LIKE '%s'
157+- ORDER BY time
158+- ''' % (where_sql, like_sql))
159++ SELECT contact_name, time, kind, show, message, subject FROM logs
160++ WHERE (%s) AND message LIKE '%s'
161++ ORDER BY time
162++ ''' % (where_sql, like_sql), jid_tuple)
163+
164+ results = self.cur.fetchall()
165+ return results
166+@@ -666,7 +665,7 @@
167+ # Error trying to create a new jid_id. This means there is no log
168+ return []
169+ days_with_logs = []
170+- where_sql = self._build_contact_where(account, jid)
171++ where_sql, jid_tuple = self._build_contact_where(account, jid)
172+
173+ # First select all date of month whith logs we want
174+ start_of_month = self.get_unix_time_from_date(year, month, 1)
175+@@ -678,13 +677,13 @@
176+ # and take only one of the same values (distinct)
177+ # Now we have timestamps of time 0:00 of every day with logs
178+ self.cur.execute('''
179+- SELECT DISTINCT time/(86400)*86400 FROM logs
180+- WHERE (%s)
181+- AND time BETWEEN %d AND %d
182+- AND kind NOT IN (%d, %d)
183+- ORDER BY time
184+- ''' % (where_sql, start_of_month, last_second_of_month,
185+- constants.KIND_STATUS, constants.KIND_GCSTATUS))
186++ SELECT DISTINCT time/(86400)*86400 FROM logs
187++ WHERE (%s)
188++ AND time BETWEEN %d AND %d
189++ AND kind NOT IN (%d, %d)
190++ ORDER BY time
191++ ''' % (where_sql, start_of_month, last_second_of_month,
192++ constants.KIND_STATUS, constants.KIND_GCSTATUS), jid_tuple)
193+ result = self.cur.fetchall()
194+
195+ # convert timestamps to day of month
196+@@ -700,19 +699,21 @@
197+ """
198+ where_sql = ''
199+ if not is_room:
200+- where_sql = self._build_contact_where(account, jid)
201++ where_sql, jid_tuple = self._build_contact_where(account, jid)
202+ else:
203+ try:
204+ jid_id = self.get_jid_id(jid, 'ROOM')
205+ except exceptions.PysqliteOperationalError, e:
206+ # Error trying to create a new jid_id. This means there is no log
207+ return None
208+- where_sql = 'jid_id = %s' % jid_id
209++ where_sql = 'jid_id = ?'
210++ jid_tuple = (jid_id,)
211+ self.cur.execute('''
212+- SELECT MAX(time) FROM logs
213+- WHERE (%s)
214+- AND kind NOT IN (%d, %d)
215+- ''' % (where_sql, constants.KIND_STATUS, constants.KIND_GCSTATUS))
216++ SELECT MAX(time) FROM logs
217++ WHERE (%s)
218++ AND kind NOT IN (%d, %d)
219++ ''' % (where_sql, constants.KIND_STATUS, constants.KIND_GCSTATUS),
220++ jid_tuple)
221+
222+ results = self.cur.fetchone()
223+ if results is not None:
224+@@ -760,6 +761,7 @@
225+ Build the where clause for a jid, including metacontacts jid(s) if any
226+ """
227+ where_sql = ''
228++ jid_tuple = ()
229+ # will return empty list if jid is not associated with
230+ # any metacontacts
231+ family = gajim.contacts.get_metacontacts_family(account, jid)
232+@@ -769,13 +771,15 @@
233+ jid_id = self.get_jid_id(user['jid'])
234+ except exceptions.PysqliteOperationalError, e:
235+ continue
236+- where_sql += 'jid_id = %s' % jid_id
237++ where_sql += 'jid_id = ?'
238++ jid_tuple += (jid_id,)
239+ if user != family[-1]:
240+ where_sql += ' OR '
241+ else: # if jid was not associated with metacontacts
242+ jid_id = self.get_jid_id(jid)
243+- where_sql = 'jid_id = %s' % jid_id
244+- return where_sql
245++ where_sql = 'jid_id = ?'
246++ jid_tuple += (jid_id,)
247++ return where_sql, jid_tuple
248+
249+ def save_transport_type(self, jid, type_):
250+ """
251
252=== added file 'debian/patches/CVE-2012-2093.patch'
253--- debian/patches/CVE-2012-2093.patch 1970-01-01 00:00:00 +0000
254+++ debian/patches/CVE-2012-2093.patch 2012-05-10 20:00:24 +0000
255@@ -0,0 +1,107 @@
256+Description: fix insecure tmpfile creation CVE-2012-2093
257+Origin: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=668710
258+Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=668710
259+Author: Nico Golde <nion@debian.org>, Julian Taylor <jtaylor@ubuntu.com>
260+
261+--- a/src/common/latex.py
262++++ b/src/common/latex.py
263+@@ -29,7 +29,7 @@
264+
265+ import os
266+ import random
267+-from tempfile import gettempdir
268++from tempfile import gettempdir,mkstemp,mkdtemp
269+ from subprocess import Popen, PIPE
270+
271+ import logging
272+@@ -57,10 +57,10 @@
273+ return True
274+ return False
275+
276+-def get_tmpfile_name():
277++def get_tmpfile_name(tmpdir):
278+ random.seed()
279+ int_ = random.randint(0, 100)
280+- return os.path.join(gettempdir(), 'gajimtex_' + int_.__str__())
281++ return os.path.join(tmpdir, 'gajimtex_' + int_.__str__())
282+
283+ def write_latex(filename, str_):
284+ texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}'
285+@@ -78,12 +78,12 @@
286+ # a wrapper for Popen so that no window gets opened on Windows
287+ # (i think this is the reason we're using Popen rather than just system())
288+ # stdout goes to a pipe so that it can be read
289+-def popen_nt_friendly(command):
290++def popen_nt_friendly(command, directory):
291+ if os.name == 'nt':
292+ # CREATE_NO_WINDOW
293+- return Popen(command, creationflags=0x08000000, cwd=gettempdir(), stdout=PIPE)
294++ return Popen(command, creationflags=0x08000000, cwd=directory, stdout=PIPE)
295+ else:
296+- return Popen(command, cwd=gettempdir(), stdout=PIPE)
297++ return Popen(command, cwd=directory, stdout=PIPE)
298+
299+ def check_for_latex_support():
300+ """
301+@@ -99,9 +99,9 @@
302+ except LatexError:
303+ return False
304+
305+-def try_run(argv):
306++def try_run(argv, directory):
307+ try:
308+- p = popen_nt_friendly(argv)
309++ p = popen_nt_friendly(argv, directory)
310+ out = p.communicate()[0]
311+ log.info(out)
312+ return p.wait()
313+@@ -126,21 +126,28 @@
314+ # we triggered the blacklist, immediately return None
315+ return None
316+
317+- tmpfile = get_tmpfile_name()
318++ tmpdir = ""
319++ tmppng = ""
320++ try:
321++ tmpdir = mkdtemp(prefix="gajim")
322++ tmppng = mkstemp(suffix=".png")[1]
323++ except Exception:
324++ raise LatexError("could not securely create one or more temporary files for LaTeX conversion")
325+
326++ tmpfile = get_tmpfile_name(tmpdir)
327+ # build latex string
328+ write_latex(os.path.join(tmpfile + '.tex'), str_)
329+
330+ # convert TeX to dvi
331+ exitcode = try_run(['latex', '--interaction=nonstopmode',
332+- tmpfile + '.tex'])
333++ tmpfile + '.tex'], tmpdir)
334+
335+ if exitcode == 0:
336+ # convert dvi to png
337+ latex_png_dpi = gajim.config.get('latex_png_dpi')
338+ exitcode = try_run(['dvipng', '-bg', bg_str, '-fg', fg_str, '-T',
339+ 'tight', '-D', latex_png_dpi, tmpfile + '.dvi', '-o',
340+- tmpfile + '.png'])
341++ tmpfile + '.png'], tmpdir)
342+
343+ # remove temp files created by us and TeX
344+ extensions = ['.tex', '.log', '.aux', '.dvi']
345+@@ -150,10 +157,16 @@
346+ except Exception:
347+ pass
348+
349++ if exitcode == 0:
350++ os.rename(tmpfile + '.png', tmppng)
351++ else:
352++ os.remove(tmppng)
353++
354++ os.rmdir(tmpdir)
355+ if isinstance(exitcode, (unicode, str)):
356+ raise LatexError(exitcode)
357+
358+ if exitcode == 0:
359+- result = tmpfile + '.png'
360++ result = tmppng
361+
362+ return result
363
364=== modified file 'debian/patches/series'
365--- debian/patches/series 2011-05-19 12:14:37 +0000
366+++ debian/patches/series 2012-05-10 20:00:24 +0000
367@@ -1,3 +1,6 @@
368 00_debian-copying.diff
369 01_configure-ac.diff
370 debian-changes-0.14.1-1ubuntu1
371+CVE-2012-2085.patch
372+CVE-2012-2086.patch
373+CVE-2012-2093.patch

Subscribers

People subscribed via source and target branches

to all changes: