--- ../clean/apport-2.17.1/data/apport 2015-04-14 09:04:46.000000000 -0500 +++ data/apport 2015-04-15 18:01:17.638806723 -0500 @@ -276,79 +276,99 @@ if len(sys.argv) == 5 and sys.argv[4].is error_log('pid %s crashed in a container without python3-lxc' % host_pid) sys.exit(0) - def list_containers(): - containers = [] - with open('/proc/net/unix', 'r') as fd: - for line in sorted(fd): - fields = line.strip().split(' ') - if len(fields) != 8: - continue + def get_ppid(pid): + with open('/proc/%s/status' % pid) as fd: + for line in fd: + if line.startswith('PPid:'): + return int(line.strip().split(':')[-1].strip()) + else: + error_log('unable to find PPid for %s' % pid) + sys.exit(0) - inode = fields[6].strip() - path = fields[7].split('/') - if path[-1] != 'command': - continue + def list_ns(pid): + return [os.readlink('/proc/%s/ns/%s' % (pid, ns)) + for ns in sorted(os.listdir('/proc/%s/ns' % pid))] - if len(path) < 2: - continue + def get_parentns_pid(pid): + ppid = pid + pid_ns = list_ns(pid) - real_path = '/'.join(path[:-2]).lstrip('@') + while ppid > 1: + ppid = get_ppid(ppid) + ppid_ns = list_ns(ppid) - container = lxc.Container(path[-2], real_path) + if ppid_ns != pid_ns: + break + return ppid - if not container.controllable: - continue + ppid = get_parentns_pid(int(host_pid)) - if container.state == 'STOPPED': - continue + os.chdir("/proc/%s/" % ppid) + + if ppid != get_parentns_pid(int(host_pid)): + error_log("ppid changed") + sys.exit(0) + + ppid_stat = os.stat(".") + + uid = -1 - ppid = 0 - with open('/proc/%s/status' % container.init_pid) as fd: - for line in fd: - if line.startswith('PPid:'): - ppid = int(line.strip().split(':')[-1].strip()) - break - else: - continue - - stat = os.stat('/proc/%s' % ppid) - uid = stat.st_uid - gid = stat.st_gid - - for fd in os.listdir('/proc/%s/fd/' % ppid): - if os.readlink('/proc/%s/fd/%s' % (ppid, fd)) \ - == 'socket:[%s]' % inode: - break - else: + with open("status", "r") as fd: + for line in fd: + if line.startswith("Uid:"): + fields = line.split() + if len(fields) < 2: continue + uid = int(fields[1]) - containers.append((container, (uid, gid))) + if uid != 0: + error_log('pid %s crashed in an untrusted container' % host_pid) + sys.exit(0) - return containers + unix = {} + with open("/proc/net/unix", "r") as fd: + for line in fd: + fields = line.strip().split(" ", 8) + if len(fields) < 8: + continue - def list_ns(pid): - return [os.readlink('/proc/%s/ns/%s' % (pid, ns)) - for ns in sorted(os.listdir('/proc/%s/ns' % pid))] + if not fields[7].endswith("/command"): + continue - def get_container(pid): - pid_ns = list_ns(pid) + if "socket:[%s]" % fields[6] in unix: + error_log('duplicate inode number in /proc/net/unix') + sys.exit(0) - for container, owner in list_containers(): - container_ns = list_ns(container.init_pid) + unix["socket:[%s]" % fields[6]] = fields[7] - if container_ns == pid_ns: - return container, owner + lxc_path = None + lxc_name = None - return (None, None) + for fd in os.listdir('fd/'): + link = os.readlink('fd/%s' % fd) + if not link.startswith('socket:['): + continue - container, owner = get_container(host_pid) - if not container: + if link not in unix: + continue + + path = unix[link].split('/') + + if len(path) < 3: + continue + + lxc_path = '/'.join(path[:-2]).lstrip('@') + lxc_name = path[-2] + break + + if not lxc_name or not lxc_path: error_log('pid %s crashed in an unknown container' % host_pid) sys.exit(0) - if owner[0] or owner[1]: - error_log('pid %s crashed in an untrusted container' % host_pid) + container = lxc.Container(lxc_name, lxc_path) + if not container.controllable or container.state != "RUNNING": + error_log('pid %s crashed in an unknown container' % host_pid) sys.exit(0) error_log('pid %s (host pid %s) crashed in container '