diff -u apport-2.20.1/debian/changelog apport-2.20.1/debian/changelog --- apport-2.20.1.orig/data/apport +++ apport-2.20.1/data/apport @@ -14,7 +14,7 @@ # the full text of the license. import sys, os, os.path, subprocess, time, traceback, pwd, io -import signal, inspect, grp, fcntl, socket, atexit, array +import signal, inspect, grp, fcntl, socket, atexit, array, struct import apport, apport.fileutils @@ -297,6 +297,18 @@ return False +def is_container_pid(pid): + if not os.path.exists('/proc/self/ns/pid') or os.readlink('/proc/%s/ns/pid' % pid) == os.readlink('/proc/self/ns/pid'): + # Crashed process is in the same namespace as apport, not a container + return False + + if not os.path.exists('/proc/self/ns/mnt') or os.readlink('/proc/%s/ns/mnt' % pid) == os.readlink('/proc/self/ns/mnt'): + # Crashed process is in the same namespace as apport, not a container + return False + + return True + + ################################################################# # # main @@ -325,16 +337,21 @@ sys.stdin.close() fds = array.array('i') - msg, ancdata, flags, addr = sock.recvmsg(4096, socket.CMSG_LEN(fds.itemsize)) + ucreds = array.array('i') + msg, ancdata, flags, addr = sock.recvmsg(4096, 4096) for cmsg_level, cmsg_type, cmsg_data in ancdata: if (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS): fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) + elif (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_CREDENTIALS): + ucreds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % ucreds.itemsize)]) sys.stdin = os.fdopen(int(fds[0]), 'r') # Replace argv by the arguments received over the socket sys.argv = [sys.argv[0]] sys.argv += msg.decode().split() + if len(ucreds) >= 3: + sys.argv[1] = "%d" % ucreds[0] # Normal startup if len(sys.argv) not in (4, 5): @@ -349,34 +366,53 @@ init_error_log() -# Check if we received a valid global PID (kernel >= 3.12). If we do, -# then compare it with the local PID. If they don't match, it's an -# indication that the crash originated from another PID namespace. +# Check if we received a global PID (kernel >= 3.12). +# If we did, then check if the crashed process's pid was in the same namespace as apport. +# # Attempt to forward it to the container -if len(sys.argv) == 5 and sys.argv[4].isdigit() and sys.argv[4] != sys.argv[1]: +if len(sys.argv) == 5: host_pid = int(sys.argv[4]) - if not os.path.exists('/proc/%d/root/run/apport.socket' % host_pid): - error_log('host pid %s crashed in a container without apport support' % - sys.argv[4]) - sys.exit(0) + if is_container_pid(host_pid): + # If the crash came from a container, don't attempt to handle + # locally as that would just result in wrong system information. + + # Instead, attempt to find apport inside the container and + # forward the process information there. + + if not os.path.exists('/proc/%d/root/run/apport.socket' % host_pid): + error_log('host pid %s crashed in a container without apport support' % + sys.argv[4]) + sys.exit(0) - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - try: - sock.connect('/proc/%d/root/run/apport.socket' % host_pid) - except: - error_log('host pid %s crashed in a container with a broken apport' % - sys.argv[4]) - sys.exit(0) + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + sock.connect('/proc/%d/root/run/apport.socket' % host_pid) + except: + error_log('host pid %s crashed in a container with a broken apport' % + sys.argv[4]) + sys.exit(0) - args = '%s %s %s' % (sys.argv[1], sys.argv[2], sys.argv[3]) + args = '%s %s %s' % (sys.argv[1], sys.argv[2], sys.argv[3]) - try: - sock.sendmsg([args.encode()], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array('i', [0]))]) - sock.shutdown(socket.SHUT_RDWR) - except socket.timeout: - error_log('Container apport failed to process crash within 30s') - sys.exit(0) + try: + sock.sendmsg([args.encode()], [ + (socket.SOL_SOCKET, socket.SCM_CREDENTIALS, struct.pack("3i", host_pid, 0, 0)), + (socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array('i', [0]))]) + sock.shutdown(socket.SHUT_RDWR) + except socket.timeout: + error_log('Container apport failed to process crash within 30s') + sys.exit(0) + else: + # If it doesn't look like the crash originated from within a + # full container, then take the global pid and replace the local + # pid with it, then move on to normal handling. + + # This bit is needed because some software like the chrome + # sandbox will use container namespaces as a security measure but are + # still otherwise host processes. When that's the case, we need to keep + # handling those crashes locally using the global pid. + sys.argv[1] = sys.argv[4] check_lock() only in patch2: unchanged: --- apport-2.20.1.orig/data/systemd/apport-forward.socket +++ apport-2.20.1/data/systemd/apport-forward.socket @@ -8,6 +8,7 @@ Accept=yes MaxConnections=10 Backlog=5 +PassCredentials=true [Install] WantedBy=sockets.target