aws / aws-nitro-enclaves-image-format

This library provides the definition of the enclave image format (EIF) file used in AWS Nitro Enclaves.
Apache License 2.0
11 stars 17 forks source link

eif_reader: Parse eif sections according to EifHeader #26

Open foersleo opened 4 months ago

foersleo commented 4 months ago

Issue #, if available: #25

Description of changes:

eif_reader: Parse eif sections according to EifHeader

The EifReader did not honor the section table as specified in the 
EifHeader. Fix this by adhering by the section table from the header for 
parsing sections.

With this fix we can cover valid enclave image files with gaps between 
the sections. However, we now have to consider the data in these gaps 
for crc calculation.

Testing done:

I ran a cli picking up these changes (See https://github.com/foersleo/aws-nitro-enclaves-cli/tree/test_image_format_issue25) on both architectures and ran the test suite in scripts/run_tests.sh successfully. All tests passed.

In addition I ran a custom EIF I generated in the following way:

  1. Build the example eif hello.eif from the aws-nitro-enclaves-cli/examples
  2. Add 64 zero bytes between the end of the EIF header and the first section header
  3. Add 64 to every address in EifHeader::section_offsets[0..(EifHeader::num_sections - 1)]
  4. Recalculate the CRC of the new file and add it to the header

Using a hacky script to display info on an EIF we can observe the changes in the header (See same section order and sizes, but notice difference in offsets and crc):

Original file:

================= EIF file 'hello.eif' ==========================
-----------------------EifHeader-----------------------------------
magic: 0x2e656966
version: 0x4 - flags: 0x0
default_mem: 0x40000000
default_cpus: 0x2
reserved: 0x0 - num_sections: 5
section_offsets[0]: 0x224
section_offsets[1]: 0x4d9200
section_offsets[2]: 0x4d9283
section_offsets[3]: 0x4d9bbc
section_offsets[4]: 0x5945c8
section_sizes[0]: 0x4d8fd0
section_sizes[1]: 0x77
section_sizes[2]: 0x92d
section_sizes[3]: 0xbaa00
section_sizes[4]: 0x41f800
reserved: 0x0
crc: 0x421a0ff7
*********************** Section 0 ***************************
type: kernel
section header offset: 0x224
section data offset: 0x230
section data size: 0x4d8fd0
*********************** Section 1 ***************************
type: cmdline
section header offset: 0x4d9200
section data offset: 0x4d920c
section data size: 0x77
*********************** Section 2 ***************************
type: metadata
section header offset: 0x4d9283
section data offset: 0x4d928f
section data size: 0x92d
*********************** Section 3 ***************************
type: ramdisk
section header offset: 0x4d9bbc
section data offset: 0x4d9bc8
section data size: 0xbaa00
*********************** Section 4 ***************************
type: ramdisk
section header offset: 0x5945c8
section data offset: 0x5945d4
section data size: 0x41f800

File with gap:

================= EIF file 'hello_with_gap.eif' ==========================
-----------------------EifHeader-----------------------------------
magic: 0x2e656966
version: 0x4 - flags: 0x0
default_mem: 0x40000000
default_cpus: 0x2
reserved: 0x0 - num_sections: 5
section_offsets[0]: 0x264
section_offsets[1]: 0x4d9240
section_offsets[2]: 0x4d92c3
section_offsets[3]: 0x4d9bfc
section_offsets[4]: 0x594608
section_sizes[0]: 0x4d8fd0
section_sizes[1]: 0x77
section_sizes[2]: 0x92d
section_sizes[3]: 0xbaa00
section_sizes[4]: 0x41f800
reserved: 0x0
crc: 0xd361cc5d
*********************** Section 0 ***************************
type: kernel
section header offset: 0x264
section data offset: 0x270
section data size: 0x4d8fd0
*********************** Section 1 ***************************
type: cmdline
section header offset: 0x4d9240
section data offset: 0x4d924c
section data size: 0x77
*********************** Section 2 ***************************
type: metadata
section header offset: 0x4d92c3
section data offset: 0x4d92cf
section data size: 0x92d
*********************** Section 3 ***************************
type: ramdisk
section header offset: 0x4d9bfc
section data offset: 0x4d9c08
section data size: 0xbaa00
*********************** Section 4 ***************************
type: ramdisk
section header offset: 0x594608
section data offset: 0x594614
section data size: 0x41f800

Both files share the same PCR0, PCR1 and PCR2 values as both share the same functional components (kernel, ramdisks, cmdline):

$ nitro-cli describe-eif --eif-path ./hello_with_gap.eif | grep PCR
    "PCR0": "30755f776a986137d281c716ed2c2a2775abd8fcea02af95af7553ef24044bf5fcec44a757b23e7d102b12e243021d2d",
    "PCR1": "bcdf05fefccaa8e55bf2c8d6dee9e79bbff31e34bf28a99aa19e6b29c37ee80b214a414b7607236edf26fcb78654e63f",
    "PCR2": "3a0893472667d5518f328bba1122a8052cdfa96512f4deab657a1101fcdfa5fcee8ebe915d352da5d87647d57c1e5777"
$ nitro-cli describe-eif --eif-path ./hello.eif | grep PCR
    "PCR0": "30755f776a986137d281c716ed2c2a2775abd8fcea02af95af7553ef24044bf5fcec44a757b23e7d102b12e243021d2d",
    "PCR1": "bcdf05fefccaa8e55bf2c8d6dee9e79bbff31e34bf28a99aa19e6b29c37ee80b214a414b7607236edf26fcb78654e63f",
    "PCR2": "3a0893472667d5518f328bba1122a8052cdfa96512f4deab657a1101fcdfa5fcee8ebe915d352da5d87647d57c1e5777"

Running hello_with_gap.eif with the original nitro-cli will successfully start the enclave and in debug mode we can observe the expected behavior through nitro-cli console command. However, as soon as we run nitro-cli describe-enclaves command we get an error (See below) and our enclave will be terminated:

$ nitro-cli run-enclave --eif-path hello_with_gap.eif --debug-mode --memory 512 --cpu-count 2 --enclave-cid 16 
Start allocating memory...
Started enclave with enclave-cid: 16, memory: 512 MiB, cpu-ids: [1, 5]
{
  "EnclaveName": "hello_with_gap",
  "EnclaveID": "i-06c28848702514cd5-enc1904e4fea1636f6",
  "ProcessID": 6383,
  "EnclaveCID": 16,
  "NumberOfCPUs": 2,
  "CPUIDs": [
    1,
    5
  ],
  "MemoryMiB": 512
}
$ nitro-cli console --enclave-id i-06c28848702514cd5-enc1904e4fea1636f6
Connecting to the console for enclave 16...
Successfully connected to the console.
TC 2022
[    0.000000] Command line: reboot=k panic=30 pci=off nomodules console=ttyS0 i8042.noaux i8042.nomux i8042.nopnp i8042.dumbkbd random.trust_cpu=on
[...]
[   1] Hello from the enclave side!
[   2] Hello from the enclave side!
[   3] Hello from the enclave side!
[   4] Hello from the enclave side!
[   5] Hello from the enclave side!
^C
$ nitro-cli describe-enclaves
[ E35 ] EIF file parsing error. Such errors appear when attempting to fill a memory region with a section of the EIF file, but reading the entire section fails. This might indicate that the required hugepages are not available.

For more details, please visit https://docs.aws.amazon.com/enclaves/latest/user/cli-errors.html#E35

If you open a support ticket, please provide the error log found at "/var/log/nitro_enclaves/err2024-06-25T07:33:30.332188378+00:00.log"
Failed connections: 1
[]
[ E39 ] Enclave process connection failure. Such error appears when the enclave manager fails to connect to at least one enclave process for retrieving the description information.

For more details, please visit https://docs.aws.amazon.com/enclaves/latest/user/cli-errors.html#E39

If you open a support ticket, please provide the error log found at "/var/log/nitro_enclaves/err2024-06-25T07:33:30.332414051+00:00.log"

Running the same commands on the nitro-cli with this fix yields working results:

$ nitro-cli run-enclave --eif-path hello_with_gap.eif --debug-mode --memory 512 --cpu-count 2 --enclave-cid 16 
Start allocating memory...
Started enclave with enclave-cid: 16, memory: 512 MiB, cpu-ids: [1, 5]
{
  "EnclaveName": "hello_with_gap",
  "EnclaveID": "i-06c28848702514cd5-enc1904e5727a63efc",
  "ProcessID": 11127,
  "EnclaveCID": 16,
  "NumberOfCPUs": 2,
  "CPUIDs": [
    1,
    5
  ],
  "MemoryMiB": 512
}
$ nitro-cli console --enclave-id i-06c28848702514cd5-enc1904e5727a63efc
Connecting to the console for enclave 16...
Successfully connected to the console.
TC 2022
[    0.000000] Command line: reboot=k panic=30 pci=off nomodules console=ttyS0 i8042.noaux i8042.nomux i8042.nopnp i8042.dumbkbd random.trust_cpu=on virtio_mmio.device=4K@0xd0000000:5 virtio_mmio.device=4K@0xd0001000:6
[...]
[   1] Hello from the enclave side!
[   2] Hello from the enclave side!
[   3] Hello from the enclave side!
[   4] Hello from the enclave side!
[   5] Hello from the enclave side!
^C
$ nitro-cli describe-enclaves
[
  {
    "EnclaveName": "hello_with_gap",
    "EnclaveID": "i-06c28848702514cd5-enc1904e5727a63efc",
    "ProcessID": 11127,
    "EnclaveCID": 16,
    "NumberOfCPUs": 2,
    "CPUIDs": [
      1,
      5
    ],
    "MemoryMiB": 512,
    "State": "RUNNING",
    "Flags": "DEBUG_MODE",
    "Measurements": {
      "HashAlgorithm": "Sha384 { ... }",
      "PCR0": "30755f776a986137d281c716ed2c2a2775abd8fcea02af95af7553ef24044bf5fcec44a757b23e7d102b12e243021d2d",
      "PCR1": "bcdf05fefccaa8e55bf2c8d6dee9e79bbff31e34bf28a99aa19e6b29c37ee80b214a414b7607236edf26fcb78654e63f",
      "PCR2": "3a0893472667d5518f328bba1122a8052cdfa96512f4deab657a1101fcdfa5fcee8ebe915d352da5d87647d57c1e5777"
    }
  }
]

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.