Claude Wrote a Full FreeBSD Remote Kernel RCE with Root Shell (CVE-2026-4747)

A critical stack-based buffer overflow in FreeBSD's rpcsec_gss module (CVE-2026-4747) enables remote kernel code execution via NFS. Attackers with a valid Kerberos ticket can overwrite the stack to gain full root access.
Advisory: FreeBSD-SA-26:08.rpcsec_gss CVE: CVE-2026-4747 Affected: FreeBSD 13.5 (<p11), 14.3 (<p10), 14.4 (<p1), 15.0 (<p5) Tested on: FreeBSD 14.4-RELEASE amd64 (GENERIC kernel, no KASLR) Attack surface: NFS server with kgssapi.ko loaded (port 2049/TCP)
In sys/rpc/rpcsec_gss/svc_rpcsec_gss.c, the function svc_rpc_gss_validate() reconstructs an RPC header into a 128-byte stack buffer (rpchdr[]) for GSS-API signature verification. It first writes 32 bytes of fixed RPC header fields, then copies the entire RPCSEC_GSS credential body (oa_length bytes) into the remaining space — without checking that oa_length fits.
static bool_t
svc_rpc_gss_validate(struct svc_rpc_gss_client *client,
struct rpc_msg *msg, gss_qop_t *qop, rpc_gss_proc_t gcproc)
{
int32_t rpchdr[128 / sizeof(int32_t)]; // 128 bytes on stack
int32_t *buf;
memset(rpchdr, 0, sizeof(rpchdr));
// Write 8 fixed-size RPC header fields (32 bytes total)
buf = rpchdr;
IXDR_PUT_LONG(buf, msg->rm_xid);
IXDR_PUT_ENUM(buf, msg->rm_direction);
IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers);
IXDR_PUT_LONG(buf, msg->rm_call.cb_prog);
IXDR_PUT_LONG(buf, msg->rm_call.cb_vers);
IXDR_PUT_LONG(buf, msg->rm_call.cb_proc);
oa = &msg->rm_call.cb_cred;
IXDR_PUT_ENUM(buf, oa->oa_flavor);
IXDR_PUT_LONG(buf, oa->oa_length);
if (oa->oa_length) {
// BUG: No bounds check on oa_length!
// After 32 bytes of header, only 96 bytes remain in rpchdr.
// If oa_length > 96, this overflows past rpchdr into:
// local variables → saved callee-saved registers → return address
memcpy((caddr_t)buf, oa->oa_base, oa->oa_length);
buf += RNDUP(oa->oa_length) / sizeof(int32_t);
}
// gss_verify_mic() called after — but overflow already happened
}
The buffer has only 128 - 32 = 96 bytes of space for the credential body. Any credential larger than 96 bytes overflows the stack buffer.
The patch adds a single bounds check before the copy:
oa = &msg->rm_call.cb_cred;
if (oa->oa_length > sizeof(rpchdr) - 8 * BYTES_PER_XDR_UNIT) {
rpc_gss_log_debug("auth length %d exceeds maximum", oa->oa_length);
client->cl_state = CLIENT_STALE;
return (FALSE);
}
From the function's prologue disassembly (objdump -d kgssapi.ko):
svc_rpc_gss_validate:
push rbp
mov rbp, rsp
push r15 ; saved at [rbp-8]
push r14 ; saved at [rbp-16]
push r13 ; saved at [rbp-24]
push r12 ; saved at [rbp-32]
push rbx ; saved at [rbp-40]
sub rsp, 0xb8 ; 184 bytes of local space
The rpchdr array is at [rbp-0xc0] (192 bytes below rbp). The memcpy writes to rpchdr + 32 = [rbp-0xa0]. The saved registers and return address are above rpchdr on the stack:
Stack layout (low → high addresses):
[rbp - 0xe0] local variables (bottom of frame)
[rbp - 0xc0] rpchdr[0] ← memset target
[rbp - 0xa0] rpchdr[32] ← memcpy destination (our overflow starts here)
[rbp - 0x40] rpchdr[128] ← end of buffer (96 bytes from memcpy start)
[rbp - 0x28] saved RBX ← OVERFLOW: credential body byte 120
[rbp - 0x20] saved R12 ← byte 128
[rbp - 0x18] saved R13 ← byte 136
[rbp - 0x10] saved R14 ← byte 144
[rbp - 0x08] saved R15 ← byte 152
[rbp + 0x00] saved RBP ← byte 160
[rbp + 0x08] RETURN ADDRESS ← byte 168
Why NFS? The vulnerable module kgssapi.ko implements RPCSEC_GSS authentication for the kernel's RPC subsystem. NFS is the primary in-kernel RPC service that uses RPCSEC_GSS. The NFS server daemon (nfsd) processes RPC packets in kernel context — making this a remote kernel code execution vulnerability reachable over the network.
Why Kerberos? The overflow is deep inside the GSS validation code path. svc_rpc_gss_validate() is only called when the RPC packet uses RPCSEC_GSS authentication and the server finds a valid client entry matching the context handle. Creating a valid GSS context requires a successful Kerberos handshake.
Source: Hacker News












