#!/bin/bash

## Copyright (C) 2026 - 2026 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## AI-Assisted

## Ensure a qemu-user binfmt_misc handler carries the 'C' (credentials) flag so
## that setuid binaries (notably 'sudo') gain root inside an emulated
## foreign-architecture chroot, such as the amd64 VirtualBox chroot built on
## an arm64 host. Without the flag the kernel derives the emulated process'
## credentials from the unprivileged qemu interpreter instead of the setuid
## target, so 'sudo' fails with a misleading
## 'sudo: effective uid is not 0 ... nosuid' error.
##
## qemu-user-binfmt registers its handlers via systemd-binfmt and ships the full
## spec on disk as a systemd binfmt.d conf: /usr/lib/binfmt.d/<name>.conf, one
## ':name:type:offset:magic:mask:interpreter:flags' line, flags 'OPF' by
## default (no credentials). This reuses that vendor spec verbatim and only adds
## 'C' to its flags field via an /etc/binfmt.d override (an /etc drop-in wins
## over the /usr/lib vendor file), then re-runs systemd-binfmt to re-register the
## handler with the new flags.
##
## Standalone and dependency-minimal (like help-steps/retry-run): it is executed
## as root, not sourced, so it reports via printf rather than the build's
## 'log'/'error' helpers. Must run as root. Idempotent: a no-op when the 'C'
## flag is already present.
##
## Usage: binfmt-credential-setup <binfmt-name>   (e.g. qemu-x86_64)

set -o errexit
set -o nounset
set -o pipefail
set -o errtrace
shopt -s inherit_errexit
shopt -s shift_verbose

binfmt_name="${1:-}"
if [ -z "${binfmt_name}" ]; then
   printf '%s\n' "${BASH_SOURCE[0]}: usage: binfmt-credential-setup <binfmt-name>" >&2
   exit 64
fi

binfmt_handler="/proc/sys/fs/binfmt_misc/${binfmt_name}"

## Already carries the credentials flag -> nothing to do.
if [ -f "${binfmt_handler}" ] && grep -- '^flags:.*C' "${binfmt_handler}" >/dev/null 2>&1; then
   printf '%s\n' "INFO: binfmt handler '${binfmt_name}' already carries the 'C' (credentials) flag."
   exit 0
fi

## If a handler isn't present under /proc/..., it's most likely because the
## architecture this handler would emulate is supported natively and doesn't
## need a handler. Therefore don't warn if the handler isn't registered. Do
## warn if the handler is registered but the config file for it is missing.
vendor_conf="/usr/lib/binfmt.d/${binfmt_name}.conf"
if [ ! -f "${vendor_conf}" ]; then
   if [ -f "${binfmt_handler}" ]; then
      printf '%s\n' "${BASH_SOURCE[0]}: binfmt handler '${binfmt_name}' is registered but has no vendor binfmt.d conf; cannot add the 'C' flag." >&2
      exit 1
   fi
   printf '%s\n' "INFO: '${binfmt_name}' is not registered on the system, architecture is most likely supported natively on this host. Nothing to do."
   exit 0
fi

## A conf is one ':name:type:offset:magic:mask:interpreter:flags' line. Take it
## verbatim and append 'C' to the trailing flags field, leaving magic / mask /
## interpreter exactly as shipped.
## '|| true' so a conf with no ':'-form line does not trip errexit.
vendor_line="$(grep -m 1 -- '^:' "${vendor_conf}")" || true
if [ -z "${vendor_line}" ]; then
   printf '%s\n' "${BASH_SOURCE[0]}: '${vendor_conf}' has no binfmt registration line." >&2
   exit 1
fi
vendor_flags="${vendor_line##*:}"
case "${vendor_flags}" in
   *C*)
      new_flags="${vendor_flags}"
      ;;
   *)
      new_flags="${vendor_flags}C"
      ;;
esac
override_line="${vendor_line%:*}:${new_flags}"

override_conf="/etc/binfmt.d/${binfmt_name}.conf"
mkdir --parents -- "/etc/binfmt.d"
printf '%s\n' "${override_line}" > "${override_conf}"
printf '%s\n' "INFO: wrote '${override_conf}' (flags '${vendor_flags}' -> '${new_flags}')."

## Re-register from the override. systemd-binfmt re-registers an already-present
## handler with the new flags, and runs standalone -- so it also covers a
## container that has systemd-binfmt installed but not running as PID 1.
systemd_binfmt="/usr/lib/systemd/systemd-binfmt"
if [ ! -x "${systemd_binfmt}" ]; then
   printf '%s\n' "${BASH_SOURCE[0]}: '${systemd_binfmt}' not found; cannot re-register binfmt handlers." >&2
   exit 1
fi
"${systemd_binfmt}" "${override_conf}"

if [ ! -f "${binfmt_handler}" ] || ! grep -- '^flags:.*C' "${binfmt_handler}" >/dev/null 2>&1; then
   printf '%s\n' "${BASH_SOURCE[0]}: failed to add the 'C' (credentials) flag to '${binfmt_name}'." >&2
   exit 1
fi
printf '%s\n' "INFO: binfmt handler '${binfmt_name}' now carries the 'C' (credentials) flag."
