Home / Alt manpages / systemd-binfmt.service(8)

  • systemd-binfmt.service(8)
  • Admin command
  • linux

Manage Binary Format Handlers with systemd-binfmt

A .py file that should just run instead throws exec format error, and systemd-binfmt is the reason it usually just works. This guide inspects the binary-format handlers systemd has registered, works out which binfmt.d file wins when two disagree, and adds or removes a handler without losing track of kernel state. Examples match systemd 255.4 on Ubuntu, package version 255.4-1ubuntu8.17. Allow about fifteen minutes.

  • Reading configuration is unprivileged.
  • Writing under /etc/binfmt.d, restarting the service, and unregistering handlers need elevated privileges. The last one is destructive and gets its own section below.

1. Confirm the installed tool

The service uses the helper at /usr/lib/systemd/systemd-binfmt. Check the version and available options before copying a command into a script:

$ /usr/lib/systemd/systemd-binfmt --version
systemd 255 (255.4-1ubuntu8.17)

$ /usr/lib/systemd/systemd-binfmt --help
systemd-binfmt [OPTIONS...] [CONFIGURATION FILE...]
...
     --cat-config       Show configuration files
     --tldr             Show non-comment parts of configuration
     --no-pager         Do not pipe output into a pager
     --unregister       Unregister all existing entries

The exact feature list varies with the systemd release. In this release, --unregister exists and has been available since systemd 246.

Warning

Do not use --unregister as a routine reload command. It removes every currently registered entry, not just yours.

2. See the effective configuration

Start with the read-only view. --cat-config prints each file and its filename; --tldr omits blank lines and comments:

$ /usr/lib/systemd/systemd-binfmt --no-pager --tldr
# /usr/lib/binfmt.d/llvm-18-runtime.binfmt.conf
:llvm-18-runtime.binfmt:M::BC::/usr/bin/lli-18:

# /usr/lib/binfmt.d/llvm-20-runtime.binfmt.conf
:llvm-20-runtime.binfmt:M::BC::/usr/bin/lli-20:

# /usr/lib/binfmt.d/python3.12.conf
:python3.12:M::\xcb\x0d\x0d\x0a::/usr/bin/python3.12:

Your output depends on installed packages. These entries are kernel binfmt_misc rules, not shell aliases: a magic rule matches bytes at an offset in a file and invokes the named interpreter. The kernel documentation describes the full registration shape as :name:type:offset:magic:mask:interpreter:flags; the separator can change when a rule needs a literal colon.

Checkpoint

Compare this output with the live kernel directory:

$ ls -l /proc/sys/fs/binfmt_misc
$ cat /proc/sys/fs/binfmt_misc/status

Registered names such as python3.12 should have corresponding files. An empty or missing directory usually means the kernel interface is not mounted or available. Do not write to register by hand while diagnosing a systemd-managed setup.

3. Understand which file wins

Configuration files must end in .conf. systemd reads administrator files from /etc/binfmt.d, runtime files from /run/binfmt.d, and package or local files from /usr/lib/binfmt.d or /usr/local/lib/binfmt.d. Higher-priority directories override a same-named file, then files are sorted by filename across directories, so a later lexicographic name can change one setting.

  • Replacing a vendor file entirely: a vendor file named 50-example.conf can be replaced completely by an /etc/binfmt.d/50-example.conf file.
  • Adding a rule without replacing the vendor one: use a later name, such as 90-local-example.conf. The recommended two-digit prefix makes the ordering visible during review.

Blank lines and lines beginning with # or ; are comments, so those characters cannot be used as a rule's field separator. Keep comments outside the registration line.

4. Add a local rule deliberately

Use a real interpreter path and a rule designed for the file format you intend to run. This is a template, not a safe claim that the placeholder interpreter exists:

# /etc/binfmt.d/90-example.conf
:example:M::MAGIC::/absolute/path/to/trusted-interpreter:

M means magic-byte matching, example is the name, MAGIC is the byte sequence, and the final path is the interpreter.

Security warning

The kernel can execute this handler whenever a file matches, so a wrong or untrusted interpreter is a security decision, not a harmless test.

Create the file with your normal administrative editor, then inspect it before applying it:

$ sudoedit /etc/binfmt.d/90-example.conf
$ sudo /usr/lib/systemd/systemd-binfmt --no-pager --cat-config | sed -n '/90-example.conf/,+2p'

Do not use a broad shell redirection with an unquoted path or user-supplied rule. Keep the file mode ordinary for configuration, and confirm the interpreter is an absolute, executable file owned and maintained by the system administrator.

5. Apply and verify the change

After editing a persistent file, restart the service during a suitable maintenance window. This changes kernel execution behaviour for matching files:

$ sudo systemctl restart systemd-binfmt.service
$ systemctl is-active systemd-binfmt.service
active
$ ls -l /proc/sys/fs/binfmt_misc/example

The service is normally a static unit, so is-enabled may print static even when is-active prints active. That is not a failure. If the restart fails, read the unit log, fix or remove the new file, then restart again:

$ journalctl -u systemd-binfmt.service -b --no-pager
$ sudoedit /etc/binfmt.d/90-example.conf
$ sudo systemctl restart systemd-binfmt.service

Keep the old configuration until a representative file has run successfully. A matching rule can affect ordinary command launches, and a handler that exits unexpectedly can make the original program look broken.

6. Override or remove a vendor rule

To disable a packaged configuration file, place a symlink with the same filename in /etc/binfmt.d pointing to /dev/null. Resolve the exact vendor filename first:

$ find /usr/lib/binfmt.d /usr/local/lib/binfmt.d -maxdepth 1 -type f -name '*.conf' -printf '%f\n' | sort
$ sudo ln -s /dev/null /etc/binfmt.d/EXACT-VENDOR-FILENAME.conf
$ sudo systemctl restart systemd-binfmt.service

Replace EXACT-VENDOR-FILENAME.conf with the filename you actually found; do not create a guessed link. If the configuration was baked into an initrd, the manpage requires regenerating that initrd as a separate, distribution-specific operation.

To undo the override, remove only the symlink you created, then restart the service:

$ test -L /etc/binfmt.d/EXACT-VENDOR-FILENAME.conf
$ sudo rm /etc/binfmt.d/EXACT-VENDOR-FILENAME.conf
$ sudo systemctl restart systemd-binfmt.service

Warning

rm is irreversible for that directory entry. The vendor file itself is not removed, but check the target with test -L first so you do not delete a real administrator file.

7. Treat unregister as an emergency operation

--unregister unregisters all currently registered binary formats, including entries that did not come from the files you are editing. It needs the privilege to change the kernel interface and can disrupt unrelated applications. Use it only with a documented recovery plan:

$ sudo /usr/lib/systemd/systemd-binfmt --unregister
$ sudo systemctl restart systemd-binfmt.service
$ /usr/lib/systemd/systemd-binfmt --no-pager --tldr

The restart re-registers the configured rules, but it cannot restore an entry that was registered by another mechanism or a configuration file you have removed. Prefer correcting binfmt.d and restarting the service when the problem is a bad local rule.

Done means

  • You confirmed the installed systemd version and inspected the effective rules with --tldr.
  • You checked both configuration precedence and the live /proc/sys/fs/binfmt_misc entries.
  • Any new rule uses a reviewed absolute interpreter path and a deliberate filename order.
  • You verified the service state after applying a change and kept a recovery edit ready.
  • You did not reach for --unregister unless clearing every handler was genuinely required.