In this blog post (a cross-post from the Midnight Blue blog) i will cover QNX’s Qnet native networking protocol and an Elevation of Privilege vulnerability (CVE-2017-3891) i discovered in it.
BlackBerry QNX is a Unix-like POSIX Real-Time Operating System (RTOS) for embedded systems found in everything from mobile devices (BlackBerry 10, BlackBerry Tablet OS) and automotive infotainment units to industrial control systems and military radios. QNX has a microkernel architecture where only the bare minimum of kernel functionality (scheduler, interrupt handling, etc.) resides in kernelspace with the rest of OS and device driver functionality residing in userspace. Communication between these various components is primarily done by means of message-passing based Interprocess Communication (IPC).
The QNX Qnet protocol extends this IPC transparently over a network of microkernels (as an overlay over anything with a packet driver eg. Ethernet, RapidIO, InfiniBand, etc.) to form a native network where programs can access any resource, from files and devices to processes, on any other node in the local subnet. This allows for simple and transparent distributed computing over multiple processors or machines which is useful in a range of applications such as industrial automation (with different machines and nodes distributed around a plant), telecom (large routers with multiple interface cards with individual processors) or automotive (sharing a single bluetooth transceiver or 3G/4G modem among different modules over CAN, LIN or MOST).
One prominent example of Qnet usage is in Cisco’s IOS-XR operating system (used in carrier-grade routers such as the CRS, 12000 and ASR9000 series) which runs its Light Weight Messaging (LWM) on top of Qnet. LWM functions as the preferred intra-node and inter-node IPC on IOS-XR.
When a Qnet network is created, hosts can locate eachother by means of either autodiscovery or static mappings depending on security and ease of use requirements. Autodiscovery allows Qnet nodes to discover eachother automatically on any transport that supports broadcasting. If the link between Qnet nodes is insecure however, or if untrusted Qnet nodes could be added one could opt for static mapping instead. Here only nodes listed in the mapping file can be accessed.
In order to start Qnet, we load the lsm-qnet.so
shared object into the network manager:
# mount -Tio-pkt lsm-qnet.so
When a node starts Qnet the /net directory is populated by the other Qnet nodes broadcasting their node information periodically (every 30 seconds by default). To see the system information of the nodes listed in /net we can use the pidin
utility:
or execute processes remotely:
Since Qnet is intended for use in a group of trusted machines, it doesn’t authenticate requests and simply fetches a user ID from the incoming connection. Interaction with resources is protected only by regular Unix permissions and potentially additional (mandatory) access controls.
Some additional security can be introduced into Qnet by using the maproot
and mapany
options (inspired by similar BSD NFS options), which map incoming connections (from root or from anyone, respectively) to a specific user ID:
mapany=map_uid
: Map any incoming user ID to map_uid and map its group ID to that of map_uid.maproot=map_uid
: If the incoming user ID is 0, map it to map_uid and map its group ID to that of map_uid.However, this still means that a compromise of a single QNX machine connected to the Qnet subnet can extend this access to all QNX machines on that subnet. What’s worse, depending on the type of network underlying Qnet (eg. a vehicle bus) access to any system (QNX or not) connected to that network would allow an attacker to intercept and forge Qnet packages and thus compromise connected QNX nodes.
While looking into Qnet, i discovered a locally and remotely exploitable Elevation of Privilege vulnerability (CVE-2017-3891). It turns out that read permission restrictions of operations executed over Qnet aren’t properly resolved by the remote resource manager. This vulnerability can of course be exploited for arbitrary read access on remote Qnet nodes:
But it can also be used to elevate local privileges. Consider the fact that permissions are resolved by the resource manager, so if we want to abuse this vulnerability to achieve the same effect locally we simply need to ensure the file read request originates (or seems to) from another Qnet node. We can do this by using Qnet to execute a command on another node to access a restricted file on our local node:
This attack works regardless of maproot
or mapany
settings.
Midnight Blue reached out to BlackBerry QNX in order to ensure a safe, coordinated disclosure process. As part of this process, BlackBerry QNX has issued an advisory addressing this issue and other vulnerabilities affecting QNX disclosed by Midnight Blue.
The official BlackBerry QNX response is to consider this issue mitigated in circumstances where an attacker has neither access to a single Qnet node nor to the network underlying Qnet. While Qnet was not designed with security guarantees in mind (after all, the absence of authentication or integrity for Qnet packets makes UID forgery possible as well), we do consider it important to emphasize the fact that the mere presence of Qnet on a QNX system effectively constitutes a break of its privilege and permission model.
Developers, project managers, system integrators and administrators are advised to either disable Qnet or deploy it only among mutually trusted, air-gapped nodes using Qnet over a secure network without the presence of untrusted systems. Given the highly complex and evolving nature of the embedded systems QNX is often deployed in, one might want to reconsider using Qnet altogether if security is a consideration however.
Update: A patch with ID 4669 for CVE-2017-3891 and other issues is available for QNX 6.6. It allows filesystems and io-blk to pass INOTIFY_QNX_EXT error notifications to user applications via the inode notify system.
samvartaka 08 December 2017