BUG/MINOR: hlua_fcn: fix potential UAF with Queue:pop_wait()
If Queue:pop_wait() excecuted from a stream context and pop_wait() is aborted due to a Lua or ressource error, then the waiting object pointing to the task will still be registered, so if the task eventually dissapears, Queue:push() may try to wake invalid task pointer.. To prevent this bug from happening, we now rely on notification_* API to deliver waiting signals. This way signals are properly garbage collected when a lua context is destroyed. It should be backported in 2.8 with 86fb22c55 ("MINOR: hlua_fcn: add Queue class"). This patch depends on ("MINOR: task: add thread safe notification_new and notification_wake variants")
This commit is contained in:
parent
b77b1a2c3a
commit
c6fa061f22
@ -515,22 +515,10 @@ struct hlua_queue_item {
|
||||
struct mt_list list;
|
||||
};
|
||||
|
||||
/* used to store wait entries in queue->wait_tasks */
|
||||
struct hlua_queue_wait
|
||||
{
|
||||
struct task *task;
|
||||
struct mt_list entry;
|
||||
};
|
||||
|
||||
/* This is the memory pool containing struct hlua_queue_item (queue items)
|
||||
*/
|
||||
DECLARE_STATIC_POOL(pool_head_hlua_queue, "hlua_queue", sizeof(struct hlua_queue_item));
|
||||
|
||||
/* This is the memory pool containing struct hlua_queue_wait
|
||||
* (queue waiting tasks)
|
||||
*/
|
||||
DECLARE_STATIC_POOL(pool_head_hlua_queuew, "hlua_queuew", sizeof(struct hlua_queue_wait));
|
||||
|
||||
static struct hlua_queue *hlua_check_queue(lua_State *L, int ud)
|
||||
{
|
||||
return hlua_checkudata(L, ud, class_queue_ref);
|
||||
@ -557,8 +545,6 @@ static int hlua_queue_push(lua_State *L)
|
||||
{
|
||||
struct hlua_queue *queue = hlua_check_queue(L, 1);
|
||||
struct hlua_queue_item *item;
|
||||
struct mt_list back;
|
||||
struct hlua_queue_wait *waiter;
|
||||
|
||||
if (lua_gettop(L) != 2 || lua_isnoneornil(L, 2)) {
|
||||
luaL_error(L, "unexpected argument");
|
||||
@ -583,9 +569,7 @@ static int hlua_queue_push(lua_State *L)
|
||||
MT_LIST_APPEND(&queue->list, &item->list);
|
||||
|
||||
/* notify tasks waiting on queue:pop_wait() (if any) */
|
||||
MT_LIST_FOR_EACH_ENTRY_LOCKED(waiter, &queue->wait_tasks, entry, back) {
|
||||
task_wakeup(waiter->task, TASK_WOKEN_MSG);
|
||||
}
|
||||
notification_wake_mt(&queue->wait_tasks);
|
||||
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
@ -641,24 +625,25 @@ static int hlua_queue_pop(lua_State *L)
|
||||
static int _hlua_queue_pop_wait(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct hlua_queue *queue = hlua_check_queue(L, 1);
|
||||
struct hlua_queue_wait *wait = lua_touserdata(L, 2);
|
||||
|
||||
/* new pop attempt */
|
||||
if (!_hlua_queue_pop(L, queue)) {
|
||||
struct hlua *hlua;
|
||||
|
||||
hlua = hlua_gethlua(L);
|
||||
if (!notification_new_mt(&hlua->com, &queue->wait_tasks, hlua->task)) {
|
||||
lua_pushnil(L);
|
||||
return 1; /* memory error, return nil */
|
||||
}
|
||||
hlua_yieldk(L, 0, 0, _hlua_queue_pop_wait, TICK_ETERNITY, 0); // wait retry
|
||||
return 0; // never reached, yieldk won't return
|
||||
}
|
||||
|
||||
/* remove task from waiting list */
|
||||
MT_LIST_DELETE(&wait->entry);
|
||||
pool_free(pool_head_hlua_queuew, wait);
|
||||
|
||||
return 1; // success
|
||||
}
|
||||
static int hlua_queue_pop_wait(lua_State *L)
|
||||
{
|
||||
struct hlua_queue *queue = hlua_check_queue(L, 1);
|
||||
struct hlua_queue_wait *wait;
|
||||
struct hlua *hlua;
|
||||
|
||||
BUG_ON(!queue);
|
||||
@ -678,21 +663,6 @@ static int hlua_queue_pop_wait(lua_State *L)
|
||||
|
||||
/* no pending items, waiting required */
|
||||
|
||||
wait = pool_alloc(pool_head_hlua_queuew);
|
||||
if (!wait) {
|
||||
lua_pushnil(L);
|
||||
return 1; /* memory error, return nil */
|
||||
}
|
||||
|
||||
wait->task = hlua->task;
|
||||
MT_LIST_INIT(&wait->entry);
|
||||
|
||||
/* add task to queue's wait list */
|
||||
MT_LIST_TRY_APPEND(&queue->wait_tasks, &wait->entry);
|
||||
|
||||
/* push wait entry at index 2 on the stack (queue is already there) */
|
||||
lua_pushlightuserdata(L, wait);
|
||||
|
||||
/* Go to waiting loop which immediately performs a new attempt to make
|
||||
* sure we didn't miss a push during the wait entry initialization.
|
||||
*
|
||||
@ -738,20 +708,8 @@ static int hlua_queue_new(lua_State *L)
|
||||
static int hlua_queue_gc(struct lua_State *L)
|
||||
{
|
||||
struct hlua_queue *queue = hlua_check_queue(L, 1);
|
||||
struct hlua_queue_wait *wait;
|
||||
struct hlua_queue_item *item;
|
||||
|
||||
/* Purge waiting tasks (if any)
|
||||
*
|
||||
* It is normally not expected to have waiting tasks, except if such
|
||||
* task has been aborted while in the middle of a queue:pop_wait()
|
||||
* function call.
|
||||
*/
|
||||
while ((wait = MT_LIST_POP(&queue->wait_tasks, typeof(wait), entry))) {
|
||||
/* free the wait entry */
|
||||
pool_free(pool_head_hlua_queuew, wait);
|
||||
}
|
||||
|
||||
/* purge remaining (unconsumed) items in the queue */
|
||||
while ((item = MT_LIST_POP(&queue->list, typeof(item), list))) {
|
||||
/* free the queue item */
|
||||
|
Loading…
x
Reference in New Issue
Block a user