TOMOYO MAC on NixOS

Hey,

I’ve been running NixOS for a little bit on three computers and was (a little) suprised at the lack of a good MAC solution for NixOS. I dabble in a bit of kernel development (in the security subsystem), and NixOS is great for building and testing different kernels. And it’s reproducibility is a game changer.

I’m making this post to gauge interest in a lesser known kernel feature/MAC framework called TOMOYO, that may be of interest to the NixOs community.

I may mess around and attempt an integration for NixOS for it if it’s interesting to anybody.

What the heck is MAC?

If you haven’t heard of them, Mandatory Access Control (MAC) systems are kernel-level security frameworks that restrict what processes can do regardless of traditional Unix permissions. Even if a process runs as root, MAC policies can prevent it from accessing files, devices, network resources, or executing other programs outside of what’s explicitly allowed. The idea is to limit the blast radius of bugs or compromises by enforcing the principle of least privilege. These days, these MAC frameworks are implemented as LSMs, or linux security modules, which are stackable (meaning multiple can be used). As of 2025, there are 9 (AppArmor, SELinux, Smack, TOMOYO, Yama, LoadPin, SafeSetID, Lockdown, BPF, and Landlock), 4 of which are MAC frameworks. (AppArmor, selinux, TOMOYO, and Smack)

On most Linux distributions, this MAC role is typically filled by SELinux (mostly RHEL family) or AppArmor (ubuntu and debian)

Why SELinux and AppArmor are so hard on NixOS?

There have been valient attempts (see 1 2) to integrate these into nixos, but they haven’t really had much success.

  • SELinux uses label-based policies and is very powerful, but it assumes mutable filesystem layouts, stable paths, and tight integration with distro packaging. Those assumptions don’t map well to NixOS’s immutable /nix/store and declarative rebuilds, and past integration attempts have struggled for that reason.

  • AppArmor is path-based and simpler in practice, but most existing profiles assume FHS-style paths like /usr/bin and /lib. On NixOS, the hashed store paths tend to make profiles unwieldy, fragile, or largely bespoke, and upstream profile reuse becomes difficult.

Because of this mismatch, NixOS currently lacks a MAC solution that feels native to its model rather than bolted on.

Why TOMOYO?

That led me to look at TOMOYO Linux, another Linux Security Module that’s been in the mainline kernel for a long time but is much less well known. TOMOYO is also path-based, but it’s explicitly designed around:

  • observing actual program behavior.

  • generating policies via a learning mode

  • and constraining execution based on those policies

TOMOYO is a path based lsm, rather than a label based, so the selinux labelling issue doesn’t pose a problem.

Interestingly, TOMOYO has a learning mode, which can be used to learn policies dynamically, and build them based on program behavior.

It does require a kernel compiled with CONFIG_TOMOYO, which is default disabled on NixOS (and most distros for that matter).

Latest Documentation: TOMOYO Linux 2.6.x : The Official Guide : Index

Has anyone used / worked with TOMOYO? I think it may more better than the FHS reliant apparmor or the file labeling approach of SELinux. It may fit well with NixOS.

Let me know your thoughts.

13 Likes

I’ve been playing around with Tomoyo and have managed to get it working on NixOS in principle. By this, I mean I have it enabled in the kernel and have been able to enforce MAC on a simple program I have created.

I don’t have everything sorted yet, but I will make a write-up and link it here when I am happy.

I have nix’d up the tomoyo-tools, which can be found here: jeslie0/tomoyo-tools: Nix flake wrapper around tomoyo-tools - Codeberg.org .

When I have a working Tomoyo NixOS module, I will report back.

2 Likes

Okay! I have an experimental nixos module that seems to work. It can be found here: jeslie0/tomoyo-experiments - Codeberg.org

This allows a user to add an appropriate Tomoyo configuration using security.tomoyo in their configuration.nix file.

I’ve added an example.nix file showing roughly what needs to be added to get Tomoyo working and enforcing a policy.

3 Likes

amazing! i am really interested in TOMOYO for mac and the possibilities it has for finix

what are your plans going forward? would love to hear more

Thank you! This is my first NixOS module, so some feedback would be useful. It would be great to get something pushed upstream eventually.

I would like to investigate ways of creating and maintaining policies. Since the policies generated by learning mode all reference store paths, it would be interesting to see how these can be eliminated by making policies into a derivation and using string interpolation (/nix/store/…/lib/libc.so.6 → ${pkgs.glibc}/lib/libc.so.6, for example). In the example I made, I just give blanket read access to the whole nix store, since the whole store is globally readable normally. The nice thing about TOMOYO is policy generation at runtime is very easy, so getting something working isn’t too challenging.

My next steps are to create a blog post detailing how to use this module and how to create and use policies.

1 Like

@jeje Very nice! I dropped this project after the initial proposal didn’t get much attention. I’ve been working on the kernel mailing lists in the meantime on Landlock LSM/ BPF subsystem … but I think TOMOYO is a better fit for nix / nixos than SELinux and AppArmor. (despite it’s relative obscurity).

The string interpolation thing is exactly what I was thinking. Nix would fit very well for this. Some interesting general system policies could be created.

This tool tomoyo-queryd(8) — tomoyo-tools — Debian stretch — Debian Manpages is definitely worth a look at too. It lets you dynamically allow/deny security events and rewrite policy.

I’d be happy to help with anything. Or do research/contact people into the kernel side. I’m active on the LSM mailing list. I’m more familiar with Linux and the kernel space than writing nix derivations though.

It may be interesting to make a tomoyo-savepolicy wrapper or scrupt that strips the nix store hash and package version from nix paths in the store (replacing it with a wildcard). That way policies from learning mode could be reused on system updates.

i.e /nix/store/9cg9a1aks0blibm7ffm50s2vdx9fdkqd-my-packge-1.16.0.3/bin becomes /nix/store/*-my-package-*/bin

Sounds useful. I’m much more familiar with SELinux than path based MAC. Could wildcarding expand the attack surface area? I could see it possibly giving certain permissions to a nefariously named program in the nix store. That being said, having a functioning policy with wildcards is massively better than having no policy at all.

1 Like

It certainly could. Technically you don’t need to be root to write to the nix store, so it seems that one could nix build a malicious package with the same name and obtain a policy exception. So that idea is a no-go.

I think the best method is to just follow the NixOS model where we declare system configuration ahead of time for stuff in /nix/store/ because after all we have access to the entire state of it during system build time. So we don’t need the wildcards if we build policy based on configuration of the system. Learning mode could be useful more for one off edits and temporary policies on non nix-store paths.

I’ve gotten TOMOYO Linux booting as well, and I’m working on implementing a rust winnow-based parser-combinator for all of the /sys/kernel/security/tomoyo interfaces. I think some of the tomoyo-tools need some different semantics to work well with nix.

1 Like