-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Handle multiple SSL_ERROR_WANT_ASYNC which is returned by ASYNC engine #1387
base: main
Are you sure you want to change the base?
Conversation
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.
Can you add a unit test that reproduces the issue you are experiencing that demonstrates your fix solves the problem?
folly/io/async/AsyncPipe.cpp
Outdated
@@ -48,8 +48,6 @@ void AsyncPipeReader::close() { | |||
|
|||
if (closeCb_) { | |||
closeCb_(fd_); | |||
} else { | |||
netops::close(fd_); |
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.
Removing this seems wrong - close() no longer closes the underlying fd when closeCb_ is not defined?
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.
This fd was added in async list by underlying openssl. Isn't it better to let the ssl library close the fd once operation is complete.
Also, If I close here, my driver handle will be closed and cannot be used for any further in the SSL connection.
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.
@afrind I will elaborate my use case too here:
I have a crypto device to which asymmetric and symmetric operations from openssl are offloaded. Instead of pipe fd, I am using the driver handle of this device as an async fd, which is signalled whenever the crypto operation is completed. I am using this same async fd throughout the handshake.
This handle has to be open throughout the length of an SSL connection (for record processing too). Also in this design, for each of crypto operation done in ASYNC mode, the SSL_ERROR_WANT_ASYNC is returned. As such after such a request is processed at folly layer and SSL_accept restarted, another crypto operation may return same error and thereby returning multiple WANT_ASYNC errors in sequence, which the existing folly is not handling correctly.
The issue is that if sslSocket_->restartSSLAccept again returns WANT_ASYNC error, asyncOperationFinishCallback_ is not be set null and further events not processed
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.
AsyncPipeWriter is generic and can have uses other than this use case. I think what you want to do instead is set the closeCB_ to a no-op in your case?
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.
@afrind , Thanks for the review. I have removed the change so as to not break other use cases. Please review rest of the code changes.
@afrind , please use the above patch to reproduce issue I currently face. I created a test case to return multiple SSL_ERROR_WANT_ASYNC, but when run it always returns a SSL_ERROR_WANT_READ between two continuous SSL_ERROR_WANT_ASYNC errors. Though the attached patch is not really creating an async job, but you can use it to quickly reproduce the error. The original folly code will hang with this change, ie when 2 continuous SSL_ERROR_WANT_ASYNC is received, and this PR fixes the issue. Please verify. |
Also please note :Existing folly code works correctly if between two SSL_ERRROR_WANT_ASYNC error codes, a non-fatal error code is returned as this will clean all stale data structures. |
@afrind , I have added a testcase to return SSL_ERROR_WANT_ASYNC multiple times. I have also committed cert/key/CAcert as the one given in repo doesn't seem to be working. Please review. Please note the error is only reproducible if between 2 SSL_ERROR_WANT_ASYNC errors, no other error codes are returned, say SSL_ERROR_WANT_READ. |
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.
@afrind has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
Legit. Can we avoid checking in new keys/certs? It should be possible to generate small keys quickly and in-memory at unit-test time. |
@afrind @yfeldblum , I have removed the certs committed earlier and used the existing certs. Please review. |
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.
@afrind has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
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.
These comments came from another developer internally
@@ -1525,6 +1525,79 @@ static int kRSAEvbExIndex = -1; | |||
static int kRSASocketExIndex = -1; | |||
static constexpr StringPiece kEngineId = "AsyncSSLSocketTest"; | |||
|
|||
int customRsaPubDec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, |
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.
Should be 'static'
return ret; | ||
} | ||
|
||
int verifyCb(X509_STORE_CTX *ctx, void *arg) { |
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.
Should be 'static'
|
||
ssl::EvpPkeyUniquePtr publicEvpPkey(X509_get_pubkey(cert)); | ||
EVP_PKEY *pkey = publicEvpPkey.get(); | ||
RSA* rsa = EVP_PKEY_get1_RSA(publicEvpPkey.get()); |
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.
I think this is a leak (openssl _get1 increments (adds by 1) the reference count of the undelrying object), and the reason why tests aren't catching this is because we disable this test when running under ASAN mode.
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.
See line 1762 for where we disable
pipeReader_->setReadCB(nullptr); | ||
sslSocket_->setAsyncOperationFinishCallback(nullptr); | ||
sslSocket_->restartSSLAccept(); |
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.
Please add a comment here explaining why order is significant
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.
@afrind I have addressed all your comments, please review
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.
@afrind has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
The test failed with a SEGV internally in opt mode?
|
@afrind please help me reproduce this error. How do I build folly in opt mode ? |
I'm actually not sure since we use a different build system internally. I think it's a combination of -NDEBUG and -O3 mostly? If you are linking against jemalloc, try MALLOC_CONF=junk:true,abort:true ? |
@afrind , Please review the updated changes as per your comments.
The changes are required to handle cases where multiple SSL_ERROR_WANT_ASYNC is returned by the async engine.
Also I have removed the code which closes the async fd as this is my crypto driver handle and should not be closed by upper layers as I require it further in my SSL connection