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
[Crash] RAND_load_file() with specific file-sizes #7449
Comments
In pull request #4328 the seeding of the DRBG via RAND_add()/RAND_seed() was implemented by buffering the data in a random pool where it is picked up later by the rand_drbg_get_entropy() callback. This buffer was limited to the size of 4096 bytes. When a larger input was added via RAND_add() or RAND_seed() to the DRBG, the reseeding failed, but the error returned by the DRBG was ignored by the two calling functions, which both don't return an error code. As a consequence, the data provided by the application was effectively ignored. This commit fixes the problem by a more efficient implementation which does not copy the data in memory and by raising the buffer the size limit to INT32_MAX (2 gigabytes). This is less than the NIST limit of 2^35 bits but it was chosen intentionally to avoid platform dependent problems like integer sizes and/or signed/unsigned conversion. Additionally, the DRBG is now less permissive on errors: In addition to pushing a message to the openssl error stack, it enters the error state, which forces a reinstantiation on next call. Thanks go to Dr. Falko Strenzke for reporting this issue to the openssl-security mailing list. After internal discussion the issue has been categorized as not being security relevant, because the DRBG reseeds automatically and is fully functional even without additional randomness provided by the application. Fixes #7381 Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from #7382)
I can now reproduce the problem with Visual Studio on Windows. |
This should fix your crash, but it's only half of the problem. I will open a pull request, but it will take little while because I have to leave now. diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c
index f40c513ce8..52e2621948 100644
--- a/crypto/rand/rand_lib.c
+++ b/crypto/rand/rand_lib.c
@@ -200,6 +200,9 @@ size_t rand_drbg_get_entropy(RAND_DRBG *drbg,
}
err:
+ if (ret == 0 && drbg->pool != NULL)
+ drbg->pool = NULL;
+
rand_pool_free(pool);
return ret;
} |
That fix works fine (no crashes with any sizes I've tried). Why is it only half of the problem? |
Actually the first patch was only part one of three:
More details in the upcoming pull request. Please be patient, I'm a hobby committer... ;-) For the moment, I would ask you to apply this second patch and try whether commit bafbab69b7cb43a0e13feeded86f47e703a40ab8 (HEAD -> master)
Author: Dr. Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com>
Date: Sat Oct 20 16:53:57 2018 +0200
RAND_load_file(): return error if reseeding failed
diff --git a/crypto/rand/randfile.c b/crypto/rand/randfile.c
index 89720eb5cf..028c1281c0 100644
--- a/crypto/rand/randfile.c
+++ b/crypto/rand/randfile.c
@@ -148,6 +148,12 @@ int RAND_load_file(const char *file, long bytes)
OPENSSL_cleanse(buf, sizeof(buf));
fclose(in);
+ if (!RAND_status()) {
+ RANDerr(RAND_F_RAND_LOAD_FILE, RAND_R_RESEED_ERROR);
+ ERR_add_error_data(2, "Filename=", file);
+ return -1;
+ }
+
return ret;
} |
Note: although the seeding fails in your case, the DRBG will automatically recover from the error in the next RAND_bytes() call. So the output of |
After applying all your patches and trying with a
gives:
No crash anymore, but I've no idea why the size should matter!? |
Because it's a bug which I introduced in 3064b55 :-) |
(Hint: 32 bytes corresponds to 256 bits which is the security strength of the DRBG.) |
This bug was introduced by openssl#7382 which enhanced RAND_add() to accept large buffer sizes. As a consequence, RAND_add() now fails for buffer sizes less than 32 bytes (i.e. less than 256 bits). In addition, rand_drbg_get_entropy() forgets to reset the attached drbg->pool in the case of an error, which leads to the heap corruption. The problem occurred with RAND_load_file(), which reads the file in chunks of 1024 bytes each. If the size of the final chunk is less than 32 bytes, then RAND_add() fails, whence RAND_load_file() fails silently for buffer sizes n = k * 1024 + r with r = 1,...,31. This commit fixes the heap corruption only. The other issues will be addressed in a separate pull request. Thanks to Gisle Vanem for reporting this issue. Fixes openssl#7449
Good job. Feel free to close this issue when you wish. |
Thank you very much for your appreciation. But actually I can return the compliment because your report pointed me to a whole bunch of minor problems. Don't worry about the issue, it will be closed automatically when the PR is merged. Regards, |
This bug was introduced by #7382 which enhanced RAND_add() to accept large buffer sizes. As a consequence, RAND_add() now fails for buffer sizes less than 32 bytes (i.e. less than 256 bits). In addition, rand_drbg_get_entropy() forgets to reset the attached drbg->pool in the case of an error, which leads to the heap corruption. The problem occurred with RAND_load_file(), which reads the file in chunks of 1024 bytes each. If the size of the final chunk is less than 32 bytes, then RAND_add() fails, whence RAND_load_file() fails silently for buffer sizes n = k * 1024 + r with r = 1,...,31. This commit fixes the heap corruption only. The other issues will be addressed in a separate pull request. Thanks to Gisle Vanem for reporting this issue. Fixes #7449 Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from #7455) (cherry picked from commit 5b4cb38)
Okay... the notification page tells me that the closing hook was issued, but it's still open. Probably because GitHub is still in confusion... Well, then I'll close it myself. |
The failure of RAND_load_file was only noticed because of the heap corruption which was reported in openssl#7499 and fixed in commit 5b4cb38. To prevent this in the future, RAND_load_file() now explicitly checks RAND_status() and reports an error if it fails. Related-to openssl#7449
Increase the load buffer size such that it exceeds the chunk size by a comfortable amount. This is done to avoid calling RAND_add() with a small final chunk. Instead, such a small final chunk will be added together with the previous chunk (unless it's the only one). Related-to openssl#7449
Commit 5b4cb38 (openssl#7382) introduced a bug which had the effect that RAND_add()/RAND_seed() failed for buffer sizes less than 32 bytes. The reason was that now the added random data was used exlusively as entropy source for reseeding. When the random input was too short or contained not enough entropy, the DRBG failed without querying the available entropy sources. This commit makes drbg_add() act smarter: it checks the entropy requirements explicitely. If the random input fails this check, it won't be added as entropy input, but only as additional data. More precisely, the behaviour depends on whether an os entropy source was configured (which is the default on most os): - If an os entropy source is avaible then we declare the buffer content as additional data by setting randomness to zero and trigger a regular reseeding. - If no os entropy source is available, a reseeding will fail inevitably. So drbg_add() uses a trick to mix the buffer contents into the DRBG state without forcing a reseeding: it generates a dummy random byte, using the buffer content as additional data. Related-to openssl#7449
The failure of RAND_load_file was only noticed because of the heap corruption which was reported in #7499 and fixed in commit 5b4cb38. To prevent this in the future, RAND_load_file() now explicitly checks RAND_status() and reports an error if it fails. Related-to: #7449 Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from #7456)
Increase the load buffer size such that it exceeds the chunk size by a comfortable amount. This is done to avoid calling RAND_add() with a small final chunk. Instead, such a small final chunk will be added together with the previous chunk (unless it's the only one). Related-to: #7449 Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from #7456)
Commit 5b4cb38 (#7382) introduced a bug which had the effect that RAND_add()/RAND_seed() failed for buffer sizes less than 32 bytes. The reason was that now the added random data was used exlusively as entropy source for reseeding. When the random input was too short or contained not enough entropy, the DRBG failed without querying the available entropy sources. This commit makes drbg_add() act smarter: it checks the entropy requirements explicitely. If the random input fails this check, it won't be added as entropy input, but only as additional data. More precisely, the behaviour depends on whether an os entropy source was configured (which is the default on most os): - If an os entropy source is avaible then we declare the buffer content as additional data by setting randomness to zero and trigger a regular reseeding. - If no os entropy source is available, a reseeding will fail inevitably. So drbg_add() uses a trick to mix the buffer contents into the DRBG state without forcing a reseeding: it generates a dummy random byte, using the buffer content as additional data. Related-to: #7449 Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from #7456)
The failure of RAND_load_file was only noticed because of the heap corruption which was reported in openssl#7499 and fixed in commit 5b4cb38. To prevent this in the future, RAND_load_file() now explicitly checks RAND_status() and reports an error if it fails. Related-to: openssl#7449 Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from openssl#7456)
Increase the load buffer size such that it exceeds the chunk size by a comfortable amount. This is done to avoid calling RAND_add() with a small final chunk. Instead, such a small final chunk will be added together with the previous chunk (unless it's the only one). Related-to: #7449 Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from #7456)
Commit 5b4cb38 (#7382) introduced a bug which had the effect that RAND_add()/RAND_seed() failed for buffer sizes less than 32 bytes. The reason was that now the added random data was used exlusively as entropy source for reseeding. When the random input was too short or contained not enough entropy, the DRBG failed without querying the available entropy sources. This commit makes drbg_add() act smarter: it checks the entropy requirements explicitely. If the random input fails this check, it won't be added as entropy input, but only as additional data. More precisely, the behaviour depends on whether an os entropy source was configured (which is the default on most os): - If an os entropy source is avaible then we declare the buffer content as additional data by setting randomness to zero and trigger a regular reseeding. - If no os entropy source is available, a reseeding will fail inevitably. So drbg_add() uses a trick to mix the buffer contents into the DRBG state without forcing a reseeding: it generates a dummy random byte, using the buffer content as additional data. Related-to: #7449 Reviewed-by: Paul Dale <paul.dale@oracle.com> (Merged from #7456) (cherry picked from commit 8817215)
Some file-sizes given to this command:
crashes in some mysterious ways while freeing the associated
RAND_POOL
. The call-stack from WinDbg:I created the
rand-file
using CygWin'struncate
:I'm on Windows-10 using MSVC-2017.
Some other discussion of this issue is here too:
3064b55#commitcomment-30980301
The text was updated successfully, but these errors were encountered: