diff -Nru apport-2.20.11/apport/fileutils.py apport-2.20.11/apport/fileutils.py --- apport-2.20.11/apport/fileutils.py 2020-08-09 11:43:11.000000000 +0000 +++ apport-2.20.11/apport/fileutils.py 2020-11-10 20:03:57.000000000 +0000 @@ -10,13 +10,16 @@ # the full text of the license. import os, glob, subprocess, os.path, time, pwd, sys, requests_unixsocket +import stat try: - from configparser import ConfigParser, NoOptionError, NoSectionError + from configparser import (ConfigParser, NoOptionError, NoSectionError, + MissingSectionHeaderError) (ConfigParser, NoOptionError, NoSectionError) # pyflakes except ImportError: # Python 2 - from ConfigParser import ConfigParser, NoOptionError, NoSectionError + from ConfigParser import (ConfigParser, NoOptionError, NoSectionError, + MissingSectionHeaderError) from problem_report import ProblemReport @@ -342,23 +345,42 @@ This is read from ~/.config/apport/settings or path. If bool is True, the value is interpreted as a boolean. ''' + if not path: + path = os.path.expanduser(_config_file) + + contents = '' + fd = None + f = None if not get_config.config: get_config.config = ConfigParser() - euid = os.geteuid() egid = os.getegid() + euid = os.geteuid() try: # drop permissions temporarily to try open users config file - os.seteuid(os.getuid()) os.setegid(os.getgid()) - if path: - get_config.config.read(path) - else: - get_config.config.read(os.path.expanduser(_config_file)) + os.seteuid(os.getuid()) + fd = os.open(path, os.O_NOFOLLOW | os.O_RDONLY) + st = os.fstat(fd) + if stat.S_ISREG(st.st_mode): + f = os.fdopen(fd, 'r') + # Limit size to prevent DoS + contents = f.read(500) + except (IOError, OSError): + pass finally: + if f is not None: + f.close() + elif fd is not None: + os.close(fd) os.seteuid(euid) os.setegid(egid) try: + get_config.config.read_string(contents) + except MissingSectionHeaderError: + pass + + try: if bool: return get_config.config.getboolean(section, setting) else: diff -Nru apport-2.20.11/apport/report.py apport-2.20.11/apport/report.py --- apport-2.20.11/apport/report.py 2020-08-09 11:43:11.000000000 +0000 +++ apport-2.20.11/apport/report.py 2020-11-10 20:03:57.000000000 +0000 @@ -10,7 +10,7 @@ # the full text of the license. import subprocess, tempfile, os.path, re, pwd, grp, os, time, io -import fnmatch, glob, traceback, errno, sys, atexit, locale, imp +import fnmatch, glob, traceback, errno, sys, atexit, locale, imp, stat import xml.dom, xml.dom.minidom from xml.parsers.expat import ExpatError @@ -1044,25 +1044,39 @@ ifpath = os.path.expanduser(_ignore_file) if orig_home is not None: os.environ['HOME'] = orig_home + contents = '' + fd = None + f = None + egid = os.getegid() euid = os.geteuid() try: # drop permissions temporarily to try open users ignore file + os.setegid(os.getgid()) os.seteuid(os.getuid()) - fp = open(ifpath, 'r') + fd = os.open(ifpath, os.O_NOFOLLOW | os.O_RDONLY) + st = os.fstat(fd) + if stat.S_ISREG(st.st_mode): + f = os.fdopen(fd, 'r') + # Limit size to prevent DoS + contents = f.read(50000) except (IOError, OSError): - fp = None + pass finally: + if f is not None: + f.close() + elif fd is not None: + os.close(fd) os.seteuid(euid) - if fp is None or os.fstat(fp.fileno()).st_size == 0: + os.setegid(egid) + + if contents == '': # create a document from scratch dom = xml.dom.getDOMImplementation().createDocument(None, 'apport', None) else: try: - dom = xml.dom.minidom.parse(fp) + dom = xml.dom.minidom.parseString(contents) except ExpatError as e: raise ValueError('%s has invalid format: %s' % (_ignore_file, str(e))) - if fp is not None: - fp.close() # remove whitespace so that writing back the XML does not accumulate # whitespace dom.documentElement.normalize() diff -Nru apport-2.20.11/data/apport apport-2.20.11/data/apport --- apport-2.20.11/data/apport 2020-10-16 20:30:49.000000000 +0000 +++ apport-2.20.11/data/apport 2020-11-10 20:03:57.000000000 +0000 @@ -121,6 +121,8 @@ the effective IDs remain. ''' if real_only: + # Drop any supplemental groups + os.setgroups([]) os.setregid(real_gid, -1) os.setreuid(real_uid, -1) else: diff -Nru apport-2.20.11/debian/changelog apport-2.20.11/debian/changelog --- apport-2.20.11/debian/changelog 2020-10-16 20:30:49.000000000 +0000 +++ apport-2.20.11/debian/changelog 2020-11-10 20:03:57.000000000 +0000 @@ -1,3 +1,14 @@ +apport (2.20.11-0ubuntu27.12) focal-security; urgency=medium + + * Various security hardening fixes (LP: #1903332) + - apport/fileutils.py: drop privileges in the correct order, limit + settings file size. + - apport/apport/report.py: properly drop privileges, limit ignore file + size. + - data/apport: drop supplemental groups. + + -- Marc Deslauriers Tue, 10 Nov 2020 15:03:57 -0500 + apport (2.20.11-0ubuntu27.11) focal; urgency=medium * data/apport: In the event that the crashing executable does not exist on