Mono `strtod` Bounds Checking Vulnerability ==== Severity ---- High Impact ---- An attacker who can cause a carefully-chosen string to be converted to a floating-point number can cause a crash and potentially induce arbitrary code execution. Details ---- The float-parsing code used in Mono (before 4.2) is derived from classic code written by David M. Gay, and lives in `mono/utils/strtod.c`. This code has a vulnerability which has been noted before, and fixed in the upstream version, but this fix was apparently not propagated into the Mono codebase. See [1]. The issue concerns the `freelist` array, which is a global array of 16 pointers to `Bigint`. This array is part of a memory allocation and reuse system which attempts to reduce the number of `malloc` and `free` calls. The system allocates blocks in power-of-two sizes, from 2^0 through 2^15, and stores freed blocks of each size in a linked list rooted at the corresponding cell of `freelist`. The `Balloc` and `Bfree` functions which operate this system fail to check if the size parameter `k` is within the allocated 0..15 range. As a result, a sufficiently large allocation will have k=16 and treat the word immediately after `freelist` as a pointer to a previously-allocated chunk. The specific results may vary significantly based on the version, platform, and compiler, since they depend on the layout of variables in memory. However, the worst-case scenario of arbitrary code execution should be assumed until it can be ruled out. For an example, in a version distributed with Ubuntu 12.04, `freelist[16]` coincides with the variable `p5s`, which stores the number 625 in `Bigint` form. Importantly, this allocation is small. When the code reuses this supposedly-free space and attempts to write a large number, the numeric data overflows the allocation and can affect other parts of the program. By overwriting `malloc` heap metadata, it is likely possible to cause arbitrary code execution, although we do not yet have a full demonstration of this. The vulnerable code does not appear in version 4.2, which seems to use a different library. [1]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0689 Reproduction ---- The following C# code suffices to demonstrate the issue on Mac OS X with packaged Mono versions 3.12.1 and 4.0.4: ~~~ using System; class Test { static void Main() { string input = "1." + new string('1', 294912); Double.Parse(input); } } ~~~ Running the input causes an immediate crash. Recommendation ---- Implement the checks found in the current version of the upstream software (http://www.netlib.org/fp/dtoa.c): Balloc ~~~ if (k <= Kmax && (rv = freelist[k])) freelist[k] = rv->next; else { ... ~~~ Bfree ~~~ if (v) { if (v->k > Kmax) #ifdef FREE FREE((void*)v); #else free((void*)v); #endif else { ACQUIRE_DTOA_LOCK(0); v->next = freelist[v->k]; freelist[v->k] = v; FREE_DTOA_LOCK(0); } } } ~~~ Consider a full upgrade, as there may be other relevant bugs in the original version. (See http://www.netlib.org/fp/changes for a rough changelog)