| Title: Some OpenBSD features that aren't widely known | |
| Author: Solène | |
| Date: 20 February 2024 | |
| Tags: openbsd unix | |
| Description: In this article, you will learn about some OpenBSD | |
| features you may not know about | |
| # Introduction | |
| In this blog post, you will learn about some OpenBSD features that can | |
| be useful, but not widespread. | |
| They often have a niche usage, but it's important to know they exist to | |
| prevent you from reinventing the wheel :) | |
| OpenBSD official project website | |
| # Features | |
| The following list of features are not all OpenBSD specific as some can | |
| be found on other BSD systems. Most of the knowledge will not be | |
| useful to Linux users. | |
| ## Secure level | |
| The secure level is a sysctl named `kern.securelevel`, it has 4 | |
| different values from level -1 to level 2, and it's only possible to | |
| increase the level. By default, the system enters the secure level 1 | |
| when in multi-user (the default when booting a regular installation). | |
| It's then possible to escalate to the last secure level (2), which will | |
| enable the following extra security: | |
| * all raw disks are read-only, so it's not possible to try to make a | |
| change to the storage devices | |
| * the time is almost lock, it's only possible to modify the clock | |
| slowly by small steps (maybe 1 second max every so often) | |
| * the PF firewall rules can't be modified, flushed or altered | |
| This feature is mostly useful for dedicated firewall with rules that | |
| rarely change. Preventing the time to change is really useful for | |
| remote logging as it allows being sure of "when" things happened, and | |
| you can be assured the past logs weren't modified. | |
| The default security level 1 already enable some extra security like | |
| "immutable" and "append-only" file flags can't be removed, these | |
| overlooked flags (that can be applied with chflags) can lock down files | |
| to prevent anyone from modifying them. The append-only flag is really | |
| useful for logs because you can't modify the content, but this doesn't | |
| prevent adding new content, history can't be modified this way. | |
| OpenBSD manual pages: securelevel | |
| OpenBSD manual pages: chflags | |
| This feature exists in other BSD systems. | |
| ## Memory allocator extra checks | |
| OpenBSD's memory allocator can be tweaked, system-wide or per command, | |
| to add extra checks. This could be either used for security reasons or | |
| to look for memory allocation related bugs in a program (this is VERY | |
| common...). | |
| There are two methods to apply the changes: | |
| * system-wide by using the sysctl `vm.malloc_conf`, either immediately | |
| with the sysctl command, or at boot in `/etc/sysctl.conf` (make sure | |
| you quote its value there, some characters such as `>` will create | |
| troubles otherwise, been there...) | |
| * on the command line by prepending `env MALLOC_OPTIONS="flags" | |
| program_to_run` | |
| The man page gives a list of flags to use as option, the easiest to use | |
| is `S` (for security checks). It is stated in the man page that a | |
| program misbehaving with any flag other than X is buggy, so it's not | |
| YOUR fault if you use malloc options and the program is crashing | |
| (except if you wrote the code ;-) ). | |
| OpenBSD manual pages: malloc (search for MALLOC OPTIONS) | |
| ## File flags | |
| You are certainly used to files attributes like permissions or | |
| ownership, but on many file systems (including OpenBSD ffs), there are | |
| flags as well! | |
| The file flags can be altered with the command `chflags`, there are a | |
| couple of flags available: | |
| * nodump: prevent the files from being saved by the command `dump` | |
| (except if you use a flag in dump to bypass this) | |
| * sappnd: the file can only be used in writing append mode, only root | |
| can set / remove this flag | |
| * schg: the file can not be change, it becomes immutable, only root can | |
| alter this flag | |
| * uappnd: same as sappnd mode but the user can alter the flag | |
| * uchg: same as schg mode but the user can alter the flag | |
| As explained in the secure level section above, in the secure level 1 | |
| (default !), the flags sappnd and schg can't be removed, you would need | |
| to boot in single user mode to remove these flags. | |
| Tip: remove the flags on a file with `chflags 0 file [...]` | |
| You can check the flags on files using `ls -ol`, this would look like | |
| this: | |
| ``` | |
| terra$ chflags uchg get_extra_users.sh | |
| terra$ ls -lo get_extra_users.sh | |
| -rwxr-xr-x 1 solene solene uchg 749 Apr 3 2023 get_extra_users.sh | |
| terra$ chflags 0 get_extra_users.sh | |
| terra$ ls -lo get_extra_users.sh | |
| -rwxr-xr-x 1 solene solene - 749 Apr 3 2023 get_extra_users.sh | |
| ``` | |
| OpenBSD manual pages: chflags | |
| ## Crontab extra parameters | |
| OpenBSD crontab format received a few neat additions over the last | |
| years. | |
| * random number for time field: you can use `~` in a field instead of a | |
| number or `*` to generate a random value that will remain stable until | |
| the crontab is reloaded. Things like `~/5` work. You can force the | |
| random value within a range with `20~40` to get values between 20 and | |
| 40. | |
| * only send an email if the return code isn't 0 for the cron job: add | |
| `-n` between the time and the command, like in `0 * * * * -n | |
| /bin/something`. | |
| * only run one instance of a job at a time: add `-s` between the time | |
| and the command, like in `* * * * * -s /bin/something`. This is | |
| incredibly useful for cron job that shouldn't be running twice in | |
| parallel, if the job duration is longer than usual, you are ensured it | |
| will never start a new instance until the previous one is done. | |
| * no logging: add `-q` between the time and the command, like in `* * * | |
| * -q /bin/something`, the effect will be that this cron job will not be | |
| logged in `/var/cron/log`. | |
| It's possible to use a combination of flags like `-ns`. The random | |
| time is useful when you have multiple systems, and you don't want them | |
| to all run a command at the same time, like in a case they would | |
| trigger a huge I/O on a remote server. This was created to prevent the | |
| usual `0 * * * * sleep $(( $RANDOM % 3600 )) && something` that would | |
| run a sleep command for a random time up to an hour before running a | |
| command. | |
| OpenBSD manual pages: crontab | |
| ## Auto installing media | |
| One cool feature on OpenBSD is the ability to easily create an | |
| installation media with pre-configured answers. This is done by | |
| injecting a specific file in the `bsd.rd` install kernel. | |
| There is a simple tool named upobsd that was created by semarie@ to | |
| easily modify such bsd.rd file to include the autoinstall file, I | |
| forked the project to continue its maintenance. | |
| In addition to automatically installing OpenBSD with users, ssh | |
| configuration, sets to install etc... it's also possible to add a | |
| site.tgz archive along with the usual sets archives that includes files | |
| you want to add to the system, this can include a script to run at | |
| first boot to trigger some automation! | |
| These features are a must-have if you run OpenBSD in production, and | |
| you have many of them to manage, enrolling a new device to the fleet | |
| should be automated as possible. | |
| GitHub project page: upobsd | |
| OpenBSD manual pages: autoinstall | |
| ## apmd daemon hooks | |
| Apmd is certainly running on most OpenBSD laptop and desktop around, | |
| but it has features that aren't related to its command line flags, so | |
| you may have missed them. | |
| There are different file names that can contain a script to be run upon | |
| some event such as suspend, resume, hibernate etc... | |
| A classic usage is to run `xlock` in one's X session on suspend, so the | |
| system will require a password on resume. | |
| Older blog post: xlock from apmd suspend script | |
| The man page explains all, but basically this works like this for | |
| running a backup program when you connect your laptop to the power | |
| plug: | |
| ```shell | |
| # mkdir -p /etc/apm | |
| # vi /etc/apm/powerup | |
| ``` | |
| You need to write a regular script: | |
| ```shell | |
| #!/bin/sh | |
| /usr/local/bin/my_backup_script | |
| ``` | |
| Then, make it executable | |
| ```shell | |
| # chmod +x /etc/apm/powerup | |
| ``` | |
| The daemon apmd will automatically run this script when you connect a | |
| system back to AC power. | |
| The method is the same for: | |
| * hibernate | |
| * resume | |
| * suspend | |
| * standby | |
| * hibernate | |
| * powerup | |
| * powerdown | |
| This makes it very easy to schedule tasks on such events. | |
| OpenBSD manual page: apmd (section FILES) | |
| ## Using hotplugd for hooks on devices events | |
| A bit similar to what apmd by running a script upon events, hotplugd is | |
| a service that allow running a script when a device is added / removed. | |
| A typical use is to automatically mount an USB memory stick when | |
| plugged in the system, or start cups daemon when powering on your USB | |
| printer. | |
| The script receives two parameters that represents the device class and | |
| device name, so you can use them in your script to know what was | |
| connected. The example provided in the man page is a good starting | |
| point. | |
| The scripts aren't really straightforward to write, you need to make a | |
| precise list of hardware you expect and what to run for each, and don't | |
| forget to skip unknown hardware. Don't forget to make the scripts | |
| executable, otherwise it won't work. | |
| OpenBSD manual page: hotplugd | |
| ## Altroot | |
| Finally, there is a feature that looks pretty cool. In the daily | |
| script, if an OpenBSD partition `/altroot/` exists in `/etc/fstab` and | |
| the daily script environment has a variable `ROOTBACKUP=1`, the root | |
| partition will be duplicated to it. This permit keeping an extra root | |
| partition in sync with the main root partition. Obviously, it's more | |
| useful if the altroot partition is on another drive. The duplication | |
| is done with `dd`. You can look at the exact code by checking the | |
| script `/etc/daily`. | |
| However, it's not clear how to boot from this partition if you didn't | |
| install a bootloader or created an EFI partition on the disk... | |
| OpenBSD manual pages: hier (hier stands for file system hierarchy) | |
| OpenBSD manual pages: daily | |
| OpenBSD FAQ: Root partition backup | |
| ## talk: local chat in the terminal | |
| OpenBSD comes with a program named "talk", this creates a 1 to 1 chat | |
| with another user, either on the local system or a remote one (setup is | |
| more complicated). This is not asynchronous, the two users must be | |
| logged in the system to use `talk`. | |
| This program isn't OpenBSD specific and can be used on Linux as well, | |
| but it's so fun, effective and easy to setup I wanted to write about | |
| it. | |
| The setup is easy: | |
| ```shell | |
| # echo "ntalk dgram udp wait root /u… | |
| # rcctl enable inetd | |
| # rcctl start inetd | |
| ``` | |
| The communication happens on localhost on UDP ports 517 and 518, don't | |
| open them to the Internet! If you want to allow a remote system, use a | |
| VPN to encrypt the traffic and allow ports 517/518 only for the VPN. | |
| The usage is simple, if you want alice and bob to talk to each other: | |
| * alice type `talk bob`, and bob must be logged in as well | |
| * bob receives a message in their terminal that alice wants to talk | |
| * bob type `talk alice` | |
| * a terminal UI appears for both users, what they write will appear on | |
| the top half of the UI, and the messages from recipient will appear on | |
| the half bottom | |
| This is a bit archaic, but it works fine and comes with the base | |
| system. It does the job when you just want to speak to someone. | |
| # Conclusion | |
| There are interesting features on OpenBSD that I wanted to highlight a | |
| bit, maybe you will find them useful. If you know cool features that | |
| could be added to this list, please reach me! |