“File flags, secure level two, extra VTs, and colour on the console!”
Jay shows us some interesting and underused features of OpenBSD
Reckless Guide
Part 10
In this final part of the series, Jay shows us some rarely used features of OpenBSD and explains how we can put them to work.
This article is part of a series - check out the index.
Website themes
The Exotic Silicon website is available in ten themes, but you haven't chosen one yet!
Underused features - introduction
Knowledge of rarely used and mysterious under-documented features can give you a competitive edge.
As well as endless hours of fun fixing the systems of people who thought that they understood the undocumented features, put them to work on production systems, and then subsequently realised that they actually didn't understand them.
File flags
Files on an FFS filesystem include a set of flags that can be set to make them read-only, or append-only, and to exclude them from certain backups.
Unlike regular file permissions set by ‘chmod’, which are ignored by the root user, some file flags do apply even when accessing files as root.
This makes them useful for preventing accidental erasure or overwriting of system files by operator error.
Manipulation of file flags can be done using the ‘chflags’ utility in /usr/bin/chflags. This is actually a symbolic link to /bin/chmod, as the source code for chmod in /usr/src/bin/chmod/chmod.c implements the functionality of chmod, chown, and chflags. In fact, /sbin/chown is just a hard link to /bin/chmod.
Technically, the flags are stored as a 32-bit value and those bits are defined in /usr/src/sys/sys/stat.h. Only a few of the 32 bits are actually used, as there are currently only seven flags available. Four of these, (those in the lower 16 bits), can be modified by the owner of the file as well as by root. The other flags, (in the upper 16 bits), are only modifyable by root, and furthermore, the two flags to make files read-only, (the immutable flag), and append-only, usually require the system to be booted into single user mode in order to reset them once they have been set.
If we have a well-tested and known good custom kernel image stored in /bsd.works, we can make use of the schg flag, (the system immutable flag), to avoid overwriting it unintentionally:
# chflags schg /bsd.works
# rm /bsd.works
rm: /bsd.works: Operation not permitted
Protect your kernel image!
With this flag in place, fat finger problems are, (hopefully), a thing of the past!
Attempting to remove the schg flag whilst the sysctl kern.securelevel is set to 1 or above, which is usually the case when running multiuser, fails:
# chflags noschg /bsd.works
chflags: /bsd.works: Operation not permitted
Instead, to remove the flag we need to boot into single user mode, which can be done by entering ‘boot -s’ at the boot prompt:
boot> boot -s
Enter pathname of shell or RETURN for sh:
Entering single user mode, where we can reset the system file flags
At this point, only the root filesystem is mounted, and it's mounted read-only. To access /usr/bin/chflags we need to mount /usr, and to actually update the flags on /bsd.works, we need to remount the root filesystem with read-write access:
# mount -oro /usr
# mount -u -orw /
# chflags noschg /bsd.works
Once in single user mode, after mounting /usr and re-mounting the root filesystem read-write we can finally remove the schg file flag from /bsd.works
Setting the sappnd flag, (system append-only flag), on a directory allows existing files in that directory to be modified, as well as allowing new files to be created, but prevents files from being deleted, (unlinked), or renamed. They can, however, still be truncated to zero size.
If you have an external hard disk that you use for archiving old files that won't change, (rather than regular backups of work in progress), then the use of either sappnd on a directory basis or schg on individual files might be useful to reduce the risk of overwriting anything that you want to keep. Of course, such a disk can simply be mounted read-only when it's only being read from, but if you periodically update it with new data, then the file flags can offer an extra layer of protection against operator error whilst it needs to be written to.
Fun fact!
The undocumented opaque flag
A file flag exists which is not documented in the manual page for chflags. It's the opaque flag, and has no function on OpenBSD since it's used in conjunction with union mounted directories, a feature which is not implemented. However this flag can still be set and reset using chflags:
# touch /tmp/scratch_file
# ls -lo /tmp/scratch_file
-rw-r--r-- 1 root wheel - 0 Feb 14 13:15 /tmp/scratch_file
# chflags opaque /tmp/scratch_file
# ls -lo /tmp/scratch_file
-rw-r--r-- 1 root wheel opaque 0 Feb 14 13:15 /tmp/scratch_file
This might be useful if you share filesystems between OpenBSD and a BSD system that does support union mounting such as NetBSD. Alternatively, you could use this flag for your own purposes.
The concept of file flags on OpenBSD systems is somewhat analogous to file attributes on Linux based systems, (which are usually controlled with chattr), but the actual functionality of the flags available differs between the systems.
It's worth noting too, that the arch flag, unlike the other flags, is settable on mounted FAT filesystems, where it toggles the ‘archive’ file attribute.
Securelevel 2, a.k.a. ‘highly secure mode’
kern.securelevel: 1 -> 2
Many web and email servers can happily run at securelevel 2 without an extra administrative burden!
Most readers are probably aware of the sysctl kern.securelevel, which is set to 0 during most of the boot process, and raised to 1 when init switches to multi-user mode. Whilst at 0, hardware devices can be accessed by the root user without further restrictions, and all of the file flags we discussed above can be reset. Once in securelevel 1, access to some hardware devices is prohibited even for the root user, access to gpio pins not previously configured is not allowed, and various sysctls cannot be changed.
The restrictions enforced by securelevel 1 are sufficiently limited to allow normal use of most systems. Filesystems can still be mounted, and softraid devices can still be added and removed, for example.
Another more restricted secure level exists, securelevel 2, which puts even further limits in place including for the root user. Some of these limits might be inconvenient for a workstation, such as not being able to add and remove softraid volumes or change firewall rulesets, but for many servers which are just left running for weeks or months on end without needing any maintenance, enabling securelevel 2 gives us a few advantages at little to no cost.
Creating extra virtual terminals
Normal users have a mere six consoles.
At Exotic Silicon we use twelve.
If you like the speed, convenience, and directness of working at the console rather than using the X window system, you might like to know that you can increase the number of virtual terminals from the default of six.
Additional terminals can either configured interactively using wsconscfg, or more easily by increasing the value of WSDISPLAY_DEFAULTSCREENS in the kernel configuration.
This will allow them to be switched to using key combinations such as control-alt-F7 and beyond. However, by default there won't be a login prompt on any of these additional terminals, as there is no getty running on them. To actually use them for interactive login sessions, we can simply edit /etc/ttys and enable /dev/ttyC6 to /dev/ttyCb by changing ‘off’ to ‘on’.
Color on the console
By default, the framebuffer console is a very monochrome experience.
Apart from the blue background of kernel messages...
it's mostly just white text on a black background.
However, userland programs certainly can display color on the console, as the following examples clearly demonstrate:
# echo "␛[41m␛[33mHello in yellow on red"
Hello in yellow on red
# echo "␛[42m␛[34mHello in blue on green"
Hello in blue on green
Remember that to enter the escape character, (␛), in the examples above, you'll need to use the ‘literal’ control character control-V first, followed by the escape key. This will display on the console as ^[.
The reason why most userland programs don't use color on the OpenBSD framebuffer console, is because they consult the terminfo database to discover which escape sequences to send for your particular terminal type. Since the default terminal type is set to vt220, which doesn't include any escape sequences for color, the default white text on a black background remains.
However, the OpenBSD terminal emulation code does support various ANSI escape sequences for background and foreground color changes, as well as the bold and underline attributes. The code that handles this is in /usr/src/sys/dev/wscons/wsemul_vt100.c and /usr/src/sys/dev/wscons/wsemul_vt100_subr.c
Fun fact!
Color attributes interaction with the cursor
You can send a set of escape sequences to the console, to set the background to black, the foreground to green, and enable bold display with the following command:
# echo "␛[40m␛[32m␛[1mHello in bold green on black"
However, notice that the cursor doesn't initially take on the bold attribute, but remains the darker green! If you type some characters and then delete them, you'll see that the cursor takes on the bold attribute whilst backspaced to the character cells which previously had characters in them. If you now type more characters, you'll notice that the cursor remains bold until it passes the last character cell that was previously used, and then turns dim again.
Unfortunately, although there are several entries in the termcap file that seem as if they should better support the OpenBSD framebuffer kernel than the default vt220 option, none of them work entirely correctly without some modification.
Important: This guide was originally written with reference to OpenBSD 7.0. Patches submitted to the OpenBSD project by Exotic Silicon improved compatibility of the framebuffer console with the terminfo entry for xterm. Since OpenBSD 7.3, using the xterm terminfo entry on the console should provide a better experience, (including support for color), than the other terminal types in almost all cases.
# grep -i openbsd /usr/src/share/termtypes/termtypes.master
Searching the terminal description file for entries that contain ‘openbsd’.
The ‘pccon’ termtype entry, along with it's variations, was added in 2011. This mostly works, but can cause an irritating visual effect due to the values specified for the ‘op’ parameter. It's quite easy to find a program that breaks when using pccon during normal usage. By way of example, although the mutt email client can be configured to render text in color on the framebuffer terminal when using pccon, after exiting the program the display becomes inverted, with black text on a while background.
If we first re-compile the terminal description file without any modifications, a warning is generated.
If we didn't already know that ‘exit_attribute_mode’ is the escape sequence to reset all attributes, a quick search through the section 5 manual page for terminfo would have enlightened us.
# cd /usr/src/share/termtypes
# make
/usr/bin/tic -x -o terminfo termtypes.master
"termtypes.master", line 2370, terminal 'pccon+base': enter_bold_mode but no exit_attribute_mode
"termtypes.master", line 2370, terminal 'pccon+base': enter_reverse_mode but no exit_attribute_mode
Out of about 2000 terminal definitions in the source file, only the pccon+base entry throws a warning. Amazingly, this seems to have either gone un-noticed or been ignored for some time.
Fun fact!
Attribute reset code
The code to implement a reset of attribute values is on line 537 of /usr/src/sys/dev/wscons/wsemul_vt100_subr.c.
Reading the code, we can see that the expected sequence is ␛[m
Sending the attribute reset sequence to the terminal restores the colors back to the default, (for all architectures except sparc64), of white text on a black background:
However, this is all just a co-incidence. Although we can silence the compile time warning from tic by moving the sgr0 parameter from pccon+sgr+acs to pccon+base, this is actually nothing to do with the inverted text problem described above!
echo "␛[m"
This is nothing to do with the inverted text problem
The inverted text is actually caused by the ‘op’ parameter, as mentioned earlier. In the pccon terminal definition, it's set to ␛[47;30m. This sets the foreground to black, and the background to white.
We could just change it to ␛[40;37m, which explicitly defines a white foreground and a black background:
# mv termtypes.master termtypes.master.dist
# sed -e 's!\[47;30m!\[40;37m!' termtypes.master.dist > termtypes.master
# make
# make install
Changing the op parameter to set a white foreground with a black background
This fixes the problem visually on the amd64 architecture. However, if we look at the code in wsemul_vt100_subr.c on lines 583 and 595, we can see that when both foreground and background colors are reset to their default values using the sequence ␛[49;39m, a flag is also reset.
The WSATTR_WSCOLORS flag is set whenever a specific foreground or background color is set. When both are reset to their default settings, using the 39 and 49 values, the WSATTR_WSCOLORS flag is also reset.
If we want to ensure that this flag toggling behaviour happens, we can set the ‘op’ parameter accordingly:
# mv termtypes.master termtypes.master.dist
# sed -e 's!\[47;30m!\[49;39m!' termtypes.master.dist > termtypes.master
# make
# make install
Changing the op parameter to set the ‘default’ foreground and background colors, which will also reset the WSATTR_WSCOLORS flag
Note that although the values 39 and 49 are correctly interpreted by wsemul_vt100_subr.c, they will be ignored by the code that handles SGR sequences in wsemul_sun.c. This means that the second version of our modified pccon entry won't work as intended on the sparc64 architecture, where the kernel option WSEMUL_SUN is defined to enable the terminal emulation routines in /usr/src/sys/dev/wscons/wsemulconf.c.
However, since the default terminal colors on the sparc64 architecture are black text on a white background, the original unmodified pccon entry doesn't cause the unwanted color inversion effect anyway.
An alternative way to provide color on the console is to simply create a new termtype entry, including the existing vt220 and ecma+color entries.
Obviously this will be inconvenient if you connect to remote machines that don't recognise your custom ‘test’ termtype.
# echo "test|Custom terminal capabilities entry," > termtypes.master
# echo " use=vt220, use=ecma+color," >> termtypes.master
# make
# make install
Creating a new entry in the terminal capabilities database
This week we looked at a variety of rarely used features in OpenBSD.
And with that, we wrap up the final installment of this ten part series! We hope that you've enjoyed it. Don't forget to check out the rest of the Exotic Silicon website for more great content, and leave us feedback via the contact page, especially if you want to see more of this sort of material in the future.