Skip to content
Suzu

OpenBMC Security Part 3: slpd-lite and CVE-2024-41660

A practical, slide-backed analysis of CVE-2024-41660 in OpenBMC slpd-lite, focusing on SLP length fields and memory corruption.

View the complete series →
On this page

The previous part focused on bmcweb, which is an HTTPS-facing component. This one is a little different. CVE-2024-41660 is about slpd-lite, a lightweight Service Location Protocol responder.

The scary part is not that SLP is complicated. The scary part is that slpd-lite listens on UDP port 427 and parses unauthenticated packets. There is no TLS handshake, no login screen, and no HTTP session. A datagram arrives, the service parses it, and any parser bug is already in play.

Slide summarizing CVE-2024-41660 in slpd-lite, including UDP port 427, SLP service discovery, and memory overflow risk.

The official OpenBMC advisory rates this as Critical. It states that OpenBMC systems including slpd-lite are affected, and that the package is installed by default when building OpenBMC.

Why This Service Matters

SLP is used for service discovery. In this OpenBMC context, slpd-lite acts as a unicast responder and handles requests such as service requests and service-type requests.

That sounds small, but I would not ignore it:

  • UDP services receive data without a connection handshake.
  • Discovery services are easy to forget in firewall rules.
  • Length fields are attacker-controlled until proven otherwise.
  • The parser runs on the BMC management plane.
  • A BMC memory corruption bug has a much bigger blast radius than a normal discovery daemon crash.

In other words, this is exactly the kind of “small parser” that deserves extra attention.

SLP Packet Structure

The packet format itself is not the whole bug, but it shows where the bug comes from. Several fields describe lengths or offsets. Those values come from the packet sender.

Slide showing the normal SLP packet flow, including version, function ID, length, flags, language tag, and payload.

The header fields highlighted in the slide deck are:

Slide listing SLP header fields, offsets, sizes, and descriptions, including Lang Tag Length and Lang Tag.

FieldOffsetSizePurpose
Version01 byteSLP version
Function-ID11 byteMessage function code
Length23 bytesTotal SLP message length
Flags52 bytesFlags and options
Next Ext Offset73 bytesOffset of next extension
XID102 bytesTransaction ID
Lang Tag Length122 bytesLength of the language tag
Lang Tag14variableLanguage tag bytes

The rule should be boring: every claimed length must be checked against the actual received buffer before the parser reads or copies anything.

Normal Packet Versus Bad Packet

This slide is the core idea:

Slide comparing a normal SLP packet where declared length matches payload size with an abnormal packet where the declared length is much larger than the real payload.

In a normal packet, the declared length and the available data agree. In a malicious packet, the declared length can be much larger than the actual datagram. If the parser trusts that declared length, it walks beyond the received buffer.

The parser entry point then has to be very strict:

Slide showing the SLP parser responsible for parsing findsrvs and findsrvtypes query content.

Out-Of-Bounds Read

The first vulnerable pattern is in header parsing. The parser reads the language tag length, then uses it to copy the language tag.

Slide showing sock_channel.cpp and parse_header flow: read language tag length, then use it to copy the language tag from OFFSET_LANG.

If the packet says:

LangTagLen = 65535

but the packet only contains:

Language Tag = "en"

then the parser has a problem.

Slide showing an out-of-bounds read where LangTagLen is 65535 but the actual language tag is only two bytes.

The safe check should be conceptually simple:

offset + langtagLen <= received_buffer_size

But even that check needs care. The addition must not overflow, and the types need to be wide enough to represent the real range.

Integer Truncation

The second pattern is more subtle, and I like it as a teaching example.

The vulnerable response-building flow calculates a response length, stores it in an 8-bit integer, allocates a buffer using the truncated value, and then copies data using the original larger length.

Slide showing slp_message_handler.cpp prepareHeader flow: calculate total length as uint8_t, allocate buffer, then copy langtag using the original length.

Here is the type problem:

Slide explaining integer truncation from size_t into uint8_t, keeping only the low 8 bits modulo 256.

If a value is stored in uint8_t, it can only represent 0 to 255. A larger value does not magically become safe. It wraps modulo 256.

The slide example uses a language tag length of 300:

Slide showing integer truncation calculation where 316 becomes 60 after uint8_t truncation.

Then the next slide shows the consequence:

Slide showing integer truncation where a 316-byte calculated length becomes 60 bytes when stored in uint8_t, causing an undersized buffer.

In text form:

MIN_LEN: 14
langtag length: 300
error size: 2
calculated length: 316
uint8_t stored value: 316 mod 256 = 60
allocated buffer: 60 bytes
copied data length: 316 bytes

Allocated size and copied size no longer match. That is an out-of-bounds write.

The slide deck summarizes the impact like this:

Slide showing OOB read and OOB write leading to possible RCE.

I would phrase it a little more carefully: exploitability depends on build settings, memory layout, allocator behavior, and service privileges. But because this is unauthenticated memory corruption on a BMC service, treating it as critical is reasonable.

Patch Direction

The official advisory points to a patch series in openbmc/slpd-lite, ending in commit 20bab74.

Slide showing the slpd-lite patch commit for adding bounds checking on buffer parsing.

The commit message says the important thing directly: there are multiple user-provided length fields, and the parser must ensure those lengths do not exceed the input buffer size.

The patch direction is exactly what I would expect:

Slide showing slpd-lite patch diff excerpts that add bounds checks before parsing variable-length SLP fields.

  • check derived positions before reading
  • reject claimed lengths larger than the real buffer
  • avoid copying variable-length fields before bounds validation
  • add parse errors instead of letting malformed packets continue
  • add tests for the malformed cases

This is the same story as the bmcweb parser bug, just over UDP: the parser must trust the buffer size, not the packet’s claimed size.

What I Would Do

The clean fix is to install firmware or an OpenBMC build that includes the upstream slpd-lite patches. If that cannot happen immediately, I would block UDP 427 from untrusted networks. If SLP is not used at all, disabling the service is even better.

For a lab, checking and disabling it looks like this:

systemctl status slpd-lite.service
systemctl disable --now slpd-lite.service

For the code, the rule is: trust the received buffer size, not the packet’s length fields. Check the offset before adding the length, use a type wide enough for the calculation, and never allocate with a truncated value while copying with the original one. That last mismatch is the whole integer-truncation bug in one sentence.

The tests should be just as direct: truncated headers, oversized language tags, maximum values, inconsistent total lengths, and weird offset combinations. If a UDP parser can be reached before authentication, those are not edge cases. Those are the cases.

Small unauthenticated parsers are easy to underestimate. On a BMC, they deserve the same attention as the obvious web interface.

References

Share this page