Sometimes it’s the little things that bite you

After installing a new OpenBSD image on my Soekris net4801, I needed to become root to perform some post installation configuration. When I ran the su command, it exited without switching me to the root user:

$ su
Password:
Sorry

This baffled me for a minute, since my user and group identifiers looked fine, and I was in the wheel group (OpenBSD allows you to use the group wheel to control which users can become uid 0):

$ id
uid=1000(matty) gid=1000(matty) groups=1000(matty), 0(wheel)

To see what was going on, I ran ktrace to view the call path for the su executable:

$ ktrace su
Password:
Sorry

After reviewing the complete dump, I noticed that the su executable couldn’t open the secure passwd database:

$ kdump | egrep ‘(NAM|open)’

 < ..... >
 28302 su       NAMI  "/etc/spwd.db"
 28302 su       RET   open -1 errno 13 Permission denied
 < ..... >

It then dawned on me that I shouldn’t be able to ktrace a setuid executable as an unprivileged user, so I decided to check the permissions of the su utility to see why the kdump worked:

$ ls -la /usr/bin/su
-r-xr-xr-x 1 root wheel 14948 Mar 2 2006 /usr/bin/su

Well I’ll be. When I extracted the files tonight to create my archive, I either extracted then as an unprivileged user (which is why the setuid / setgid bits weren’t preserved), or I forgot to use tar’s “-p” option to preserve the file modes (I no longer have the history file, so I can’t see where I made my mistake). I think the tryptophan from the turkey is setting in. :)

Locating OpenBSD devices for kernel builds

I run OpenBSD on a few soekris net4801s, which don’t have a whole lot of memory. To ensure that I am efficiently using the hardware, I build custom kernels that contain just the devices needed to load and run the OpenBSD kernel on the soekris. This minizes the kernel memory footprint, and allows me to eeek out a few extra pages of spare memory. To build a custom kernel with just the devices I need, I usually start by running the dmassage utility to identify the devices on my system:

$ dmassage -t

root
 \-mainbus0
    |-bios0
    |  \-pcibios0
    |-cpu0
    \-pci0
       |-auich0
       |  \-audio0
       |-ichpcib0
       |  \-isa0
       |     |-fdc0
       |     |  \-fd0
       |     |-isadma0
       |     |-npx0
       |     |-pckbc0
       |     |  |-pckbd0
       |     |  |  \-wskbd0
       |     |  \-pmsi0
       |     |     \-wsmouse0
       |     \-pcppi0
       |        |-midi0
       |        \-spkr0
       |-ne3
       |-pchb0
       |-pciide0
       |  |-atapiscsi0
       |  |  \-scsibus0
       |  |     \-cd0
       |  \-wd0
       |-uhci0
       |  \-usb0
       |     \-uhub0
       \-vga1
          \-wsdisplay0

Once I have the devices, I use my OpenBSD kernel build procedure, but trim the devices that aren’t displayed by dmassage. This works pretty well, and allows me to maximize the hardware in my Soekris.

Monitoring hardware sensors with the OpenBSD sensor daemon

In OpenBSD 3.9, the sensor framework was added to allow users to monitor systems that contained hardware sensors (e.g., temperature, voltage, fan speed, etc.). Sensor data is made available through one or more “hw.sensors” kernel state variables, which can be viewed with the sysctl utility:

$ sysctl -a | grep “hw.sensors”

hw.sensors.0=nsclpcsio0, TSENS1, temp, 127.00 degC / 260.60 degF
hw.sensors.1=nsclpcsio0, TSENS2, temp, 127.00 degC / 260.60 degF
hw.sensors.2=nsclpcsio0, TNSC, temp, 57.00 degC / 134.60 degF
hw.sensors.3=nsclpcsio0, VSENS0, volts_dc, 3.01 V
hw.sensors.4=nsclpcsio0, VSENS1, volts_dc, 2.02 V
hw.sensors.5=nsclpcsio0, VSENS2, volts_dc, 2.52 V
hw.sensors.6=nsclpcsio0, VSENS3, volts_dc, 0.60 V
hw.sensors.7=nsclpcsio0, VSENS4, volts_dc, 2.48 V
hw.sensors.8=nsclpcsio0, VSENS5, volts_dc, 2.49 V
hw.sensors.9=nsclpcsio0, VSENS6, volts_dc, 0.00 V
hw.sensors.10=nsclpcsio0, VSB, volts_dc, 3.28 V
hw.sensors.11=nsclpcsio0, VDD, volts_dc, 3.31 V
hw.sensors.12=nsclpcsio0, VBAT, volts_dc, 3.01 V
hw.sensors.13=nsclpcsio0, AVDD, volts_dc, 3.26 V
hw.sensors.14=nsclpcsio0, TS1, volts_dc, 1.63 V
hw.sensors.15=nsclpcsio0, TS2, volts_dc, 1.62 V
hw.sensors.16=nsclpcsio0, TS3, volts_dc, 1.51 V

In addition to kernel support, OpenBSD has a userland daemon, sensorsd, which can be used to monitor one or more sensor values. If one of the sensor values that sensorsd is monitoring goes above or below an administrator defined threshold, sensorsd will by default write an entry similar to the following to the system log:

Oct 27 18:27:42 [192.168.1.1.2.2] sensorsd[8513]: hw.sensors.2: exceed limits, value: 56.00C/132.80F

Sensor thresholds are defined in the file /etc/sensorsd.conf. Each entry in /etc/sensorsd.conf contains the name of a sensor to monitor, the value “high” or “low” to indicate a peak or valley for the sensor value, and the value the sensor value cannot go above or below. The following example shows one of the entries I use to monitor the CPU temperature in my Soekris net4801-60:

$ cat /etc/sensorsd.conf
hw.sensors.2:high=55C

If syslog entries aren’t sufficient for monitoring, you can also use the “command” option to run a program when sensorsd detects that a value has crossed one of the thresholds. This script can email an administrator, send an SNMP trap to a network monitoring station, or shutdown the system (this could be useful it a fan fails or if a voltage level takes a turn for the worst). This is a sweet feature, and super super valuable!

Setting up the OpenBSD watchdog daemon (watchdogd)

The watchdog daemon (watchdogd) was introduced in OpenBSD 3.8, and can be used to help machines automatically recover from system hangs. If the OpenBSD hardware watchdog daemon is enabled, it will periodically update the hardware watchdog timer built into the system. If this timer is not reset for a period of time, the hardware will reset itself. The watchdog daemon is not enabled by default, and can be enabled (assuming OpenBSD can find a watchdog timer in your system) by adding a pair of empty quotes to the watchdog_flags variables in /etc/rc.conf:

$ grep watchdog /etc/rc.conf
watchdogd_flags=”” # for normal use: “”

The update interval is controlled through the kern.watchdog.period variable, which can be set in /etc/sysctl.conf, and viewed with the sysctl(8) command:

$ sysctl -a | grep watchdog
kern.watchdog.period=30
kern.watchdog.auto=0

Using the hardware watchdog can be useful when you are running routers and access points in remote locations, and don’t want to spend time driving to a remote location to reboot a hung system. I always add an rc script to the servers I support to E-mail me when the system boots. If I get an E-mail while I am performing planned maintenance, I can toss it in the trash can. If I get an E-mail because the machine reboots due to faulty hardware or a kernel bug, I will know that the system reset, and can begin investigating the the source of the problem. There are definitely times (e.g., clustered nodes) when it’s better to leave the hardware watchdog disabled, and have a monitoring station alert you to a hung system.

Fixing brk()

While reading through my daily mailing lists, I came across the following post. At first I was a bit nervous about the widespread chaos this would cause to OpenBSD users. After further analysis, it dawned on me that this will actually FIX more than it will break. Since software is getting worse by the day, it is nice to see that an Operating System takes pride in protecting users from crappy software.