hlua_error() is a printf-family function (calls vsnprintf), but
hlua_patref_set, hlua_patref_add, and _hlua_patref_add_bulk pass
errmsg directly as the format string. errmsg is built by pattern.c
helpers that embed the user-supplied key or value verbatim, e.g.
pat_ref_set_elt() generates "unable to parse '<value>'".
A Lua script calling:
ref:set("key", "%p.%p.%p.%p.%p.%p.%p.%p")
against a map with an integer output type (where the parse fails)
gets stack/register contents formatted into the (nil, err) return
value -> ASLR/canary leak. With %n and no _FORTIFY_SOURCE this
becomes an arbitrary write primitive.
Combined with the httpclient stack overflow (commit de764e64fa44),
the leak defeats stack canaries to achieve reliable RCE.
This must be backported as far as the Patref Lua API exists.
---
src/hlua_fcn.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/hlua_fcn.c b/src/hlua_fcn.c
index 36c5f98d021f..f204c0a048c4 100644
--- a/src/hlua_fcn.c
+++ b/src/hlua_fcn.c
@@ -2870,7 +2870,7 @@ int hlua_patref_add(lua_State *L)
if (!ret) {
- ret = hlua_error(L, errmsg);
+ ret = hlua_error(L, "%s", errmsg);
ha_free(&errmsg);
return ret;
}
@@ -2919,7 +2919,7 @@ static int _hlua_patref_add_bulk(lua_State *L, int
status, lua_KContext ctx)
if (!pat_ref_load(ref->ptr, curr_gen, key, value, -1, &errmsg))
{
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->ptr->lock);
- ret = hlua_error(L, errmsg);
+ ret = hlua_error(L, "%s", errmsg);
ha_free(&errmsg);
return ret;
}
@@ -3023,7 +3023,7 @@ int hlua_patref_set(lua_State *L)
HA_RWLOCK_WRUNLOCK(PATREF_LOCK, &ref->ptr->lock);
if (!ret) {
- ret = hlua_error(L, errmsg);
+ ret = hlua_error(L, "%s", errmsg);
ha_free(&errmsg);
return ret;
}
--
2.53.0