[BUG / PATCH] Critical Mach IPC Memory Corruption, Integer Overflow, and
Deadlock Under Load in gnumach/ipc/ipc_kmsg.c
Hello GNU Hurd Maintainers and Developers,

During low-level stress testing and static/dynamic analysis of GNU Mach
under realistic workloads (e.g., continuous socket traffic, heavy package
management operations), the Mach IPC subsystem repeatedly enters circular
deadlocks and kernel panics.

An audit of `gnumach/ipc/ipc_kmsg.c` reveals several fundamental memory
safety violations and a complete absence of basic defensive C programming
bounds checks:

1. Integer Multiplication Overflow (`ipc_kmsg_get`):
   `mach_msg_size_t ksize = size * IKM_EXPAND_FACTOR;`
   There is no upper-bounds validation on user-controlled `size`. Large
allocations wrap around `mach_msg_size_t`, allocating a truncated buffer
via `ikm_alloc()`, followed immediately by an out-of-bounds copy in
`copyinmsg()`. This leads directly to Heap Buffer Overflows and Kernel
Memory Corruption.

2. Zone Cache Corruption on Allocation Failures:
   When `copyinmsg()` fails, `ikm_free(kmsg)` is invoked
unconditionally—even if the message buffer was allocated from the zone
cache via `ikm_cache_alloc()`. Returning a cached object to the general
zone allocator corrupts the kernel memory zone structure, causing cascading
deadlocks under high IPC contention.

3. Unchecked Dereference & Bounds Violation (`ipc_kmsg_free`):
   `ipc_kmsg_free()` dereferences `kmsg->ikm_size` directly without
validating against `IKM_NULL`. Furthermore, it lacks upper-bound checks
prior to calling `kfree()`, allowing corrupt message headers to destabilize
the kernel memory pool.

To resolve these vulnerabilities and stabilize IPC message queues under
load, I have implemented defensive guard clauses, branch prediction hints
(`unlikely()`), and strict bounds validation.

The full patch and engineering post-mortem notes are available here:
https://github.com/erkanalperen54-boop/HURD/blob/main/test/devnotes/24-07-2026.md

Below is the inline diff for review:

--- gnumach/ipc/ipc_kmsg.c
+++ gnumach/ipc/ipc_kmsg.c
@@ -449,12 +449,20 @@ ipc_kmsg_free(ipc_kmsg_t kmsg)
 {
  vm_size_t size;

+ /* Early exit: NULL kmsg protection */
+ if (unlikely(kmsg == IKM_NULL))
+ return;

  size = kmsg->ikm_size;

  if (size == IKM_SIZE_NETWORK) {
  net_kmsg_put(kmsg);
  return;
  }

+ /* Sanity check: Size bounds validation before kfree */
+ if (unlikely(size == 0 || size > IKM_SAVED_MAX)) {
+ printf("ipc_kmsg_free: corrupt kmsg size (%lu), leaking to prevent
crash\n",
+       (unsigned long)size);
+ return;
+ }

  kfree((vm_offset_t) kmsg, size);
 }

 mach_msg_return_t
 ipc_kmsg_get(
  mach_msg_user_header_t *msg,
  mach_msg_size_t size,
  ipc_kmsg_t *kmsgp)
 {
  ipc_kmsg_t kmsg;
  mach_msg_size_t ksize;

  /* 1. Lower bound and alignment check */
  if (unlikely((size < sizeof(mach_msg_user_header_t)) ||
              mach_msg_user_is_misaligned(size)))
  return MACH_SEND_MSG_TOO_SMALL;

  /* 2. Upper bound and integer overflow protection */
  if (unlikely(size > IKM_SAVED_MAX ||
              size > (MACH_MSG_SIZE_MAX / IKM_EXPAND_FACTOR)))
  return MACH_SEND_NO_BUFFER;

  ksize = size * IKM_EXPAND_FACTOR;

  /* 3. Buffer allocation */
  if (ksize <= IKM_SAVED_MSG_SIZE) {
  kmsg = ikm_cache_alloc();
  if (unlikely(kmsg == IKM_NULL))
  return MACH_SEND_NO_BUFFER;
  } else {
  kmsg = ikm_alloc(ksize);
  if (unlikely(kmsg == IKM_NULL))
  return MACH_SEND_NO_BUFFER;
  ikm_init(kmsg, ksize);
  }

  /* 4. Safe copyin and proper cleanup on failure */
  if (unlikely(copyinmsg(msg, &kmsg->ikm_header, size, kmsg->ikm_size))) {
  ipc_kmsg_free(kmsg);
  return MACH_SEND_INVALID_DATA;
  }

  *kmsgp = kmsg;
  return MACH_MSG_SUCCESS;
 }

Please review and apply.

A quick note: I’ve come across a few more of these dreadful bugs today; I’m
updating them in a repository called HURD on my GitHub account, and during
the development process I’m creating Markdown files for each day, labelled
with the respective date. If you’d like, you can follow the bug-finding
process in real time or review the notes from the bug-finding process at
the address below (see the `tests/devnotes/*.md` files):
     [
https://github.com/erkanalperen54-boop/HURD](https://github.com/erkanalperen54-boop/HURD)
If you spot any edge cases or errors in this patch, please do let me know!

Regards,
Alperen Erkan
  • [no subject] Alperen Erkan
    • Re: Bradley Morgan
    • Re: Samuel Thibault
      • Fwd: Alperen Erkan
        • Re: Alperen Erkan
          • Re: Bradley Morgan
          • Re: Samuel Thibault
            • Re: Alperen Erkan
              • Re: Samuel Thibault
        • Re: Fwd: Samuel Thibault
    • Re: Bradley Morgan

Reply via email to