CVE-2026-4747 — FreeBSD kgssapi.ko RPCSEC_GSS Stack Buffer Overflow
Full Remote Kernel RCE → uid 0 Reverse Shell
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)
1. The Vulnerability
Root Cause
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 Fix (14.4-RELEASE-p1)
The patch adds a single bounds check before the copy:
... continue reading