package/wayland: fix CVE-2021-3782

Add an upstream patch to fix CVE-2021-3782:
An internal reference count is held on the buffer pool, incremented
every time a new buffer is created from the pool. The reference count is
maintained as an int; on LP64 systems this can cause the reference count
to overflow if the client creates a large number of wl_shm buffer
objects, or if it can coerce the server to create a large number of
external references to the buffer storage. With the reference count
overflowing, a use-after-free can be constructed on the wl_shm_pool
tracking structure, where values may be incremented or decremented; it
may also be possible to construct a limited oracle to leak 4 bytes of
server-side memory to the attacking client at a time.

The first patch (0003-util-set-errno-in-wl_map_reserve_new.patch) comes
from upstream and its sole purpose is to allow the patch fixing
CVE-2021-3782 to be cleanly applied without any modification.

Cc: Quentin Schulz <foss+buildroot@0leil.net>
Signed-off-by: Quentin Schulz <quentin.schulz@theobroma-systems.com>
Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
This commit is contained in:
Quentin Schulz 2022-12-16 12:29:08 +01:00 committed by Peter Korsgaard
parent ea51485ee9
commit 01548a7be1
3 changed files with 202 additions and 0 deletions

View File

@ -0,0 +1,92 @@
From ddf558b9a269f24bf1a47043b942065e8f28fed0 Mon Sep 17 00:00:00 2001
From: Aleksandr Mezin <mezin.alexander@gmail.com>
Date: Wed, 9 Feb 2022 04:10:42 +0600
Subject: [PATCH] util: set errno in wl_map_reserve_new()
And also fix wl_connection_demarshal() to pass through that errno.
Signed-off-by: Aleksandr Mezin <mezin.alexander@gmail.com>
[Retrieved (only for clean application of next patch) from
https://gitlab.freedesktop.org/wayland/wayland/-/commit/03e8a1f84b6a15c9531db1ca8d0a25f9fcffaf25]
Signed-off-by: Quentin Schulz <quentin.schulz@theobroma-systems.com>
---
src/connection.c | 10 ++++++----
src/wayland-util.c | 14 +++++++++++---
2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/src/connection.c b/src/connection.c
index d0c7d9f..6a116ad 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -803,10 +803,12 @@ wl_connection_demarshal(struct wl_connection *connection,
}
if (wl_map_reserve_new(objects, id) < 0) {
- wl_log("not a valid new object id (%u), "
- "message %s(%s)\n",
- id, message->name, message->signature);
- errno = EINVAL;
+ if (errno == EINVAL) {
+ wl_log("not a valid new object id (%u), "
+ "message %s(%s)\n", id,
+ message->name,
+ message->signature);
+ }
goto err;
}
diff --git a/src/wayland-util.c b/src/wayland-util.c
index d5973bf..5d28531 100644
--- a/src/wayland-util.c
+++ b/src/wayland-util.c
@@ -24,6 +24,7 @@
* SOFTWARE.
*/
+#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
@@ -257,13 +258,17 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i)
struct wl_array *entries;
if (i < WL_SERVER_ID_START) {
- if (map->side == WL_MAP_CLIENT_SIDE)
+ if (map->side == WL_MAP_CLIENT_SIDE) {
+ errno = EINVAL;
return -1;
+ }
entries = &map->client_entries;
} else {
- if (map->side == WL_MAP_SERVER_SIDE)
+ if (map->side == WL_MAP_SERVER_SIDE) {
+ errno = EINVAL;
return -1;
+ }
entries = &map->server_entries;
i -= WL_SERVER_ID_START;
@@ -271,8 +276,10 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i)
count = entries->size / sizeof *start;
- if (count < i)
+ if (count < i) {
+ errno = EINVAL;
return -1;
+ }
if (count == i) {
wl_array_add(entries, sizeof *start);
@@ -281,6 +288,7 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i)
} else {
start = entries->data;
if (start[i].data != NULL) {
+ errno = EINVAL;
return -1;
}
}
--
2.38.1

View File

@ -0,0 +1,106 @@
From 62b9b6f86421ac7afc7cfe7b1627a8ec2a3c4874 Mon Sep 17 00:00:00 2001
From: Derek Foreman <derek.foreman@collabora.com>
Date: Fri, 28 Jan 2022 13:18:37 -0600
Subject: [PATCH] util: Limit size of wl_map
Since server IDs are basically indistinguishable from really big client
IDs at many points in the source, it's theoretically possible to overflow
a map and either overflow server IDs into the client ID space, or grow
client IDs into the server ID space. This would currently take a massive
amount of RAM, but the definition of massive changes yearly.
Prevent this by placing a ridiculous but arbitrary upper bound on the
number of items we can put in a map: 0xF00000, somewhere over 15 million.
This should satisfy pathological clients without restriction, but stays
well clear of the 0xFF000000 transition point between server and client
IDs. It will still take an improbable amount of RAM to hit this, and a
client could still exhaust all RAM in this way, but our goal is to prevent
overflow and undefined behaviour.
Fixes #224
Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
[Retrieved from
https://gitlab.freedesktop.org/wayland/wayland/-/commit/b19488c7154b902354cb26a27f11415d7799b0b2]
Signed-off-by: Quentin Schulz <quentin.schulz@theobroma-systems.com>
---
src/wayland-private.h | 1 +
src/wayland-util.c | 25 +++++++++++++++++++++++--
2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 9bf8cb7..35dc40e 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -45,6 +45,7 @@
#define WL_MAP_SERVER_SIDE 0
#define WL_MAP_CLIENT_SIDE 1
#define WL_SERVER_ID_START 0xff000000
+#define WL_MAP_MAX_OBJECTS 0x00f00000
#define WL_CLOSURE_MAX_ARGS 20
struct wl_object {
diff --git a/src/wayland-util.c b/src/wayland-util.c
index 5d28531..c712f03 100644
--- a/src/wayland-util.c
+++ b/src/wayland-util.c
@@ -196,6 +196,7 @@ wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data)
union map_entry *start, *entry;
struct wl_array *entries;
uint32_t base;
+ uint32_t count;
if (map->side == WL_MAP_CLIENT_SIDE) {
entries = &map->client_entries;
@@ -216,10 +217,25 @@ wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data)
start = entries->data;
}
+ /* wl_array only grows, so if we have too many objects at
+ * this point there's no way to clean up. We could be more
+ * pro-active about trying to avoid this allocation, but
+ * it doesn't really matter because at this point there is
+ * nothing to be done but disconnect the client and delete
+ * the whole array either way.
+ */
+ count = entry - start;
+ if (count > WL_MAP_MAX_OBJECTS) {
+ /* entry->data is freshly malloced garbage, so we'd
+ * better make it a NULL so wl_map_for_each doesn't
+ * dereference it later. */
+ entry->data = NULL;
+ return 0;
+ }
entry->data = data;
entry->next |= (flags & 0x1) << 1;
- return (entry - start) + base;
+ return count + base;
}
int
@@ -236,6 +252,9 @@ wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data)
i -= WL_SERVER_ID_START;
}
+ if (i > WL_MAP_MAX_OBJECTS)
+ return -1;
+
count = entries->size / sizeof *start;
if (count < i)
return -1;
@@ -274,8 +293,10 @@ wl_map_reserve_new(struct wl_map *map, uint32_t i)
i -= WL_SERVER_ID_START;
}
- count = entries->size / sizeof *start;
+ if (i > WL_MAP_MAX_OBJECTS)
+ return -1;
+ count = entries->size / sizeof *start;
if (count < i) {
errno = EINVAL;
return -1;
--
2.38.1

View File

@ -14,6 +14,10 @@ WAYLAND_INSTALL_STAGING = YES
WAYLAND_DEPENDENCIES = host-pkgconf host-wayland expat libffi libxml2
HOST_WAYLAND_DEPENDENCIES = host-pkgconf host-expat host-libffi host-libxml2
# 0003-util-set-errno-in-wl_map_reserve_new.patch
# 0004-util-Limit-size-of-wl_map.patch
WAYLAND_IGNORE_CVES += CVE-2021-3782
WAYLAND_CONF_OPTS = -Dtests=false -Ddocumentation=false
HOST_WAYLAND_CONF_OPTS = -Dtests=false -Ddocumentation=false