2020-11-13 00:01:31 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/* Copyright(c) 2016-20 Intel Corporation. */
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
#include "defines.h"
|
|
|
|
|
2021-11-15 10:35:24 -08:00
|
|
|
/*
|
2023-10-05 17:38:51 +02:00
|
|
|
* Data buffer spanning two pages that will be placed first in the .data
|
2023-10-05 17:38:52 +02:00
|
|
|
* segment via the linker script. Even if not used internally the second page
|
|
|
|
* is needed by external test manipulating page permissions, so mark
|
|
|
|
* encl_buffer as "used" to make sure it is entirely preserved by the compiler.
|
2021-11-15 10:35:24 -08:00
|
|
|
*/
|
2023-10-05 17:38:52 +02:00
|
|
|
static uint8_t __used __section(".data.encl_buffer") encl_buffer[8192] = { 1 };
|
2021-06-10 11:30:21 +03:00
|
|
|
|
2022-05-10 11:08:58 -07:00
|
|
|
enum sgx_enclu_function {
|
|
|
|
EACCEPT = 0x5,
|
|
|
|
EMODPE = 0x6,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void do_encl_emodpe(void *_op)
|
|
|
|
{
|
|
|
|
struct sgx_secinfo secinfo __aligned(sizeof(struct sgx_secinfo)) = {0};
|
|
|
|
struct encl_op_emodpe *op = _op;
|
|
|
|
|
|
|
|
secinfo.flags = op->flags;
|
|
|
|
|
|
|
|
asm volatile(".byte 0x0f, 0x01, 0xd7"
|
2023-10-05 17:38:44 +02:00
|
|
|
: /* no outputs */
|
2022-05-10 11:08:58 -07:00
|
|
|
: "a" (EMODPE),
|
|
|
|
"b" (&secinfo),
|
2023-10-05 17:38:44 +02:00
|
|
|
"c" (op->epc_addr)
|
|
|
|
: "memory" /* read from secinfo pointer */);
|
2022-05-10 11:08:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void do_encl_eaccept(void *_op)
|
|
|
|
{
|
|
|
|
struct sgx_secinfo secinfo __aligned(sizeof(struct sgx_secinfo)) = {0};
|
|
|
|
struct encl_op_eaccept *op = _op;
|
|
|
|
int rax;
|
|
|
|
|
|
|
|
secinfo.flags = op->flags;
|
|
|
|
|
|
|
|
asm volatile(".byte 0x0f, 0x01, 0xd7"
|
|
|
|
: "=a" (rax)
|
|
|
|
: "a" (EACCEPT),
|
|
|
|
"b" (&secinfo),
|
2023-10-05 17:38:44 +02:00
|
|
|
"c" (op->epc_addr)
|
|
|
|
: "memory" /* read from secinfo pointer */);
|
2022-05-10 11:08:58 -07:00
|
|
|
|
|
|
|
op->ret = rax;
|
|
|
|
}
|
|
|
|
|
2020-11-13 00:01:31 +02:00
|
|
|
static void *memcpy(void *dest, const void *src, size_t n)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
((char *)dest)[i] = ((char *)src)[i];
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2022-05-10 11:09:02 -07:00
|
|
|
static void *memset(void *dest, int c, size_t n)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
((char *)dest)[i] = c;
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void do_encl_init_tcs_page(void *_op)
|
|
|
|
{
|
|
|
|
struct encl_op_init_tcs_page *op = _op;
|
|
|
|
void *tcs = (void *)op->tcs_page;
|
|
|
|
uint32_t val_32;
|
|
|
|
|
|
|
|
memset(tcs, 0, 16); /* STATE and FLAGS */
|
|
|
|
memcpy(tcs + 16, &op->ssa, 8); /* OSSA */
|
|
|
|
memset(tcs + 24, 0, 4); /* CSSA */
|
|
|
|
val_32 = 1;
|
|
|
|
memcpy(tcs + 28, &val_32, 4); /* NSSA */
|
|
|
|
memcpy(tcs + 32, &op->entry, 8); /* OENTRY */
|
|
|
|
memset(tcs + 40, 0, 24); /* AEP, OFSBASE, OGSBASE */
|
|
|
|
val_32 = 0xFFFFFFFF;
|
|
|
|
memcpy(tcs + 64, &val_32, 4); /* FSLIMIT */
|
|
|
|
memcpy(tcs + 68, &val_32, 4); /* GSLIMIT */
|
|
|
|
memset(tcs + 72, 0, 4024); /* Reserved */
|
|
|
|
}
|
|
|
|
|
2021-11-15 10:35:23 -08:00
|
|
|
static void do_encl_op_put_to_buf(void *op)
|
2021-11-15 10:35:22 -08:00
|
|
|
{
|
2021-11-15 10:35:23 -08:00
|
|
|
struct encl_op_put_to_buf *op2 = op;
|
2021-11-15 10:35:22 -08:00
|
|
|
|
|
|
|
memcpy(&encl_buffer[0], &op2->value, 8);
|
|
|
|
}
|
|
|
|
|
2021-11-15 10:35:23 -08:00
|
|
|
static void do_encl_op_get_from_buf(void *op)
|
2020-11-13 00:01:31 +02:00
|
|
|
{
|
2021-11-15 10:35:23 -08:00
|
|
|
struct encl_op_get_from_buf *op2 = op;
|
2021-06-10 11:30:21 +03:00
|
|
|
|
2021-11-15 10:35:22 -08:00
|
|
|
memcpy(&op2->value, &encl_buffer[0], 8);
|
|
|
|
}
|
|
|
|
|
2021-11-15 10:35:24 -08:00
|
|
|
static void do_encl_op_put_to_addr(void *_op)
|
|
|
|
{
|
|
|
|
struct encl_op_put_to_addr *op = _op;
|
|
|
|
|
|
|
|
memcpy((void *)op->addr, &op->value, 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void do_encl_op_get_from_addr(void *_op)
|
|
|
|
{
|
|
|
|
struct encl_op_get_from_addr *op = _op;
|
|
|
|
|
|
|
|
memcpy(&op->value, (void *)op->addr, 8);
|
|
|
|
}
|
|
|
|
|
2021-11-15 10:35:26 -08:00
|
|
|
static void do_encl_op_nop(void *_op)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
selftests/sgx: Handle relocations in test enclave
Static-pie binaries normally include a startup routine to perform any ELF
relocations from .rela.dyn. Since the enclave loading process is different
and glibc is not included, do the necessary relocation for encl_op_array
entries manually at runtime relative to the enclave base to ensure correct
function pointers.
When keeping encl_op_array as a local variable on the stack, gcc without
optimizations generates code that explicitly gets the right function
addresses and stores them to create the array on the stack:
encl_body:
/* snipped */
lea do_encl_op_put_to_buf(%rip), %rax
mov %rax, -0x50(%rbp)
lea do_encl_op_get_from_buf(%rip), %rax
mov %rax,-0x48(%rbp)
lea do_encl_op_put_to_addr(%rip), %rax
/* snipped */
However, gcc -Os or clang generate more efficient code that initializes
encl_op_array by copying a "prepared copy" containing the absolute
addresses of the functions (i.e., relative to the image base starting from
0) generated by the compiler/linker:
encl_body:
/* snipped */
lea prepared_copy(%rip), %rsi
lea -0x48(%rsp), %rdi
mov $0x10,%ecx
rep movsl %ds:(%rsi),%es:(%rdi)
/* snipped */
When building the enclave with -static-pie, the compiler/linker includes
relocation entries for the function symbols in the "prepared copy":
Relocation section '.rela.dyn' at offset 0x4000 contains 12 entries:
Offset Info Type Symbol
/* snipped; "prepared_copy" starts at 0x6000 */
000000006000 000000000008 R_X86_64_RELATIVE <do_encl_emodpe>
000000006008 000000000008 R_X86_64_RELATIVE <do_encl_eaccept>
000000006010 000000000008 R_X86_64_RELATIVE <do_encl_op_put_to_buf>
000000006018 000000000008 R_X86_64_RELATIVE <do_encl_op_get_from_buf>
000000006020 000000000008 R_X86_64_RELATIVE <do_encl_op_put_to_addr>
000000006028 000000000008 R_X86_64_RELATIVE <do_encl_op_get_from_addr>
000000006030 000000000008 R_X86_64_RELATIVE <do_encl_op_nop>
000000006038 000000000008 R_X86_64_RELATIVE <do_encl_init_tcs_page>
Static-pie binaries normally include a glibc "_dl_relocate_static_pie"
routine that will perform these relocations as part of the startup.
However, since the enclave loading process is different and glibc is not
included, we cannot rely on these relocations to be performed. Without
relocations, the code would erroneously jump to the _absolute_ function
address loaded from the local copy.
Thus, declare "encl_op_array" as global and manually relocate the loaded
function-pointer entries relative to the enclave base at runtime. This
generates the following code:
encl_body:
/* snipped */
lea encl_op_array(%rip), %rcx
lea __encl_base(%rip), %rax
add (%rcx,%rdx,8),%rax
jmp *%rax
Signed-off-by: Jo Van Bulck <jo.vanbulck@cs.kuleuven.be>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Acked-by: Kai Huang <kai.huang@intel.com>
Link: https://lore.kernel.org/all/150d8ca8-2c66-60d1-f9fc-8e6279824e94@cs.kuleuven.be/
Link: https://lore.kernel.org/all/5c22de5a-4b3b-1f38-9771-409b4ec7f96d@cs.kuleuven.be/#r
Link: https://lore.kernel.org/all/20231005153854.25566-9-jo.vanbulck%40cs.kuleuven.be
2023-10-05 17:38:49 +02:00
|
|
|
/*
|
|
|
|
* Symbol placed at the start of the enclave image by the linker script.
|
|
|
|
* Declare this extern symbol with visibility "hidden" to ensure the compiler
|
|
|
|
* does not access it through the GOT and generates position-independent
|
|
|
|
* addressing as __encl_base(%rip), so we can get the actual enclave base
|
|
|
|
* during runtime.
|
|
|
|
*/
|
|
|
|
extern const uint8_t __attribute__((visibility("hidden"))) __encl_base;
|
|
|
|
|
|
|
|
typedef void (*encl_op_t)(void *);
|
|
|
|
static const encl_op_t encl_op_array[ENCL_OP_MAX] = {
|
|
|
|
do_encl_op_put_to_buf,
|
|
|
|
do_encl_op_get_from_buf,
|
|
|
|
do_encl_op_put_to_addr,
|
|
|
|
do_encl_op_get_from_addr,
|
|
|
|
do_encl_op_nop,
|
|
|
|
do_encl_eaccept,
|
|
|
|
do_encl_emodpe,
|
|
|
|
do_encl_init_tcs_page,
|
|
|
|
};
|
|
|
|
|
2021-11-15 10:35:22 -08:00
|
|
|
void encl_body(void *rdi, void *rsi)
|
|
|
|
{
|
selftests/sgx: Handle relocations in test enclave
Static-pie binaries normally include a startup routine to perform any ELF
relocations from .rela.dyn. Since the enclave loading process is different
and glibc is not included, do the necessary relocation for encl_op_array
entries manually at runtime relative to the enclave base to ensure correct
function pointers.
When keeping encl_op_array as a local variable on the stack, gcc without
optimizations generates code that explicitly gets the right function
addresses and stores them to create the array on the stack:
encl_body:
/* snipped */
lea do_encl_op_put_to_buf(%rip), %rax
mov %rax, -0x50(%rbp)
lea do_encl_op_get_from_buf(%rip), %rax
mov %rax,-0x48(%rbp)
lea do_encl_op_put_to_addr(%rip), %rax
/* snipped */
However, gcc -Os or clang generate more efficient code that initializes
encl_op_array by copying a "prepared copy" containing the absolute
addresses of the functions (i.e., relative to the image base starting from
0) generated by the compiler/linker:
encl_body:
/* snipped */
lea prepared_copy(%rip), %rsi
lea -0x48(%rsp), %rdi
mov $0x10,%ecx
rep movsl %ds:(%rsi),%es:(%rdi)
/* snipped */
When building the enclave with -static-pie, the compiler/linker includes
relocation entries for the function symbols in the "prepared copy":
Relocation section '.rela.dyn' at offset 0x4000 contains 12 entries:
Offset Info Type Symbol
/* snipped; "prepared_copy" starts at 0x6000 */
000000006000 000000000008 R_X86_64_RELATIVE <do_encl_emodpe>
000000006008 000000000008 R_X86_64_RELATIVE <do_encl_eaccept>
000000006010 000000000008 R_X86_64_RELATIVE <do_encl_op_put_to_buf>
000000006018 000000000008 R_X86_64_RELATIVE <do_encl_op_get_from_buf>
000000006020 000000000008 R_X86_64_RELATIVE <do_encl_op_put_to_addr>
000000006028 000000000008 R_X86_64_RELATIVE <do_encl_op_get_from_addr>
000000006030 000000000008 R_X86_64_RELATIVE <do_encl_op_nop>
000000006038 000000000008 R_X86_64_RELATIVE <do_encl_init_tcs_page>
Static-pie binaries normally include a glibc "_dl_relocate_static_pie"
routine that will perform these relocations as part of the startup.
However, since the enclave loading process is different and glibc is not
included, we cannot rely on these relocations to be performed. Without
relocations, the code would erroneously jump to the _absolute_ function
address loaded from the local copy.
Thus, declare "encl_op_array" as global and manually relocate the loaded
function-pointer entries relative to the enclave base at runtime. This
generates the following code:
encl_body:
/* snipped */
lea encl_op_array(%rip), %rcx
lea __encl_base(%rip), %rax
add (%rcx,%rdx,8),%rax
jmp *%rax
Signed-off-by: Jo Van Bulck <jo.vanbulck@cs.kuleuven.be>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Acked-by: Kai Huang <kai.huang@intel.com>
Link: https://lore.kernel.org/all/150d8ca8-2c66-60d1-f9fc-8e6279824e94@cs.kuleuven.be/
Link: https://lore.kernel.org/all/5c22de5a-4b3b-1f38-9771-409b4ec7f96d@cs.kuleuven.be/#r
Link: https://lore.kernel.org/all/20231005153854.25566-9-jo.vanbulck%40cs.kuleuven.be
2023-10-05 17:38:49 +02:00
|
|
|
struct encl_op_header *header = (struct encl_op_header *)rdi;
|
|
|
|
encl_op_t op;
|
|
|
|
|
|
|
|
if (header->type >= ENCL_OP_MAX)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The enclave base address needs to be added, as this call site
|
|
|
|
* *cannot be* made rip-relative by the compiler, or fixed up by
|
|
|
|
* any other possible means.
|
|
|
|
*/
|
|
|
|
op = ((uint64_t)&__encl_base) + encl_op_array[header->type];
|
|
|
|
|
|
|
|
(*op)(header);
|
2020-11-13 00:01:31 +02:00
|
|
|
}
|