** Description changed:

  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.
+ process, even when not using chroot(2): the user can define a /run mount
+ point within a user namespace when combined with unsharing the mount
+ namespace (actually equal to what is the case with an actual container
+ OS), and Apport on the host OS would access that in-namespace mount
+ point via /proc/<namespace_pid>/root/run/.
+ 
+ Thus, both /proc/<pid>/root/ and /proc/<pid>/root/run/ are
+ user-controllable, and neither can be trusted by Apport.
  
  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
+ 
+    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:
+ As a different exploit example, the /proc/<pid>/root/run/apport.socket
+ file may be created as a symbolic link pointing to an arbitrary file
+ (which could even point to a destination outside the unshared namespace),
+ for example an actual socket file, enabling other damage / exploitation
+ scenarios.  Apport in this case will follow such symbolic link, and
+ communicate with the destination (socket) file.  This can be abused
+ into leading to several different consequences.  (Side note: even
+ though /proc/ is used which enables the kernel to "see" the unshared
+ mount namespace, which seems to be intended behavior, the kernel still
+ considers the destination of the link relative to its own namespace,
+ not to the namespace's mount namespace; if this is not intended behavior
+ but the kernel should see the destination of the link relative to the
+ mount namespace instead, for example by using the root directory of the
+ mount namespaces's process, then this might actually be a kernel bug.)
+ 
+ One abuse consequence of the above symlink attack scenario is that a
+ user is able to both start specific new as well as influence specific
+ already running specific processes, including root processes and actual
+ container Apport processes.  This on itself could be abused to run as many
+ processes as root as wished for possibly issuing a system DoS (e.g., due
+ to "RLIMIT_NPROC" not applying to root), or potentially DoS or shutdown
+ the sytem via files like or similar in nature to /proc/sysrq-trigger.
+ As a side effect, this can also make the dumping procedure of the crashed
+ process never-ending, e.g., in case the process started by the receiving
+ socket keeps running indefinitely (maliously intended or not), or is a
+ "normal" persistent system process.
+ 
+ As an example of starting a process as root, the following will start
+ the LXD service (at least in case it was not started already) creating
+ an 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.
+ lvmpolld(8) (as can be seen for example by the appearance of
+ "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.
+ Starting processes as a different user, specifically root, is already
+ harmful on itself; however, actually influnencing (newly created or
+ already running) (root) processes may lead to more advanced and severe
+ exploitation methods.
+ 
+ In the above case of LXD for example, interacting with the LXD socket
+ in its actual API protocol by embedding legitimate LXD commands into
+ the core dump contents (being arbitrary data defined by the attacker)
+ and / or ancillary / ucred data (which can partially be defined by the
+ attacker), all which are sent over the socket by the sending Apport
+ instance to the destination socket, might be possible.  This could lead
+ to arbitrary commands being issues to the LXD service including creating,
+ starting, and stopping containers, or even stopping the LXD service as
+ a whole.  The same aspect of sending commands to processes holds true for
+ other socket files in case of linking to them, e.g., snapd socket files,
+ which may then also start root processes and / or be able to set up more
+ complex communication over such socket.
+ 
+ The most notable, and certainly potentially extremely harmful,
+ example case of communicating with (root) processes is symlinking to
+ an _actual_ container Apport socket file.  This will start an Apport
+ process (as root) in said container, and communicate the socket data
+ (which is already "Apport-valid" data) to the receiving Apport instance.
+ 
+ More interestingly, the above can be done in a host-to-container,
+ container-to-itself, and container-to-arbitrary-other-container sense,
+ leading to for example host-to-container and cross-container dumping.
+ 
+ Exploit scenarios of the above include container escaping, (root)
+ privilege escalation in (or: into) a container OS, and DoS via system
+ resource exhaustion or storage resource exhaustion on a container OS.
+ 
+ Note that starting an Apport instance on a (different) container OS via
+ the above Apport socket-as-asymlink scenario, as well as the above LXD
+ manipulation scenario, can be considered remote exploitation scenarios:
+ container OSes (in most cases) are in fact (virtually) distinct systems,
+ i.e., "remote" to the system on which the attacker operates.

-- 
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 not using chroot(2): the user can define a /run mount
  point within a user namespace when combined with unsharing the mount
  namespace (actually equal to what is the case with an actual container
  OS), and Apport on the host OS would access that in-namespace mount
  point via /proc/<namespace_pid>/root/run/.

  Thus, both /proc/<pid>/root/ and /proc/<pid>/root/run/ are
  user-controllable, and neither can be trusted by Apport.

  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.

  As a different exploit example, the /proc/<pid>/root/run/apport.socket
  file may be created as a symbolic link pointing to an arbitrary file
  (which could even point to a destination outside the unshared namespace),
  for example an actual socket file, enabling other damage / exploitation
  scenarios.  Apport in this case will follow such symbolic link, and
  communicate with the destination (socket) file.  This can be abused
  into leading to several different consequences.  (Side note: even
  though /proc/ is used which enables the kernel to "see" the unshared
  mount namespace, which seems to be intended behavior, the kernel still
  considers the destination of the link relative to its own namespace,
  not to the namespace's mount namespace; if this is not intended behavior
  but the kernel should see the destination of the link relative to the
  mount namespace instead, for example by using the root directory of the
  mount namespaces's process, then this might actually be a kernel bug.)

  One abuse consequence of the above symlink attack scenario is that a
  user is able to both start specific new as well as influence specific
  already running specific processes, including root processes and actual
  container Apport processes.  This on itself could be abused to run as many
  processes as root as wished for possibly issuing a system DoS (e.g., due
  to "RLIMIT_NPROC" not applying to root), or potentially DoS or shutdown
  the sytem via files like or similar in nature to /proc/sysrq-trigger.
  As a side effect, this can also make the dumping procedure of the crashed
  process never-ending, e.g., in case the process started by the receiving
  socket keeps running indefinitely (maliously intended or not), or is a
  "normal" persistent system process.

  As an example of starting a process as root, the following will start
  the LXD service (at least in case it was not started already) creating
  an 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 can be seen for example by the appearance of
  "Started LVM2 poll daemon." in /var/log/syslog).

  Starting processes as a different user, specifically root, is already
  harmful on itself; however, actually influnencing (newly created or
  already running) (root) processes may lead to more advanced and severe
  exploitation methods.

  In the above case of LXD for example, interacting with the LXD socket
  in its actual API protocol by embedding legitimate LXD commands into
  the core dump contents (being arbitrary data defined by the attacker)
  and / or ancillary / ucred data (which can partially be defined by the
  attacker), all which are sent over the socket by the sending Apport
  instance to the destination socket, might be possible.  This could lead
  to arbitrary commands being issues to the LXD service including creating,
  starting, and stopping containers, or even stopping the LXD service as
  a whole.  The same aspect of sending commands to processes holds true for
  other socket files in case of linking to them, e.g., snapd socket files,
  which may then also start root processes and / or be able to set up more
  complex communication over such socket.

  The most notable, and certainly potentially extremely harmful,
  example case of communicating with (root) processes is symlinking to
  an _actual_ container Apport socket file.  This will start an Apport
  process (as root) in said container, and communicate the socket data
  (which is already "Apport-valid" data) to the receiving Apport instance.

  More interestingly, the above can be done in a host-to-container,
  container-to-itself, and container-to-arbitrary-other-container sense,
  leading to for example host-to-container and cross-container dumping.

  Exploit scenarios of the above include container escaping, (root)
  privilege escalation in (or: into) a container OS, and DoS via system
  resource exhaustion or storage resource exhaustion on a container OS.

  Note that starting an Apport instance on a (different) container OS via
  the above Apport socket-as-asymlink scenario, as well as the above LXD
  manipulation scenario, can be considered remote exploitation scenarios:
  container OSes (in most cases) are in fact (virtually) distinct systems,
  i.e., "remote" to the system on which the attacker operates.

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

Reply via email to