Hi all,
A verified out-of-bounds read vulnerability exists in the kname() function within `ldebug.c`.
Affected versions: 5.4.8 (while the PoC is for v5.4.8 on a MacOS, the bug is also tested on 5.3.4 with a different PoC on a downstream project)
Vulnerability Type: oob_read
File: ldebug.c
Affected Code:
static const char *kname (const Proto *p, int index, const char **name) {
TValue *kvalue = &p->k[index]; // <-- SINK
if (ttisstring(kvalue)) {
*name = getstr(tsvalue(kvalue));
return "constant";
}
else {
*name = "?";
return NULL;
}
}
Root cause:
The function assumes that `index` is a valid, non-negative index within the bounds of the constant table `p->k`. There are:
- No checks for `index < 0`
- No checks for `index >= p->sizek` (or equivalent size field)
- No validation that `p` or `p->k` is non-NULL
As a result, pointer arithmetic on `p->k[index]` may compute an address outside the allocated array.
Scenario:
- Craft malformed Lua bytecode chunk with manipulated instruction operands that decode into invalid constant index.During execution, particularily in debug, error-reporting or symbol resolution paths, the vm invokes kname() to get a constant's name.
Because kname() blindly dereferences `p->k[index]`, a maliciously chosen `index` (negative or excessively large) causes the vm to read memory outside the constant table. Depending on memory layout this could:
- leak adjacent heap
- segfault (DoS)
PoC:
a malformed Lua bytecode, when run (lua exploit54_patched.luac) makes kname() read invalid memory when trying to format error message (instead of reading constant string 'undefined_var', it tries to read garbage from p->k[255]).
Example patch:
static const char *kname (const Proto *p, int index, const char **name) {
if (p == NULL || p->k == NULL || index < 0 || index >= p->sizek) {
*name = "?";
return NULL;
}
TValue *kvalue = &p->k[index];
if (ttisstring(kvalue)) {
*name = getstr(tsvalue(kvalue));
return "constant";
}
else {
*name = "?";
return NULL;
}
}
Regards,
Biniam