Skip to content

Fix out-of-bound (OOB) input read in AES-XTS Decrypt in AVX-512 implementation#2227

Merged
nebeid merged 6 commits intoaws:mainfrom
nebeid:aes-xts-avx512
Feb 28, 2025
Merged

Fix out-of-bound (OOB) input read in AES-XTS Decrypt in AVX-512 implementation#2227
nebeid merged 6 commits intoaws:mainfrom
nebeid:aes-xts-avx512

Conversation

@nebeid
Copy link
Copy Markdown
Contributor

@nebeid nebeid commented Feb 28, 2025

Issues:

Resolves #V1681992550

Description of changes:

  • Fix instruction that caused out-of-bound read in the input reading of the 16x loop (which processes a batch of 16 blocks of AES, 1 block = 16 bytes). This was triggered on lengths that are in the range [16k * (16 bytes), (16k +3)* (16 bytes)-1], k = 1, 2, ... The instruction was reading up to 3*16 bytes beyond the input length bound.

  • The fix was inspired by the 8x loop in

    vmovdqu8 0x70($input),%xmm5

  • The existing unit tests cover those cases but there were no explicit memory protections and ASAN doesn't instrument assembly code to check for out-of-bound reads even when the adjacent memory is explicitly poisoned.

  • The OOB read existed only on the decrypt path which rereads the last block when looping over 16 blocks (and over 8 blocks, but the instruction in the 8x case linked above didn't over-read) .

Call-outs:

N/A

Testing:

  • The existing unit tests exercised the OOB read but no existing tools can test it; Valgrind doesn't support AVX-512 yet and ASAN doesn't instrument assembly code.
  • We added explicit memory protection tests and proved they catch the error:
    On c6i, without the fix, the unit test segfaults
./crypto/crypto_test "--gtest_filter=XTSTest.*"
Note: Google Test filter = XTSTest.*
[==========] Running 4 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 4 tests from XTSTest
[ RUN      ] XTSTest.TestVectors
Segmentation fault (core dumped)

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.

@nebeid nebeid requested a review from a team as a code owner February 28, 2025 16:22
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 79.05%. Comparing base (50e6d59) to head (059bc86).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2227   +/-   ##
=======================================
  Coverage   79.05%   79.05%           
=======================================
  Files         612      612           
  Lines      106476   106483    +7     
  Branches    15051    15050    -1     
=======================================
+ Hits        84177    84184    +7     
- Misses      21646    21647    +1     
+ Partials      653      652    -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@nebeid nebeid merged commit eb0c0c0 into aws:main Feb 28, 2025
110 of 114 checks passed
nebeid added a commit to nebeid/aws-lc that referenced this pull request Feb 28, 2025
…mentation (aws#2227)

- Fix instruction that caused out-of-bound read in the input reading of
the 16x loop (which processes a batch of 16 blocks of AES, 1 block = 16
bytes). This was triggered on lengths that are in the range 
[16*k * (16 bytes), (16*k +3)* (16 bytes)-1], k = 1, 2, ... 
The instruction was reading up to 3*16 bytes beyond the input length bound.

- The fix was inspired by the 8x loop in
https://github.com/aws/aws-lc/blob/becf5785c131012bb5a64f3da6cdb117ddc0f431/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L2544

- The existing unit tests cover those cases but there were no explicit
memory protections and ASAN doesn't instrument assembly code to check
for out-of-bound reads even when the subsequent memory is explicitly
poisoned.
 
### Call-outs:
N/A

### Testing:
On c6i, without the fix, the unit test segfaults
```
./crypto/crypto_test "--gtest_filter=XTSTest.*"
Note: Google Test filter = XTSTest.*
[==========] Running 4 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 4 tests from XTSTest
[ RUN      ] XTSTest.TestVectors
Segmentation fault (core dumped)
```
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
nebeid added a commit that referenced this pull request Mar 28, 2025
…ts. (#2286)

This change hardens the tests introduced in #2227 Fix out-of-bound (OOB)
input read in AES-XTS Decrypt in AVX-512 implementation.
It adds a memory page preceding the input and output buffer that is
protected against read and write in order to detect any under-read, in
which case a segfault occurs.

The suspected code that can potentially cause a "pre-bound" OOB is the
cipher-stealing section in Encrypt

[crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L1809-L1810](https://github.com/aws/aws-lc/blob/v1.48.5/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L1809-L1810)
and decrypt

[crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#2572-L2573](https://github.com/aws/aws-lc/blob/v1.48.5/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L2572-L2573).

### Testing:
The efficacy of the added test was shown by changing the decrypt
cipher-stealing code for example to:
```diff
--- a/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl
+++ b/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl
@@ -2569,7 +2569,7 @@ ___
   vpshufb       %xmm10,%xmm8,%xmm8
 
 
-  vmovdqu       -0x10($input,$length,1),%xmm3
+  vmovdqu       -0x12($input,$length,1),%xmm3
   vmovdqu       %xmm8,-0x10($output,$length,1)
 ```
With this change, a segmentation fault occurs in the test vector of input length 17 bytes (1 AES block + 1 byte); which is the smallest test vector that requires cipher stealing. At the changed line:
- `$input` points at byte 16, i.e. past the first block
- `$length` = 1, after [l.2429](https://github.com/aws/aws-lc/blob/v1.48.5/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L2429)
- the read index with the diff change is `$input + $length - 18` = `$input -17`, which points at byte "-1", i.e. the byte right before byte 0 of the input, i.e. an underread, this causes a segfault at this vector.
- Other larger changes, e.g. -0x20, will have the same result.

Another test changes the location of the written output
```@@ -2607,7 +2607,7 @@ ___
 
   .L_done_${rndsuffix}:
   # store last ciphertext value
-  vmovdqu       %xmm8,-0x10($output)
+  vmovdqu       %xmm8,-0x11($output)
 ___
   }
 ```
- This test caused a segfault with the smallest input of 1 block = 16
bytes

Similar tests in the encrypt path gave the same result of segfaulting
when trying to read before the input beginning.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
nebeid added a commit to nebeid/aws-lc that referenced this pull request Apr 8, 2025
…ts. (aws#2286)

This change hardens the tests introduced in aws#2227 Fix out-of-bound (OOB)
input read in AES-XTS Decrypt in AVX-512 implementation.
It adds a memory page preceding the input and output buffer that is
protected against read and write in order to detect any under-read, in
which case a segfault occurs.

The suspected code that can potentially cause a "pre-bound" OOB is the
cipher-stealing section in Encrypt

[crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L1809-L1810](https://github.com/aws/aws-lc/blob/v1.48.5/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L1809-L1810)
and decrypt

[crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#2572-L2573](https://github.com/aws/aws-lc/blob/v1.48.5/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L2572-L2573).

The efficacy of the added test was shown by changing the decrypt
cipher-stealing code for example to:
```diff
--- a/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl
+++ b/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl
@@ -2569,7 +2569,7 @@ ___
   vpshufb       %xmm10,%xmm8,%xmm8

-  vmovdqu       -0x10($input,$length,1),%xmm3
+  vmovdqu       -0x12($input,$length,1),%xmm3
   vmovdqu       %xmm8,-0x10($output,$length,1)
 ```
With this change, a segmentation fault occurs in the test vector of input length 17 bytes (1 AES block + 1 byte); which is the smallest test vector that requires cipher stealing. At the changed line:
- `$input` points at byte 16, i.e. past the first block
- `$length` = 1, after [l.2429](https://github.com/aws/aws-lc/blob/v1.48.5/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L2429)
- the read index with the diff change is `$input + $length - 18` = `$input -17`, which points at byte "-1", i.e. the byte right before byte 0 of the input, i.e. an underread, this causes a segfault at this vector.
- Other larger changes, e.g. -0x20, will have the same result.

Another test changes the location of the written output
```@@ -2607,7 +2607,7 @@ ___

   .L_done_${rndsuffix}:
   # store last ciphertext value
-  vmovdqu       %xmm8,-0x10($output)
+  vmovdqu       %xmm8,-0x11($output)
 ___
   }
 ```
- This test caused a segfault with the smallest input of 1 block = 16
bytes

Similar tests in the encrypt path gave the same result of segfaulting
when trying to read before the input beginning.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.
nebeid added a commit to nebeid/aws-lc that referenced this pull request Apr 8, 2025
…ts. (aws#2286)

This change hardens the tests introduced in aws#2227 Fix out-of-bound (OOB)
input read in AES-XTS Decrypt in AVX-512 implementation.
It adds a memory page preceding the input and output buffer that is
protected against read and write in order to detect any under-read, in
which case a segfault occurs.

The suspected code that can potentially cause a "pre-bound" OOB is the
cipher-stealing section in Encrypt

[crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L1809-L1810](https://github.com/aws/aws-lc/blob/v1.48.5/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L1809-L1810)
and decrypt

[crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#2572-L2573](https://github.com/aws/aws-lc/blob/v1.48.5/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L2572-L2573).

The efficacy of the added test was shown by changing the decrypt
cipher-stealing code for example to:
```diff
--- a/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl
+++ b/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl
@@ -2569,7 +2569,7 @@ ___
   vpshufb       %xmm10,%xmm8,%xmm8

-  vmovdqu       -0x10($input,$length,1),%xmm3
+  vmovdqu       -0x12($input,$length,1),%xmm3
   vmovdqu       %xmm8,-0x10($output,$length,1)
 ```
With this change, a segmentation fault occurs in the test vector of input length 17 bytes (1 AES block + 1 byte); which is the smallest test vector that requires cipher stealing. At the changed line:
- `$input` points at byte 16, i.e. past the first block
- `$length` = 1, after [l.2429](https://github.com/aws/aws-lc/blob/v1.48.5/crypto/fipsmodule/aes/asm/aesni-xts-avx512.pl#L2429)
- the read index with the diff change is `$input + $length - 18` = `$input -17`, which points at byte "-1", i.e. the byte right before byte 0 of the input, i.e. an underread, this causes a segfault at this vector.
- Other larger changes, e.g. -0x20, will have the same result.

Another test changes the location of the written output
```@@ -2607,7 +2607,7 @@ ___

   .L_done_${rndsuffix}:
   # store last ciphertext value
-  vmovdqu       %xmm8,-0x10($output)
+  vmovdqu       %xmm8,-0x11($output)
 ___
   }
 ```
- This test caused a segfault with the smallest input of 1 block = 16
bytes

Similar tests in the encrypt path gave the same result of segfaulting
when trying to read before the input beginning.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.

(cherry picked from commit a39439b)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants