Introduction

This post assumes an x86_64 system running FreeBSD 14.0-RELEASE-p4, which was the latest as of writing. These options may vary depending on system architecture (x86_64, ARM, etc…) and/or FreeBSD version.

Basic Hardening Options

During installation, the installer presents a few hardening options. After installation, if you want to check what those installation hardening options are, look at the file at /usr/libexec/bsdinstall/hardening. This can be helpful if you didn’t select some or all of the options and want to see what they would’ve done so you can add them later.

We’re going to be adding a few additional options that are not presented during installation.

The descriptions for each sysctl option can be gotten by running sysctl -d [sysctl_name].

/etc/sysctl.conf

Example:

security.bsd.see_other_uids=0
security.bsd.see_other_gids=0
security.bsd.hardlink_check_uid=1
security.bsd.hardlink_check_gid=1
security.bsd.see_jail_proc=0
security.bsd.unprivileged_read_msgbuf=0
security.bsd.unprivileged_proc_debug=0
security.bsd.allow_ptrace=0
kern.randompid=1
kern.elf32.allow_wx=0
kern.elf64.allow_wx=0

Breakdown:

  • security.bsd.see_other_uids=0 and security.bsd.see_other_gids=0
    • Prevent unprivileged processes from seeing subjects/objects with different real uid/gid.
    • For example, unprivileged user deku won’t be able to see bakugo’s processes.
  • security.bsd.hardlink_check_uid=1 and security.bsd.hardlink_check_gid=1
    • Prevent unprivileged processes from creating hard links to files owned by other users/groups.
    • For example, unprivileged user deku won’t be able to create a hardlink to a file owned by bakugo.
  • security.bsd.see_jail_proc=0
    • Prevent unprivileged processes from seeing subjects/objects with different jail ids.
    • For example, unprivileged user deku won’t be able to see processes running in another jail.
  • security.bsd.unprivileged_read_msgbuf=0
    • Prevent unprivileged processes from reading the kernel message buffer.
    • For example, unprivileged user deku won’t be able to see the kernel message buffer by running dmesg.
  • security.bsd.unprivileged_proc_debug=0
    • Prevent unprivileged processes from using process debugging facilities.
  • security.bsd.allow_ptrace=0
    • Prevent usage of ptrace(2).
  • kern.randompid=1
    • Use random PIDs, setting this to 1 chooses a random PID modulus for you.
    • Some say this option may result in an increased chance of PID reuse, or that it might not really help security.
    • Random PIDs are used by default in OpenBSD. 1
    • It doesn’t really hurt to enable, and there theoretically are security benefits to enabling it.
  • kern.elf32.allow_wx=0 and kern.elf64.allow_wx=0
    • WARNING: May break some programs! If some programs don’t work correctly, try removing/commenting out these values.
    • Prevents pages from being mapped simultaneously writable and executable for ELF64 and ELF32 binaries.

/boot/loader.conf

Example:

security.bsd.allow_destructive_dtrace=0
cpu_microcode_load="YES"
cpu_microcode_name="/boot/firmware/intel-ucode.bin"

Breakdown:

  • security.bsd.allow_destructive_dtrace=0
    • One of the options in the FreeBSD installer.
    • Prevents destructive use of dtrace.
  • cpu_microcode_load="YES" and cpu_microcode_name="/boot/firmware/[intel/amd]-ucode.bin"
    • Load updated CPU microcode. This loading happens early so the kernel can make use of new features.
    • Updated microcode often contains mitigations for vulnerabilities, and/or fixes for errata. You should keep the system firmware (UEFI) up to date as it usually contains updated microcode, but sometimes the system vendor takes too long or stops providing firmware updates entirely.
    • Install either the cpu-microcode-intel or cpu-microcode-amd package depending on your CPU. It will place the microcode files in /boot/firmware/.
    • Choose one of /boot/firmware/intel-ucode.bin or /boot/firmware/amd-ucode.bin depending on CPU.

/etc/rc.conf

Example:

clear_tmp_enable="YES"
syslogd_flags="-ss"
kern_securelevel_enable="YES"
kern_securelevel="3"
#kld_list="nullfs if_epair fdescfs" #use if needed

Breakdown:

  • clear_tmp_enable="YES"
    • Clears the /tmp/ directory on startup. Helps clean up in case sensitive files were accidentally left behind.
  • syslogd_flags="-ss"
    • Secure syslogd so it doesn’t open network sockets. This will disable remote syslog.
  • sendmail_enable="NONE"
    • Disable sendmail. Disabling this means you won’t get mail from tasks run by periodic for example, but usually this isn’t wanted anyway.
    • Note: FreeBSD 14.0 replaced sendmail with dma as the system default. 2
  • kern_securelevel_enable="YES" and kern_securelevel="[level]"
    • WARNING: This may break some programs, as well as be quite invasive to general system use/maintenance.
      • smartctl from the smartmontools package isn’t useful when securelevel is 2 or higher.
      • System updates using freebsd-update cannot be installed when securelevel is enabled. Disable securelevel and reboot before installing updates, then re-enable and reboot afterwards.
      • Kernel modules cannot be loaded or unloaded, first check which kernel modules your system loads when running all the software you use and specify them in kld_list="module1 module2 etc..." before enabling securelevel. For example, check the output of kldstat on a fresh boot with nothing running, then start all your software and check the output again. In a case with VNET jails, you might need nullfs if_epair fdescfs.
    • Enable kernel securelevel feature and set the securelevel.
    • Check security(7) using man security for valid securelevels and how tight each of them are.

Vulnerability Mitigations

Depending on the system, FreeBSD enables certain mitigations. You can check these mitigations using sysctl machdep.mitigations. Note that enabling most of these options will negatively impact system performance.

Another mitigation exists called Page Table Isolation (PTI) under the sysctl vm.pmap.pti. This may be enabled by default but can come at a heavy performance cost depending on the system. If you want to set this option, it must be set in /boot/loader.conf as it cannot be set during runtime.

Choosing whether to enable or disable mitigations is up to you. You may want to selectively enable mitigations depending on which ones are needed for your system, taking the performance impact into consideration. The package spectre-meltdown-checker may be useful to determine this.

On a Xeon X3460 (Lynnfield) system, leaving vm.pmap.pti enabled (set to 1) reduces the score of Unixbench from ~2800 to ~2300. Enabling all the mitigations by setting the appropriate sysctl options under machdep.mitigations reduces the score further to just ~1100 for a whopping 60% decrease from the original performance! Real world applications may not be impacted as heavily as benchmarks, but the slowdown is very noticable on this system. More modern systems won’t be impacted as badly, and updated microcode can perform more efficient mitigations in some cases.

Conclusion

This basic hardening is just one way to increase security. Installing and running only what you need, using a firewall, using secure configurations for programs and staying up to date with security fixes are important ways to improve security.

Make smart decisions when setting up software. For example, when setting up a reverse proxy server for a website, consider securing the communication between the reverse proxy and the backend servers with TLS and/or using VLANs, or using UNIX Domain Sockets with tight permissions instead of just leaving it all out in the open. Think about file permissions, don’t leave things like private keys with 777 permissions lying around. Errors like this can have more impact and be more important than any of the system hardening done in this post. Stay alert! Keep security in mind, and stay safe.