CVE-2024-22181
An out-of-bounds write vulnerability exists in the readNODE functionality of libigl v2.5.0. A specially crafted .node file can lead to an out-of-bounds write. An attacker can provide a malicious file to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
libigl v2.5.0
libigl - https://libigl.github.io/
7.8 - CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-129 - Improper Validation of Array Index
libigl is a C++ geometry processing library that is designed to be simple to integrate into projects using a header-only construction for the code base. This library is widely utilized in industries ranging from Triple-A game development to 3D printing, and it can be found in many applications that require the geometry processing of various file formats.
There exists an out-of-bounds write condition when parsing a .NODE file where the number of entries declared in the header is inconsistent with the number of entries actually present in the file. This can lead to the corruption of the vectors used to load this data in memory.
IGL_INLINE bool igl::readNODE(
const std::string node_file_name,
Eigen::PlainObjectBase<DerivedV>& V,
Eigen::PlainObjectBase<DerivedI>& I)
{
...
// Read header
// n number of points
// dim dimension
// num_attr number of attributes
// num_bm number of boundary markers
int n,dim,num_attr,num_bm;
[0] int head_count = sscanf(line,"%d %d %d %d", &n, &dim, &num_attr, &num_bm);
...
// resize output
[1] V.resize(n,dim);
I.resize(n,1);
int line_no = 0;
int p = 0;
while (fgets(line, LINE_MAX, node_file) != NULL)
{
...
[2] if(sscanf(l,"%d%n",&I(p),&offset) != 1)
{
fprintf(stderr,"readNODE Error: bad index (%d) in %s...\n",
line_no,
node_file_name.c_str());
fclose(node_file);
return false;
}
// adjust offset
l += offset;
// Read coordinates
for(int d = 0;d < dim;d++)
{
[3] if(sscanf(l,"%lf%n",&V(p,d),&offset) != 1)
{
fprintf(stderr,"readNODE Error: bad coordinates (%d) in %s...\n",
line_no,
node_file_name.c_str());
fclose(node_file);
return false;
}
// adjust offset
l += offset;
}
...
[4] p++;
}
assert(p == V.rows());
fclose(node_file);
return true;
}
The readNODE
function resizes the V
and I
matrices at [1] based on the number of points declared in the .node
file header at [0]. However the p
variable in incremented at [4] is based on the number of lines processed and used as an index to the V
and I
matrices at [2] and [3]. This happens without verifying if p
is within the proper range. As such, if more lines are present in the .node
file than announced in the header, an out-of-bound write will occur when writing to I
and V
.
2023-11-22 - Initial Vendor Contact
2023-11-28 - Initial Vendor Contact
2023-11-30 - Request for confirmation
2023-12-11 - Advisories sent
2024-02-07 - Four more advisories sent, after the initial two
2024-02-27 - Request for status update
2024-04-10 - Request for status update
2ß24-05-15 - Request for status update via Github issue, no reply
2024-05-28 - Public Release
Discovered by Philippe Laulheret of Cisco Talos.