#!/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 -- for example 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. No magic/mask reconstruction, and systemd-binfmt
## re-registers an already-registered handler in place.
##
## 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 [ -e "${binfmt_handler}" ] && grep --quiet -- '^flags:.*C' "${binfmt_handler}"; then
   printf '%s\n' "INFO: binfmt handler '${binfmt_name}' already carries the 'C' (credentials) flag."
   exit 0
fi

## The vendor systemd binfmt.d conf holds the full spec; only its flags change.
## Its absence means qemu-user does not emulate this architecture on this host:
## the target runs natively (e.g. armhf on an arm64 host with AArch32
## support), so there is no qemu handler and nothing to flag --
## not an error. qemu-user-binfmt (installed by the build) ships a conf for every
## architecture it actually emulates, so a missing conf means native execution.
## The one odd case is a handler already registered by some other tool with no
## conf to re-flag, which cannot be fixed idiomatically -- surface that.
vendor_conf="/usr/lib/binfmt.d/${binfmt_name}.conf"
if [ ! -e "${vendor_conf}" ]; then
   if [ -e "${binfmt_handler}" ]; then
      printf '%s\n' "${BASH_SOURCE[0]}: binfmt handler '${binfmt_name}' is registered but has no vendor binfmt.d conf to re-flag with credentials; cannot add the 'C' flag." >&2
      exit 1
   fi
   printf '%s\n' "INFO: no vendor binfmt.d conf '${vendor_conf}'; '${binfmt_name}' is not emulated on this host (native execution), 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 (grep exits 1) does not trip
## errexit before the guard below can report it.
vendor_line="$(grep -m 1 -- '^:' "${vendor_conf}")" || true
if [ -z "${vendor_line}" ]; then
   printf '%s\n' "${BASH_SOURCE[0]}: '${vendor_conf}' has no ':'-form 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 [ ! -e "${binfmt_handler}" ] || ! grep --quiet -- '^flags:.*C' "${binfmt_handler}"; 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."
