mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-11-03 09:01:42 -05:00
Demarshal robustness fixes
This commit is contained in:
parent
6d70202f80
commit
5b0079aed5
3 changed files with 90 additions and 31 deletions
81
connection.c
81
connection.c
|
|
@ -29,6 +29,7 @@
|
||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "wayland-util.h"
|
#include "wayland-util.h"
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
|
@ -279,7 +280,7 @@ wl_connection_vmarshal(struct wl_connection *connection,
|
||||||
wl_connection_write(connection, args, size);
|
wl_connection_write(connection, args, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
wl_connection_demarshal(struct wl_connection *connection,
|
wl_connection_demarshal(struct wl_connection *connection,
|
||||||
uint32_t size,
|
uint32_t size,
|
||||||
struct wl_hash_table *objects,
|
struct wl_hash_table *objects,
|
||||||
|
|
@ -289,8 +290,8 @@ wl_connection_demarshal(struct wl_connection *connection,
|
||||||
{
|
{
|
||||||
ffi_type *types[20];
|
ffi_type *types[20];
|
||||||
ffi_cif cif;
|
ffi_cif cif;
|
||||||
uint32_t *p, result, length;
|
uint32_t *p, *next, *end, result, length;
|
||||||
int i, count;
|
int i, count, ret = 0;
|
||||||
union {
|
union {
|
||||||
uint32_t uint32;
|
uint32_t uint32;
|
||||||
char *string;
|
char *string;
|
||||||
|
|
@ -305,12 +306,12 @@ wl_connection_demarshal(struct wl_connection *connection,
|
||||||
count = strlen(message->signature) + 2;
|
count = strlen(message->signature) + 2;
|
||||||
if (count > ARRAY_LENGTH(types)) {
|
if (count > ARRAY_LENGTH(types)) {
|
||||||
printf("too many args (%d)\n", count);
|
printf("too many args (%d)\n", count);
|
||||||
return;
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sizeof buffer < size) {
|
if (sizeof buffer < size) {
|
||||||
printf("request too big, should malloc tmp buffer here\n");
|
printf("request too big, should malloc tmp buffer here\n");
|
||||||
return;
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
types[0] = &ffi_type_pointer;
|
types[0] = &ffi_type_pointer;
|
||||||
|
|
@ -323,7 +324,17 @@ wl_connection_demarshal(struct wl_connection *connection,
|
||||||
|
|
||||||
wl_connection_copy(connection, buffer, size);
|
wl_connection_copy(connection, buffer, size);
|
||||||
p = &buffer[2];
|
p = &buffer[2];
|
||||||
|
end = (uint32_t *) ((char *) (p + size));
|
||||||
for (i = 2; i < count; i++) {
|
for (i = 2; i < count; i++) {
|
||||||
|
if (p + 1 > end) {
|
||||||
|
printf("message too short, "
|
||||||
|
"object (%d), message %s(%s)\n",
|
||||||
|
*p, message->name, message->signature);
|
||||||
|
errno = EINVAL;
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
switch (message->signature[i - 2]) {
|
switch (message->signature[i - 2]) {
|
||||||
case 'u':
|
case 'u':
|
||||||
case 'i':
|
case 'i':
|
||||||
|
|
@ -333,21 +344,37 @@ wl_connection_demarshal(struct wl_connection *connection,
|
||||||
case 's':
|
case 's':
|
||||||
types[i] = &ffi_type_pointer;
|
types[i] = &ffi_type_pointer;
|
||||||
length = *p++;
|
length = *p++;
|
||||||
|
|
||||||
|
next = p + DIV_ROUNDUP(length, sizeof *p);
|
||||||
|
if (next > end) {
|
||||||
|
printf("message too short, "
|
||||||
|
"object (%d), message %s(%s)\n",
|
||||||
|
*p, message->name, message->signature);
|
||||||
|
errno = EINVAL;
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
values[i].string = malloc(length + 1);
|
values[i].string = malloc(length + 1);
|
||||||
if (values[i].string == NULL) {
|
if (values[i].string == NULL) {
|
||||||
/* FIXME: Send NO_MEMORY */
|
errno = ENOMEM;
|
||||||
return;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
memcpy(values[i].string, p, length);
|
memcpy(values[i].string, p, length);
|
||||||
values[i].string[length] = '\0';
|
values[i].string[length] = '\0';
|
||||||
p += DIV_ROUNDUP(length, sizeof *p);
|
p = next;
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
types[i] = &ffi_type_pointer;
|
types[i] = &ffi_type_pointer;
|
||||||
object = wl_hash_table_lookup(objects, *p);
|
object = wl_hash_table_lookup(objects, *p);
|
||||||
if (object == NULL && *p != 0)
|
if (object == NULL && *p != 0) {
|
||||||
printf("unknown object (%d), message %s(%s)\n",
|
printf("unknown object (%d), message %s(%s)\n",
|
||||||
*p, message->name, message->signature);
|
*p, message->name, message->signature);
|
||||||
|
errno = EINVAL;
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
values[i].object = object;
|
values[i].object = object;
|
||||||
p++;
|
p++;
|
||||||
break;
|
break;
|
||||||
|
|
@ -355,26 +382,46 @@ wl_connection_demarshal(struct wl_connection *connection,
|
||||||
types[i] = &ffi_type_uint32;
|
types[i] = &ffi_type_uint32;
|
||||||
values[i].new_id = *p;
|
values[i].new_id = *p;
|
||||||
object = wl_hash_table_lookup(objects, *p);
|
object = wl_hash_table_lookup(objects, *p);
|
||||||
if (object != NULL)
|
if (object != NULL) {
|
||||||
printf("object already exists (%d)\n", *p);
|
printf("not a new object (%d), "
|
||||||
|
"message %s(%s)\n",
|
||||||
|
*p, message->name, message->signature);
|
||||||
|
errno = EINVAL;
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
p++;
|
p++;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
types[i] = &ffi_type_pointer;
|
types[i] = &ffi_type_pointer;
|
||||||
length = *p++;
|
length = *p++;
|
||||||
values[i].array = malloc(length + sizeof *values[i].array);
|
|
||||||
|
next = p + DIV_ROUNDUP(length, sizeof *p);
|
||||||
|
if (next > end) {
|
||||||
|
printf("message too short, "
|
||||||
|
"object (%d), message %s(%s)\n",
|
||||||
|
*p, message->name, message->signature);
|
||||||
|
errno = EINVAL;
|
||||||
|
ret = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
values[i].array =
|
||||||
|
malloc(length + sizeof *values[i].array);
|
||||||
if (values[i].array == NULL) {
|
if (values[i].array == NULL) {
|
||||||
/* FIXME: Send NO_MEMORY */
|
errno = ENOMEM;
|
||||||
return;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
values[i].array->size = length;
|
values[i].array->size = length;
|
||||||
values[i].array->alloc = 0;
|
values[i].array->alloc = 0;
|
||||||
values[i].array->data = values[i].array + 1;
|
values[i].array->data = values[i].array + 1;
|
||||||
memcpy(values[i].array->data, p, length);
|
memcpy(values[i].array->data, p, length);
|
||||||
p += DIV_ROUNDUP(length, sizeof *p);
|
p = next;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("unknown type\n");
|
printf("unknown type\n");
|
||||||
|
assert(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
args[i] = &values[i];
|
args[i] = &values[i];
|
||||||
|
|
@ -383,6 +430,8 @@ wl_connection_demarshal(struct wl_connection *connection,
|
||||||
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types);
|
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, count, &ffi_type_uint32, types);
|
||||||
ffi_call(&cif, func, &result, args);
|
ffi_call(&cif, func, &result, args);
|
||||||
|
|
||||||
|
out:
|
||||||
|
count = i;
|
||||||
for (i = 2; i < count; i++) {
|
for (i = 2; i < count; i++) {
|
||||||
switch (message->signature[i - 2]) {
|
switch (message->signature[i - 2]) {
|
||||||
case 's':
|
case 's':
|
||||||
|
|
@ -393,4 +442,6 @@ wl_connection_demarshal(struct wl_connection *connection,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
connection.h
12
connection.h
|
|
@ -48,11 +48,11 @@ void wl_connection_vmarshal(struct wl_connection *connection,
|
||||||
uint32_t opcode, va_list ap,
|
uint32_t opcode, va_list ap,
|
||||||
const struct wl_message *message);
|
const struct wl_message *message);
|
||||||
|
|
||||||
void wl_connection_demarshal(struct wl_connection *connection,
|
int wl_connection_demarshal(struct wl_connection *connection,
|
||||||
uint32_t size,
|
uint32_t size,
|
||||||
struct wl_hash_table *objects,
|
struct wl_hash_table *objects,
|
||||||
void (*func)(void),
|
void (*func)(void),
|
||||||
void *data, struct wl_object *target,
|
void *data, struct wl_object *target,
|
||||||
const struct wl_message *message);
|
const struct wl_message *message);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
24
wayland.c
24
wayland.c
|
|
@ -86,7 +86,7 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
|
||||||
struct wl_object *object;
|
struct wl_object *object;
|
||||||
uint32_t p[2], opcode, size;
|
uint32_t p[2], opcode, size;
|
||||||
uint32_t cmask = 0;
|
uint32_t cmask = 0;
|
||||||
int len;
|
int len, ret;
|
||||||
|
|
||||||
if (mask & WL_EVENT_READABLE)
|
if (mask & WL_EVENT_READABLE)
|
||||||
cmask |= WL_CONNECTION_READABLE;
|
cmask |= WL_CONNECTION_READABLE;
|
||||||
|
|
@ -123,13 +123,21 @@ wl_client_connection_data(int fd, uint32_t mask, void *data)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_connection_demarshal(client->connection,
|
ret = wl_connection_demarshal(client->connection,
|
||||||
size,
|
size,
|
||||||
client->display->objects,
|
client->display->objects,
|
||||||
object->implementation[opcode],
|
object->implementation[opcode],
|
||||||
client,
|
client,
|
||||||
object,
|
object,
|
||||||
&object->interface->methods[opcode]);
|
&object->interface->methods[opcode]);
|
||||||
|
|
||||||
|
if (ret < 0 && errno == EINVAL)
|
||||||
|
wl_client_post_event(client, &client->display->base,
|
||||||
|
WL_DISPLAY_INVALID_METHOD,
|
||||||
|
p[0], opcode);
|
||||||
|
if (ret < 0 && errno == ENOMEM)
|
||||||
|
wl_client_post_event(client, &client->display->base,
|
||||||
|
WL_DISPLAY_NO_MEMORY);
|
||||||
|
|
||||||
wl_connection_consume(connection, size);
|
wl_connection_consume(connection, size);
|
||||||
len -= size;
|
len -= size;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue