(unknown)

Alperen Erkan <[email protected]> Fri, 24 Jul 2026 13:01:16 +0300
Newsgroups gmane.os.hurd.bugs,gmane.os.hurd.general
Message-ID <CAB6ChQ7G_WFMsMnfUEqxyX89FcmEj4ezu5EhHfdtq=aY31hP4A@mail.gmail.com>
--000000000000c548d70657587450
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

[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 =3D 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=E2=80=94even if the message buffer was allocated from the z=
one
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-2=
026.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 =3D=3D IKM_NULL))
+ return;

  size =3D kmsg->ikm_size;

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

+ /* Sanity check: Size bounds validation before kfree */
+ if (unlikely(size =3D=3D 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 =3D size * IKM_EXPAND_FACTOR;

  /* 3. Buffer allocation */
  if (ksize <=3D IKM_SAVED_MSG_SIZE) {
  kmsg =3D ikm_cache_alloc();
  if (unlikely(kmsg =3D=3D IKM_NULL))
  return MACH_SEND_NO_BUFFER;
  } else {
  kmsg =3D ikm_alloc(ksize);
  if (unlikely(kmsg =3D=3D 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 =3D kmsg;
  return MACH_MSG_SUCCESS;
 }

Please review and apply.

A quick note: I=E2=80=99ve come across a few more of these dreadful bugs to=
day; I=E2=80=99m
updating them in a repository called HURD on my GitHub account, and during
the development process I=E2=80=99m creating Markdown files for each day, l=
abelled
with the respective date. If you=E2=80=99d like, you can follow the bug-fin=
ding
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/erkanalpere=
n54-boop/HURD)
If you spot any edge cases or errors in this patch, please do let me know!

Regards,
Alperen Erkan

--000000000000c548d70657587450
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><p>[BUG / PATCH] Critical Mach IPC Memory Corruption, Inte=
ger Overflow, and Deadlock Under Load in <code>gnumach/ipc/ipc_kmsg.c</code=
></p><span class=3D"gmail-no-md"><span class=3D"gmail-ng-tns-c3586008462-36=
5 enable-luminous-code-block gmail-ng-star-inserted"><div class=3D"gmail-co=
de-block gmail-ng-tns-c3586008462-365 gmail-ng-animate-disabled gmail-ng-tr=
igger gmail-ng-trigger-codeBlockRevealAnimation" style=3D"display:block"><d=
iv class=3D"gmail-formatted-code-block-internal-container gmail-ng-tns-c358=
6008462-365"><div class=3D"gmail-animated-opacity gmail-ng-tns-c3586008462-=
365"><div class=3D"gmail-code-block-decoration gmail-header-formatted gmail=
-gds-emphasized-body-m gmail-ng-tns-c3586008462-365 gmail-ng-star-inserted"=
><span class=3D"gmail-ng-tns-c3586008462-365">Hello GNU Hurd Maintainers an=
d Developers,<br><br>During low-level stress testing and static/dynamic ana=
lysis of GNU Mach under realistic workloads (e.g., continuous socket traffi=
c, heavy package management operations), the Mach IPC subsystem repeatedly =
enters circular deadlocks and kernel panics.<br><br>An audit of `gnumach/ip=
c/ipc_kmsg.c` reveals several fundamental memory safety violations and a co=
mplete absence of basic defensive C programming bounds checks:<br><br>1. In=
teger Multiplication Overflow (`ipc_kmsg_get`):<br>=C2=A0 =C2=A0`mach_msg_s=
ize_t ksize =3D size * IKM_EXPAND_FACTOR;`<br>=C2=A0 =C2=A0There is no uppe=
r-bounds validation on user-controlled `size`. Large allocations wrap aroun=
d `mach_msg_size_t`, allocating a truncated buffer via `ikm_alloc()`, follo=
wed immediately by an out-of-bounds copy in `copyinmsg()`. This leads direc=
tly to Heap Buffer Overflows and Kernel Memory Corruption.<br><br>2. Zone C=
ache Corruption on Allocation Failures:<br>=C2=A0 =C2=A0When `copyinmsg()` =
fails, `ikm_free(kmsg)` is invoked unconditionally=E2=80=94even if the mess=
age buffer was allocated from the zone cache via `ikm_cache_alloc()`. Retur=
ning a cached object to the general zone allocator corrupts the kernel memo=
ry zone structure, causing cascading deadlocks under high IPC contention.<b=
r><br>3. Unchecked Dereference &amp; Bounds Violation (`ipc_kmsg_free`):<br=
>=C2=A0 =C2=A0`ipc_kmsg_free()` dereferences `kmsg-&gt;ikm_size` directly w=
ithout validating against `IKM_NULL`. Furthermore, it lacks upper-bound che=
cks prior to calling `kfree()`, allowing corrupt message headers to destabi=
lize the kernel memory pool.<br><br>To resolve these vulnerabilities and st=
abilize IPC message queues under load, I have implemented defensive guard c=
lauses, branch prediction hints (`unlikely()`), and strict bounds validatio=
n.<br><br>The full patch and engineering post-mortem notes are available he=
re:<br><a href=3D"https://github.com/erkanalperen54-boop/HURD/blob/main/tes=
t/devnotes/24-07-2026.md">https://github.com/erkanalperen54-boop/HURD/blob/=
main/test/devnotes/24-07-2026.md</a><br><br>Below is the inline diff for re=
view:<br><br>--- gnumach/ipc/ipc_kmsg.c<br>+++ gnumach/ipc/ipc_kmsg.c<br>@@=
 -449,12 +449,20 @@ ipc_kmsg_free(ipc_kmsg_t kmsg)<br>=C2=A0{<br>=C2=A0	vm_=
size_t size;<br><br>+	/* Early exit: NULL kmsg protection */<br>+	if (unlik=
ely(kmsg =3D=3D IKM_NULL))<br>+		return;<br><br>=C2=A0	size =3D kmsg-&gt;ik=
m_size;<br><br>=C2=A0	if (size =3D=3D IKM_SIZE_NETWORK) {<br>=C2=A0		net_km=
sg_put(kmsg);<br>=C2=A0		return;<br>=C2=A0	}<br><br>+	/* Sanity check: Size=
 bounds validation before kfree */<br>+	if (unlikely(size =3D=3D 0 || size =
&gt; IKM_SAVED_MAX)) {<br>+		printf(&quot;ipc_kmsg_free: corrupt kmsg size =
(%lu), leaking to prevent crash\n&quot;,<br>+		 =C2=A0 =C2=A0 =C2=A0 (unsig=
ned long)size);<br>+		return;<br>+	}<br><br>=C2=A0	kfree((vm_offset_t) kmsg=
, size);<br>=C2=A0}<br><br>=C2=A0mach_msg_return_t<br>=C2=A0ipc_kmsg_get(<b=
r>=C2=A0	mach_msg_user_header_t 	*msg,<br>=C2=A0	mach_msg_size_t 	size,<br>=
=C2=A0	ipc_kmsg_t 		*kmsgp)<br>=C2=A0{<br>=C2=A0	ipc_kmsg_t 	kmsg;<br>=C2=
=A0	mach_msg_size_t ksize;<br><br>=C2=A0	/* 1. Lower bound and alignment ch=
eck */<br>=C2=A0	if (unlikely((size &lt; sizeof(mach_msg_user_header_t)) ||=
<br>=C2=A0	 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 mach_msg_user_is_misa=
ligned(size)))<br>=C2=A0		return MACH_SEND_MSG_TOO_SMALL;<br><br>=C2=A0	/* =
2. Upper bound and integer overflow protection */<br>=C2=A0	if (unlikely(si=
ze &gt; IKM_SAVED_MAX ||<br>=C2=A0	 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 size &gt; (MACH_MSG_SIZE_MAX / IKM_EXPAND_FACTOR)))<br>=C2=A0		return M=
ACH_SEND_NO_BUFFER;<br><br>=C2=A0	ksize =3D size * IKM_EXPAND_FACTOR;<br><b=
r>=C2=A0	/* 3. Buffer allocation */<br>=C2=A0	if (ksize &lt;=3D IKM_SAVED_M=
SG_SIZE) {<br>=C2=A0		kmsg =3D ikm_cache_alloc();<br>=C2=A0		if (unlikely(k=
msg =3D=3D IKM_NULL))<br>=C2=A0			return MACH_SEND_NO_BUFFER;<br>=C2=A0	} e=
lse {<br>=C2=A0		kmsg =3D ikm_alloc(ksize);<br>=C2=A0		if (unlikely(kmsg =
=3D=3D IKM_NULL))<br>=C2=A0			return MACH_SEND_NO_BUFFER;<br>=C2=A0		ikm_in=
it(kmsg, ksize);<br>=C2=A0	}<br><br>=C2=A0	/* 4. Safe copyin and proper cle=
anup on failure */<br>=C2=A0	if (unlikely(copyinmsg(msg, &amp;kmsg-&gt;ikm_=
header, size, kmsg-&gt;ikm_size))) {<br>=C2=A0		ipc_kmsg_free(kmsg);<br>=C2=
=A0		return MACH_SEND_INVALID_DATA;<br>=C2=A0	}<br><br>=C2=A0	*kmsgp =3D km=
sg;<br>=C2=A0	return MACH_MSG_SUCCESS;<br>=C2=A0}<br><br>Please review and =
apply.</span></div><div class=3D"gmail-code-block-decoration gmail-header-f=
ormatted gmail-gds-emphasized-body-m gmail-ng-tns-c3586008462-365 gmail-ng-=
star-inserted"><p>A quick note: I=E2=80=99ve come across a few more of thes=
e dreadful bugs today; I=E2=80=99m updating them in a repository called HUR=
D on my GitHub account, and during the development process I=E2=80=99m crea=
ting Markdown files for each day, labelled with the respective date. If you=
=E2=80=99d like, you can follow the bug-finding process in real time or rev=
iew the notes from the bug-finding process at the address below (see the `t=
ests/devnotes/*.md` files):<br>=C2=A0 =C2=A0 =C2=A0[<a href=3D"https://gith=
ub.com/erkanalperen54-boop/HURD](https://github.com/erkanalperen54-boop/HUR=
D)">https://github.com/erkanalperen54-boop/HURD](https://github.com/erkanal=
peren54-boop/HURD)</a></p>If you spot any edge cases or errors in this patc=
h, please do let me know!</div><div class=3D"gmail-code-block-decoration gm=
ail-header-formatted gmail-gds-emphasized-body-m gmail-ng-tns-c3586008462-3=
65 gmail-ng-star-inserted"><br><span class=3D"gmail-ng-tns-c3586008462-365"=
>Regards,<br>Alperen Erkan</span></div></div></div></div></span></span><br>=
</div>

--000000000000c548d70657587450--