#!/bin/bash

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

## Runs inside a cowbuilder amd64 chroot. Creates the VirtualBox VM
## (convertfromraw, createvm, storageattach, modifyvm, ...) so that
## 'VBoxManage' does not need to be installed on the build host.
## Invoked by 'build-steps.d/*_create-vbox-vm' via 'cowbuilder --execute'.

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

true "INFO: Currently running chroot script: ${BASH_SOURCE[0]}"

## Variables arrive through the environment: the '4600_create-vbox-vm' host
## wrapper exports the curated allowlist and invokes `sudo ... cowbuilder`
## with '--preserve-env', so they are carried into this chroot (VMNAME, VMRAM,
## VRAM, binary_image_raw_file, ...). Fail loud if a required one did not
## make it.
for required_var in \
   VMNAME VMRAM VRAM binary_image_raw_file binary_image_vdi_dir HOMEVAR_VBOX_TEMP \
   SUDO_TO_VBOX_TEMP vm_names_to_be_exported ; do
   if [ ! -v "$required_var" ]; then
      printf '%s\n' "ERROR: required variable '$required_var' not present in the chroot environment." >&2
      exit 1
   fi
done

## This script runs as root inside the cowbuilder chroot (via
## 'cowbuilder --execute'), so 'sudo' to root is redundant. Worse, sudo's
## 'env_reset' drops 'COWDANCER_ILISTFILE' while cowbuilder's 'libcowdancer'
## remains LD_PRELOAD'ed, leaving the copy-on-write layer half-initialized so
## that root file operations fail with 'cp: ... Cannot allocate memory'. Run
## root commands directly (without sudo) so the inherited cowdancer
## environment stays intact. '$SUDO_TO_VBOX_TEMP' is deliberately NOT cleared
## here: it must drop privileges to the 'dm-vbox-temp' account.
SUDO_TO_ROOT=""

## Absolute path of the VM disk. It lives under '$binary_image_vdi_dir' (on the
## bind-mounted host build folder, '/rw'-backed), NOT the chroot-local
## 'dm-vbox-temp' home, so the multi-gigabyte disk stays off the small
## pbuilder chroot filesystem and out of 'base.cow'. The VirtualBox registry
## (persisted into 'base.cow' via '--save-after-login') records this absolute
## path; the same bind mount is re-established in the export step, so it
## resolves there too. See 'help-steps/variables' ('binary_image_vdi_dir').
vdi_dir="$binary_image_vdi_dir/$VMNAME"
vdi_file="$vdi_dir/$VMNAME.vdi"

error() {
   printf '%s\n' "ERROR: $*" >&2
   exit 1
}

setup_vbox_temp_sudo() {
   ## '$SUDO_TO_VBOX_TEMP' runs 'sudo --chdir' (-D), which sudo refuses
   ## unless the policy permits 'runcwd'. On the build host that rule is
   ## installed by 'build-steps.d/*_prepare-build-machine'; inside this
   ## chroot it must be installed here. This script runs as root (via
   ## 'cowbuilder --execute'), so the invoking user is root and a global
   ## 'Defaults runcwd=*' is the matching rule. 'sponge' (used on the host)
   ## may be absent in the chroot, so use 'tee' (as
   ## 'pbuilder-chroot-script-virtualbox' does).
   printf '%s\n' "Defaults runcwd=*" \
      | SUDO_EDITOR="" VISUAL="" EDITOR=tee visudo -f /etc/sudoers.d/dm-vbox-temp-runcwd >/dev/null

   ## Sanity test.
   visudo --strict --check /etc/sudoers.d/dm-vbox-temp-runcwd
}

debugging_pre() {
   qemu-img \
      info \
         "$binary_image_raw_file"
}

delete_vbox_vm() {
   ## Turning off the VM without saving.
   $SUDO_TO_VBOX_TEMP VBoxManage controlvm "$VMNAME" poweroff || true
   sync

   ## Delete old VM.
   $SUDO_TO_VBOX_TEMP VBoxManage unregistervm "$VMNAME" --delete || true
   sync

   ## The "$SUDO_TO_VBOX_TEMP VBoxManage unregistervm --delete" does not do its job,
   ## we have to manually delete the VM folder (the machine registration, which
   ## 'createvm --register' stores in the 'dm-vbox-temp' default machine folder)
   ## and the VM disk work folder (on the bind-mounted host build folder).
   $SUDO_TO_ROOT safe-rm -r -f -- "$HOMEVAR_VBOX_TEMP/VirtualBox VMs/$VMNAME"
   $SUDO_TO_ROOT safe-rm -r -f -- "$vdi_dir"
   sync

   ## Delete old ova.
   #$SUDO_TO_ROOT safe-rm -f -- "$binary_image_ova_file"
   #sync
}

convert_raw_to_vdi() {
   $SUDO_TO_ROOT mkdir --parents "$vdi_dir"

   ## Must be deleted for this step to be idempotent. Otherwise
   ## "VBoxManage convertfromraw" would fail.
   $SUDO_TO_ROOT safe-rm -f -- "$vdi_file"

   ## Convert directly from the bind-mounted '$binary_image_raw_file'; no
   ## intermediate multi-gigabyte copy is made. 'convertfromraw' only reads its
   ## source, so run it as root (this script already runs as root; '$SUDO_TO_ROOT'
   ## is empty here, and root reads the bind-mounted raw regardless of its mode).
   ## The output '.vdi' lands on the bind-mounted host build folder (/rw), not
   ## the chroot (dmroot).
   ## TODO: Sequential / non-parallel. Not yet parallelizable builds.
   $SUDO_TO_ROOT VBoxManage convertfromraw "$binary_image_raw_file" "$vdi_file"

   ## Hand ownership of the per-VM disk folder and its '.vdi' to 'dm-vbox-temp'
   ## so the subsequent 'VBoxManage' calls (which drop to that account to
   ## compact and register the disk) can read/write it. Chown the bind-mount
   ## root itself too, but NON-recursively: making 'dm-vbox-temp' its owner
   ## lets it traverse into the per-VM folder regardless of the host umask on
   ## the mount point, while leaving sibling per-flavor VM folders under it
   ## (e.g. a Gateway folder while building the Workstation) untouched.
   $SUDO_TO_ROOT chown "dm-vbox-temp:dm-vbox-temp" "$binary_image_vdi_dir"
   $SUDO_TO_ROOT chown --recursive "dm-vbox-temp:dm-vbox-temp" "$vdi_dir"

   ## Debugging.
   $SUDO_TO_VBOX_TEMP qemu-img info "$vdi_file"

   if [ "${dist_build_fast1:-}" = "1" ]; then
      printf '%s\n' "INFO: run with '--fast 1' switch, skipping compacting vdi."
   else
      $SUDO_TO_VBOX_TEMP VBoxManage modifymedium --compact "$vdi_file"
   fi

   ## Debugging.
   $SUDO_TO_VBOX_TEMP qemu-img info "$vdi_file"
}

general_setup() {
   ## Create a new VM. Name: $VMNAME
   ##
   ## The platform architecture is fixed at 'createvm' time and the OS type must
   ## match it, so select both from '$dist_build_target_arch' with an exact
   ## 'case' (a substring test for '64' would misfile 'arm64' as x86-64).
   case "$dist_build_target_arch" in
      i386)
         $SUDO_TO_VBOX_TEMP VBoxManage createvm --name "$VMNAME" --register
         $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --ostype Debian
         ;;
      amd64)
         $SUDO_TO_VBOX_TEMP VBoxManage createvm --name "$VMNAME" --register
         $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --ostype Debian_64
         ;;
      arm64)
         $SUDO_TO_VBOX_TEMP VBoxManage createvm --name "$VMNAME" --platform-architecture arm --register
         $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --ostype Debian_arm64
         ## ARM has no legacy BIOS; boot via EFI.
         $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --firmware efi
         ;;
      *)
         error "Unsupported dist_build_target_arch '$dist_build_target_arch' for VirtualBox VM creation."
         ;;
   esac

   ## SATA AHCI is VirtualBox's default for VMs created using the VirtualBox
   ## graphical user interface (GUI) for Debian 64-bit VMs.
   ##
   ## No longer using `--add sas`, because:
   ## https://forums.whonix.org/t/whonix-virtualbox-failed-to-start-ns-error-failure-0x80004005-the-vm-session-was-aborted/11471
   ## Related:
   ## - https://github.com/Whonix/Whonix/issues/274
   ## - https://www.virtualbox.org/ticket/10031
   ## - https://www.whonix.org/wiki/VirtualBox/Troubleshooting#Failed_to_open_a_session_for_the_virtual_machine
   ##
   ## `--name` is mandatory by `$SUDO_TO_VBOX_TEMP VBoxManage`.
   ## `--name "controller"` is arbitrary. VirtualBox default for VMs created
   ## by VirtualBox GUI would be "Controller: SATA". Keeping it generic to
   ## simplify maybe required later manual user changes.
   $SUDO_TO_VBOX_TEMP VBoxManage storagectl "$VMNAME" --add sata --name "controller"

   ## Only 4 sata ports instead of 30. Speeds up booting.
   $SUDO_TO_VBOX_TEMP VBoxManage storagectl "$VMNAME" --name "controller" --portcount 4

   ## HDD gets added in the gateway / workstation specific functions below.

   ## Attach the HDD.
   $SUDO_TO_VBOX_TEMP VBoxManage storageattach "$VMNAME" --storagectl "controller" --nonrotational=on --discard=on --type hdd --port 0 --medium "$vdi_file"

   ## RAM
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --memory "$VMRAM"

   ## Settings->Display->Video Memory
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --vram "$VRAM"

   ## Enable PAE. x86-only feature.
   if [ ! "$dist_build_target_arch" = "arm64" ]; then
      $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --x86-pae on
   fi

   ## 3 virtual CPU cores by default.
   ## No longer 4 virtual CPU cores by default.
   ## https://www.virtualbox.org/ticket/19500
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --cpus 3

   ## Restrict Boot devices
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --boot4 none
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --boot3 none
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --boot2 none
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --boot1 disk

   ## Hide hosts CPU info. This does not have a GUI option.
   ## Was removed from VirtualBox.
   ## https://phabricator.whonix.org/T408
   #$SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --synthcpu on

   ## Quote VirtualBox documentation:
   ##
   ## "[...] Advanced Configuration and Power Interface (ACPI) which VirtualBox
   ## presents to the guest operating system by default. ACPI is the current
   ## industry standard to allow operating systems to recognize hardware,
   ## configure motherboards and other devices and manage power. As all modern
   ## PCs contain this feature and Windows and Linux have been supporting it
   ## for years, it is also enabled by default in VirtualBox. [...]"
   ##
   ## Conclusion: The linux kernel is better tested with ACPI enabled
   ## rather than ACPI disabled.
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --acpi on

   ## VirtualBox documentation can be found on:
   ## https://www.virtualbox.org/manual/ch03.html
   ##
   ## Quote VirtualBox documentation:
   ## "[...] Enabling the I/O APIC is required for 64-bit guest operating
   ## systems, especially Windows Vista; it is also required if you want to use
   ## more than one virtual CPU in a virtual machine. [...]"
   ##
   ## Conclusion: it is better to leave it enabled to avoid support requests by
   ## users who wish to use more than one virtual CPU, or create their own
   ## Custom-Whonix-Workstation.
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --ioapic on

   ## Set system clock of VM to UTC.
   ## When VirtualBox starts it looks up date and time of the host, i.e. "JAN 15 2012 00:00:00"
   ## and sets the VM clock to that date and time. The following option translates the date
   ## and time to UTC, thus hiding the hosts timezone from the guest.
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --rtcuseutc on

   ## Deactivate time synchronization between host and VMs.
   ## This is documented in Whonix Design on TimeSync page
   ## Thanks to
   ## http://www.braingia.org/webnotes/2011/06/22/disable-time-sync-with-virtualbox/
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" "VBoxInternal/Devices/VMMDev/0/Config/GetHostTimeDisabled" "1"

   ## Clipboard sharing.
   ## https://www.whonix.org/wiki/VirtualBox_Guest_Additions#Clipboard_Sharing
   ## Disabled due to security concerns.
   #$SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --clipboard-mode bidirectional
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --clipboard-mode disabled

   ## Drag 'n Drop
   ## Disabled due to usability issues. Causes "Drag and Drop operation
   ## failed" popups if the user is dragging something within the VM and the
   ## mouse pointer accidentally leaves the VM window.
   #$SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --draganddrop hosttoguest
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --draganddrop disabled

   ## Disable microphones.
   ## https://www.whonix.org/wiki/Hardware_Threat_Minimization#Microphones
   ## was: --audioin off
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --audio-in=off

   ## equivalent to:
   ## VirtualBox -> click a VM -> Settings -> Display -> Graphics Controller -> VMSVGA -> OK
   ##
   ## Quote https://www.virtualbox.org/manual/ch03.html
   ## > "VMSVGA: Use this graphics controller to emulate a VMware SVGA graphics device."
   ## > "This is the default graphics controller for Linux guests."
   ##
   ## - Has better desktop resolution in CLI (virtual terminal) mode.
   ## - functional VirtualBox VM Window -> View -> Virtual Screen 1 -> resize to resolution
   ## - functional VirtualBox VM Window -> View -> Adjust Window Size
   ##
   ## Broken for some users?
   ## https://forums.whonix.org/t/black-screen-on-15-0-0-6-6-and-15-0-0-7-1/8554
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --graphicscontroller vmsvga

   ## Debugging.
   $SUDO_TO_VBOX_TEMP VBoxManage getextradata "$VMNAME"

   ## Quote https://www.virtualbox.org/manual/ch09.html#max-resolution-guests
   ##
   ## > "Configuring the Maximum Resolution of Guests When Using the Graphical Frontend"
   ##
   ## > "When guest systems with the Guest Additions installed are started using the graphical frontend, the normal Oracle VM VirtualBox application, they will not be allowed to use screen resolutions greater than the host's screen size unless the user manually resizes them by dragging the window, switching to full screen or seamless mode or sending a video mode hint using $SUDO_TO_VBOX_TEMP VBoxManage. This behavior is what most users will want, but if you have different needs, you can change it by issuing one of the following commands from the command line:"
   ##
   ## In conclusion, by VirtualBox default the VM screen resolution will not be higher than the
   ## host's screen size. Therefore set to "standard screen resolution 1920x1080".
   ## https://forums.whonix.org/t/consider-making-screen-resolution-1920x1080-by-default-for-all-vms/9143
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" GUI/LastGuestSizeHint "1920, 1080"

   ## Debugging.
   $SUDO_TO_VBOX_TEMP VBoxManage getextradata "$VMNAME"
}

spectre_meltdown_defenses() {
   ## This code is currently not in use! Reasons:
   ## https://www.whonix.org/wiki/Spectre_Meltdown#VirtualBox

   ## https://www.virtualbox.org/manual/ch08.html
   ## > "--ibpb-on-vm-[enter|exit] on|off: Enables flushing of the indirect branch prediction buffers on every VM enter or exit respectively. This could be enabled by users overly worried about possible spectre attacks by the VM. Please note that these options may have sever impact on performance."
   ##
   ## There is a mistake in VirtualBox manual saying 'enter' which does not work. It's 'entry'.
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --ibpb-on-vm-entry on
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --ibpb-on-vm-exit on

   ## https://www.virtualbox.org/manual/ch08.html
   ## > "--l1d-flush-on-vm-enter on|off: Enables flushing of the level 1 data cache on VM enter. See Section 13.4.1, "CVE-2018-3646"."
   ##
   ## There is a mistake in VirtualBox manual saying 'enter' which does not work. It's 'entry'.
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --l1d-flush-on-vm-entry on

   ## https://www.virtualbox.org/manual/ch08.html
   ## > "--l1d-flush-on-sched on|off: Enables flushing of the level 1 data cache on scheduling EMT for guest execution. See Section 13.4.1, "[https://www.virtualbox.org/manual/ch13.html#sec-rec-cve-2018-3646 CVE-2018-3646]"."
   ## https://www.virtualbox.org/manual/ch13.html#sec-rec-cve-2018-3646
   ## > "For users not concerned by this security issue, the default mitigation can be disabled using
   ##    $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --l1d-flush-on-sched off"
   ## Since we want to enable the security feature we set '--l1d-flush-on-sched on'.
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --l1d-flush-on-sched on

   ## https://www.virtualbox.org/manual/ch08.html
   ## > "--spec-ctrl on|off: This setting enables/disables exposing speculation control interfaces to the guest, provided they are available on the host. Depending on the host CPU and workload, enabling speculation control may significantly reduce performance."
   ## According to https://www.virtualbox.org/ticket/17987 '--spec-ctrl' should be set to 'on'.
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --spec-ctrl on

   ## https://www.virtualbox.org/manual/ch08.html
   ## > "--nestedpaging on|off: If hardware virtualization is enabled, this additional setting enables or disables the use of the nested paging feature in the processor of your host system; see Section 10.7, "Nested paging and VPIDs" and Section 13.4.1, "CVE-2018-3646"."
   ## https://www.virtualbox.org/manual/ch13.html#sec-rec-cve-2018-3646
   ## > "13.4.1. CVE-2018-3646"
   ##
   ## > "This security issue affects a range of Intel CPUs with nested paging. AMD CPUs are expected not to be impacted (pending direct confirmation by AMD). Also the issue does not affect VMs running with hardware virtualization disabled or with nested paging disabled."
   ##
   ## > "For more information about nested paging, see Section 10.7, "Nested paging and VPIDs"."
   ##
   ## > "Mitigation options:"
   ## > "13.4.1.1. Disable nested paging"
   ##
   ## > "By disabling nested paging (EPT), the VMM will construct page tables shadowing the ones in the guest. It is no possible for the guest to insert anything fishy into the page tables, since the VMM carefully validates each entry before shadowing it."
   ##
   ## > "As a side effect of disabling nested paging, several CPU features will not be made available to the guest. Among these features are AVX, AVX2, XSAVE, AESNI, and POPCNT. Not all guests may be able to cope with dropping these features after installation. Also, for some guests, especially in SMP configurations, there could be stability issues arising from disabling nested paging. Finally, some workloads may experience a performance degradation."
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --nestedpaging off
}

hardware_obfuscation() {
   # This code is no longer in use!
   # remove attempts to hide CPU information from VM in VirtualBox
   # https://phabricator.whonix.org/T881
   # It could be enabled through an optional build option if there is interest.

   # Thanks to dumbmouse contributing this!
   # https://phabricator.whonix.org/T408#11595

   # Clear existing (not necessary for initial install)
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --cpuidremoveall

   # GenuineIntel
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/00000000/ebx 0x756e6547
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/00000000/ecx 0x6c65746e
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/00000000/edx 0x49656e69
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000000/ebx 0x756e6547
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000000/ecx 0x6c65746e
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000000/edx 0x49656e69

   # Model/Family/Stepping
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/00000001/eax 0x00000f43
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000001/eax 0x00000f43

   # Pentium model name
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000002/eax 0x20202020
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000002/ebx 0x20202020
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000002/ecx 0x20202020
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000002/edx 0x6e492020
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000003/eax 0x286c6574
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000003/ebx 0x50202952
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000003/ecx 0x69746e65
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000003/edx 0x52286d75
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000004/eax 0x20342029
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000004/ebx 0x20555043
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000004/ecx 0x30302e33
   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" VBoxInternal/CPUM/HostCPUID/80000004/edx 0x007a4847
}

whonix-gateway_specific() {
   ## Disable Audio
   ## was: --audio none
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --audio-driver=none
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --audio-enabled=off

   ## Leave Adapter 1 as NAT.
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --nic1 nat

   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --cableconnected1 on

   ## Enable Adapter 2, set to "Internal Network".
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --nic2 intnet

   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --cableconnected2 on

   ## Change the internal network to "Whonix", IMPORTANT!
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --intnet2 "Whonix"
}

whonix-workstation_specific() {
   ## Add Adapter 1, an internal network, IMPORTANT!
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --nic1 intnet

   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --cableconnected1 on

   ## Change the internal network to "Whonix", IMPORTANT!
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --intnet1 "Whonix"
}

whonix-custom-workstation_specific() {
   whonix-workstation_specific

   ## Only for Whonix-Custom-Workstation.
   ## https://forums.whonix.org/t/no-longer-add-virtual-dvd-drive-to-vm-by-default/9337

   ## Add DVD.
   $SUDO_TO_VBOX_TEMP VBoxManage storageattach "$VMNAME" --storagectl "controller" --type dvddrive --port 1 --medium emptydrive

   $SUDO_TO_VBOX_TEMP VBoxManage setextradata "$VMNAME" "GUI/FirstRun" "yes"
}

debian_specific() {
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --nic1 nat

   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --cableconnected1 on
}

audio_enable() {
   ## Enable audio controller.
   ## https://www.kicksecure.com/wiki/Dev/audio
   ##
   ## sb16:
   ## Obsolete.
   ##
   ## ac97:
   ## Older. Issues have been reported:
   ## https://forums.whonix.org/t/choppy-sound-on-workstation-change-virtualbox-audio-settings-to-virtualbox-defaults-ac97-versus-intel-hd/17876
   ## But overall was still better than Intel HD in combination with PipeWire.
   ##
   ## hda:
   ## Completely broken in combination with PipeWire.
   ## https://forums.whonix.org/t/virtualbox-intel-hd-audio-and-pipewire-incompatibility-audio-broken-after-increasing-ram-to-5-gb-no-sound-after-latest-updates-pipewire-bug/18211
   ## https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4263
   #$SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --audio-controller=hda
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --audio-controller=ac97

   ## Host audio driver can be oss, alsa or pulse.
   ## Unfortunately, no auto detection available.
   ## Depends on host driver.
   ## Ubuntu host uses pulse audio.
   #$SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --audio-driver=pulse

   ## Activate audio output.
   ## According to the manual but does not actually do anything.
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --audio-enabled=on
   ## Undocumented but functional.
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --audioout on
}

dns_specific() {
   ## https://serverfault.com/questions/453185/vagrant-virtualbox-dns-10-0-2-3-not-working

   ## Prevents leaking DNS info from the host into the guest.
   ## Also useful in other cases.
   ## https://www.virtualbox.org/manual/ch09.html#nat-adv-dns
   ##
   ## '--natdnsproxy1 on' might cause issues:
   ## https://forums.virtualbox.org/viewtopic.php?f=6&t=94671&p=457620#p457620
   ##
   ## Probably not both required 'natdnsproxy1 on' and 'natdnshostresolver1 on'.
   ##
   ## Both enabled at the same time causes an error in VirtualBox VM log:
   ## 00:00:00.933430 NAT: Host Resolver conflicts with DNS proxy, the last one was forcely ignored
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --natdnsproxy1 off

   ## Prevents leaking DNS info from the host into the guest.
   ## Also useful in other cases.
   ## https://www.virtualbox.org/manual/ch09.html#nat_host_resolver_proxy
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --natdnshostresolver1 on

   ## Do not pass the domain name for network name resolution to the VM.
   $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --natdnspassdomain1 off
}

debugging_post() {
   $SUDO_TO_VBOX_TEMP VBoxManage showvminfo "$VMNAME"
   $SUDO_TO_VBOX_TEMP VBoxManage getextradata "$VMNAME"
}

main() {
   if [ ! "${dist_build_virtualbox:-}" = "true" ]; then
      printf '%s\n' "INFO: Skipping ${BASH_SOURCE[0]}, because dist_build_virtualbox is not set to 'true'."
      return 0
   fi

   setup_vbox_temp_sudo

   debugging_pre

   delete_vbox_vm

   convert_raw_to_vdi

   general_setup

   ## Possibly not worth it due to huge performance penalty and unclear security benefits. Despite:
   ##
   ##     host microcode upgrade
   ##     host kernel upgrade
   ##     VM kernel upgrade
   ##     spectre-meltdown-checker on the host showing "not vulnerable"
   ##     latest VirtualBox version
   ##     all spectre/meltdown related VirtualBox settings tuned for better security as documented below
   ##
   ## VirtualBox is likely still vulnerable to spectre/meltdown. For reference see VirtualBox bug report / forum discussion.
   ## https://www.whonix.org/wiki/Spectre_Meltdown#VirtualBox
   ## https://www.virtualbox.org/ticket/17987
   ## https://forums.virtualbox.org/viewtopic.php?f=7&t=89395
   ## https://forums.whonix.org/t/whonix-vulerable-due-to-missing-processor-microcode-packages/5739/22
   #spectre_meltdown_defenses

   if [ "${dist_build_type_long:-}" = "gateway" ]; then
      whonix-gateway_specific
      dns_specific
      ## For screen reader support.
      audio_enable
   elif [ "${dist_build_type_long:-}" = "workstation" ]; then
      whonix-workstation_specific
      audio_enable
   elif [ "${dist_build_type_long:-}" = "custom-workstation" ]; then
      whonix-custom-workstation_specific
      audio_enable
   elif [ "${dist_build_type_long:-}" = "whonix-host" ]; then
      debian_specific
      dns_specific
      audio_enable
   elif [ "${dist_build_type_short:-}" = "kicksecure" ]; then
      debian_specific
      audio_enable
   else
      error "Invalid dist_build_flavor '${dist_build_flavor:-}'. Please report this bug!"
   fi

   debugging_post

   ## Safe disk space.
   ## Delete temporary VM in temporary VM user build folder to save disk space
   ## during the build process.
   ## Out-commented.
   ## NOTE: Not possible at this time. The VM will be exported in later step
   ##       prepare-release.
   #delete_vbox_vm

   if [ "${dist_build_raw:-}" = "true" ]; then
      printf '%s\n' "INFO: Skip deletion of raw image because using dist_build_raw=true."
   else
      ## Safe disk space.
      ## Delete no longer needed raw image to save disk space during the build process.
      ## The raw image is bind-mounted from the host, so deleting it from
      ## inside the chroot deletes it on the host too (intentional: matches
      ## the previous host-side behavior).
      $SUDO_TO_ROOT safe-rm -f -- "$binary_image_raw_file"
   fi

   sync
}

main "$@"
