-
Notifications
You must be signed in to change notification settings - Fork 438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix CVE-2022-24795 #240
base: master
Are you sure you want to change the base?
Fix CVE-2022-24795 #240
Conversation
There was an integer overflow in yajl_buf_ensure_available() leading to allocating less memory than requested. Then data were written past the allocated heap buffer in yajl_buf_append(), the only caller of yajl_buf_ensure_available(). Another result of the overflow was an infinite loop without a return from yajl_buf_ensure_available(). yajl-ruby project, which bundles yajl, fixed it <brianmario/yajl-ruby#211> by checking for the integer overflow, fortifying buffer allocations, and report the failures to a caller. But then the caller yajl_buf_append() skips a memory write if yajl_buf_ensure_available() failed leading to a data corruption. A yajl fork mainter recommended calling memory allocation callbacks with the large memory request and let them to handle it. But that has the problem that it's not possible pass the overely large size to the callbacks. This patch catches the integer overflow and terminates the process with abort(). lloyd#239 GHSA-jj47-x69x-mxrm
Note that there is no such thing as an "overly large size" here -- the left shift guarantees a maximum allowable buffer allocation size of So, either way the newly calculated "need" size is passed to the Calling As for the infinite loop, yes, that's definitely a bug too (and would actually prevent any heap corruption!). It is easily fixed by adding the following term to the condition for the (Without the new term the loop probably exhibits Undefined Behaviour, though UBSAN hasn't caught it in past testing I've done.) |
V Thu, Apr 07, 2022 at 11:07:19AM -0700, Greg A. Woods napsal(a):
Note that there is no such thing as an "overly large size" here -- the left
shift guarantees a maximum allowable buffer allocation size of
`2^((sizeof(int)*CHAR_BIT)-1)` bytes, and otherwise it "overflows" to zero
and stays at zero.
So, either way the newly calculated "need" size is passed to the
`yaf->realloc` function, and either it is a valid non-zero number, or it is
zero;
Yes.
and the latter condition is sufficient for the realloc function to
detect the overflow.
No.
0 is a valid input for realloc(). POSIX claims:
If the size of the space requested is zero, the behavior shall be
implementation-defined
Hence you cannot expect a realloc callback to recognize 0 as a mistake of
yajl.
Calling `abort()` for a failure which can already be detected and handled by
the realloc function introduces a hard failure that then cannot be avoided
and handled differently by the realloc function, and that alone would cause
YAJL to be unusable in several embedded systems projects I've used it on in
the past. Use of `abort()` in general purpose libraries should be forbidden
except via `<assert.h.>`.
I fully agree. But in case of yajl's memory callbacks, there is is no way of
reporting a failure from the callback to yajl.
I only inspected libbson which used to bundle yajl and it does abort().
…-- Petr
|
It's not |
BTW, the allocator wrapper functions can report an error to the calling application and escape with |
That would be an API incompatible change, as it currently does not need to. So for avoiding the problem with current code abort() seems to be preferable. ( For a new version that breaks compatibility by using a new yaf with a different name, your suggestion might work, but I think instead making it explicit to the caller and passing the error via the return path instead of a callback and setjmp might reduce the chanche for errors when using the library. ) |
I think given the fact the default in YAJL is not to do any error reporting on memory allocation failures (other than via optional calls to In any case, calling YAJL's API could be re-designed to make more advanced memory allocation error handling easier, but that's way beyond the scope of fixing this little infinite loop problem. |
The patch uses an abort() to prevent heap memory corruption, but per the discussion here lloyd#240 it seems that's the best option available without a significant rewrite of the library.
There was an integer overflow in yajl_buf_ensure_available() leading
to allocating less memory than requested. Then data were written past
the allocated heap buffer in yajl_buf_append(), the only caller of
yajl_buf_ensure_available(). Another result of the overflow was an
infinite loop without a return from yajl_buf_ensure_available().
yajl-ruby project, which bundles yajl, fixed it
brianmario/yajl-ruby#211 by checking for the
integer overflow, fortifying buffer allocations, and report the
failures to a caller. But then the caller yajl_buf_append() skips
a memory write if yajl_buf_ensure_available() failed leading to a data
corruption.
A yajl fork mainter recommended calling memory allocation callbacks with
the large memory request and let them to handle it. But that has the
problem that it's not possible pass the overely large size to the
callbacks.
This patch catches the integer overflow and terminates the process
with abort().
#239
GHSA-jj47-x69x-mxrm