CVE-2018-20742 (C++, published 2019-01-24T05:29Z)
Description: value: An issue was discovered in UC Berkeley RISE Opaque before 2018-12-01. There is no boundary check on ocall_malloc. The return value could be a pointer to enclave memory. It could cause an arbitrary enclave memory write.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-787 \u2014 Out-of-bounds Write
The product writes data past the end, or before the beginning, of the intended buffer.
Repository: https://github.com/ucbrise/opaque
Files changed:
src/enclave/App/App.cpp
src/enclave/Enclave/Enclave.cpp
src/enclave/Enclave/Enclave.edl
src/enclave/Enclave/util.cpp
src/enclave/Enclave/util.h
Commit message: Check that ecall [user_check] pointers and ocall_malloc result pointer are outside enclave (#67)

This should reduce the enclave's attack surface by preventing an attacker from invoking ecalls on or triggering unexpected writes to arbitrary enclave memory, which could potentially leak information about that memory or lead to incorrect results.

Fixes #36. Fixes #66.

Vulnerable code:
void ocall_malloc(size_t size, uint8_t **ret) {
    void ocall_malloc(size_t size, [out] uint8_t **ret);

Fixed code:
void unsafe_ocall_malloc(size_t size, uint8_t **ret) {
#include "sgx_lfence.h"
  // Guard against encrypting or overwriting enclave memory
  assert(sgx_is_outside_enclave(plaintext, plaintext_length) == 1);
  assert(sgx_is_outside_enclave(ciphertext, cipher_length) == 1);
  sgx_lfence();

  // Guard against operating on arbitrary enclave memory
  assert(sgx_is_outside_enclave(input_rows, input_rows_length) == 1);
  sgx_lfence();

  // Guard against operating on arbitrary enclave memory
  assert(sgx_is_outside_enclave(input_rows, input_rows_length) == 1);
  sgx_lfence();

  // Guard against operating on arbitrary enclave memory
  assert(sgx_is_outside_enclave(input_rows, input_rows_length) == 1);
  sgx_lfence();

  // Guard against operating on arbitrary enclave memory
  assert(sgx_is_outside_enclave(input_rows, input_rows_length) == 1);
  sgx_lfence();

  // Guard against operating on arbitrary enclave memory
  assert(sgx_is_outside_enclave(input_rows, input_rows_length) == 1);
  assert(sgx_is_outside_enclave(boundary_rows, boundary_rows_length) == 1);
  sgx_lfence();

  // Guard against operating on arbitrary enclave memory
  assert(sgx_is_outside_enclave(input_rows, input_rows_length) == 1);
  sgx_lfence();

  // Guard against operating on arbitrary enclave memory
  assert(sgx_is_outside_enclave(input_rows, input_rows_length) == 1);
  sgx_lfence();

  // Guard against operating on arbitrary enclave memory
  assert(sgx_is_outside_enclave(input_rows, input_rows_length) == 1);
  assert(sgx_is_outside_enclave(join_row, join_row_length) == 1);
  sgx_lfence();

  // Guard against operating on arbitrary enclave memory
  assert(sgx_is_outside_enclave(input_rows, input_rows_length) == 1);
  sgx_lfence();

  // Guard against operating on arbitrary enclave memory
  assert(sgx_is_outside_enclave(input_rows, input_rows_length) == 1);
  assert(sgx_is_outside_enclave(next_partition_first_row, next_partition_first_row_length) == 1);
  assert(sgx_is_outside_enclave(prev_partition_last_group, prev_partition_last_group_length) == 1);
  assert(sgx_is_outside_enclave(prev_partition_last_row, prev_partition_last_row_length) == 1);
  sgx_lfence();


    /**
     * Allocate memory outside of the enclave and return the pointer in `ret`.
     *
     * Before dereferencing the resulting pointer, the caller must check whether it is actually
     * outside the enclave using `sgx_is_outside_enclave()`. Otherwise, an attacker could cause the
     * enclave to perform unexpected operations on its own memory. The function `ocall_malloc()`
     * wraps this function with such a bounds check and most callers should use that function
     * instead.
     */
    void unsafe_ocall_malloc(size_t size, [out] uint8_t **ret);

#include "sgx_lfence.h"
void ocall_malloc(size_t size, uint8_t **ret) {
  unsafe_ocall_malloc(size, ret);

  // Guard against overwriting enclave memory
  assert(sgx_is_outside_enclave(*ret, size) == 1);
  sgx_lfence();
}

/**
 * Allocate memory outside of the enclave and return the pointer in `ret`.
 *
 * This is a checked wrapper around `unsafe_ocall_malloc`. The resulting pointer is safe to write
 * to.
 */
void ocall_malloc(size_t size, uint8_t **ret);