CVE-2024-42247 - Preventing Unaligned Memory Access in WireGuard's AllowedIPs Module on Linux

In June 2024, the Linux kernel maintainers addressed a critical issue in the WireGuard VPN's AllowedIPs module: CVE-2024-42247. This bug, while subtle, could cause kernel panics or unexpected warnings on certain architectures—potentially compromising stability or even security in sensitive environments.

This article will break down what happened, why it’s important, how it’s fixed, and—even if you’re not a kernel developer—how you can understand and check for this issue. We’ll also provide a simple example code snippet and real kernel log output, with references to the official patch and WireGuard discussions.

What is WireGuard and AllowedIPs?

WireGuard is a modern VPN protocol included in the Linux kernel. It’s designed for simplicity and high performance. One of its core modules, AllowedIPs, manages which IP addresses are permitted for each peer—crucial for routing VPN traffic securely.

The Problem – Unaligned Memory Access

On some CPUs, particularly older or less-common ones like parisc (used in Hewlett Packard PA-RISC systems), reading from or writing to memory locations that aren’t properly aligned to their size (for example, accessing a 64-bit value from a 4-byte aligned address) causes warnings or even fatal errors.

If you had a WireGuard tunnel running on parisc, you might see kernel messages like these

Kernel: unaligned access to x55f4688c in wg_allowedips_insert_v6+x2c/x80 [wireguard] (iir xf301df)
Kernel: unaligned access to x55f46884 in wg_allowedips_insert_v6+x38/x80 [wireguard] (iir xf201dc)

Each line tells you the kernel's memory manager had to fix up an access that could have crashed older CPUs. This sort of issue can happen in high-performance code that handles network addresses, especially IPv6 (which is 128-bit).

The Vulnerable Code

The original code in allowedips.c read a 128-bit IPv6 address by splitting into two 64-bit reads, like this:

u64 a = *((u64 *)&src[]);
u64 b = *((u64 *)&src[8]);

This works fine on most modern x86 hardware, but on parisc and some ARM or MIPS CPUs, this could crash or at least generate warnings if src is not perfectly 8-byte aligned.

The Fix: Using get_unaligned_be64()

The Linux kernel provides helpers to safely read unaligned memory on any CPU, such as get_unaligned_be64(). The patched code replaces direct pointer casts with these helpers:

#include <linux/unaligned/be_struct.h>

u64 a = get_unaligned_be64(src);
u64 b = get_unaligned_be64(src + 8);

This makes sure the address read happens correctly, even if the data isn’t aligned, and swaps to big-endian if necessary.

Note: The [Jason: replace src[8] in original patch with src+8] refers to making sure the second half of the address starts at the right position, 8 bytes ahead in the array.

Exploitability

While this issue doesn’t directly allow an attacker to take control of the system, it can be triggered with specially crafted IPv6 addresses. In a worst-case scenario, repeated unaligned accesses might lead to denial-of-service via kernel panics on affected architectures, especially if kernel config is harsh on alignment faults.

If you want to see what happens in a userspace test (for educational purposes)

#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>

// Simulated get_unaligned_be64() for demonstration
uint64_t get_unaligned_be64(const uint8_t *src) {
    return ((uint64_t)src[] << 56) | ((uint64_t)src[1] << 48) |
           ((uint64_t)src[2] << 40) | ((uint64_t)src[3] << 32) |
           ((uint64_t)src[4] << 24) | ((uint64_t)src[5] << 16) |
           ((uint64_t)src[6] << 8)  | ((uint64_t)src[7]);
}

int main() {
    uint8_t src[16] __attribute__((aligned(1))) = {}; // badly aligned!
    uint64_t a = get_unaligned_be64(src);
    uint64_t b = get_unaligned_be64(src + 8);
    printf("a = %llu, b = %llu\n", a, b);
    return ;
}

Modern CPUs usually shrug this off, but on non-x86 you’d need to take extra care!

How to Check If You're Affected

1. Kernel Version: The fix landed in Linux kernels around June 2024. Check your kernel source in net/wireguard/allowedips.c for use of get_unaligned_be64.

2. Distro Updates: Most distributions (Debian, Fedora, Ubuntu) will carry this as a security update.

3. Manual Testing: On affected hardware (parisc, some ARM/MIPS), try establishing a WireGuard tunnel and check dmesg or journalctl -k for “unaligned access” messages.

WireGuard Patch:

WireGuard Mailing List — “allowedips: avoid unaligned 64-bit memory accesses”

Linux Kernel Commit:

kernel.org commit: wireguard: allowedips: avoid unaligned 64-bit memory accesses

WireGuard Documentation:

https://www.wireguard.com/

Conclusion

CVE-2024-42247 is a great example of how coding for performance in network code can run up against the divergent realities of different CPU architectures. Thanks to the quick identification and fix by the Linux and WireGuard teams, this bug is gone for good. If you run WireGuard in production, especially on non-x86 platforms, make sure your kernel is up-to-date!

If you like learning about hidden kernel bugs, stay tuned for more! Let us know if you want deep dives into other Linux CVEs.


*This post is part of our exclusive CVE series. If you found it helpful, please share or bookmark for your devops/security peers!*

Timeline

Published on: 08/07/2024 16:15:47 UTC
Last modified on: 08/08/2024 14:52:25 UTC