Skip to content

Commit 8e74276

Browse files
Darleleta-denoyelle
authored andcommitted
BUG/MINOR: hlua: don't use lua_pushfstring() when we don't expect LJMP
lua_pushfstring() is used in multiple cleanup paths (upon error) to push the error message that will be raised by lua_error(). However this is often done from an unprotected environment, or in the middle of a cleanup sequence, thus we don't want the function to LJMP! (it may cause various issues ranging from memory leaks to crashing the process..) Hopefully this has very few chances of happening but since the use of lua_pushfstring() is limited to error reporting here, it's ok to use our own hlua_pushfstring_safe() implementation with a little overhead to ensure that the function will never LJMP. This could be backported to all stable versions. (cherry picked from commit c0a3c12) Signed-off-by: Amaury Denoyelle <[email protected]>
1 parent 1780d58 commit 8e74276

File tree

1 file changed

+80
-11
lines changed

1 file changed

+80
-11
lines changed

src/hlua.c

Lines changed: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,70 @@ static const char *hlua_tostring_safe(lua_State *L, int index)
260260
return str;
261261
}
262262

263+
/* below is an helper function similar to lua_pushvfstring() to push a
264+
* formatted string on Lua stack but in a safe way (function may not LJMP).
265+
* It can be useful to push allocated strings (ie: error messages) on the
266+
* stack and ensure proper cleanup.
267+
*
268+
* Returns a pointer to the internal copy of the string on success and NULL
269+
* on error.
270+
*
271+
* It is assumed that the calling function is allowed to manipulate <L>
272+
*/
273+
__LJMP static int _hlua_pushvfstring_safe(lua_State *L)
274+
{
275+
const char **dst = lua_touserdata(L, 1);
276+
const char *fmt = lua_touserdata(L, 2);
277+
va_list *argp = lua_touserdata(L, 3);
278+
279+
*dst = lua_pushvfstring(L, fmt, *argp);
280+
return 1;
281+
}
282+
static const char *hlua_pushvfstring_safe(lua_State *L, const char *fmt, va_list argp)
283+
{
284+
const char *dst = NULL;
285+
va_list cpy_argp; /* required if argp is implemented as array type */
286+
287+
if (!lua_checkstack(L, 4))
288+
return NULL;
289+
290+
va_copy(cpy_argp, argp);
291+
292+
/* push our custom _hlua_pushvfstring_safe() function on the stack, then
293+
* push our destination string pointer, fmt and arg list
294+
*/
295+
lua_pushcfunction(L, _hlua_pushvfstring_safe);
296+
lua_pushlightuserdata(L, &dst); // 1st func argument = dst string pointer
297+
lua_pushlightuserdata(L, (void *)fmt); // 2nd func argument = fmt
298+
lua_pushlightuserdata(L, &cpy_argp); // 3rd func argument = arg list
299+
300+
/* call our custom function with proper arguments using pcall() to catch
301+
* exceptions (if any)
302+
*/
303+
switch (lua_pcall(L, 3, 1, 0)) {
304+
case LUA_OK:
305+
break;
306+
default:
307+
/* error was caught */
308+
dst = NULL;
309+
}
310+
va_end(cpy_argp);
311+
312+
return dst;
313+
}
314+
315+
static const char *hlua_pushfstring_safe(lua_State *L, const char *fmt, ...)
316+
{
317+
va_list argp;
318+
const char *dst;
319+
320+
va_start(argp, fmt);
321+
dst = hlua_pushvfstring_safe(L, fmt, argp);
322+
va_end(argp);
323+
324+
return dst;
325+
}
326+
263327
#define SET_SAFE_LJMP_L(__L, __HLUA) \
264328
({ \
265329
int ret; \
@@ -1367,8 +1431,8 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
13671431
}
13681432
reg = regex_comp(argp[idx].data.str.area, !(argp[idx].type_flags & ARGF_REG_ICASE), 1, &err);
13691433
if (!reg) {
1370-
msg = lua_pushfstring(L, "error compiling regex '%s' : '%s'",
1371-
argp[idx].data.str.area, err);
1434+
msg = hlua_pushfstring_safe(L, "error compiling regex '%s' : '%s'",
1435+
argp[idx].data.str.area, err);
13721436
free(err);
13731437
goto error;
13741438
}
@@ -1388,7 +1452,8 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
13881452
ul = auth_find_userlist(argp[idx].data.str.area);
13891453

13901454
if (!ul) {
1391-
msg = lua_pushfstring(L, "unable to find userlist '%s'", argp[idx].data.str.area);
1455+
msg = hlua_pushfstring_safe(L, "unable to find userlist '%s'",
1456+
argp[idx].data.str.area);
13921457
goto error;
13931458
}
13941459
argp[idx].type = ARGT_USR;
@@ -1412,9 +1477,9 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
14121477

14131478
/* Check for type of argument. */
14141479
if ((mask & ARGT_MASK) != argp[idx].type) {
1415-
msg = lua_pushfstring(L, "'%s' expected, got '%s'",
1416-
arg_type_names[(mask & ARGT_MASK)],
1417-
arg_type_names[argp[idx].type & ARGT_MASK]);
1480+
msg = hlua_pushfstring_safe(L, "'%s' expected, got '%s'",
1481+
arg_type_names[(mask & ARGT_MASK)],
1482+
arg_type_names[argp[idx].type & ARGT_MASK]);
14181483
goto error;
14191484
}
14201485

@@ -1960,9 +2025,11 @@ static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
19602025
msg = hlua_tostring_safe(lua->T, -1);
19612026
trace = hlua_traceback(lua->T, ", ");
19622027
if (msg)
1963-
lua_pushfstring(lua->T, "[state-id %d] runtime error: %s from %s", lua->state_id, msg, trace);
2028+
hlua_pushfstring_safe(lua->T, "[state-id %d] runtime error: %s from %s",
2029+
lua->state_id, msg, trace);
19642030
else
1965-
lua_pushfstring(lua->T, "[state-id %d] unknown runtime error from %s", lua->state_id, trace);
2031+
hlua_pushfstring_safe(lua->T, "[state-id %d] unknown runtime error from %s",
2032+
lua->state_id, trace);
19662033

19672034
/* Move the error msg at the top and then empty the stack except last msg */
19682035
lua_insert(lua->T, -lua_gettop(lua->T));
@@ -1984,9 +2051,11 @@ static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
19842051
}
19852052
msg = hlua_tostring_safe(lua->T, -1);
19862053
if (msg)
1987-
lua_pushfstring(lua->T, "[state-id %d] message handler error: %s", lua->state_id, msg);
2054+
hlua_pushfstring_safe(lua->T, "[state-id %d] message handler error: %s",
2055+
lua->state_id, msg);
19882056
else
1989-
lua_pushfstring(lua->T, "[state-id %d] message handler error", lua->state_id);
2057+
hlua_pushfstring_safe(lua->T, "[state-id %d] message handler error",
2058+
lua->state_id);
19902059

19912060
/* Move the error msg at the top and then empty the stack except last msg */
19922061
lua_insert(lua->T, -lua_gettop(lua->T));
@@ -4700,7 +4769,7 @@ __LJMP static int hlua_run_sample_fetch(lua_State *L)
47004769

47014770
/* Run the special args checker. */
47024771
if (f->val_args && !f->val_args(args, NULL)) {
4703-
lua_pushfstring(L, "error in arguments");
4772+
hlua_pushfstring_safe(L, "error in arguments");
47044773
goto error;
47054774
}
47064775

0 commit comments

Comments
 (0)