#!/bin/bash

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

## AI-Assisted

## Compile emerg-shutdown.c with the project's standard hardening
## flag set, statically linked (the binary is intended to run after
## the root device has been yanked - libc can't be paged in from a
## gone disk, so libc must be in the image already).
##
## Pure compile - the helper does not chmod, mv, or otherwise install
## the produced binary; the caller decides.
##
## Usage:
##   compile-emerg-shutdown <source.c> <output-binary>
##
## Used by:
##   * usr/libexec/security-misc/emerg-shutdown (first-run on the
##     user's machine: compiles C code into /run/emerg-shutdown then
##     execs it)
##   * ci/codeql-build.sh (CodeQL static analysis prebuild)
##
## Holding the gcc command in one place keeps the runtime build path
## and the CI analysis path from drifting on hardening flags.

set -o errexit
set -o nounset
set -o errtrace
set -o pipefail

export LC_ALL=C

if [ "$#" -ne 2 ]; then
  printf '%s\n' "usage: ${BASH_SOURCE[0]} <source.c> <output-binary>" >&2
  exit 64
fi

source_file="$1"
output_binary="$2"

gcc_hardening_options=(
  "-O2" "-Wall" "-Wextra" "-Wformat" "-Wformat=2" "-Wconversion"
  "-Wimplicit-fallthrough" "-Werror=format-security" "-Werror=implicit"
  "-Werror=int-conversion" "-Werror=incompatible-pointer-types"
  "-Wformat-overflow" "-Wformat-signedness" "-Wformat-truncation"
  "-Wnull-dereference" "-Winit-self"
  "-Wmissing-include-dirs" "-Wshift-negative-value" "-Wshift-overflow"
  "-Wswitch-default" "-Wuninitialized" "-Walloca" "-Warray-bounds"
  "-Wfloat-equal" "-Wshadow" "-Wpointer-arith" "-Wundef" "-Wunused-macros"
  "-Wbad-function-cast" "-Wcast-qual" "-Wcast-align" "-Wwrite-strings"
  "-Wdate-time" "-Wstrict-prototypes" "-Wold-style-definition"
  "-Wredundant-decls" "-Winvalid-utf8" "-Wvla" "-Wdisabled-optimization"
  "-Wstack-protector" "-Wdeclaration-after-statement" "-Wtrampolines"
  "-Wbidi-chars=any,ucn" "-Wformat-overflow=2" "-Wformat-truncation=2"
  "-Wshift-overflow=2" "-Wtrivial-auto-var-init" "-Wstringop-overflow=3"
  "-Wstrict-flex-arrays" "-Walloc-zero" "-Warray-bounds=2"
  "-Wattribute-alias=2" "-Wduplicated-branches" "-Wduplicated-cond"
  "-Wcast-align=strict" "-Wjump-misses-init" "-Wlogical-op" "-U_FORTIFY_SOURCE"
  "-D_FORTIFY_SOURCE=3" "-fstack-clash-protection" "-fstack-protector-all"
  "-fno-delete-null-pointer-checks" "-fno-strict-aliasing"
  "-fno-strict-overflow" "-fstrict-flex-arrays=3"
  "-ftrivial-auto-var-init=pattern" "-fPIE"
)

gcc_machine="$(gcc -dumpmachine)"
if [ "${gcc_machine}" = 'x86_64-linux-gnu' ]; then
  gcc_hardening_options+=( '-fcf-protection=full' )
  gcc_hardening_options+=( '-fzero-call-used-regs=all' )
elif [ "${gcc_machine}" = 'aarch64-linux-gnu' ]; then
  gcc_hardening_options+=( '-mbranch-protection=standard' )
  gcc_hardening_options+=( '-fzero-call-used-regs=all' )
fi

gcc_hardening_options+=(
  "-Wl,-z,nodlopen" "-Wl,-z,noexecstack" "-Wl,-z,relro" "-Wl,-z,now"
  "-Wl,-z,separate-code" "-Wl,--as-needed" "-Wl,--no-copy-dt-needed-entries"
  "-pie"
)

gcc \
  -g \
  "${source_file}" \
  -o "${output_binary}" \
  -static \
  "${gcc_hardening_options[@]}"
