Attribute: sizefunc
The Intel® Software Guard Extensions sizefunc
attribute modifier depends on a user defined trusted function which is called by the edge-routines to get the number of bytes to be copied. The sizefunc
has similar functionality as the sizeof()
operator. An example of where sizefunc
can be used is for marshaling variable-length structures, which are buffers whose total size is specified by a combination of values stored at well-defined locations inside the buffer (although typically it is at a single location). To prevent “check first, use later” type of attacks, sizefunc
is called twice. In the first call, sizefunc
operates in untrusted memory. The second time, sizefunc
operates in the data copied into trusted memory. If the sizes returned by the two sizefunc
calls do not match, the trusted bridge will cancel the ECALL and will report an error to the untrusted application. Note that sizefunc
must not be combined with the size
attribute. sizefunc
cannot be used with out
alone, however sizefunc
with both in
and out
is accepted. Additionally, users cannot define sizefunc
as strlen
or wcslen
. In all these scenarios, the sgx_edger8r
will throw an error. Strings should not be passed with the sizefunc
modifier, but with the string
or wstring
keyword. sizefunc
can be used with the count
attribute which gives the total length to be equal to sizefunc
* count
. The following items are the prototype of the trusted sizefunc
that you need to define inside the enclave:
size_t sizefunc_function_name(const parameter_type * p);
Where parameter_type
is the data type of the parameter annotated with the sizefunc
attribute. If you do not provide the definition of the sizefunc
function, the linker will report an error.
Note
The function implementing a sizefunc
should validate the input pointer carefully, before really using it. Since the function is called before the pointer is checked by the generated code.
Example
enclave{
trusted {
// Copies '100' bytes
public void test_size1([in, size=100] void* ptr, size_t len);
// Copies ‘len’ bytes
public void test_size2([in, size=len] void* ptr, size_t len);
// Copies cnt * sizeof(int) bytes
public void test_count([in, count=cnt] int* ptr, unsigned cnt);
// Copies cnt * len bytes
public void test_count_size([in, count=cnt, size=len] int* ptr,
unsigned cnt, size_t len);
// Copies get_packet_size bytes
// User must provide a function definition that matches
// size_t get_packet_size(const void* ptr);
void test_sizefunc([in, sizefunc=get_packet_size] void* ptr);
// Copies (get_packet_size * cnt) bytes
void test_sizefunc2(
[in, sizefunc=get_packet_size, count=cnt] void* ptr,
unsigned cnt);
};
};
Illegal Syntax:
enclave{
include "user_types.h"
trusted {
// size/count/sizefunc attributes must be used with
// pointer direction ([in, out])
void test_attribute_cant([size=len] void* ptr, size_t len);
// Cannot use sizefunc and size together
void test_sizefunc_size(
[in, size=100, sizefunc=packet_len] header* h);
// Cannot use strlen or wcslen as sizefunc
void test_sizefunc_strlen([in, sizefunc=strlen] header* h);
void test_sizefunc_wcslen([in, sizefunc=wcslen] header* h);
};
};
]]>Arrays
The Enclave Definition Language (EDL) supports multidimensional, fixed-size arrays to be used in data structure definition and parameter declaration. Zero-length array and flexible array member, however, are not supported. The special attribute isary
is used to designate function parameters that are of a user defined type array.
Example
enclave {
include "user_types.h" //for uArray - typedef int uArray[10];
trusted {
public void test_array([in] int arr[4]);
public void test_array_multi([in] int arr[4][4]);
public void test_isary([in, isary, size=len] uArray arr,
size_tlen);
};
};
Illegal Syntax:
enclave {
include "user_types.h" //for uArray - typedef int uArray[10];
trusted {
// Flexible array is not supported
public void test_flexible(int arr[][4]);
// Zero-length array is not supported.
public void test_zero(int arr[0]);
// User-defined array types need "isary"
public void test_miss_isary([in, size=len] uArray arr,
size_t len);
};
};
Support for arrays also includes attributes [in]
, [out]
and [user_check]
, which are similar in usage to the pointers.
Allowing Untrusted Functions to Call Trusted Functions
The default behavior is that the untrusted functions (specified in the untrusted section in the EDL file) of an enclave cannot call any of the trusted functions of this enclave.
If you want to grant an untrusted function access to an enclave exported function, specify this access using the allow
keyword.
Syntax
untrusted {
<function prototype> allow (func_name, func2_name, …);
};
Example
enclave {
trusted {
public void get_secret([out] secret_t* secret);
void set_secret([in] secret_t* secret);
};
untrusted {
void replace_secret(
[in] secret_t* new_secret,
[out] secret_t* old_secret)
allow (set_secret);
};
};
]]>