** Information type changed from Private Security to Public Security -- You received this bug notification because you are a member of Ubuntu Touch seeded packages, which is subscribed to apport in Ubuntu. https://bugs.launchpad.net/bugs/1839420
Title: Per-process user controllable Apport socket file Status in Apport: New Status in apport package in Ubuntu: Fix Released Bug description: Author: Sander Bos, <https://www.sbosnet.nl/> Date: 2019-07-30 As defined in data/apport, when Apport thinks a crash originated in a container it will forward the crash handling to a /proc/<pid>/root/run/apport.socket file, using /proc/ information from the crashed process: 424 if not is_same_ns(host_pid, "pid") and not is_same_ns(host_pid, "mnt"): 425 # If the crash came from a container, don't attempt to handle 426 # locally as that would just result in wrong system information. 427 428 # Instead, attempt to find apport inside the container and 429 # forward the process information there. ... 436 try: 437 sock.connect('/proc/%d/root/run/apport.socket' % host_pid) Normally, a user can't change the root directory of a process since the chroot(2) system call can only be used by root / privileged processes. This also means only processes set up by the super user may have a different root directory, e.g., legitimate LXC containers, and that root can trust the value of the root directory. However, a user can create a user namespace using unshare(2), define itself root in it, and then in fact be able to use chroot(2). Then, /proc/<pid>/root/ for that process can lead anywhere. Thus, the root directory should not be trusted by Apport, since it is user controllable, meaning the /root/run/apport.socket path can't be trusted either to be in fact an actual, legitimate Apport socket file within an actual, legitimate container. The same applies to the /run/ directory within the root directory of the process, even when the user did not use chroot(2), as the user can define a /run/ mount point within a user namespace when combined with unsharing the mount namespace (and due to the fact that the /run/ directory gets accessed by Apport via /proc/ instead of via an actual file system path, making it "see" such in-namespace mount point). Thus, not only /proc/<pid>/root/ is user-controllable, but also /proc/<pid>/root/run/, and neither can be trusted. Example of manipulating the root directory via a user namespace: user@ubuntu$ chroot /bin/ ./busybox sleep 100 # normal situation, chroot(2) not permitted chroot: cannot change root directory to '/bin/': Operation not permitted user@ubuntu$ unshare -Ufmpr chroot /bin/ ./busybox sleep 100 # this works root@ubuntu# readlink /proc/$(pgrep busybox)/root /bin Example of manipulating /run/ via a user namespace (the two command lines are started simultaneously): user@ubuntu$ echo 'sleep 5; mount -t tmpfs tmpfs /run; touch /run/apport.socket; sleep 5' | unshare -Ufmpr sh root@ubuntu# sleep 2; ls /proc/$(pgrep unshare)/root/run/apport.socket; sleep 5; ls /proc/$(pgrep unshare)/root/run/apport.socket ls: cannot access '/proc/6118/root/run/apport.socket': No such file or directory /proc/6118/root/run/apport.socket Thus, per-process, the user controls the socket file (via two separate path locations, as shown above). This can for example be abused to "catch" a core dump of a "tainted" process: for such process a "core" core dump file is normally not written, and the crash report file in /var/crash/ is created as root. This makes a user unable to read such core dump, which is intended for security since it might contain privileged contents. However, using the methods above the apport.socket file is user controllable and may for example be an (altered) Apport systemd socket file registered to a "systemd --user" user initiated systemd process, so that the host Apport instance can still communicate properly with the socket. Such altered and user controlled apport.socket file may then for example save the core dump in a file owned by the user effectively making a tainted, "privileged" core dump user readable to the user (instead of just to root) and thus defeating the intention of "fs.suid_dumpable=2" dumping a "tainted" core dump non-readable to the user, as root. Due to things happening in a root user namespace this might be difficult to exploit for a setuid process, but it it easily doable for non-readable binaries, as those also fall under the category of "tainted" core dumps. Moreover, the apport.socket file may be created as a symbolic link pointing to an arbitrary (socket) file, enabling other damage / exploitation scenarios since Apport will follow such /proc/<pid>/root/run/apport.socket symbolic link and, as root, communicate with the given socket file. For example, the following will start the whole of LXD (at least in case it was not started already) creating a LXD network bridge, populating /var/lib/lxd/, et cetera: user@ubuntu$ echo 'mount -t tmpfs tmpfs /run; ln -s /var/lib/lxd/unix.socket /run/apport.socket; timeout -s 11 1 sleep 100' | unshare -Ufmpr sh As another example, linking to /run/lvm/lvmpolld.socket will run lvmpolld(8), as for example indicated by "Started LVM2 poll daemon." in /var/log/syslog. These things are already harmful on themselves; however, more advanced and severe exploitation methods are likely possible from there on, e.g., by communicating with the LXD socket in its actual API protocol by communicating core dump contents (i.e., standard input on the Apport socket) and / or ancillary / ucred data sent over the socket. The same might hold true for other socket files in case of linking to them, e.g., snapd socket files, which may also start root processes and / or be able to set up more complex communication over such socket. To manage notifications about this bug go to: https://bugs.launchpad.net/apport/+bug/1839420/+subscriptions -- Mailing list: https://launchpad.net/~touch-packages Post to : touch-packages@lists.launchpad.net Unsubscribe : https://launchpad.net/~touch-packages More help : https://help.launchpad.net/ListHelp