diff --git a/src/connection.c b/src/connection.c index 593f52f..28d2753 100644 --- a/src/connection.c +++ b/src/connection.c @@ -619,6 +619,28 @@ wl_connection_get_fd(struct wl_connection *connection) return connection->fd; } +size_t +wl_connection_header_size(struct wl_connection *connection) +{ + // Adjust WL_HEADER_MAX_SIZE when increasing this. + return 8; +} + +void +wl_connection_parse_header(struct wl_connection *connection, + uint32_t *header, + uint32_t *sender_id, + int *size, + int *opcode) +{ + *sender_id = header[0]; + uint32_t field2 = header[1]; + uint32_t field2_hi = field2 >> 16; + uint32_t field2_lo = field2 & 0xffff; + *size = (int)field2_hi; + *opcode = (int)field2_lo; +} + static int wl_connection_put_fd(struct wl_connection *connection, int32_t fd) { @@ -894,14 +916,14 @@ wl_connection_demarshal(struct wl_connection *connection, uint32_t *p, *next, *end, length, length_in_u32, id; int fd; char *s; - int i, count, num_arrays; + int i, count, num_arrays, ssize, opcode; const char *signature; struct argument_details arg; struct wl_closure *closure; struct wl_array *array_extra; /* Space for sender_id and opcode */ - if (size < 2 * sizeof *p) { + if (size < wl_connection_header_size(connection)) { wl_log("message too short, invalid header\n"); wl_connection_consume(connection, size); errno = EINVAL; @@ -921,8 +943,9 @@ wl_connection_demarshal(struct wl_connection *connection, end = p + size / sizeof *p; wl_connection_copy(connection, p, size); - closure->sender_id = *p++; - closure->opcode = *p++ & 0x0000ffff; + wl_connection_parse_header(connection, p, &closure->sender_id, &ssize, &opcode); + closure->opcode = (uint32_t)opcode; + p += wl_connection_header_size(connection) / sizeof *p; signature = message->signature; for (i = 0; i < count; i++) { @@ -1283,7 +1306,7 @@ copy_fds_to_connection(struct wl_closure *closure, static uint32_t -buffer_size_for_closure(struct wl_closure *closure) +buffer_size_for_closure(struct wl_connection *connection, struct wl_closure *closure) { const struct wl_message *message = closure->message; int i, count; @@ -1329,23 +1352,24 @@ buffer_size_for_closure(struct wl_closure *closure) } } - return buffer_size + 2; + return buffer_size + wl_connection_header_size(connection) / sizeof(uint32_t); } static int -serialize_closure(struct wl_closure *closure, uint32_t *buffer, - size_t buffer_count) +serialize_closure(struct wl_connection *connection, struct wl_closure *closure, + uint32_t *buffer, size_t buffer_count) { const struct wl_message *message = closure->message; unsigned int i, count, size; uint32_t *p, *end; struct argument_details arg; const char *signature; + uint32_t header_words = wl_connection_header_size(connection) / sizeof(*buffer); - if (buffer_count < 2) + if (buffer_count < header_words) goto overflow; - p = buffer + 2; + p = buffer + header_words; end = buffer + buffer_count; signature = message->signature; @@ -1414,7 +1438,7 @@ serialize_closure(struct wl_closure *closure, uint32_t *buffer, size = (p - buffer) * sizeof *p; buffer[0] = closure->sender_id; - buffer[1] = size << 16 | (closure->opcode & 0x0000ffff); + buffer[1] = size << 16 | (closure->opcode & 0x0000ffff); return size; @@ -1436,7 +1460,7 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection) if (copy_fds_to_connection(closure, connection)) return -1; - buffer_size = buffer_size_for_closure(closure); + buffer_size = buffer_size_for_closure(connection, closure); buffer = zalloc(buffer_size * sizeof buffer[0]); if (buffer == NULL) { wl_log("wl_closure_send error: buffer allocation failure of " @@ -1446,7 +1470,7 @@ wl_closure_send(struct wl_closure *closure, struct wl_connection *connection) return -1; } - size = serialize_closure(closure, buffer, buffer_size); + size = serialize_closure(connection, closure, buffer, buffer_size); if (size < 0) { free(buffer); return -1; @@ -1469,7 +1493,7 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection) if (copy_fds_to_connection(closure, connection)) return -1; - buffer_size = buffer_size_for_closure(closure); + buffer_size = buffer_size_for_closure(connection, closure); buffer = malloc(buffer_size * sizeof buffer[0]); if (buffer == NULL) { wl_log("wl_closure_queue error: buffer allocation failure of " @@ -1479,7 +1503,7 @@ wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection) return -1; } - size = serialize_closure(closure, buffer, buffer_size); + size = serialize_closure(connection, closure, buffer, buffer_size); if (size < 0) { free(buffer); return -1; diff --git a/src/wayland-client.c b/src/wayland-client.c index c863304..aa04ed7 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -1564,7 +1564,7 @@ increase_closure_args_refcount(struct wl_closure *closure) static int queue_event(struct wl_display *display, int len) { - uint32_t p[2], id; + uint32_t p[WL_MAX_HEADER_U32], id; int opcode, size; struct wl_proxy *proxy; struct wl_closure *closure; @@ -1574,10 +1574,8 @@ queue_event(struct wl_display *display, int len) unsigned int time; int num_zombie_fds; - wl_connection_copy(display->connection, p, sizeof p); - id = p[0]; - opcode = p[1] & 0xffff; - size = p[1] >> 16; + wl_connection_copy(display->connection, p, wl_connection_header_size(display->connection)); + wl_connection_parse_header(display->connection, p, &id, &size, &opcode); /* * If the message is larger than the maximum size of the @@ -1736,6 +1734,7 @@ read_events(struct wl_display *display) { int total, rem, size; uint32_t serial; + int header_size = wl_connection_header_size(display->connection); display->reader_count--; if (display->reader_count == 0) { @@ -1760,7 +1759,7 @@ read_events(struct wl_display *display) return -1; } - for (rem = total; rem >= 8; rem -= size) { + for (rem = total; rem >= header_size; rem -= size) { size = queue_event(display, rem); if (size == -1) { display_fatal_error(display, errno); diff --git a/src/wayland-private.h b/src/wayland-private.h index d7ba9da..b2e14a8 100644 --- a/src/wayland-private.h +++ b/src/wayland-private.h @@ -49,6 +49,8 @@ #define WL_CLOSURE_MAX_ARGS 20 #define WL_BUFFER_DEFAULT_SIZE_POT 12 #define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT) +#define WL_MAX_HEADER_SIZE 8 +#define WL_MAX_HEADER_U32 (WL_MAX_HEADER_SIZE / 4) #if WL_BUFFER_DEFAULT_MAX_SIZE < WL_MAX_MESSAGE_SIZE # error default buffer cannot hold maximum-sized message #endif @@ -164,6 +166,16 @@ wl_connection_queue(struct wl_connection *connection, int wl_connection_get_fd(struct wl_connection *connection); +size_t +wl_connection_header_size(struct wl_connection *connection); + +void +wl_connection_parse_header(struct wl_connection *connection, + uint32_t *header, + uint32_t *sender_id, + int *size, + int *opcode); + struct wl_closure { int count; const struct wl_message *message; diff --git a/src/wayland-server.c b/src/wayland-server.c index 482743b..cd954f3 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -357,10 +357,12 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) struct wl_object *object; struct wl_closure *closure; const struct wl_message *message; - uint32_t p[2]; + uint32_t p[WL_MAX_HEADER_U32]; uint32_t resource_flags; + uint32_t object_id; int opcode, size, since; int len; + size_t header_size = wl_connection_header_size(connection); if (mask & WL_EVENT_HANGUP) { wl_client_destroy(client); @@ -394,10 +396,9 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) } } - while (len >= 0 && (size_t) len >= sizeof p) { - wl_connection_copy(connection, p, sizeof p); - opcode = p[1] & 0xffff; - size = p[1] >> 16; + while (len >= 0 && (size_t) len >= header_size) { + wl_connection_copy(connection, p, header_size); + wl_connection_parse_header(connection, p, &object_id, &size, &opcode); /* * If the message is larger than the maximum size of the @@ -424,12 +425,12 @@ wl_client_connection_data(int fd, uint32_t mask, void *data) if (len < size) break; - resource = wl_map_lookup(&client->objects, p[0]); - resource_flags = wl_map_lookup_flags(&client->objects, p[0]); + resource = wl_map_lookup(&client->objects, object_id); + resource_flags = wl_map_lookup_flags(&client->objects, object_id); if (resource == NULL) { wl_resource_post_error(client->display_resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "invalid object %u", p[0]); + "invalid object %u", object_id); break; }