Skip to content

Commit 22be8c8

Browse files
committed
libretro-common/nbio_linux: fix realloc-to-self leak on OOM in nbio_linux_resize
nbio_linux_resize committed the new length before realloc could be validated: handle->ptr = realloc(handle->ptr, len); handle->len = len; If realloc() returns NULL, handle->ptr is overwritten with NULL and the original buffer is leaked. handle->len is then updated to the new (larger) size, so the handle reports that it owns 'len' bytes of data that actually live at a NULL pointer. Every subsequent nbio_linux_get_ptr / read / write call that iterates up to handle->len walks off NULL. The sibling nbio_stdio_resize (libretro-common/file/nbio/nbio_stdio.c line 261) already uses the correct tmp-pointer-then-commit pattern and explicitly calls out the same pre-patch bug in a code comment. The linux variant was the lone holdout. Fix: realloc into a new_ptr local, only commit on success. On OOM return early without updating handle->ptr or handle->len, leaving the handle in its pre-resize state. Callers that currently crash on NULL-deref now see the old len and the old pointer - which is the same 'no-op on OOM' behaviour that nbio_stdio_resize already promises. Thread-safety: unchanged. nbio handles are owned by whichever thread is servicing them (typically a task queue thread); no shared state touched.
1 parent 04252ec commit 22be8c8

1 file changed

Lines changed: 16 additions & 1 deletion

File tree

libretro-common/file/nbio/nbio_linux.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ static bool nbio_linux_iterate(void *data)
153153
static void nbio_linux_resize(void *data, size_t len)
154154
{
155155
struct nbio_linux_t* handle = (struct nbio_linux_t*)data;
156+
void *new_ptr;
156157
if (!handle)
157158
return;
158159

@@ -166,7 +167,21 @@ static void nbio_linux_resize(void *data, size_t len)
166167
abort(); /* this one returns void and I can't find any other way
167168
for it to report failure */
168169

169-
handle->ptr = realloc(handle->ptr, len);
170+
/* Attempt the realloc BEFORE committing the new length. If it
171+
* fails, the old pointer and its old size are still valid; the
172+
* caller can retry or abandon. Matches the sibling pattern in
173+
* nbio_stdio_resize - the pre-patch form
174+
*
175+
* handle->ptr = realloc(handle->ptr, len);
176+
* handle->len = len;
177+
*
178+
* set handle->ptr to NULL on OOM (leaking the old buffer) and
179+
* then claimed the new length, so subsequent get_ptr()/read/write
180+
* walked a NULL pointer assuming len bytes. */
181+
if (!(new_ptr = realloc(handle->ptr, len)))
182+
return;
183+
184+
handle->ptr = new_ptr;
170185
handle->len = len;
171186
}
172187

0 commit comments

Comments
 (0)