macOS/iOS Kernel - Heap Overflow Due to Lack of Lower Size Check in getvolattrlist

EDB-ID: 44848
Author: Google Security Research
Published: 2018-06-06
CVE: CVE-2018-4243
Type: Dos
Platform: Multiple
Aliases: N/A
Advisory/Source: Link
Tags: Heap Overflow
Vulnerable App: N/A

 getvolattrlist takes a user controlled bufferSize argument via the fgetattrlist syscall. 

When allocating a kernel buffer to serialize the attr list to there's the following comment:

/*
* Allocate a target buffer for attribute results.
* Note that since we won't ever copy out more than the caller requested,
* we never need to allocate more than they offer.
*/
ab.allocated = ulmin(bufferSize, fixedsize + varsize);
if (ab.allocated > ATTR_MAX_BUFFER) {
error = ENOMEM;
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab.allocated, ATTR_MAX_BUFFER);
goto out;
}
MALLOC(ab.base, char *, ab.allocated, M_TEMP, M_ZERO | M_WAITOK);

The problem is that the code doesn't then correctly handle the case when the user supplied buffer size
is smaller that the requested header size. If we pass ATTR_CMN_RETURNED_ATTRS we'll hit the following code:

/* Return attribute set output if requested. */
if (return_valid) {
ab.actual.commonattr |= ATTR_CMN_RETURNED_ATTRS;
if (pack_invalid) {
/* Only report the attributes that are valid */
ab.actual.commonattr &= ab.valid.commonattr;
ab.actual.volattr &= ab.valid.volattr;
}
bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof (ab.actual));
}

There's no check that the allocated buffer is big enough to hold at least that.

Tested on MacOS 10.13.4 (17E199)
*/

// ianbeer
#if 0
MacOS/iOS kernel heap overflow due to lack of lower size check in getvolattrlist

getvolattrlist takes a user controlled bufferSize argument via the fgetattrlist syscall.

When allocating a kernel buffer to serialize the attr list to there's the following comment:

/*
* Allocate a target buffer for attribute results.
* Note that since we won't ever copy out more than the caller requested,
* we never need to allocate more than they offer.
*/
ab.allocated = ulmin(bufferSize, fixedsize + varsize);
if (ab.allocated > ATTR_MAX_BUFFER) {
error = ENOMEM;
VFS_DEBUG(ctx, vp, "ATTRLIST - ERROR: buffer size too large (%d limit %d)", ab.allocated, ATTR_MAX_BUFFER);
goto out;
}
MALLOC(ab.base, char *, ab.allocated, M_TEMP, M_ZERO | M_WAITOK);

The problem is that the code doesn't then correctly handle the case when the user supplied buffer size
is smaller that the requested header size. If we pass ATTR_CMN_RETURNED_ATTRS we'll hit the following code:

/* Return attribute set output if requested. */
if (return_valid) {
ab.actual.commonattr |= ATTR_CMN_RETURNED_ATTRS;
if (pack_invalid) {
/* Only report the attributes that are valid */
ab.actual.commonattr &= ab.valid.commonattr;
ab.actual.volattr &= ab.valid.volattr;
}
bcopy(&ab.actual, ab.base + sizeof(uint32_t), sizeof (ab.actual));
}

There's no check that the allocated buffer is big enough to hold at least that.

Tested on MacOS 10.13.4 (17E199)

Related Posts