From c102c20f01c84abde71b7f208aae9b232226da1e Mon Sep 17 00:00:00 2001 From: chi ding Date: Thu, 5 Dec 2013 14:28:53 +0100 Subject: [PATCH] Fix buffer overflow when serializing a closure object Here is the JIRA page of this issue https://bugs.tizen.org/jira/browse/TIVI-1889 Change-Id: I773a6d2d8f6fd02ff10c92450db1fa8a69544219 Signed-off-by: Chi Ding Closes: https://bugs.freedesktop.org/show_bug.cgi?id=65186 --- src/connection.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 8 deletions(-) diff --git a/src/connection.c b/src/connection.c index 1d8b61b..d05341a 100644 --- a/src/connection.c +++ b/src/connection.c @@ -962,6 +962,57 @@ copy_fds_to_connection(struct wl_closure *closure, return 0; } + +static uint32_t +buffer_size_for_closure(struct wl_closure *closure) +{ + const struct wl_message *message = closure->message; + int i, count; + struct argument_details arg; + const char *signature; + uint32_t size, buffer_size = 0; + + signature = message->signature; + count = arg_count_for_signature(signature); + for (i = 0; i < count; i++) { + signature = get_next_argument(signature, &arg); + + switch (arg.type) { + case 'h': + break; + case 'u': + case 'i': + case 'f': + case 'o': + case 'n': + buffer_size++; + break; + case 's': + if (closure->args[i].s == NULL) { + buffer_size++; + break; + } + + size = strlen(closure->args[i].s) + 1; + buffer_size += 1 + DIV_ROUNDUP(size, sizeof(uint32_t)); + break; + case 'a': + if (closure->args[i].a == NULL) { + buffer_size++; + break; + } + + size = closure->args[i].a->size; + buffer_size += (1 + DIV_ROUNDUP(size, sizeof(uint32_t))); + break; + default: + break; + } + } + + return buffer_size + 2; +} + static int serialize_closure(struct wl_closure *closure, uint32_t *buffer, size_t buffer_count) @@ -1055,33 +1106,57 @@ overflow: int wl_closure_send(struct wl_closure *closure, struct wl_connection *connection) { - uint32_t buffer[256]; int size; + uint32_t buffer_size; + uint32_t *buffer; + int result; if (copy_fds_to_connection(closure, connection)) return -1; - size = serialize_closure(closure, buffer, 256); - if (size < 0) + buffer_size = buffer_size_for_closure(closure); + buffer = malloc(buffer_size * sizeof buffer[0]); + if (buffer == NULL) + return -1; + + size = serialize_closure(closure, buffer, buffer_size); + if (size < 0) { + free(buffer); return -1; + } + + result = wl_connection_write(connection, buffer, size); + free(buffer); - return wl_connection_write(connection, buffer, size); + return result; } int wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection) { - uint32_t buffer[256]; int size; + uint32_t buffer_size; + uint32_t *buffer; + int result; if (copy_fds_to_connection(closure, connection)) return -1; - size = serialize_closure(closure, buffer, 256); - if (size < 0) + buffer_size = buffer_size_for_closure(closure); + buffer = malloc(buffer_size * sizeof buffer[0]); + if (buffer == NULL) + return -1; + + size = serialize_closure(closure, buffer, buffer_size); + if (size < 0) { + free(buffer); return -1; + } + + result = wl_connection_queue(connection, buffer, size); + free(buffer); - return wl_connection_queue(connection, buffer, size); + return result; } void -- 2.7.4