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 <chi.ding@mobica.com>
Closes: https://bugs.freedesktop.org/show_bug.cgi?id=65186
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 @@
 	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 @@
 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;
 
-	return wl_connection_write(connection, buffer, size);
+	size = serialize_closure(closure, buffer, buffer_size);
+	if (size < 0) {
+		free(buffer);
+		return -1;
+	}
+
+	result = wl_connection_write(connection, buffer, size);
+	free(buffer);
+
+	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;
 
-	return wl_connection_queue(connection, buffer, size);
+	size = serialize_closure(closure, buffer, buffer_size);
+	if (size < 0) {
+		free(buffer);
+		return -1;
+	}
+
+	result = wl_connection_queue(connection, buffer, size);
+	free(buffer);
+
+	return result;
 }
 
 void