liberpal-skeleton.c 6.3 KB
Newer Older
1 2 3 4
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
// Copyright(c) 2016-18 Intel Corporation.

#include <elf.h>
5
#include <errno.h>
6
#include <fcntl.h>
7
#include <stdbool.h>
8 9 10 11 12 13 14 15 16 17 18 19
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include "defines.h"
#include "sgx_call.h"
20

21
#define PAGE_SIZE  4096
22

23 24
#define SGX_REG_PAGE_FLAGS \
	(SGX_SECINFO_REG | SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_X)
25

26 27 28
#define IMAGE		"encl.bin"
#define SIGSTRUCT	"encl.ss"
#define TOKEN		"encl.token"
29

30 31 32 33 34
static struct sgx_secs secs;
static bool initialized = false;

static bool encl_create(int dev_fd, unsigned long bin_size,
			struct sgx_secs *secs)
35
{
36 37 38 39 40 41 42 43
	struct sgx_enclave_create ioc;
	void *area;
	int rc;

	memset(secs, 0, sizeof(*secs));
	secs->ssa_frame_size = 1;
	secs->attributes = SGX_ATTR_MODE64BIT | SGX_ATTR_DEBUG;
	secs->xfrm = 7;
44

45 46 47 48 49 50 51
	for (secs->size = PAGE_SIZE; secs->size < bin_size; )
		secs->size <<= 1;

	area = mmap(NULL, secs->size * 2, PROT_NONE, MAP_SHARED, dev_fd, 0);
	if (area == MAP_FAILED) {
		perror("mmap");
		return false;
52 53
	}

54 55 56 57
	secs->base = ((uint64_t)area + secs->size - 1) & ~(secs->size - 1);
	munmap(area, secs->base - (uint64_t)area);
	munmap((void *)(secs->base + secs->size),
	       (uint64_t)area + secs->size - secs->base);
58

59 60
	if (mprotect((void *)secs->base, secs->size, PROT_READ | PROT_WRITE | PROT_EXEC)) {
		perror("mprotect");
61
		munmap((void *)secs->base, secs->size);
62 63 64 65 66 67 68 69 70 71 72 73
		return false;
	}

	ioc.src = (unsigned long)secs;
	rc = ioctl(dev_fd, SGX_IOC_ENCLAVE_CREATE, &ioc);
	if (rc) {
		fprintf(stderr, "ECREATE failed rc=%d, err=%d.\n", rc, errno);
		munmap((void *)secs->base, secs->size);
		return false;
	}

	return true;
74 75
}

76
static bool encl_add_pages(int dev_fd, uint64_t addr, void *data,
77
			   unsigned long length, uint64_t flags)
78
{
79 80 81
	struct sgx_enclave_add_page ioc;
	struct sgx_secinfo secinfo;
	int rc;
82

83 84
	memset(&secinfo, 0, sizeof(secinfo));
	secinfo.flags = flags;
85

86 87 88 89
	ioc.src = (uint64_t)data;
	ioc.addr = addr;
	ioc.secinfo = (unsigned long)&secinfo;
	ioc.mrmask = (__u16)-1;
90

91 92 93 94 95 96
	uint64_t added_size = 0;
	while (added_size < length) {
		rc = ioctl(dev_fd, SGX_IOC_ENCLAVE_ADD_PAGE, &ioc);
		if (rc) {
			fprintf(stderr, "EADD failed rc=%d.\n", rc);
			return false;
97
		}
98 99 100 101 102 103 104 105 106 107

		ioc.addr += PAGE_SIZE;
		ioc.src += PAGE_SIZE;
		added_size += PAGE_SIZE;
	}

	return true;
}

static bool encl_build(struct sgx_secs *secs, void *bin, unsigned long bin_size, 
108 109
		       struct sgx_sigstruct *sigstruct,
		       struct sgx_einittoken *token)
110 111 112 113 114 115 116 117 118
{
	struct sgx_enclave_init ioc;
	int dev_fd;
	int rc;

	dev_fd = open("/dev/isgx", O_RDWR);
	if (dev_fd < 0) {
		fprintf(stderr, "Unable to open /dev/sgx\n");
		return false;
119 120
	}

121 122 123 124
	if (!encl_create(dev_fd, bin_size, secs))
		goto out_dev_fd;

	if (!encl_add_pages(dev_fd, secs->base + 0, bin, PAGE_SIZE, SGX_SECINFO_TCS))
125
		goto out_map;
126 127 128

	if (!encl_add_pages(dev_fd, secs->base + PAGE_SIZE, bin + PAGE_SIZE,
			    bin_size - PAGE_SIZE, SGX_REG_PAGE_FLAGS))
129
		goto out_map;
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148

	ioc.addr = secs->base;
	ioc.sigstruct = (uint64_t)sigstruct;
	ioc.einittoken = (uint64_t)token;
	rc = ioctl(dev_fd, SGX_IOC_ENCLAVE_INIT, &ioc);
	if (rc) {
		printf("EINIT failed rc=%d\n", rc);
		goto out_map;
	}

	close(dev_fd);
	return true;
out_map:
	munmap((void *)secs->base, secs->size);
out_dev_fd:
	close(dev_fd);
	return false;
}

149
static bool get_file_size(const char *path, off_t *bin_size)
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
{
	struct stat sb;
	int ret;

	ret = stat(path, &sb);
	if (ret) {
		perror("stat");
		return false;
	}

	if (!sb.st_size || sb.st_size & 0xfff) {
		fprintf(stderr, "Invalid blob size %lu\n", sb.st_size);
		return false;
	}

	*bin_size = sb.st_size;
	return true;
}

169
static bool encl_data_map(const char *path, void **bin, off_t *bin_size)
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
{
	int fd;

	fd = open(path, O_RDONLY);
	if (fd == -1)  {
		fprintf(stderr, "open() %s failed, errno=%d.\n", path, errno);
		return false;
	}

	if (!get_file_size(path, bin_size))
		goto err_out;

	*bin = mmap(NULL, *bin_size, PROT_READ, MAP_PRIVATE, fd, 0);
	if (*bin == MAP_FAILED) {
		fprintf(stderr, "mmap() %s failed, errno=%d.\n", path, errno);
		goto err_out;
	}

	close(fd);
	return true;

err_out:
	close(fd);
	return false;
}

196
static bool load_sigstruct(const char *path, void *sigstruct)
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
{
	int fd;

	fd = open(path, O_RDONLY);
	if (fd == -1)  {
		fprintf(stderr, "open() %s failed, errno=%d.\n", path, errno);
		return false;
	}

	if (read(fd, sigstruct, sizeof(struct sgx_sigstruct)) !=
	    sizeof(struct sgx_sigstruct)) {
		fprintf(stderr, "read() %s failed, errno=%d.\n", path, errno);
		close(fd);
		return false;
	}

	close(fd);
	return true;
}

217
static bool load_token(const char *path, void *token)
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
{
	int fd;

	fd = open(path, O_RDONLY);
	if (fd == -1)  {
		fprintf(stderr, "open() %s failed, errno=%d.\n", path, errno);
		return false;
	}

	if (read(fd, token, sizeof(struct sgx_einittoken)) !=
		sizeof(struct sgx_einittoken)) {
		fprintf(stderr, "read() %s failed, errno=%d.\n", path, errno);
		close(fd);
		return false;
	}

	close(fd);
	return true;
}

238 239 240 241 242 243
int pal_get_version(void)
{
	return 1;
}

int pal_init(const char *args, const char *log_level)
244 245 246 247 248 249 250
{
	struct sgx_sigstruct sigstruct;
	struct sgx_einittoken token;
	off_t bin_size;
	void *bin;

	if (!encl_data_map(IMAGE, &bin, &bin_size))
251
		return -ENOENT;
252 253

	if (!load_sigstruct(SIGSTRUCT, &sigstruct))
254
		return -ENOENT;
255 256

	if (!load_token(TOKEN, &token))
257
		return -ENOENT;
258 259

	if (!encl_build(&secs, bin, bin_size, &sigstruct, &token))
260
		return -EINVAL;
261 262

	initialized = true;	
263

264 265 266
	return 0;
}

267 268
int pal_exec(char *path, char *argv[], const char *envp[],
	     int *exit_code, int stdin, int stdout, int stderr)
269
{
270 271 272 273 274 275 276 277 278
        FILE *fp = fdopen(stderr, "w");
        if (!fp)
                return -1;

	if (!initialized) {
	        fprintf(fp, "enclave runtime skeleton uninitialized yet!\n");
		fclose(fp);
	        return -1;
	}
279

280
	uint64_t result = 0;
281 282 283 284 285 286 287 288
	int ret = SGX_ENTER_1_ARG(ECALL_MAGIC, (void *)secs.base, &result);
	if (ret) {
		fprintf(fp, "failed to initialize enclave\n");
		fclose(fp);
		return ret;
	}
	if (result != INIT_MAGIC) {
		fprintf(fp, "Unexpected result: 0x%lx != 0x%lx\n", result, INIT_MAGIC);
289
		fclose(fp);
290 291 292
		return -1;
	}

293
	fprintf(fp, "Enclave runtime skeleton initialization succeeded\n");
294
	fclose(fp);
295

296
	*exit_code = 0;
297

298 299 300
	return 0;
}

301
int pal_destroy(void)
302 303
{
	if (!initialized) {
304
		fprintf(stderr, "Enclave runtime skeleton uninitialized yet!\n");
305 306 307 308
		return -1;
	}
	return 0;
}