ucode-mod-uline: fix crash on cleanup

- only run a single poll in the uloop_fd cb to avoid use-after-free on close
- delete the uloop_fd on close
- when calling into ucode, fetch the vm pointer before the call in order
  to avoid accessing the stale uline context

Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
Felix Fietkau 2025-04-30 10:40:38 +02:00
parent b9685dcf3d
commit d07c48fa09

View file

@ -306,15 +306,16 @@ cb_prepare(struct uc_uline_state *us, const char *name)
static uc_value_t * static uc_value_t *
cb_call_ret(struct uc_uline_state *us, size_t args, ...) cb_call_ret(struct uc_uline_state *us, size_t args, ...)
{ {
uc_vm_t *vm = us->vm;
va_list ap; va_list ap;
va_start(ap, args); va_start(ap, args);
for (size_t i = 0; i < args; i++) for (size_t i = 0; i < args; i++)
uc_vm_stack_push(us->vm, ucv_get(va_arg(ap, void *))); uc_vm_stack_push(vm, ucv_get(va_arg(ap, void *)));
va_end(ap); va_end(ap);
if (uc_vm_call(us->vm, true, args) == EXCEPTION_NONE) if (uc_vm_call(vm, true, args) == EXCEPTION_NONE)
return uc_vm_stack_pop(us->vm); return uc_vm_stack_pop(vm);
return NULL; return NULL;
} }
@ -369,21 +370,19 @@ static void uc_uline_poll_cb(struct uloop_fd *fd, unsigned int events)
struct uc_uline_state *us = container_of(fd, struct uc_uline_state, fd); struct uc_uline_state *us = container_of(fd, struct uc_uline_state, fd);
uc_value_t *val; uc_value_t *val;
while (!uloop_cancelled && us->poll_cb) { uline_poll(&us->s);
uline_poll(&us->s);
val = us->line; val = us->line;
if (!val) if (!val)
break; return;
us->line = NULL; us->line = NULL;
if (!ucv_is_callable(us->poll_cb)) if (!ucv_is_callable(us->poll_cb))
return; return;
uc_vm_stack_push(us->vm, ucv_get(us->res)); uc_vm_stack_push(us->vm, ucv_get(us->res));
uc_vm_stack_push(us->vm, ucv_get(us->poll_cb)); uc_vm_stack_push(us->vm, ucv_get(us->poll_cb));
cb_call(us, 1, val); cb_call(us, 1, val);
}
} }
static bool static bool
@ -543,6 +542,7 @@ static void free_state(void *ptr)
if (!us) if (!us)
return; return;
uloop_fd_delete(&us->fd);
registry = uc_vm_registry_get(us->vm, "uline.registry"); registry = uc_vm_registry_get(us->vm, "uline.registry");
ucv_array_set(registry, us->registry_index, NULL); ucv_array_set(registry, us->registry_index, NULL);
uline_free(&us->s); uline_free(&us->s);