mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-10-31 22:25:25 -04:00
connection: Don't write past the end of the connection buffer
If a message was too big to fit in the connection buffer, the code in wl_buffer_put would just write past the end of it. I haven't seen any real world use case that would trigger this bug, but it was possible to trigger it by sending a long enough string to the wl_data_source.offer request. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=69267
This commit is contained in:
parent
5e2cfd2a0a
commit
bfc93649cb
2 changed files with 54 additions and 8 deletions
|
|
@ -61,11 +61,18 @@ struct wl_connection {
|
||||||
int want_flush;
|
int want_flush;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static int
|
||||||
wl_buffer_put(struct wl_buffer *b, const void *data, size_t count)
|
wl_buffer_put(struct wl_buffer *b, const void *data, size_t count)
|
||||||
{
|
{
|
||||||
uint32_t head, size;
|
uint32_t head, size;
|
||||||
|
|
||||||
|
if (count > sizeof(b->data)) {
|
||||||
|
wl_log("Data too big for buffer (%d > %d).\n",
|
||||||
|
count, sizeof(b->data));
|
||||||
|
errno = E2BIG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
head = MASK(b->head);
|
head = MASK(b->head);
|
||||||
if (head + count <= sizeof b->data) {
|
if (head + count <= sizeof b->data) {
|
||||||
memcpy(b->data + head, data, count);
|
memcpy(b->data + head, data, count);
|
||||||
|
|
@ -76,6 +83,8 @@ wl_buffer_put(struct wl_buffer *b, const void *data, size_t count)
|
||||||
}
|
}
|
||||||
|
|
||||||
b->head += count;
|
b->head += count;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -243,8 +252,8 @@ decode_cmsg(struct wl_buffer *buffer, struct msghdr *msg)
|
||||||
size /= sizeof(int32_t);
|
size /= sizeof(int32_t);
|
||||||
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++)
|
||||||
close(((int*)CMSG_DATA(cmsg))[i]);
|
close(((int*)CMSG_DATA(cmsg))[i]);
|
||||||
} else {
|
} else if (wl_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) {
|
||||||
wl_buffer_put(buffer, CMSG_DATA(cmsg), size);
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -350,7 +359,9 @@ wl_connection_write(struct wl_connection *connection,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_buffer_put(&connection->out, data, count);
|
if (wl_buffer_put(&connection->out, data, count) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
connection->want_flush = 1;
|
connection->want_flush = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -367,7 +378,7 @@ wl_connection_queue(struct wl_connection *connection,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_buffer_put(&connection->out, data, count);
|
return wl_buffer_put(&connection->out, data, count);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -394,9 +405,7 @@ wl_connection_put_fd(struct wl_connection *connection, int32_t fd)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_buffer_put(&connection->fds_out, &fd, sizeof fd);
|
return wl_buffer_put(&connection->fds_out, &fd, sizeof fd);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,27 @@ expected_fail_marshal(int expected_error, const char *format, ...)
|
||||||
assert(errno == expected_error);
|
assert(errno == expected_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
expected_fail_marshal_send(struct marshal_data *data, int expected_error,
|
||||||
|
const char *format, ...)
|
||||||
|
{
|
||||||
|
struct wl_closure *closure;
|
||||||
|
static const uint32_t opcode = 4444;
|
||||||
|
static struct wl_object sender = { NULL, NULL, 1234 };
|
||||||
|
struct wl_message message = { "test", format, NULL };
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
assert(closure);
|
||||||
|
assert(wl_closure_send(closure, data->write_connection) < 0);
|
||||||
|
assert(errno == expected_error);
|
||||||
|
|
||||||
|
wl_closure_destroy(closure);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(connection_marshal_nullables)
|
TEST(connection_marshal_nullables)
|
||||||
{
|
{
|
||||||
struct marshal_data data;
|
struct marshal_data data;
|
||||||
|
|
@ -490,6 +511,22 @@ TEST(connection_marshal_alot)
|
||||||
release_marshal_data(&data);
|
release_marshal_data(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(connection_marshal_too_big)
|
||||||
|
{
|
||||||
|
struct marshal_data data;
|
||||||
|
char *big_string = malloc(5000);
|
||||||
|
|
||||||
|
memset(big_string, ' ', 4999);
|
||||||
|
big_string[4999] = '\0';
|
||||||
|
|
||||||
|
setup_marshal_data(&data);
|
||||||
|
|
||||||
|
expected_fail_marshal_send(&data, E2BIG, "s", big_string);
|
||||||
|
|
||||||
|
release_marshal_data(&data);
|
||||||
|
free(big_string);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
marshal_helper(const char *format, void *handler, ...)
|
marshal_helper(const char *format, void *handler, ...)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue