libubus: limit stack depth for incoming invoke requests

This commit is contained in:
Felix Fietkau 2011-10-27 14:03:19 +02:00
parent f07b02b560
commit 8e5a6af1db
2 changed files with 42 additions and 1 deletions

View file

@ -56,6 +56,13 @@ struct ubus_pending_data {
struct blob_attr data[];
};
struct ubus_pending_invoke {
struct list_head list;
struct ubus_msghdr hdr;
};
static void ubus_process_pending_invoke(struct ubus_context *ctx);
static int ubus_cmp_id(const void *k1, const void *k2, void *ptr)
{
const uint32_t *id1 = k1, *id2 = k2;
@ -387,6 +394,7 @@ send:
static void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr)
{
struct ubus_pending_invoke *pending;
struct ubus_request *req;
switch(hdr->type) {
@ -405,11 +413,36 @@ static void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr)
break;
case UBUS_MSG_INVOKE:
ubus_process_invoke(ctx, hdr);
if (ctx->stack_depth > 2) {
pending = calloc(1, sizeof(*pending) +
blob_raw_len(hdr->data));
if (!pending)
return;
memcpy(&pending->hdr, hdr, sizeof(*hdr) +
blob_raw_len(hdr->data));
list_add(&pending->list, &ctx->pending);
} else {
ubus_process_invoke(ctx, hdr);
}
break;
}
}
static void ubus_process_pending_invoke(struct ubus_context *ctx)
{
struct ubus_pending_invoke *pending, *tmp;
list_for_each_entry_safe(pending, tmp, &ctx->pending, list) {
list_del(&pending->list);
ubus_process_msg(ctx, &pending->hdr);
free(pending);
if (ctx->stack_depth > 2)
break;
}
}
void ubus_abort_request(struct ubus_context *ctx, struct ubus_request *req)
{
if (!list_empty(&req->list))
@ -486,12 +519,14 @@ int ubus_complete_request(struct ubus_context *ctx, struct ubus_request *req,
ubus_complete_request_async(ctx, req);
req->complete_cb = ubus_sync_req_cb;
ctx->stack_depth++;
while (!req->status_msg) {
bool cancelled = uloop_cancelled;
uloop_cancelled = false;
uloop_run();
uloop_cancelled = cancelled;
}
ctx->stack_depth--;
if (timeout)
uloop_timeout_cancel(&cb.timeout);
@ -506,6 +541,9 @@ int ubus_complete_request(struct ubus_context *ctx, struct ubus_request *req,
if (!registered)
uloop_fd_delete(&ctx->sock);
if (!ctx->stack_depth)
ubus_process_pending_invoke(ctx);
return status;
}
@ -868,6 +906,7 @@ struct ubus_context *ubus_connect(const char *path)
ctx->connection_lost = ubus_default_connection_lost;
INIT_LIST_HEAD(&ctx->requests);
INIT_LIST_HEAD(&ctx->pending);
avl_init(&ctx->objects, ubus_cmp_id, false, NULL);
if (!ctx->local_id)

View file

@ -93,11 +93,13 @@ struct ubus_event_handler {
struct ubus_context {
struct list_head requests;
struct avl_tree objects;
struct list_head pending;
struct uloop_fd sock;
uint32_t local_id;
uint32_t request_seq;
int stack_depth;
void (*connection_lost)(struct ubus_context *ctx);