Skip to content

Commit 174b7a3

Browse files
committed
buffer: fix printing into out-of-memory buffer
Before printing into a `git_buf` structure, we always call `ENSURE_SIZE` first. This macro will reallocate the buffer as-needed depending on whether the current amount of allocated bytes is sufficient or not. If `asize` is big enough, then it will just do nothing, otherwise it will call out to `git_buf_try_grow`. But in fact, it is insufficient to only check `asize`. When we fail to allocate any more bytes e.g. via `git_buf_try_grow`, then we set the buffer's pointer to `git_buf__oom`. Note that we touch neither `asize` nor `size`. So if we just check `asize > targetsize`, then we will happily let the caller of `ENSURE_SIZE` proceed with an out-of-memory buffer. As a result, we will print all bytes into the out-of-memory buffer instead, resulting in an out-of-bounds write. Fix the issue by having `ENSURE_SIZE` verify that the buffer is not marked as OOM. Add a test to verify that we're not writing into the OOM buffer.
1 parent 208f1d7 commit 174b7a3

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

src/buffer.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ char git_buf__initbuf[1];
1818
char git_buf__oom[1];
1919

2020
#define ENSURE_SIZE(b, d) \
21-
if ((d) > (b)->asize && git_buf_grow((b), (d)) < 0)\
21+
if ((b)->ptr == git_buf__oom || \
22+
((d) > (b)->asize && git_buf_grow((b), (d)) < 0))\
2223
return -1;
2324

2425

tests/core/buffer.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,3 +1220,23 @@ void test_core_buffer__dont_hit_infinite_loop_when_resizing(void)
12201220

12211221
git_buf_dispose(&buf);
12221222
}
1223+
1224+
void test_core_buffer__avoid_printing_into_oom_buffer(void)
1225+
{
1226+
git_buf buf = GIT_BUF_INIT;
1227+
1228+
/* Emulate OOM situation with a previous allocation */
1229+
buf.asize = 8;
1230+
buf.ptr = git_buf__oom;
1231+
1232+
/*
1233+
* Print the same string again. As the buffer still has
1234+
* an `asize` of 8 due to the previous print,
1235+
* `ENSURE_SIZE` would not try to reallocate the array at
1236+
* all. As it didn't explicitly check for `git_buf__oom`
1237+
* in earlier versions, this would've resulted in it
1238+
* returning successfully and thus `git_buf_puts` would
1239+
* just print into the `git_buf__oom` array.
1240+
*/
1241+
cl_git_fail(git_buf_puts(&buf, "foobar"));
1242+
}

0 commit comments

Comments
 (0)