From 43056b399eec0929827d684334204a522d1814bf Mon Sep 17 00:00:00 2001 From: Michal Schmidt Date: Apr 17 2012 09:42:16 +0000 Subject: CVE-2012-2093 gajim (LaTeX module): Insecure creation of temporary file --- diff --git a/gajim-0.15-12438.patch b/gajim-0.15-12438.patch new file mode 100644 index 0000000..c8f97b3 --- /dev/null +++ b/gajim-0.15-12438.patch @@ -0,0 +1,86 @@ +# HG changeset patch +# User Yann Leboulanger +# Date 1285362921 -7200 +# Node ID c821dd3af25fdd8b534b2fa2e39dd9f6068517a3 +# Parent e81ceeabe85a44ebb07fe493bd4482f2e32c4d7d +[Zhihao Yuan & I] use convert is dvipng doesn't work. Fixes #5935 + +diff --git a/src/common/latex.py b/src/common/latex.py +--- a/src/common/latex.py ++++ b/src/common/latex.py +@@ -115,11 +115,16 @@ + result = None + exitcode = 0 + +- try: +- bg_str, fg_str = gajim.interface.get_bg_fg_colors() +- except: +- # interface may not be available when we test latext at startup +- bg_str, fg_str = 'rgb 1.0 1.0 1.0', 'rgb 0.0 0.0 0.0' ++ def fg_str(fmt): ++ try: ++ return [{'hex' : '+level-colors', 'tex' : '-fg'}[fmt], ++ gajim.interface.get_fg_color(fmt)] ++ except KeyError: ++ # interface may not be available when we test latex at startup ++ return [] ++ except AttributeError: ++ # interface may not be available when we test latext at startup ++ return ['-fg', 'rgb 0.0 0.0 0.0'] + + # filter latex code with bad commands + if check_blacklist(str_): +@@ -138,9 +143,13 @@ + if exitcode == 0: + # convert dvi to png + latex_png_dpi = gajim.config.get('latex_png_dpi') +- exitcode = try_run(['dvipng', '-bg', bg_str, '-fg', fg_str, '-T', +- 'tight', '-D', latex_png_dpi, tmpfile + '.dvi', '-o', +- tmpfile + '.png']) ++ exitcode = try_run(['dvipng'] + fg_str('tex') + ['-T', 'tight', '-D', ++ latex_png_dpi, tmpfile + '.dvi', '-o', tmpfile + '.png']) ++ ++ if exitcode: ++ # dvipng failed, try convert ++ exitcode = try_run(['convert'] + fg_str('hex') + ['-trim', ++ '-density', latex_png_dpi, tmpfile + '.dvi', tmpfile + '.png']) + + # remove temp files created by us and TeX + extensions = ['.tex', '.log', '.aux', '.dvi'] +diff --git a/src/features_window.py b/src/features_window.py +--- a/src/features_window.py ++++ b/src/features_window.py +@@ -92,8 +92,8 @@ + _('Requires python2.5.')), + _('LaTeX'): (self.latex_available, + _('Transform LaTeX expressions between $$ $$.'), +- _('Requires texlive-latex-base and dvipng. You have to set \'use_latex\' to True in the Advanced Configuration Editor.'), +- _('Requires texlive-latex-base and dvipng (All is in MikTeX). You have to set \'use_latex\' to True in the Advanced Configuration Editor.')), ++ _('Requires texlive-latex-base and (dvipng or ImageMagick). You have to set \'use_latex\' to True in the Advanced Configuration Editor.'), ++ _('Requires texlive-latex-base and (dvipng or ImageMagick) (All is in MikTeX). You have to set \'use_latex\' to True in the Advanced Configuration Editor.')), + _('End to End message encryption'): (self.pycrypto_available, + _('Encrypting chat messages.'), + _('Requires python-crypto.'), +diff --git a/src/gui_interface.py b/src/gui_interface.py +--- a/src/gui_interface.py ++++ b/src/gui_interface.py +@@ -2704,6 +2704,19 @@ + fg_str = format_gdkcolor(style.text[gtk.STATE_NORMAL]) + return (bg_str, fg_str) + ++ def get_fg_color(self, fmt='hex'): ++ def format_gdkcolor (c): ++ if fmt == 'tex': ++ return ' '.join([str(s) for s in ++ ('rgb', c.red_float, c.green_float, c.blue_float)]) ++ elif fmt == 'hex': ++ return str(c) ++ ++ # get foreground style color and create string ++ dummy = gtk.Invisible() ++ dummy.ensure_style() ++ return format_gdkcolor(dummy.get_style().text[gtk.STATE_NORMAL]) ++ + def read_sleepy(self): + """ + Check idle status and change that status if needed diff --git a/gajim-0.15-13759-bac8e353d25c.patch b/gajim-0.15-13759-bac8e353d25c.patch new file mode 100644 index 0000000..a8d30ca --- /dev/null +++ b/gajim-0.15-13759-bac8e353d25c.patch @@ -0,0 +1,32 @@ +# HG changeset patch +# User Yann Leboulanger +# Date 1334071532 -7200 +# Node ID bac8e353d25c7196f2635ef7c2b2e479f6818fab +# Parent a360737332cd0135df68fb212e6156931ebab312 +improve temp file search when using latex to prevent overwriting files + +diff --git a/src/common/latex.py b/src/common/latex.py +--- a/src/common/latex.py ++++ b/src/common/latex.py +@@ -59,8 +59,19 @@ + + def get_tmpfile_name(): + random.seed() +- int_ = random.randint(0, 100) +- return os.path.join(gettempdir(), 'gajimtex_' + int_.__str__()) ++ while(nb < 100): ++ int_ = random.randint(0, 10000) ++ filename = os.path.join(gettempdir(), 'gajimtex_' + int_.__str__()) ++ # Check if a file to not overwrite it ++ ok = True ++ extensions = ['.tex', '.log', '.aux', '.dvi'] ++ for ext in extensions: ++ if os.path.exists(filename + ext): ++ ok = False ++ break ++ if ok: ++ return filename ++ return filename + + def write_latex(filename, str_): + texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}' diff --git a/gajim-0.15-13761-f6f78f3802c0.patch b/gajim-0.15-13761-f6f78f3802c0.patch new file mode 100644 index 0000000..5d87423 --- /dev/null +++ b/gajim-0.15-13761-f6f78f3802c0.patch @@ -0,0 +1,26 @@ +# HG changeset patch +# User Yann Leboulanger +# Date 1334207870 -7200 +# Node ID f6f78f3802c07736cb63b3e696778dabe8263cbb +# Parent ab4f06e5e024b0e1bb1aab3d4ec5f8a39c5d32aa +fix a loop. Fixes #7142 + +diff --git a/src/common/latex.py b/src/common/latex.py +--- a/src/common/latex.py ++++ b/src/common/latex.py +@@ -59,6 +59,7 @@ + + def get_tmpfile_name(): + random.seed() ++ nb = 0 + while(nb < 100): + int_ = random.randint(0, 10000) + filename = os.path.join(gettempdir(), 'gajimtex_' + int_.__str__()) +@@ -71,6 +72,7 @@ + break + if ok: + return filename ++ nb += 1 + return filename + + def write_latex(filename, str_): diff --git a/gajim-0.15-13766-f046e4aaf7d4.patch b/gajim-0.15-13766-f046e4aaf7d4.patch new file mode 100644 index 0000000..5eb6787 --- /dev/null +++ b/gajim-0.15-13766-f046e4aaf7d4.patch @@ -0,0 +1,148 @@ +# HG changeset patch +# User Yann Leboulanger +# Date 1334652355 -7200 +# Node ID f046e4aaf7d49b2934622db66da1667ddddb1703 +# Parent 0a8585330ccaa26f97ead998c29427d31c5d395b +more secure tmp file creation for latex + +diff --git a/src/common/latex.py b/src/common/latex.py +--- a/src/common/latex.py ++++ b/src/common/latex.py +@@ -29,7 +29,7 @@ + + import os + import random +-from tempfile import gettempdir ++from tempfile import mkstemp, mkdtemp + from subprocess import Popen, PIPE + + import logging +@@ -57,24 +57,6 @@ + return True + return False + +-def get_tmpfile_name(): +- random.seed() +- nb = 0 +- while(nb < 100): +- int_ = random.randint(0, 10000) +- filename = os.path.join(gettempdir(), 'gajimtex_' + int_.__str__()) +- # Check if a file to not overwrite it +- ok = True +- extensions = ['.tex', '.log', '.aux', '.dvi'] +- for ext in extensions: +- if os.path.exists(filename + ext): +- ok = False +- break +- if ok: +- return filename +- nb += 1 +- return filename +- + def write_latex(filename, str_): + texstr = '\\documentclass[12pt]{article}\\usepackage[dvips]{graphicx}' + texstr += '\\usepackage{amsmath}\\usepackage{amssymb}' +@@ -91,12 +73,13 @@ + # a wrapper for Popen so that no window gets opened on Windows + # (i think this is the reason we're using Popen rather than just system()) + # stdout goes to a pipe so that it can be read +-def popen_nt_friendly(command): ++def popen_nt_friendly(command, directory): + if os.name == 'nt': + # CREATE_NO_WINDOW +- return Popen(command, creationflags=0x08000000, cwd=gettempdir(), stdout=PIPE) ++ return Popen(command, creationflags=0x08000000, cwd=directory, ++ stdout=PIPE) + else: +- return Popen(command, cwd=gettempdir(), stdout=PIPE) ++ return Popen(command, cwd=directory, stdout=PIPE) + + def check_for_latex_support(): + """ +@@ -112,16 +95,16 @@ + except LatexError: + return False + +-def try_run(argv): ++def try_run(argv, directory): + try: +- p = popen_nt_friendly(argv) ++ p = popen_nt_friendly(argv, directory) + out = p.communicate()[0] + log.info(out) + return p.wait() + except Exception, e: + return _('Error executing "%(command)s": %(error)s') % { +- 'command': " ".join(argv), +- 'error': helpers.decode_string(str(e))} ++ 'command': " ".join(argv), ++ 'error': helpers.decode_string(str(e))} + + + def latex_to_image(str_): +@@ -137,32 +120,41 @@ + return [] + except AttributeError: + # interface may not be available when we test latext at startup +- return ['-fg', 'rgb 0.0 0.0 0.0'] ++ return {'hex': ['+level-colors', '0x000000'], ++ 'tex': ['-fg', 'rgb 0.0 0.0 0.0']}[fmt] + + # filter latex code with bad commands + if check_blacklist(str_): + # we triggered the blacklist, immediately return None + return None + +- tmpfile = get_tmpfile_name() ++ try: ++ tmpdir = mkdtemp(prefix='gajimtex') ++ tmppng = mkstemp(prefix='gajim_tex', suffix='.png')[1] ++ except Exception: ++ raise LatexError('could not securely create one or more temporary files' ++ ' for LaTeX conversion') ++ ++ tmpfile = os.path.join(tmpdir, 'gajim_tex') + + # build latex string +- write_latex(os.path.join(tmpfile + '.tex'), str_) ++ write_latex(tmpfile + '.tex', str_) + + # convert TeX to dvi +- exitcode = try_run(['latex', '--interaction=nonstopmode', +- tmpfile + '.tex']) ++ exitcode = try_run(['latex', '--interaction=nonstopmode', tmpfile + '.tex'], ++ tmpdir) + + if exitcode == 0: + # convert dvi to png + latex_png_dpi = gajim.config.get('latex_png_dpi') + exitcode = try_run(['dvipng'] + fg_str('tex') + ['-T', 'tight', '-D', +- latex_png_dpi, tmpfile + '.dvi', '-o', tmpfile + '.png']) ++ latex_png_dpi, tmpfile + '.dvi', '-o', tmpfile + '.png'], tmpdir) + + if exitcode: + # dvipng failed, try convert + exitcode = try_run(['convert'] + fg_str('hex') + ['-trim', +- '-density', latex_png_dpi, tmpfile + '.dvi', tmpfile + '.png']) ++ '-density', latex_png_dpi, tmpfile + '.dvi', tmpfile + '.png'], ++ tmpdir) + + # remove temp files created by us and TeX + extensions = ['.tex', '.log', '.aux', '.dvi'] +@@ -172,10 +164,15 @@ + except Exception: + pass + ++ if exitcode == 0: ++ os.rename(tmpfile + '.png', tmppng) ++ ++ os.rmdir(tmpdir) ++ + if isinstance(exitcode, (unicode, str)): + raise LatexError(exitcode) + + if exitcode == 0: +- result = tmpfile + '.png' ++ result = tmppng + + return result diff --git a/gajim.spec b/gajim.spec index a942ea0..df3d933 100644 --- a/gajim.spec +++ b/gajim.spec @@ -9,7 +9,13 @@ URL: http://gajim.org/ Source0: http://gajim.org/downloads/%{majorver}/%{name}-%{version}.tar.bz2 # libasyncns triggers a kernel bug (RHBZ#529202), so let's not use it until # it's fixed. -Patch2: gajim-0.14-disable-libasyncns.patch +Patch1: gajim-0.14-disable-libasyncns.patch +# 4 patches to fix insecure temp file in the LaTeX plugin +Patch2: gajim-0.15-12438.patch +Patch3: gajim-0.15-13759-bac8e353d25c.patch +Patch4: gajim-0.15-13761-f6f78f3802c0.patch +Patch5: gajim-0.15-13766-f046e4aaf7d4.patch + BuildArch: noarch BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) @@ -56,6 +62,7 @@ BuildRequires: intltool BuildRequires: pygtk2-devel BuildRequires: hardlink + %description Gajim is a Jabber client written in PyGTK. The goal of Gajim's developers is to provide a full featured and easy to use xmpp client for the GTK+ users. @@ -63,7 +70,11 @@ Gajim does not require GNOME to run, even though it exists with it nicely. %prep %setup -q +%patch1 -p1 %patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 %build %configure --docdir=%{_docdir}/%{name}-%{version} @@ -121,6 +132,10 @@ rm -rf %{buildroot} %{_datadir}/%{name}/src %changelog +* Tue Apr 17 2012 Michal Schmidt 0.14.4-1 +- Update to 0.14.4. +- Apply fix for CVE-2012-2093. + * Fri Feb 25 2011 Michal Schmidt 0.14.1-3.el6.1 - python-kerberos is not available in RHEL6.0.