-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
http2: Do not call non-reentrant nghttp2 functions from nghttp2 callback #39076
Conversation
The nghttp2 functions nghttp2_session_send, nghttp2_session_mem_send, nghttp2_session_recv and nghttp2_session_mem_recv are documented as not being able to be called from nghttp2 callback functions. Add a tracker so we can tell when we are within the scope of an nghttp2 callback and early return from ConsumeHTTP2Data and SendPendingData which are the only two methods that use the prohibited methods. This prevents a use-after-free crash bug that can be triggered otherwise. Fixes: nodejs#38964 Refs: https://nghttp2.org/documentation/programmers-guide.html#remarks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OMG, you are amazing @mdouglass 😄
😊 thanks :) |
@jasnell I've been looking into the test failures here and picked one pretty much at random -- test-http2-compat-errors.js.
That code is executed inside the I can see a couple possible solutions:
Any thoughts? |
Definitely appreciate this. I had it in my list to investigate but hadn't yet been able to get to it. Good stuff |
Hmmm I don't know right off hand. And I'm not near my laptop at that moment. I'll look at it on Monday morning .. |
Yeah, I think that would be too heavy on the benchmarks to be a good solution :/
The native That being said … if the test is calling |
I had wondered if that might be the case, but it seemed like such a straightforward example and I hadn't verified that all the other broken tests had a similar cause that I was hesitant to suggest it. |
Responding to my own suggestion -- I don't think this is doable in the general case as the return value of some of the nghttp2 callbacks are meaningful (eg. |
Could this land? |
Unfortunately, tests don't pass in the current form of this PR. I need some advice from someone more involved with the project on how to handle this:
I'd really like to get a fix in and am happy to do the work, but I'm blocked at this point. |
If the code above is the source of the problem (write after destroy without any guarantee of data writing down), I'd just recommend to edit the tests. |
@mdouglass, I looked into the double-free memory issue. It seems the How do you think about delaying the callbacks to javascript side (env->http2session_on_stream_close_function) on stream close callbacks (OnStreamClose) with setImmediate and not for all the |
I am fairly certain I was seeing reentrant calls to the nghttp2 library. I have nghttp2/nghttp2#1591 open against nghttp2 that will warn when reentrant calls are made on the same session object. If I use that PR in place of the vendored version of nghttp then it triggers reliably from my sample code. That being said, I'm new to both these codebases so could be wrong.
I think adding the setImmediate call is likely to work as it is pretty much an internal implementation of my original workaround from the bug report:
The validity of that really rests on rather I am correct or not on the underlying reentrancy issue :) |
I am also new to the node codebase. Please help me if I miss something.
You might be seeing calls to the nghttp2 library from the JS side of callbacks. I think that should not be a problem.
|
So got this opened back up enough and back up to speed with where I was a few weeks ago. There are definitely reentrant calls that go nghttp2 library -> nghttp2 callback in node_http2.cc -> nghttp2 library. You can see that in log output from my PR when you see the log line: https://github.com/mdouglass/node/commits/fix/38964-alt - This just adds reentrancy detection to nghttp2, running that with any of the existing http2 tests will trigger an ASAN violation. https://github.com/mdouglass/node/commits/fix/38964-debug-help - Adds the reentrancy detection on the nghttp2 and nodejs sides as well as a lot of extra logging (from when I was trying to figure out what was going on). That being said, using setImmediate on the close operation might still be an interesting way to allow the not-yet-working fix in this PR to prevent the reentrant operations while avoiding the behavior changes. I'll try to play with that a bit more tomorrow. |
Any update on this? |
It should probably be closed. It was fixed a while back as a CVE that was separated from this issue: #39423. |
@mdouglass Is it actually fixed though? I was still able to reproduce what I believe is the same issue on LTS/Current recently in code at my job. I am having a hard time isolating and reproducing the exact conditions to make a minimal repo example though. For me it only seems to happen under extreme load using GHZ to load test + NestJS's gRPC framework, and modifying Nest's source code to cancel the call in a |
My original fix was not used as it had other issues. A fix was made without my involvement as part of the CVE process and I have not retested my poc with it. Sorry, I don't have more info. |
Hi @ssilve1989, Could you share more details about what you see with your test? The node has a fix to avoid the issue but I believe the actual bug is with nghttp2 that frees up memory early and call the stream close callback with a specific flow of |
@kumarak Hi, i re-ran my scenario yesterday and it looks like this was fixed in |
The nghttp2 functions nghttp2_session_send, nghttp2_session_mem_send,
nghttp2_session_recv and nghttp2_session_mem_recv are documented as not
being able to be called from nghttp2 callback functions.
Add a tracker so we can tell when we are within the scope of an nghttp2
callback and early return from ConsumeHTTP2Data and SendPendingData
which are the only two methods that use the prohibited methods.
This prevents a use-after-free crash bug that can be triggered otherwise.
Fixes: #38964
Refs: https://nghttp2.org/documentation/programmers-guide.html#remarks