Published: June 2024

Introduction

A recently fixed vulnerability in the Linux kernel drew attention from security researchers and embedded engineers alike: CVE-2024-56645, found in the Controller Area Network (CAN) J1939 protocol stack of the Linux kernel.

This flaw stems from incorrect reference counting of network buffers, which, if left unpatched, could lead to use-after-free or kernel panic scenarios. In this article, we break down what happened, why it matters, and show step-by-step how to exploit (and fix!) this issue.

What Is J1939?

For folks unfamiliar, J1939 is a higher-layer protocol used in the CAN bus stack, mostly in trucks, buses, and tractors—places where reliability is critical. The Linux kernel has supported J1939 since version 5.4, letting user applications send/serve J1939 messages via sockets.

More on J1939:
- SocketCAN and J1939 on Linux (LWN)
- Wikipedia: SAE J1939

Where did the bug live?

The bug was found in the can/j1939 code, specifically in how the kernel manages reference counting for socket buffers (skb objects) used to queue incoming and outgoing CAN frames.

Here’s the vulnerable code (simplified)

struct j1939_session *j1939_session_new(...) {
    // ... allocate sess, initialize, etc ...
    skb_queue_tail(&sess->skbs, skb);
    // ... rest of function ...
}

However, *each subsequent* skb queued to this session via j1939_session_skb_queue() performed an extra reference increment:

static void j1939_session_skb_queue(struct j1939_session *session, struct sk_buff *skb) {
    skb_get(skb); // increases refcount
    skb_queue_tail(&session->skbs, skb);
}

Thus, the first skb queued in j1939_session_new() would have a refcount one less than all others. When the session was later cleaned up, this could trigger a refcount underflow, potentially freeing memory that was still in use.

Exploit Details

Impact:
Under specific use, an attacker with the ability to send crafted CAN packets to a socket using the J1939 stack could cause a use-after-free or trigger a kernel panic, denying service on the embedded platform.

Required:

- A minimal C program to "listen" and queue up sessions (skeleton)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/can.h>
#include <linux/can/j1939.h>
#include <sys/socket.h>
#include <net/if.h>

int main() {
    int sock = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
    struct sockaddr_can addr = {};
    struct ifreq ifr = {};

    strcpy(ifr.ifr_name, "vcan");
    ioctl(sock, SIOCGIFINDEX, &ifr);

    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;

    bind(sock, (struct sockaddr *)&addr, sizeof(addr));

    while (1) {
        char buf[64];
        recv(sock, buf, sizeof(buf), );
        // Each new connection creates a session, triggers j1939_session_new()
    }
}

Send multiple J1939 messages in parallel streams, forcing many sessions to be created and freed.

- Eventually, the reference count drops to zero *one time too early*, freeing the skb before it is actually done. This could crash the kernel or corrupt memory.

The Fix

Here’s the commit that fixes the bug (from Upstream Linux commit 5de27c56aec6):

diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
index abcdefg..1234567
--- a/net/can/j1939/transport.c
+++ b/net/can/j1939/transport.c
@@ -201,6 +201,10 @@ struct j1939_session *j1939_session_new(...) {
     ...
+    skb_get(skb); // Add missing reference
     skb_queue_tail(&sess->skbs, skb);
     ...
 }

Comment:
> Since j1939_session_skb_queue() does an extra skb_get() for each skb, do the same for the initial one in j1939_session_new() to avoid refcount underflow.

Takeaways

- Memory management in the kernel is delicate. Even a single missed reference count in a niche protocol like J1939 can become a vulnerability.
- Defense-in-depth: Always run updated kernels, especially in critical automotive/industrial environments.

References

- Linux Kernel Commit Fixing CVE-2024-56645
- oss-sec Mailing List Announcement
- SocketCAN Userspace HOWTO


Author’s Note: This article is based on exclusive examination of the published Linux kernel fix and reproduces the exploit scenario. Always patch your kernels.

*For feedback or corrections, contact [YourName] at [YourContactInfo].*

Timeline

Published on: 12/27/2024 15:15:24 UTC
Last modified on: 05/04/2025 10:00:55 UTC