The OnePlus 3 and the OnePlus 3T are among the best phones you can purchase right now. While the upcoming flagships of 2017 are yet to be revealed to consumers, in their absence the OnePlus 3/3T dominate real world performance at an affordable price.

But, if we are to be fair in assessing the device, we need to acknowledge that despite OnePlus's best efforts, the OnePlus 3/3T are not without their faults. For example, we've previously reported on security issues such as OnePlus leaking IMEI details over the network when you check for updates on your phone. And now, we have another security issue to add to the list, this one with potentially more dangerous ramifications.

A vulnerability in the bootloader of the OnePlus 3/3T opens up doors to malicious attacks. As found by Roee Hay of the IBM X-Force Application Security Research Team and revealed on the IBM X-Force Exchange platform, this vulnerability allows an attacker to manipulate the SELinux state on the devices, thereby toggling it to permissive mode. All the attacker needs is either physical access to the device, or remote access to an ADB connection to the device.

SELinux, or Security-Enhanced Linux, is a Linux kernel security module which allows for access and management of security policies. SELinux was introduced to Android starting with Android 4.3 and was set to Enforcing mode as default since Android 4.4. This mandatory access control system helps enforce the existing access control rights and attempts to prevent privilege escalation attacks. This acts as a hurdle for unauthorized control over your device, such as an app or vulnerability aiming to gain root access maliciously. Setting SELinux to Enforcing by default on Android serves as the first step to protect normal users from such attacks.

The vulnerability is rather straightforward to exploit - in fact, it appears to be a huge oversight on OnePlus's part rather than what you would imagine your typical exploit to look like. First, an attacker reboots the OnePlus 3/3T into 'fastboot' mode - if you have physical access, simply press the Volume-Up button during boot, but if you don't you can issue the ADB command adb reboot bootloader to the device. The fastboot mode on the device exposes a USB interface, which should not allow any security sensitive command to complete on locked devices. But on the OnePlus 3/3T, simply issuing the fastboot oem selinux permissive command through the fastboot interface toggles the SELinux mode from Enforcing to Permissive.

        fastboot oem selinux permissive
...
OKAY [ 0.045s]
finished. total time: 0.047s

....

OnePlus3:/ $ getenforce
Permissive
OnePlus3:/ $

To further complicate the problem, the OnePlus 3 and 3T do not possess any entry in the 'About Screen' to mention the current SELinux state of the device. A victim will continue to remain oblivious to the compromised state of their device if they did not witness the exploit being actively used. The lack of an SELinux state entry in the 'About Screen' is missing from both the Android 6.0 based Open Beta releases as well as Android 7.0 official ROMs.

Several apps exist to toggle SELinux state to Permissive such as the SELinuxModeChanger application. Toggling SELinux through this method does not allow the state to persist through a reboot. Though, you can utilize scripts to maintain the Permissive SELinux state across hard reboots. Both of these methods require root access, which implies that the user already has knowledge of the risks they are exposed to. But the major difference with changing the SELinux mode to Permissive using the above vulnerability is that it not only persists across hard reboots, it does so without needing root access.

No remedies exist against the vulnerability as of today.


UPDATE: 

We reached out to Sultanxda, one of the most recognized custom ROM developers for OnePlus devices, to see if he could help us learn more about this issue. He promptly dug into the code to find the root source, this is what he found:

The way that the "fastboot oem selinux <state>" command works is that it adds an extra argument onto the kernel command line when booting Linux. The extra argument comes in the form of "androidboot.selinux=<state>", where <state> can be "permissive". There's where things get funny: "androidboot.<something>" arguments on the kernel command line are parsed by Android's init. In a normal Android production build (a "user" build), the "androidboot.selinux" argument is totally ignored and selinux is always forced to enforcing. So this bug is composed of two issues:

  1. Users can make the bootloader pass a flag that would normally make selinux permissive on an engineering/debugging ROM build
  2. OnePlus modified Android's init in order to honor the "androidboot.selinux" flag even for production ROM builds

Here's where Android's init is configured to ignored the "androidboot.selinux" flag for production builds: https://android.googlesource.com/platform/system/core/+/android-6.0.0_r41/init/Android.mk#7

The ALLOW_DISABLE_SELINUX flag in the source code is only set to 1 for userdebug and engineering builds

(My ROM is not affected by this because I build my ROM in production (user) mode)

So "androidboot.selinux" is simply ignored in my ROM, the "fastboot oem selinux <state>" command also seems to be something that OnePlus created, as no such command exists in CAF's public bootloader sources. Off the top of my head, I can think of 4 ways to fix this for users with unlocked bootloaders:

  1. Hex-edit the bootloader to change all instances of the string "selinux" to something different (like "sclinux") so that the flag won't be recognized by Android's init
  2. Hex-edit the Android init binary in OxygenOS to replace all instances of "androidboot.selinux" to something different (like "androidboot.sclinux") so that Android init won't recognize the androidboot.selinux flag
  3. Add a hack to the kernel command line driver similar to my SafetyNet bypass in order to hide the "androidboot.selinux" flag from Android's init

We'd like to thank Sultanxda for his time and effort in helping us figure out what's going on behind the scenes. We've also reached out to OnePlus, who's aware of the situation and is looking into the matter.


We hope OnePlus publicly acknowledges the serious issue and is transparent in their plans towards fixing it.