wayland: 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 thereference 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.

Reference:
https://nvd.nist.gov/vuln/detail/CVE-2021-3782

Upstream patch:
b19488c715

(From OE-Core rev: 09b8ff8d2361b2db001bc963f481db294ccf2170)

Signed-off-by: Narpat Mali <narpat.mali@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Narpat Mali
2022-11-03 17:00:43 -10:00
committed by Richard Purdie
parent d30ae5d97f
commit 305b505557
2 changed files with 113 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
From 5eed6609619cc2e4eaa8618d11c15d442abf54be 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>
Upstream-Status: Backport
CVE: CVE-2021-3782
Reference to upstream patch:
https://gitlab.freedesktop.org/wayland/wayland/-/commit/b19488c7154b902354cb26a27f11415d7799b0b2
[DP: adjust context for wayland version 1.20.0]
Signed-off-by: Dragos-Marian Panait <dragos.panait@windriver.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 d5973bf..3e45d19 100644
--- a/src/wayland-util.c
+++ b/src/wayland-util.c
@@ -195,6 +195,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;
@@ -215,10 +216,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
@@ -235,6 +251,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;
@@ -269,8 +288,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)
return -1;
--
2.37.3

View File

@@ -16,7 +16,9 @@ SRC_URI = "https://wayland.freedesktop.org/releases/${BPN}-${PV}.tar.xz \
file://run-ptest \
file://0002-Do-not-hardcode-the-path-to-wayland-scanner.patch \
file://0001-build-Fix-strndup-detection-on-MinGW.patch \
file://CVE-2021-3782.patch \
"
SRC_URI[sha256sum] = "b8a034154c7059772e0fdbd27dbfcda6c732df29cae56a82274f6ec5d7cd8725"
UPSTREAM_CHECK_URI = "https://wayland.freedesktop.org/releases.html"