Hello Linux Gurus,

I am seeking divine inspiration.

I don’t understand the apparent lack of hypervisor-based kernel protections in desktop Linux. It seems there is a significant opportunity for improvement beyond the basics of KASLR, stack canaries, and shadow stacks. However, I don’t see much work in this area on Linux desktop, and people who are much smarter than me develop for the kernel every day yet have not seen fit to produce some specific advanced protections at this time that I get into below. Where is the gap in my understanding? Is this task so difficult or costly that the open source community cannot afford it?

Windows PCs, recent Macs, iPhones, and a few Android vendors such as Samsung run their kernels atop a hypervisor. This design permits introspection and enforcement of security invariants from outside or underneath the kernel. Common mitigations include protection of critical data structures such as page table entries, function pointers, or SELinux decisions to raise the bar on injecting kernel code. Hypervisor-enforced kernel integrity appears to be a popular and at least somewhat effective mitigation although it doesn’t appear to be common on desktop Linux despite its popularity with other OSs.

Meanwhile, in the desktop Linux world, users are lucky if a distribution even implements secure boot and offers signed kernels. Popular software packages often require short-circuiting this mechanism so the user can build and install kernel modules, such as NVidia and VirtualBox drivers. SELinux is uncommon, ergo root access is more or less equivalent to the kernel privileges including introduction of arbitrary code into the kernel on most installations. TPM-based disk encryption is only officially supported experimentally by Ubuntu and is usually linked to secure boot, while users are largely on their own elsewhere. Taken together, this feels like a missed opportunity to implement additional defense-in-depth.

It’s easy to put code in the kernel. I can do it in a couple of minutes for a “hello world” module. It’s really cool that I can do this, but is it a good idea? Shouldn’t somebody try and stop me?

Please insert your unsigned modules into my brain-kernel. What have I failed to understand, or why is this the design of the kernel today? Is it an intentional omission? Is it somehow contrary to the desktop Linux ethos?

  • @[email protected]
    link
    fedilink
    English
    162 days ago

    It’s easy to put code in the kernel. I can do it in a couple of minutes for a “hello world” module. It’s really cool that I can do this, but is it a good idea? Shouldn’t somebody try and stop me?

    Yes, not being root stops you. Don’t run untrusted code as root.

    • @[email protected]OP
      link
      fedilink
      English
      -5
      edit-2
      2 days ago

      My illustration is meant to highlight the lack of care that is taken w.r.t. kernel code compared to systems that require code signing. If some privileged process is compromised, it can simply ask the kernel to insert a module with arbitrary code. Should processes be able to do this? For many systems, the answer is no: only otherwise authenticated code can run in the kernel. No userspace process has the right to insert arbitrary code. A system with a complete secure boot implementation and signed kernel modules prevents even root from inserting an unauthorized module. Indeed, on Android on a Samsung device with RKP, unconfined root still cannot insert a kernel module that isn’t signed by Samsung. The idea of restricting even root from doing dangerous things isn’t new. SELinux uses rules to enforce similar concepts.

      Yes, not being root is a useful step, but protecting the kernel from root might still be desirable and many systems try to do this. Exploits can sometimes get untrusted code running as root on otherwise reasonable secure systems. It’s nice if we can have layered security that goes beyond, so I ask: why don’t we have this today when other systems do?

      • lurch (he/him)
        link
        fedilink
        English
        72 days ago

        if you don’t want modules, you can compile a monolithic kernel. i have done so for a few years. it saves time if you run something like gentoo or LFS, because you don’t need an initrd and no mechanisms for loading modules. it has the downside of not being able to change some parameters during runtime, ie. you have to reboot and pass different parameters via booloader. you can then also switch off support for loading modules.

        • Blaster M
          link
          English
          3
          edit-2
          2 days ago

          Ah, yes, I do enjoy spending 6 months rebuilding my daily driven car in the garage because the air filter is integrated deep in the engine and not easily replaceable.

          The whole “I compile all my linux from source” might work if you are an IT major or have a lot of free time you can devote to maintaining your PC, but the majority of people that use a PC do not have the time, skill, attention span, or knowledge to do any more than press “Easy” and let the system have at it.

          • lurch (he/him)
            link
            fedilink
            English
            11 day ago

            i just read there is even some kind of macro for switching all modules to built-in:

            make mod2yesconfig
            # and/or
            make localyesconfig
            
          • lurch (he/him)
            link
            fedilink
            English
            22 days ago

            compiling a kernel from the provided source is surprisingly easy tho. you can start with the default config from your distro, just toggle the options you want different in the menuconfig and compile it. there are howtos. also, once a pro has done it, they can share the config for others with similar setups.

            if you fail and your kernel is broken, you can just use the old one again until you get it right. just don’t overwrite the old one when putting it where the boot loader is looking for it and give the new one it’s own boot loader entry.

        • @[email protected]OP
          link
          fedilink
          English
          12 days ago

          This is interesting especially in embedded, and it’s a way to make loading code harder because now the kernel may not even have a facility for loading code. This does go in the right direction. Not even root can do it if there just isn’t code to load a module.

          But, many if not most popular OSs go a step further and inspect the kernel to make sure it isn’t adding code to itself to the maximum extent possible, even if it were exploited by a bug.

          • lurch (he/him)
            link
            fedilink
            English
            1
            edit-2
            1 day ago

            i just read there is even some kind of macro for switching all modules to built-in:

            make mod2yesconfig
            # and/or
            make localyesconfig
            

            Also, the module blacklist file may accept wildcards, so you can blacklist all modules. And there is a sysctl switch “kernel.modules_disabled”, which lets you switch module changes off and on as required. Then again, an attacker who gained root to load modules could also re-enable it and de-blacklist his modules; so this is a lot weaker.

            //edit: the blacklist is useless for security, because it only affects easy module loading with modprobe, not using insmod what an attacker would use.

      • Possibly linux
        link
        fedilink
        English
        62 days ago

        What is your threat model? If someone gains root they can do whatever they want. No security will protect you from that.

        • Blaster M
          link
          English
          32 days ago

          If a browserjack malware does a complicated zero-click attack to gain root when you accidently typo a website, unfettered access to the system by root is a big problem. This is why SELinux exists. This is why browser sandboxing exists. This is why virtualization of modules and drivers and so on exists. This “security theatre” as you call it is to provide protection. Is protection guaranteed? No, but it’s the difference between locking your door at night and leaving it wide open.

          • @[email protected]
            link
            fedilink
            English
            11 day ago

            Jesus H Christ youre running your browser as root?

            Unless you mean an oceans 11-esque double zero-day exploit that jacks the userspace browser, stacked on a root-level privilege escalation zero-day on arguably the most secure OS in the world.

            I think we have insanely different threat models

            • Blaster M
              link
              English
              21 day ago

              And yet, state actors have done exactly what you’ve laid out. This is challenge accepted to a hacker.

              • @[email protected]
                link
                fedilink
                English
                11 day ago

                So your threat model is state level hackers?

                On desktop PC’s?

                Any malicious actor in the universe would love to be able to make a bot net out of 90% of the worlds computers, doesn’t make it any less plausible out of movies

          • Possibly linux
            link
            fedilink
            English
            2
            edit-2
            1 day ago

            There are no zero click root on any platform. That’s not how it works.

            Browsers don’t run as root and all of the browser processes are sandboxed with least privilege being enforced. So many things would need to go wrong.

          • @[email protected]OP
            link
            fedilink
            English
            -12 days ago

            Precisely! It’s about making compromise expensive, multi-layered, driving up the cost so it becomes fiscally unattractive for the attacker.

        • @[email protected]OP
          link
          fedilink
          English
          0
          edit-2
          2 days ago

          The threat model is that root shouldn’t have to be a lose condition. It is certainly very bad, but there should be some things root cannot do, like modify the kernel, while still being the highest privilege level designed into the system. SELinux rules severely constrain the root user on Android for example to frustrate a total system compromise even if an attacker gains root.

          The attacker must then find a way to patch the kernel to get the unconstrained root that we have today on Linux desktops.

          • Possibly linux
            link
            fedilink
            English
            21 day ago

            A root use can modify the kernel on disk and then trigger a reboot. You need either containers or full virtualization to protect against that.

            • @[email protected]OP
              link
              fedilink
              English
              11 day ago

              This cannot be done on most consumer OSs like Macs or Windows, or Android smartphones, because secure boot would refuse to load a modified kernel from the disk. It is possible on typical desktop Linux installations if they don’t implement secure boot.

              • Possibly linux
                link
                fedilink
                English
                21 day ago

                Secure boot is build on a model of proprietary software and antiuser freedom. For secure boot to do anything you first have to restrict what software the user can run which is already a no no. If you ignore that secure boot is often riddle with security problems and many companies use default keys. Your average device has multiple exploits.

                Also, why would it matter if an adversary gain root vs kernel level access? Root can do anything so it wouldn’t matter much.

              • @[email protected]
                link
                fedilink
                English
                11 day ago

                Root access on any of these platforms would still result in persistent low level system access

                • @[email protected]OP
                  link
                  fedilink
                  English
                  1
                  edit-2
                  1 day ago

                  On Android, secure boot causes boot loader validation, kernel validation, and subsequent validation by the kernel of all application code that is loaded into the system. You need an additional bug to obtain persistent access if the code has not been signed by an authorized party.

                  This is why iPhone jailbreaks are bifurcated into teathered and unteathered — many modern OSs require a second bug to survive a reboot and achieve persistence. The introduced code won’t pass signature check.

      • @[email protected]
        link
        fedilink
        English
        32 days ago

        I should not be forbidden from running my own code on my own hardware, right? But I should be protected from random code taking over my entire system, right? That’s why Linux restricts certain operations to root.

        • @[email protected]OP
          link
          fedilink
          English
          0
          edit-2
          2 days ago

          Absolutely! It’s your computer and it should always obey you. Trouble is, the kernel doesn’t know the difference between you the human being and you the program running as root user in your service, like wpa_supplicant for example, that may be potentially open to compromise.

          Perhaps, like a safety on a gun, there should be another step to inserting code into your kernel to ensure it’s being done very deliberately. We kind of see this with mokmanager for enrolling secure boot keys. Physical button presses are required to add a key and it cannot be (easily) automated software by design. You have to reboot and physically do it in the UEFI.

          This is where runtime or hypervisor kernel protections make sense – in making sure the kernel is behaving under expected parameters except when we really, truly want to load new kernel code. It’s the same reason why we have syscall filtering on so many services, like OpenSSH server process pre-authentication. We don’t want the system to get confused when it really matters.