From 2ee9ef098b9b84f914ae503ded2bc85e97746bc9 Mon Sep 17 00:00:00 2001 From: Demi Marie Obenour Date: Mon, 5 Aug 2024 12:17:02 -0400 Subject: [PATCH] connection: Ensure buffer sizes do not exceed INT_MAX or PTRDIFF_MAX Pointer arithmetic beyond PTRDIFF_MAX is broken, so buffer sizes exceeding PTRDIFF_MAX (which is half of the address space!) are a bad idea. Furthermore, the code uses int for sizes in various places, so buffer sizes exceeding INT_MAX are also a bad idea. Therefore, limit buffer sizes to (PTRDIFF_MAX / 2) + 1 or (INT_MAX / 2) + 1, whichever is smaller. Tests would require 2GiB of RAM and so have been omitted. The test would check for wl_connection_flush() flushing more than INT_MAX bytes in one call, causing it to return a negative number and causing its caller to wrongly believe an error occurred. Signed-off-by: Demi Marie Obenour --- src/connection.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/connection.c b/src/connection.c index a2232799..41d821eb 100644 --- a/src/connection.c +++ b/src/connection.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -70,7 +71,19 @@ struct wl_connection { int fd; int want_flush; }; -#define WL_BUFFER_MAX_SIZE_POT ((size_t)(8 * sizeof(size_t) - 1)) + +/* Pointer arithmetic beyond PTRDIFF_MAX is broken, so don't rely on it. + * ((ptrdiff_t)1 << (CHAR_BIT * sizeof(ptrdiff_t) - 1)) is undefined behavior + * (wrapping to PTRDIFF_MIN with -fwrapv), not PTRDIFF_MAX, so limit buffer size + * to ((size_t)1 << (CHAR_BIT * sizeof(ptrdiff_t) - 2)). int is used for + * sizes in various places, so for safety also use + * ((size_t)1 << (CHAR_BIT * sizeof(int) - 2)) as a limit. + */ +#if PTRDIFF_MAX < INT_MAX +# define WL_BUFFER_MAX_SIZE_POT ((size_t)(CHAR_BIT * sizeof(ptrdiff_t) - 2)) +#else +# define WL_BUFFER_MAX_SIZE_POT ((size_t)(CHAR_BIT * sizeof(int) - 2)) +#endif static inline size_t size_pot(uint32_t size_bits)