Hi, uploading a 0-day NMU to fix this bug. debdiff is attached and will be also archived on: http://people.debian.org/~nion/nmu-diff/comix-3.6.4-1_3.6.4-1.1.patch
Kind regards Nico -- Nico Golde - http://www.ngolde.de - [EMAIL PROTECTED] - GPG: 0x73647CFF For security reasons, all text in this mail is double-rot13 encrypted.
diff -u comix-3.6.4/debian/changelog comix-3.6.4/debian/changelog --- comix-3.6.4/debian/changelog +++ comix-3.6.4/debian/changelog @@ -1,3 +1,15 @@ +comix (3.6.4-1.1) unstable; urgency=high + + * Non-maintainer upload by the Security Team. + * Apply patch by Mamoru Tasaka to fix arbitrary code execution + via crafted file names because of passing the filename directly + to string concatenation used in os.popen (CVE-2008-1568; Closes: #462840). + * Apply patch by Mamoru Tasaka to use empfile.mkdtemp() to enable comix + for multi-user environments and thus prevent a race condition in /tmp + without a real security impact (Closes: #462836). + + -- Nico Golde <[EMAIL PROTECTED]> Thu, 03 Apr 2008 00:49:49 +0200 + comix (3.6.4-1) unstable; urgency=low * New upstream release only in patch2: unchanged: --- comix-3.6.4.orig/mime/comicthumb +++ comix-3.6.4/mime/comicthumb @@ -22,6 +22,10 @@ import StringIO import re import shutil + +import subprocess +import tempfile + try: import Image except: @@ -48,9 +52,13 @@ sys.exit(1) # temp directory needed for multiple archives -if not os.path.exists('/tmp/comicthumb/'): - os.makedirs('/tmp/comicthumb/') - os.chmod('/tmp/comicthumb/', 0700) +#if not os.path.exists('/tmp/comicthumb/'): +# os.makedirs('/tmp/comicthumb/') +# os.chmod('/tmp/comicthumb/', 0700) +_tmp_dir = tempfile.mkdtemp(prefix='comixthumb', suffix=os.sep, + dir = '/tmp') +_tmp_dir += "/" + # return the first image in the list def first_image (filelist): @@ -101,10 +109,10 @@ else: subarchive = first_archive(zipfiles) if subarchive: - output = open("/tmp/comicthumb/archive%d" % (depth), "wb") + output = open( _tmp_dir + "archive%d" % (depth), "wb") output.write(zip.read(subarchive)) output.close() - return get_image("/tmp/comicthumb/archive%d" % (depth), + return get_image( _tmp_dir + "archive%d" % (depth), depth + 1) elif tarfile.is_tarfile(compressed_file): TYPE = TYPE or 'cbt' @@ -119,10 +127,10 @@ else: subarchive = first_archive(tarfiles) if subarchive: - output = open("/tmp/comicthumb/archive%d" % (depth), "wb") + output = open( _tmp_dir + "archive%d" % (depth), "wb") output.write(tar.extractfile(subarchive).read()) output.close() - return get_image("/tmp/comicthumb/archive%d" % (depth), + return get_image( _tmp_dir + "archive%d" % (depth), depth + 1) elif open(compressed_file, 'rb').read(4) == 'Rar!': TYPE = TYPE or 'cbr' @@ -138,20 +146,36 @@ if not rar: print "You must install unrar or rar to thumbnail RAR archives." sys.exit(1) - rarfiles = os.popen('%s vb "%s"' % (rar, compressed_file)).readlines() + #rarfiles = os.popen('%s vb "%s"' % (rar, compressed_file)).readlines() + rarfiles = subprocess.Popen([rar, 'vb', compressed_file], + stdout=subprocess.PIPE).communicate()[0].splitlines() for i in range(len(rarfiles)): rarfiles[i] = rarfiles[i].rstrip("\n") rarfiles.sort() cover = guessCover(rarfiles) if cover: - picture = StringIO.StringIO(os.popen('%s p -inul -- "%s" "%s"' - % (rar, compressed_file, cover), "r").read()) + #picture = StringIO.StringIO(os.popen('%s p -inul -- "%s" "%s"' + #% (rar, compressed_file, cover), "r").read()) + picture = StringIO.StringIO(subprocess.Popen( + [rar, 'p', '-inul', '--', compressed_file, cover], + stdout=subprocess.PIPE).stdout.read()) else: subarchive = first_archive(rarfiles) if subarchive: - os.popen('%s p -inul -- "%s" "%s" > "/tmp/comicthumb/archive%d"' - % (rar, compressed_file, subarchive, depth), "r") - return get_image("/tmp/comicthumb/archive%d" % (depth), + #os.popen('%s p -inul -- "%s" "%s" > "/tmp/comicthumb/archive%d"' + #% (rar, compressed_file, subarchive, depth), "r") + filen = _tmp_dir + "archive%d"%(depth) + try: + os.remove(filen) + except: + pass + fp = open(filen, 'w') + fdp = fp.fileno() + subprocess.Popen( + [rar, 'p', '-inul', '--', compressed_file, subarchive], + stdout = fdp).wait() + fp.close() + return get_image( _tmp_dir + "archive%d" % (depth), depth + 1) return picture @@ -207,8 +231,8 @@ exit_flag = 1 # remove tempory stuff -if os.path.isdir('/tmp/comicthumb/'): - shutil.rmtree('/tmp/comicthumb/') +if os.path.isdir(_tmp_dir): + shutil.rmtree(_tmp_dir) # and exit sys.exit(exit_flag) only in patch2: unchanged: --- comix-3.6.4.orig/comix +++ comix-3.6.4/comix @@ -44,6 +44,11 @@ import pwd import cPickle +import subprocess +import string + +import tempfile + try: import pygtk pygtk.require('2.0') @@ -254,6 +259,8 @@ window_height = 0 colour_adjust_signal_kill = False colour_adjust_dialog_displayed = False + + _tmp_dir = None def close_application(self, widget, event=None): @@ -267,8 +274,8 @@ self.prefs['page of last file'] = self.file_number if os.path.exists(self.base_dir): shutil.rmtree(self.base_dir) - if len(os.listdir('/tmp/comix')) == 0: - shutil.rmtree('/tmp/comix') + if len(os.listdir(self._tmp_dir)) == 0: + shutil.rmtree(self._tmp_dir) self.exit = True # ======================================================= @@ -366,9 +373,9 @@ # ======================================================= if os.path.exists(self.base_dir): shutil.rmtree(self.base_dir) - if os.path.isdir('/tmp/comix'): - if len(os.listdir('/tmp/comix')) == 0: - shutil.rmtree('/tmp/comix') + if os.path.isdir(self._tmp_dir): + if len(os.listdir(self._tmp_dir)) == 0: + shutil.rmtree(self._tmp_dir) # ======================================================= @@ -6277,9 +6284,12 @@ archive = tarfile.open(path, 'r') files = archive.getnames() elif type == 'rar': + #files = \ + #os.popen(self.rar + ' vb "' + path + + #'"').readlines() files = \ - os.popen(self.rar + ' vb "' + path + - '"').readlines() + subprocess.Popen([self.rar, 'vb', path], + stdout=subprocess.PIPE).communicate()[0].splitlines() files = [file.rstrip('\n') for file in files] cover = None files.sort() @@ -6302,9 +6312,20 @@ break if cover != None: if type == 'rar': - os.popen(self.rar + ' p -inul -- "' + path + '" "' + - cover + '" > "' + thumb_dir + - '/temp" 2>/dev/null', "r").close() + #os.popen(self.rar + ' p -inul -- "' + path + '" "' + + #cover + '" > "' + thumb_dir + + #'/temp" 2>/dev/null', "r").close() + filen = thumb_dir + '/temp' + try: + os.remove(filen) + except: + pass + fp = open(filen, 'w') + fdp = fp.fileno() + p = subprocess.Popen( + [self.rar, 'p', '-inul', '--', path, + cover ], stdout = fdp).wait() + fp.close() image = Image.open(thumb_dir + '/temp') os.remove(thumb_dir + '/temp') elif type == 'zip': @@ -8010,7 +8031,7 @@ return False # We don't want to open files from our selves. - if selection.data.startswith('file:///tmp/comix/'): + if selection.data.startswith('file://' + self._tmp_dir): return uri = selection.data.strip() @@ -8733,8 +8754,10 @@ # ======================================================= elif archive_type == 'rar': if self.rar: - os.popen( - self.rar + ' x "' + src_path + '" "' + dst_path + '"') + #os.popen( + #self.rar + ' x "' + src_path + '" "' + dst_path + '"') + subprocess.Popen( + [self.rar, 'x', src_path, dst_path],stdout=sys.stdout).wait() else: self.statusbar.push(0, _('Could not find the unrar executable. Please install it if you wish to open RAR archives.')) @@ -9168,9 +9191,37 @@ self.are_you_sure_dialog.hide() if response != -5: return - os.popen(self.jpegtran + ' -copy all -trim ' + operation + - ' -outfile "' + self.file[self.file_number] + '" "' + - self.file[self.file_number] + '"') + #os.popen(self.jpegtran + ' -copy all -trim ' + operation + + #' -outfile "' + self.file[self.file_number] + '" "' + + #self.file[self.file_number] + '"') + op = operation.split() + op_len = len(op) + + i=1 + filen = self.file[self.file_number] + while (1): + tmp_file = filen + '.tmp' + 'z' * i + if os.path.exists(tmp_file): + i += 1 + else: + break + + # Ugly hack :( + if op_len == 2: + p = subprocess.Popen( + [self.jpegtran, '-copy', 'all', '-trim', op[0], op[1], + '-outfile', tmp_file, filen], + stdin=sys.stdin, stdout=sys.stdout) + else: + p = subprocess.Popen( + [self.jpegtran, '-copy', 'all', '-trim', op[0], + '-outfile', tmp_file, filen], + stdin=sys.stdin, stdout=sys.stdout) + p.wait() + if p.returncode == 0: + shutil.copymode(filen, tmp_file) + shutil.copy(tmp_file, filen) + os.remove(tmp_file) try: uri = 'file://' + urllib.pathname2url(self.file[self.file_number]) thumb_path = md5.new() @@ -10496,15 +10547,20 @@ # The dir is /tmp/comix/<num> where <num> is 1 or higher # depending on the number of Comix sessions opened. # ======================================================= - if not os.path.exists('/tmp/comix/'): - os.makedirs('/tmp/comix/') - os.chmod('/tmp/comix/', 0700) + #if not os.path.exists('/tmp/comix/'): + # os.makedirs('/tmp/comix/') + # os.chmod('/tmp/comix/', 0700) + + self._tmp_dir = tempfile.mkdtemp(prefix='comix.', suffix=os.sep, + dir = '/tmp') + self._tmp_dir += "/" + dir_number = 1 while 1: - if not os.path.exists('/tmp/comix/' + str(dir_number)): - os.mkdir('/tmp/comix/' + str(dir_number)) - os.chmod('/tmp/comix/' + str(dir_number), 0700) - self.base_dir = '/tmp/comix/' + str(dir_number) + '/' + if not os.path.exists(self._tmp_dir + str(dir_number)): + os.mkdir(self._tmp_dir + str(dir_number)) + os.chmod(self._tmp_dir + str(dir_number), 0700) + self.base_dir = self._tmp_dir + str(dir_number) + '/' break dir_number += 1
pgpTjNXNQ6Ou2.pgp
Description: PGP signature