Census ID: census-2010-0001
URL:
http://census-labs.com/news/2010/05/26/freebsd-kernel-nfsclient/
CVE ID: CVE-2010-2020
Affected Products: FreeBSD 8.0-RELEASE, 7.3-RELEASE, 7.2-RELEASE
Class: Improper Input Validation (CWE-20)
Remote: No
Discovered by: Patroklos Argyroudis
We have discovered two improper input validation vulnerabilities in the
FreeBSD kernel's NFS client-side implementation (FreeBSD 8.0-RELEASE,
7.3-RELEASE and 7.2-RELEASE) that allow local unprivileged users to
escalate their privileges, or to crash the system by performing a denial
of service attack.
Details
FreeBSD (http://www.freebsd.org/) is an advanced operating system which
focuses on reliability and performance. More information about its
features can be found at http://www.freebsd.org/about.html.
FreeBSD 8.0-RELEASE, 7.3-RELEASE and 7.2-RELEASE employ an improper input
validation method in the kernel's NFS client-side implementation.
Specifically, the first vulnerability is in function nfs_mount() (file
src/sys/nfsclient/nfs_vfsops.c) which is reachable from the mount(2) and
nmount(2) system calls. In order for them to be enabled for unprivileged
users the sysctl(8) variable vfs.usermount must be set to a non-zero
value.
The function nfs_mount() employs an insufficient input validation method
for copying data passed in a structure of type nfs_args from userspace to
kernel. Specifically, the file handle buffer to be mounted (args.fh) and
its size (args.fhsize) are completely user-controllable. The unbounded copy
operation is in file src/sys/nfsclient/nfs_vfsops.c (the excerpts are from
8.0-RELEASE):
1094: if (!has_fh_opt) {
1095: error = copyin((caddr_t)args.fh, (caddr_t)nfh,
1096: args.fhsize);
1097: if (error) {
1098: goto out;
1099: }
The declaration of the variables args and nfh is at:
786: static int
787: nfs_mount(struct mount *mp)
788: {
789: struct nfs_args args = {
790: .version = NFS_ARGSVERSION,
...
820: u_char nfh[NFSX_V3FHMAX];
This vulnerability can cause a kernel stack overflow which leads to
privilege escalation on FreeBSD 7.3-RELEASE and 7.2-RELEASE. On FreeBSD
8.0-RELEASE the result is a kernel crash/denial of service due to the
SSP/ProPolice kernel stack-smashing protection which is enabled by
default. Versions 7.1-RELEASE and earlier do not appear to be
vulnerable since the bug was introduced in 7.2-RELEASE. In order to
demonstrate the impact of the vulnerability we have developed a
proof-of-concept privilege escalation exploit:
http://census-labs.com/media/nfs_mount_ex.c
A sample run of the exploit follows:
[argp@julius ~]$ uname -rsi
FreeBSD 7.3-RELEASE GENERIC
[argp@julius ~]$ sysctl vfs.usermount
vfs.usermount: 1
[argp@julius ~]$ id
uid=1001(argp) gid=1001(argp) groups=1001(argp)
[argp@julius ~]$ gcc -Wall nfs_mount_ex.c -o nfs_mount_ex
[argp@julius ~]$ ./nfs_mount_ex
[*] calling nmount()
[!] nmount error: -1030740736
nmount: Unknown error: -1030740736
[argp@julius ~]$ id
uid=0(root) gid=0(wheel) egid=1001(argp) groups=1001(argp)
The second vulnerability exists in the function mountnfs() that is called
from function nfs_mount():
1119: error = mountnfs(&args, mp, nam, args.hostname, &vp,
1120: curthread->td_ucred);
The function mountnfs() is reachable from the mount(2) and nmount(2) system
calls by unprivileged users. As with the nfs_mount() case above, this
requires the sysctl(8) variable vfs.usermount to be set to a non-zero value.
The file handle to be mounted (argp->fh) and its size (argp->fhsize)
are passed to function mountnfs() from function nfs_mount() and are
user-controllable. These are subsequently used in an unbounded bcopy()
call (file src/sys/nfsclient/nfs_vfsops.c):
1219: bcopy((caddr_t)argp->fh, (caddr_t)nmp->nm_fh, argp->fhsize);
The above can cause a kernel heap overflow when argp->fh is bigger than 128
bytes (the size of nmp->nm_fh) since nmp is an allocated item on the
Universal Memory Allocator (UMA, the FreeBSD kernel's heap allocator)
zone nfsmount_zone (again from src/sys/nfsclient/nfs_vfsops.c):
1160: static int
1161: mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
1162: char *hst, struct vnode **vpp, struct ucred *cred)
1163: {
1164: struct nfsmount *nmp;
1165: struct nfsnode *np;
1166: int error;
1167: struct vattr attrs;
1168:
1169: if (mp->mnt_flag &MNT_UPDATE) {
1170: nmp = VFSTONFS(mp);
1171: printf("%s: MNT_UPDATE is no longer handled here\n",
__func__);
1172: free(nam, M_SONAME);
1173: return (0);
1174: } else {
1175: nmp = uma_zalloc(nfsmount_zone, M_WAITOK);
This kernel heap overflow can lead on FreeBSD 8.0-RELEASE, 7.3-RELEASE and
7.2-RELEASE to privilege escalation and/or a kernel crash/denial of
service attack. Similarly to the first vulnerability, FreeBSD 7.1-RELEASE
and earlier versions do not appear to be vulnerable. We have developed a
proof-of-concept DoS exploit to demonstrate the vulnerability:
http://census-labs.com/media/mountnfsex.c
Furthermore, we have also developed a privilege escalation exploit for this
second vulnerability which will not be released at this point.
FreeBSD has released an official advisory and a patch to address both
vulnerabilities:
http://security.freebsd.org/advisories/FreeBSD-SA-10:06.nfsclient.asc
All affected parties are advised to follow the upgrade instructions
included in the advisory and patch their systems.
--
Patroklos Argyroudis
http://www.census-labs.com/