OpenBSD Journal

g2k22 Hackathon Report: Martijn van Duren on snmpd(8) improvements

Contributed by rueda on from the agentx my PDUs dept.

We are delighted to have received a report on the recently-concluded g2k22 hackathon. Martijn van Duren (martijn@) writes:

Coming to Bad Liebenzell for the 3rd year in a row I knew what to expect, but the scenery still continues to amaze me. Driving through the black forest was a nice little escape before plunging back into the SNMP world.

One of the biggest misconceptions I've seen floating around and one of my biggest irks with snmpd(8) was its privilege separation situation. While true that snmpd(8) always had multiple processes it was never used to any meaningful degree. The engine process (snmpe) handled everything snmp related: Handling packets/connections, de-/encoding the BER, handling authentication, finding the correct object and retrieving the data from the proper source (usually the kernel). Because some metrics fell outside the scope of pledge it also ran without the pledge seat belt. The engine however does run inside a /var/empty chroot, this is where the other (parent) process comes into play. When a trap (notification) is received and covered by "trap handle" it's forwarded to the parent process, which then executes the "command".

During k2k20 I committed libagentx which was the first piece of the puzzle to making privilege separation between the handling of the (network facing) packets and the handling of the metrics possible. The other big piece was (re-)adding agentx support to snmpd. Because the original code was build around the idea that all metrics originate from within the engine certain assumptions in the code were made that didn't quite fit into an agentx based world:

  • The code assumed objects instead of regions. Since objects can't overlap it's easy to just walk the edge of the tree, which also comes with a great speed benefit. Agentx however requires regions, which can happily overlap.
  • The code worked sequential, meaning that every varbind would wait for its value as soon as it was processed. This could cause the entire snmpd to hang if one backend were to hang.
  • The code wasn't really set up to handle inserting and removing of new regions/objects.

During h2k21 I wrote support for the new application layer, which now handles the PDUs and is designed to handle the above requirements. This came with an legacy handler, which calls out to the old code so we don't lose any functionality while transitioning.

During r2k22 I polished up the agentx master code which I wrote in tandem with the new application layer. This code mostly translates between the agentx line format and the application.c API, which does all the heavy lifting. This code got committed a week before the g2k22.

With all the core pieces for agentx based communication in place it was only a matter of landing on a design on how to set up the backends, which was my main goal for g2k22. I already had the idea that the new backend(s) should function as a standalone binary, because I don't want to link libagentx against snmpd. From here I decided on creating a dedicated libexec/snmpd directory, inspired by smtpd's libexec/smtpd. For now all binaries inside this directory are being executed and the snmpd side of the socketpair is registered inside the agentx subsystem with some additional flags, making sure that the regions registered by these backends are exclusively owned and can't be overwritten by rogue dynamic backends.

I talked over the design with tb@ and claudio@ and got committed only a few days later, allowing snmpd to finally enter the realm of OpenBSD's privsepped daemons, making the engine process pledged "stdio recvfd inet unix" for now, hoping that it can be locked down even further in the future.

(Comments are closed)


Credits

Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original deadly.org with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]