openssl: AVX512-specific heap buffer overflow with 3.0.4 release

Build OpenSSL-3.0.4 on a CPU with AVX512 (my CPU is a Core i7-1065G7) with:

CFLAGS="-O3 -g -fsanitize=address" ./config
make

Run a test:

make V=1 TESTS=test_exp test

The sanitizer complains:

==481618==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60c000089400 at pc 0x7f01e32a9509 bp 0x7fff643ec100 sp 0x7fff643ec0f8
READ of size 8 at 0x60c000089400 thread T0
    #0 0x7f01e32a9508 in bn_select_words crypto/bn/rsaz_exp.h:64
    #1 0x7f01e32a9508 in bn_reduce_once_in_place crypto/bn/rsaz_exp.h:74
    #2 0x7f01e32a9508 in ossl_rsaz_mod_exp_avx512_x2 crypto/bn/rsaz_exp_x2.c:223
    #3 0x7f01e3287dc8 in BN_mod_exp_mont_consttime_x2 crypto/bn/bn_exp.c:1448
    #4 0x4042c3 in test_mod_exp_x2 test/exptest.c:260
    #5 0x40611a in run_tests test/testutil/driver.c:370
    #6 0x4039ba in main test/testutil/main.c:30
    #7 0x7f01e2c29319 in __libc_start_call_main (/usr/lib/libc.so.6+0x29319)
    #8 0x7f01e2c293e4 in __libc_start_main_impl (/usr/lib/libc.so.6+0x293e4)
    #9 0x403c40 in _start (/home/xry111/sources/lfs/openssl-3.0.4/test/exptest+0x403c40)

0x60c000089400 is located 0 bytes to the right of 128-byte region [0x60c000089380,0x60c000089400)
allocated by thread T0 here:
    #0 0x7f01e3ae5107 in __interceptor_malloc ../../../../libsanitizer/asan/asan_malloc_linux.cpp:69
    #1 0x7f01e34aa7a8 in CRYPTO_zalloc crypto/mem.c:197

SUMMARY: AddressSanitizer: heap-buffer-overflow crypto/bn/rsaz_exp.h:64 in bn_select_words
Shadow bytes around the buggy address:
  0x0c1880009230: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
  0x0c1880009240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c1880009250: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c1880009260: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
  0x0c1880009270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c1880009280:[fa]fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c1880009290: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
  0x0c18800092a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c18800092b0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c18800092c0: 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa
  0x0c18800092d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==481618==ABORTING

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 6
  • Comments: 27 (22 by maintainers)

Commits related to this issue

Most upvoted comments

I’m not sure I understand how it’s not a security vulnerability. It’s a heap buffer overflow that’s triggerable by things like RSA signatures, which can easily happen in remote contexts (e.g. a TLS handshake).

Actually I don’t like the idea of “marking every heap buffer overflow as a security vulnerability”. Vim has started to do such thing in this year. Now we are being noised by about ten “high severity” vim CVEs per month, w/o any exploit in practice. I think we shouldn’t mark a bug as “security vulnerability” unless we have some evidence showing it can (or at least, may) be expolited.

That being said, to me 3.0.5 should be released ASAP because this issue is very severe, regardless of it’s a vulnerability or not.

I’ll also add my voice to those urging a quick 3.0.5 release as well. If that is not feasible then the openssl project should consider sending an email to the announcement/release list about this issue. Many people don’t follow the project closely enough to be aware that there is a known severe bug in the latest release.

@khantext

An attacker could theoretically exploit this vulnerability by sending a transmission across a network

Yes. Here is a program (derived from the OpenSSL server fuzzer code) which sets up an SSL server and sends an offending payload. It uses memory buffers rather than TCP/IP but they are functionally analogous.

With AddressSanitizer enabled, this crashes as follows:

=================================================================
==671281==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61200000225f at pc 0x0000009800c2 bp 0x7ffcf8dd0b30 sp 0x7ffcf8dd0b28
READ of size 32 at 0x61200000225f thread T0
    #0 0x9800c1 in bn_select_words /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/rsaz_exp.h:64:46
    #1 0x9800c1 in bn_reduce_once_in_place /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/rsaz_exp.h:74:5
    #2 0x9800c1 in ossl_rsaz_mod_exp_avx512_x2 /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/rsaz_exp_x2.c:223:5
    #3 0x96ae63 in BN_mod_exp_mont_consttime_x2 /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/bn_exp.c:1448:15
    #4 0x771f8f in rsa_ossl_mod_exp /home/ubuntu/gh-issue/openssl-3.0.4/crypto/rsa/rsa_ossl.c:702:17
    #5 0x7711d3 in rsa_ossl_private_decrypt /home/ubuntu/gh-issue/openssl-3.0.4/crypto/rsa/rsa_ossl.c:442:14
    #6 0x818db6 in rsa_decrypt /home/ubuntu/gh-issue/openssl-3.0.4/providers/implementations/asymciphers/rsa_enc.c:238:15
    #7 0x5bef21 in tls_process_cke_rsa /home/ubuntu/gh-issue/openssl-3.0.4/ssl/statem/statem_srvr.c:2924:16
    #8 0x5bef21 in tls_process_client_key_exchange /home/ubuntu/gh-issue/openssl-3.0.4/ssl/statem/statem_srvr.c:3306:14
    #9 0x57f159 in read_state_machine /home/ubuntu/gh-issue/openssl-3.0.4/ssl/statem/statem.c:647:19
    #10 0x57f159 in state_machine /home/ubuntu/gh-issue/openssl-3.0.4/ssl/statem/statem.c:442:21
    #11 0x4f56b1 in SSL_do_handshake /home/ubuntu/gh-issue/openssl-3.0.4/ssl/ssl_lib.c:3923:19
    #12 0x4f6b8b in SSL_accept /home/ubuntu/gh-issue/openssl-3.0.4/ssl/ssl_lib.c:1735:12
    #13 0x4f6b8b in SSL_read_early_data /home/ubuntu/gh-issue/openssl-3.0.4/ssl/ssl_lib.c:1911:15
    #14 0x4c9a29 in main /home/ubuntu/gh-issue/openssl-3.0.4/server.c:637:19
    #15 0x7fb8d6116082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16
    #16 0x41d06d in _start (/home/ubuntu/gh-issue/openssl-3.0.4/a.out+0x41d06d)

0x61200000225f is located 15 bytes to the right of 272-byte region [0x612000002140,0x612000002250)
allocated by thread T0 here:
    #0 0x4982cd in malloc (/home/ubuntu/gh-issue/openssl-3.0.4/a.out+0x4982cd)
    #1 0x70bdcd in CRYPTO_malloc /home/ubuntu/gh-issue/openssl-3.0.4/crypto/mem.c:190:12
    #2 0x70bdcd in CRYPTO_zalloc /home/ubuntu/gh-issue/openssl-3.0.4/crypto/mem.c:197:11
    #3 0x61327d in bn_expand_internal /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/bn_lib.c:281:13
    #4 0x61327d in bn_expand2 /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/bn_lib.c:305:23
    #5 0x95c46e in bn_div_fixed_top /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/bn_div.c:327:10
    #6 0x95bd99 in BN_div /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/bn_div.c:229:11
    #7 0x61caa6 in BN_MONT_CTX_set /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/bn_mont.c:397:10
    #8 0x961d72 in BN_mod_exp_mont_consttime /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/bn_exp.c:645:14
    #9 0x95f15c in BN_mod_exp_mont /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/bn_exp.c:309:16
    #10 0x956f0e in BN_BLINDING_create_param /home/ubuntu/gh-issue/openssl-3.0.4/crypto/bn/bn_blind.c:294:14
    #11 0x768b34 in RSA_setup_blinding /home/ubuntu/gh-issue/openssl-3.0.4/crypto/rsa/rsa_crpt.c:155:15
    #12 0x771081 in rsa_get_blinding /home/ubuntu/gh-issue/openssl-3.0.4/crypto/rsa/rsa_ossl.c:170:25
    #13 0x771081 in rsa_ossl_private_decrypt /home/ubuntu/gh-issue/openssl-3.0.4/crypto/rsa/rsa_ossl.c:420:20
    #14 0x818db6 in rsa_decrypt /home/ubuntu/gh-issue/openssl-3.0.4/providers/implementations/asymciphers/rsa_enc.c:238:15
    #15 0x5bef21 in tls_process_cke_rsa /home/ubuntu/gh-issue/openssl-3.0.4/ssl/statem/statem_srvr.c:2924:16
    #16 0x5bef21 in tls_process_client_key_exchange /home/ubuntu/gh-issue/openssl-3.0.4/ssl/statem/statem_srvr.c:3306:14
    #17 0x57f159 in read_state_machine /home/ubuntu/gh-issue/openssl-3.0.4/ssl/statem/statem.c:647:19
    #18 0x57f159 in state_machine /home/ubuntu/gh-issue/openssl-3.0.4/ssl/statem/statem.c:442:21
    #19 0x4f56b1 in SSL_do_handshake /home/ubuntu/gh-issue/openssl-3.0.4/ssl/ssl_lib.c:3923:19
    #20 0x4f6b8b in SSL_accept /home/ubuntu/gh-issue/openssl-3.0.4/ssl/ssl_lib.c:1735:12
    #21 0x4f6b8b in SSL_read_early_data /home/ubuntu/gh-issue/openssl-3.0.4/ssl/ssl_lib.c:1911:15
    #22 0x4c9a29 in main /home/ubuntu/gh-issue/openssl-3.0.4/server.c:637:19
    #23 0x7fb8d6116082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16

disrupt services (i.e., DoS)

Yes.

If the application halts upon crashing, a single payload transmission constitutes a succesful DoS attack.

If the embedding application (e.g. Apache web server) automatically respawns after crashing, then repeated transmissions will render the server mostly unusable.

The ratio between the cost of launching the attack (sending only 2 dozen bytes of payload) vs. the cost of bearing the attack (crashing and respawning) is high, so it’s trivial to do this from basic hardware and network connection.

steal information in memory (i.e., confidentiality breach)

Three buffer are overwritten: res1, res2 and storage. There are 2 arrays which are read, but not written to: m1 and m2. After the buffer overflow:

  • The values of m1 can be inferred from res1.
  • The values of m2 can be inferred from res2.
  • If res2 is known, the values of m2 can be inferred from storage.
  • If m2 is known, the values of res2 can be inferred from storage.

From this it follows that if the attacker controls a certain region (e.g. the values pre-overwrite can be known or defined, and the values post-overwrite can be read), then the values of an unrelated memory region (which may (but not necessarily does) contain sensitive information), can be known.

A region can be controlled by the attacker if it is allocated by either:

  • the OpenSSL TLS state machine, and its contents is sent back at a later step in the protocol flow
  • an equivalent procedure performed the embedding application (e.g. web server)

For this to work it is imperative that a crash due to corrupted malloc chunks does not occur, either by chance or by manipulation by the attacker.

alter information in memory (i.e., integrity breach)

If the attacker controls the contents of a region (e.g. m1), and res1 is known to constitute some internal data structure, and the pre-overwrite contents of res1 is known, then the data structure contents can be filled in with bytes of the attacker’s choosing.

Apart from this it is also necessary to avert a crash for the data structure rewrite to be meaningful.

Impacting the integrity of certain data structures (e.g. increasing the remaining field of a PACKET) may lead to additional escalation.

invoke/execute a definable list of specific actions on the target application/host invoke/execute arbitrary commands/code on the target application/host

I don’t see any reason to rule out a full compromise. Despite the fact that all inputs to the modexp function are unknown to the attacker (private key components, blinding factor), these inputs bear little relation to the post-overwrite state of the out-of-bounds memory. Given that OpenSSL makes heavy use of function pointers, overwriting a pointer to refer to execve or similar may be fruitful. Furthermore, the subtraction logic performed by bn_reduce_once_in_place lends itself to circumventing ASLR without prior knowledge of the (randomized) memory layout, as shown in the blog post.

I want to note that each of these except DoS are speculative and not trivial to perform, and are predicated upon meticulously controlling the regions that are overread and overwritten by way of influencing the state machine flow, though automatic exploit generators based on symbolic execution reportedly do exist.

For applications that immediately respawn the exploit does not have to be very reliable. If it works as intended 1/10000th of the time that’s good enough to eventually achieve the goal.

I would strongly advocate for it to occur quickly. I think this issue qualifies as a CRITICAL within OpenSSL’s vulnerability severity policy, and it makes it effectively impossible for users to upgrade to 3.0.4 to obtain its security fixes.

Using OPENSSL_ia32cap=:~0x200000 (disabling just AVX512IFMA) seems to fix the problem when I test it.

I’ve fixed the text above.

This vulnerability have been allocated the CVE-2022-2274 name. It has been classified by the project as HIGH severity.

There is a workaround that can be used until the 3.0.5 release is done:

export OPENSSL_ia32cap=:~0x200000

We anticipate that the 3.0.5 release will be done on Tuesday the 5th of July.

Edit: corrected the value in the workaround.