Solaris NFS Client Module Vulnerability

Release date: 27-06-2009


1. Summary

There is a vulnerability in Solaris 10 kernel RPC implementation resulting in an attacker being able to perform a denial of service attack on an NFS server service. One crafted UDP packet is sufficient to send to port 2049 (rpc program number 100003 or program number 100227) to trigger the kernel panic and subsequent core dump. Remote code execution is very unlikely though. Solaris 10 SPARC, x86 and x64 platforms are affected, all with the latest 10_Recommended patches applied. Other versions were not tested. The source code references come from the Nevada projects sources available on http://cvs.opensolaris.org dated on 25.02.2007.


2. Details

The code snippets aren taken from http://cvs.opensolaris.org, and may be different than the Solaris 10 code which I tested and debugged this issue on (see section 5). The line numbers correspond to the current source tree on the webpage.
The kernel RPC implementation performs insufficient sanitization checks on RPC functions parameters coming in via the network, packaged using the eXternal Data Representation (XDR) language (RFC-1014). Specifically, when the variable length opaque data type parameter is being passed via XDR to NFS server (such as the file handle for the NFS operation, see RFC mentioned), the data is followed by the 4 byte length field. If the length is modified to be negative, the system crashes with the panic message similar to the below:

panic[cpu0]/thread=d5e50400:
BAD TRAP: type=e (#pf Page fault) rp=d5df0a08 addr=9a6be424 occurred in module "
genunix" due to an illegal access to a user address


nfsd:
#pf Page fault
Bad kernel fault at addr=0x9a6be424
pid=4722, pc=0xfe9790c2, sp=0xd5df0b3c, eflags=0x10216
cr0: 8005003b<pg,wp,ne,et,ts,mp,pe> cr4:6b8<xmme,fxsr,pge,pae,pse,de>
cr2: 9a6be424 cr3: 701b020
         gs: 534601b0  fs: 45530000  es: 54540160  ds: 6c630160
        edi:        0 esi: d4d7a444 ebp: d5df0a58 esp: d5df0a40
        ebx: d41b2e80 edx: d4d7a444 ecx: d4d7a444 eax: 9a6be424
        trp:        e err:        0 eip: fe9790c2  cs:      158
        efl:    10216 usp: d5df0b3c  ss: d5df0a68

d5df0968 unix:die+a7 (e, d5df0a08, 9a6be4)
d5df09f4 unix:trap+103f (d5df0a08, 9a6be424,)
d5df0a08 unix:_cmntrap+9a (534601b0, 45530000,)
d5df0a58 genunix:xdrmblk_getint32+72 (d4d7a444, d5df0a8c,)
d5df0a68 genunix:xdr_u_int+32 (d4d7a444, d5df0a8c)
d5df0a90 nfs:xdr_string3+4c (d4d7a444, d5df0b3c,)
d5df0aa8 nfs:xdr_diropargs3+5f (d4d7a444, d5df0af0,)
d5df0ab8 rpcsec:svc_authany_wrap+e (d4d7a404, d4d7a444,)
d5df0ad0 rpcmod:svc_clts_kgetargs+1b (d4d7a3c0, fa0e1f98,)
d5df0d24 nfssrv:common_dispatch+e2 (d5df0d9c, d4d7a3c0,)
d5df0d44 nfssrv:rfs_dispatch+1c (d5df0d9c, d4d7a3c0)
d5df0dd0 rpcmod:svc_getreq+158 (d4d7a3c0, d437b400)
d5df0df8 rpcmod:svc_run+125 (d5f44d50)
d5df0e0c rpcmod:rdmadrhashstat+24c20430 (1)
d5df0f84 nfs:nfssys+4cf (e, d2970fd4, d686, )

3. Code analysis

The xdrmblk_control() function is responsible for getting the arguments out of the UDP packet and moving the pointer forward to the next argument. If the length is negative, the xdrmblk_control() will not verify this and will execute the following code:

xdr_mblk.c#547 ::

           m->b_rptr += len

As the len is a negative number, it makes the m->b_rptr point to a buggy address (the address depends on the current memory layout). If this pointer is later referenced to pick up the next argument from the packet, it will most likely reference the unmapped address and cause the unhandled page fault with a subsequent panic. For example, if the next argument is supposed to be an integer (like in setfattr() call), the following part of the xdrmblk_getint32() function is to be executed:
xdr_mblk.c#133 ::

           int32p = ntohl(((int32_t *)(m->b_rptr)));

As the m->b_rptr pointer points to the buggy address, the system will crash with the panic message similar to the one section 2 while trying to dereference m->b_rptr.
Remote code execution is unlikely, because the m->b_rprt (EAX register in the above x86 panic message) value depends on a current kernel memory allocation layout.


4. Exploit

The malicious udp packet makes the system call the setfattr() NFS function (function number 2 in the program interface number 100003) with a negative length (0xAABBCCDD) of the following filehandle parameter. If the `share' command has been executed and the nfs server is running, the system will crash. The malicious UDP packet is not included in this advisory.


5. Fix

This bug seems to be corrected in http://cvs.opensolaris.org code I viewed:

xdr_mblk.c#532 ::

        if (len < 0)
                    return (FALSE);

But still all my Solaris 10 boxes are vulnerable to this issue (with the latest Recommended patches applied). This patch seems not to be included in Solaris 10 (at least I couldn't find the assembly part that matches this code). Neither I could find any Sun Alert describing this issue either.


UPDATE: this issue has been fixed by the vendor: http://sunsolve.sun.com/search/document.do?assetkey=1-26-102911-1