A userdebug build is also needed to avoid having kernel.modules_disabled=1 set in early boot, otherwise even with su there isn’t control over the kernel. It doesn’t simply add a su binary usable by the ADB shell user to escalate privileges. It sets up a whole SELinux domain for su where everything is permitted with a domain transition to it, along with a bunch of changes to other domains to support debugging them, etc. It has a pretty big impact on the security of the SELinux policy since it’s very locked down without this. Usually, there’s barely anything running close to real root: primarily init and vold and even those don’t necessary have much control over the kernel.
Exposing root to apps is a whole different story. That significantly reduces security by having complex state and security checks leading to full root access from the application layer. We found multiple privilege vulnerabilities in the CyanogenMod (now LineageOS) su implementation when we lightly audited it. It’s much more complex than the userdebug su which checks for the shell user (AID_SHELL) from a setuid binary. Simply having state controlling whether root is enabled / accessible to apps and state for which apps have access to root destroys the security model. It opens up a huge attack surface for escalating to root, including completely bypassing verified boot. There’s not much point of verified boot if you have state that malware can use to persist with root / kernel level privileges… the main purpose of verified boot is to make it more difficult for an attacker to gain root and keep it across a reboot. A more extreme take on verified boot can extend that to any code execution at all, which is essentially the goal that’s being worked towards starting with higher privileged code execution. An attacker should need a verified boot exploit to persist with a high level of privilege, or they should need to persist with low privileges and exploit the OS again. It doesn’t just make persistent harder but means factory resets have very useful security guarantees and so do updates.
When we put effort into not only leveraging the existing verified boot feature but making substantial improvements to it, including removing dependence on far less trusted state than something like root access controls, it would be ridiculous to throw it all away and completely break the feature by completely trusting state with root access. It’s not going to be easy to make progress towards eliminating trust in state and there are going to be bigger sacrifices than a niche feature that wasn’t present before we started. Eliminating usage of /data/dalvik-cache is largely to avoid having persistent state with non-system_server system app level privileges by not loading any code from state (/data) in the base OS. There are still issues like fairly trusted package manager state, etc. that need to be eliminated. The last thing we’re going to do is undo all of that security work to add features that aren’t wanted by the niche CopperheadOS is aimed at in the first place.
CopperheadOS makes substantial sacrifices unrelated to power user control to implement security features. Lots of exploit mitigations have a significant performance cost, and some have a compatibility cost in terms of breaking apps that have latent bugs uncovered by them. There are sacrifices to app compatibility to improve the permission model by tightening up SELinux policy and the high level Android permission model too. For example, a network monitor is bundled with the OS and placed in a special SELinux domain with access to network statistics and regular apps have access to network statistics removed. Elsewhere, apps can use /proc/net/tcp to monitor all connections made by other processes on the system. The hidepid=2 feature we integrated and then upstreamed is very similar, as are other usability/flexibility tradeoffs made by Android and the changes CopperheadOS makes to take that further.
Improving security is not easy and comes with sacrifices. It has always been clear to us that we weren’t going to be able to do that while pleasing power users and it was never our goal. The sources are published and allow people with the knowledge / skills to make their own decisions about these tradeoffs to make them on their own, without needing to negatively impact our customers. There isn’t any code whatsoever that isn’t published or any internal build documentation. Our employees build with the same build documentation that everyone else can use.
CopperheadOS is also intended to eventually be targeted at much less technical users, where the main threats are the user being tricked into doing something like installing a malicious app, or granting malicious privileges. The main dangers for them are able to sideload apps, grant dangerous privileges without a constant reminder, turn apps into device managers, turn apps into accessibility services or grant scary special privileges like drawing over other apps (which was crippled to not draw over system UI and to show a warning). Having dangerous features within reach is very bad for those users. Most people aren’t as technical as anyone reading stuff here and they need to someone to look out for them. The answer is not expecting everyone to become a technical expert rather than using devices as appliances / tools and those devices making it very difficult to shoot themselves in the foot.
The same empty feel good statement about “freedom” could be used about safe programming languages… which remove flexibility and the ability to shoot yourselves in the foot and drastically improve security by eliminating classes of vulnerabilities like memory corruption / type confusion / dynamic code execution bugs which are the top sources of software vulnerabilities. The ability to do whatever you want is still there, but rather than a shotgun that’s always within reach it’s locked away in a safe. That’s how root access works for CopperheadOS. It is available because users have ultimate control over the devices as long as they have the password to unlock + access developer settings + enable oem unlocking + unlock with physical access + make whatever changes they want. That’s how CopperheadOS can run on those devices in the first place…