1ee546289SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause 2ee546289SJens Wiklander /* 3ee546289SJens Wiklander * Copyright (c) 2019, Linaro Limited 4ee546289SJens Wiklander */ 5ee546289SJens Wiklander 6ee546289SJens Wiklander #include <crypto/crypto.h> 7ee546289SJens Wiklander #include <crypto/internal_aes-gcm.h> 8ee546289SJens Wiklander #include <kernel/panic.h> 9ee546289SJens Wiklander #include <mm/core_memprot.h> 10ee546289SJens Wiklander #include <mm/core_mmu.h> 11ee546289SJens Wiklander #include <mm/fobj.h> 12ee546289SJens Wiklander #include <mm/tee_mm.h> 13ee546289SJens Wiklander #include <stdlib.h> 14ee546289SJens Wiklander #include <string.h> 15ee546289SJens Wiklander #include <tee_api_types.h> 16ee546289SJens Wiklander #include <types_ext.h> 17ee546289SJens Wiklander #include <util.h> 18ee546289SJens Wiklander 19ee546289SJens Wiklander #ifdef CFG_WITH_PAGER 20ee546289SJens Wiklander 21ee546289SJens Wiklander #define RWP_AE_KEY_BITS 256 22ee546289SJens Wiklander 23ee546289SJens Wiklander struct rwp_aes_gcm_iv { 24ee546289SJens Wiklander uint32_t iv[3]; 25ee546289SJens Wiklander }; 26ee546289SJens Wiklander 27ee546289SJens Wiklander #define RWP_AES_GCM_TAG_LEN 16 28ee546289SJens Wiklander 29ee546289SJens Wiklander struct rwp_state { 30ee546289SJens Wiklander uint64_t iv; 31ee546289SJens Wiklander uint8_t tag[RWP_AES_GCM_TAG_LEN]; 32ee546289SJens Wiklander }; 33ee546289SJens Wiklander 34ee546289SJens Wiklander struct fobj_rwp { 35ee546289SJens Wiklander uint8_t *store; 36ee546289SJens Wiklander struct rwp_state *state; 37ee546289SJens Wiklander struct fobj fobj; 38ee546289SJens Wiklander }; 39ee546289SJens Wiklander 40ee546289SJens Wiklander static struct fobj_ops ops_rw_paged; 41ee546289SJens Wiklander 42ee546289SJens Wiklander static struct internal_aes_gcm_key rwp_ae_key; 43ee546289SJens Wiklander 44ee546289SJens Wiklander void fobj_generate_authenc_key(void) 45ee546289SJens Wiklander { 46ee546289SJens Wiklander uint8_t key[RWP_AE_KEY_BITS / 8] = { 0 }; 47ee546289SJens Wiklander 48ee546289SJens Wiklander if (crypto_rng_read(key, sizeof(key)) != TEE_SUCCESS) 49ee546289SJens Wiklander panic("failed to generate random"); 50ee546289SJens Wiklander if (internal_aes_gcm_expand_enc_key(key, sizeof(key), &rwp_ae_key)) 51ee546289SJens Wiklander panic("failed to expand key"); 52ee546289SJens Wiklander } 53ee546289SJens Wiklander 54ee546289SJens Wiklander static void fobj_init(struct fobj *fobj, const struct fobj_ops *ops, 55ee546289SJens Wiklander unsigned int num_pages) 56ee546289SJens Wiklander { 57ee546289SJens Wiklander fobj->ops = ops; 58ee546289SJens Wiklander fobj->num_pages = num_pages; 59ee546289SJens Wiklander refcount_set(&fobj->refc, 1); 60*b83c0d5fSJens Wiklander TAILQ_INIT(&fobj->areas); 61ee546289SJens Wiklander } 62ee546289SJens Wiklander 63ee546289SJens Wiklander static void fobj_uninit(struct fobj *fobj) 64ee546289SJens Wiklander { 65ee546289SJens Wiklander assert(!refcount_val(&fobj->refc)); 66*b83c0d5fSJens Wiklander assert(TAILQ_EMPTY(&fobj->areas)); 67*b83c0d5fSJens Wiklander tee_pager_invalidate_fobj(fobj); 68ee546289SJens Wiklander } 69ee546289SJens Wiklander 70ee546289SJens Wiklander struct fobj *fobj_rw_paged_alloc(unsigned int num_pages) 71ee546289SJens Wiklander { 72ee546289SJens Wiklander tee_mm_entry_t *mm = NULL; 73ee546289SJens Wiklander struct fobj_rwp *rwp = NULL; 74ee546289SJens Wiklander size_t size = 0; 75ee546289SJens Wiklander 76ee546289SJens Wiklander assert(num_pages); 77ee546289SJens Wiklander 78ee546289SJens Wiklander rwp = calloc(1, sizeof(*rwp)); 79ee546289SJens Wiklander if (!rwp) 80ee546289SJens Wiklander return NULL; 81ee546289SJens Wiklander 82ee546289SJens Wiklander rwp->state = calloc(num_pages, sizeof(*rwp->state)); 83ee546289SJens Wiklander if (!rwp->state) 84ee546289SJens Wiklander goto err; 85ee546289SJens Wiklander 86ee546289SJens Wiklander if (MUL_OVERFLOW(num_pages, SMALL_PAGE_SIZE, &size)) 87ee546289SJens Wiklander goto err; 88ee546289SJens Wiklander mm = tee_mm_alloc(&tee_mm_sec_ddr, size); 89ee546289SJens Wiklander if (!mm) 90ee546289SJens Wiklander goto err; 91ee546289SJens Wiklander rwp->store = phys_to_virt(tee_mm_get_smem(mm), MEM_AREA_TA_RAM); 92ee546289SJens Wiklander assert(rwp->store); /* to assist debugging if it would ever happen */ 93ee546289SJens Wiklander if (!rwp->store) 94ee546289SJens Wiklander goto err; 95ee546289SJens Wiklander 96ee546289SJens Wiklander fobj_init(&rwp->fobj, &ops_rw_paged, num_pages); 97ee546289SJens Wiklander 98ee546289SJens Wiklander return &rwp->fobj; 99ee546289SJens Wiklander 100ee546289SJens Wiklander err: 101ee546289SJens Wiklander tee_mm_free(mm); 102ee546289SJens Wiklander free(rwp->state); 103ee546289SJens Wiklander free(rwp); 104ee546289SJens Wiklander 105ee546289SJens Wiklander return NULL; 106ee546289SJens Wiklander } 107ee546289SJens Wiklander 108ee546289SJens Wiklander static struct fobj_rwp *to_rwp(struct fobj *fobj) 109ee546289SJens Wiklander { 110ee546289SJens Wiklander assert(fobj->ops == &ops_rw_paged); 111ee546289SJens Wiklander 112ee546289SJens Wiklander return container_of(fobj, struct fobj_rwp, fobj); 113ee546289SJens Wiklander } 114ee546289SJens Wiklander 115ee546289SJens Wiklander static void rwp_free(struct fobj *fobj) 116ee546289SJens Wiklander { 117ee546289SJens Wiklander struct fobj_rwp *rwp = to_rwp(fobj); 118ee546289SJens Wiklander 119ee546289SJens Wiklander fobj_uninit(fobj); 120ee546289SJens Wiklander tee_mm_free(tee_mm_find(&tee_mm_sec_ddr, virt_to_phys(rwp->store))); 121ee546289SJens Wiklander free(rwp->state); 122ee546289SJens Wiklander free(rwp); 123ee546289SJens Wiklander } 124ee546289SJens Wiklander 125ee546289SJens Wiklander static TEE_Result rwp_load_page(struct fobj *fobj, unsigned int page_idx, 126ee546289SJens Wiklander void *va) 127ee546289SJens Wiklander { 128ee546289SJens Wiklander struct fobj_rwp *rwp = to_rwp(fobj); 129ee546289SJens Wiklander struct rwp_state *state = rwp->state + page_idx; 130ee546289SJens Wiklander uint8_t *src = rwp->store + page_idx * SMALL_PAGE_SIZE; 131ee546289SJens Wiklander struct rwp_aes_gcm_iv iv = { 132ee546289SJens Wiklander .iv = { (vaddr_t)state, state->iv >> 32, state->iv } 133ee546289SJens Wiklander }; 134ee546289SJens Wiklander 135ee546289SJens Wiklander assert(refcount_val(&fobj->refc)); 136ee546289SJens Wiklander assert(page_idx < fobj->num_pages); 137ee546289SJens Wiklander 138ee546289SJens Wiklander if (!state->iv) { 139ee546289SJens Wiklander /* 140ee546289SJens Wiklander * iv still zero which means that this is previously unused 141ee546289SJens Wiklander * page. 142ee546289SJens Wiklander */ 143ee546289SJens Wiklander memset(va, 0, SMALL_PAGE_SIZE); 144ee546289SJens Wiklander return TEE_SUCCESS; 145ee546289SJens Wiklander } 146ee546289SJens Wiklander 147ee546289SJens Wiklander return internal_aes_gcm_dec(&rwp_ae_key, &iv, sizeof(iv), 148ee546289SJens Wiklander NULL, 0, src, SMALL_PAGE_SIZE, va, 149ee546289SJens Wiklander state->tag, sizeof(state->tag)); 150ee546289SJens Wiklander } 151ee546289SJens Wiklander KEEP_PAGER(rwp_load_page); 152ee546289SJens Wiklander 153ee546289SJens Wiklander static TEE_Result rwp_save_page(struct fobj *fobj, unsigned int page_idx, 154ee546289SJens Wiklander const void *va) 155ee546289SJens Wiklander { 156ee546289SJens Wiklander struct fobj_rwp *rwp = to_rwp(fobj); 157ee546289SJens Wiklander struct rwp_state *state = rwp->state + page_idx; 158ee546289SJens Wiklander size_t tag_len = sizeof(state->tag); 159ee546289SJens Wiklander uint8_t *dst = rwp->store + page_idx * SMALL_PAGE_SIZE; 160ee546289SJens Wiklander struct rwp_aes_gcm_iv iv; 161ee546289SJens Wiklander 162ee546289SJens Wiklander memset(&iv, 0, sizeof(iv)); 163*b83c0d5fSJens Wiklander 164*b83c0d5fSJens Wiklander if (!refcount_val(&fobj->refc)) { 165*b83c0d5fSJens Wiklander /* 166*b83c0d5fSJens Wiklander * This fobj is being teared down, it just hasn't had the time 167*b83c0d5fSJens Wiklander * to call tee_pager_invalidate_fobj() yet. 168*b83c0d5fSJens Wiklander */ 169*b83c0d5fSJens Wiklander assert(TAILQ_EMPTY(&fobj->areas)); 170*b83c0d5fSJens Wiklander return TEE_SUCCESS; 171*b83c0d5fSJens Wiklander } 172*b83c0d5fSJens Wiklander 173ee546289SJens Wiklander assert(page_idx < fobj->num_pages); 174ee546289SJens Wiklander assert(state->iv + 1 > state->iv); 175ee546289SJens Wiklander 176ee546289SJens Wiklander state->iv++; 177ee546289SJens Wiklander /* 178ee546289SJens Wiklander * IV is constructed as recommended in section "8.2.1 Deterministic 179ee546289SJens Wiklander * Construction" of "Recommendation for Block Cipher Modes of 180ee546289SJens Wiklander * Operation: Galois/Counter Mode (GCM) and GMAC", 181ee546289SJens Wiklander * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf 182ee546289SJens Wiklander */ 183ee546289SJens Wiklander 184ee546289SJens Wiklander iv.iv[0] = (vaddr_t)state; 185ee546289SJens Wiklander iv.iv[1] = state->iv >> 32; 186ee546289SJens Wiklander iv.iv[2] = state->iv; 187ee546289SJens Wiklander 188ee546289SJens Wiklander return internal_aes_gcm_enc(&rwp_ae_key, &iv, sizeof(iv), 189ee546289SJens Wiklander NULL, 0, va, SMALL_PAGE_SIZE, dst, 190ee546289SJens Wiklander state->tag, &tag_len); 191ee546289SJens Wiklander } 192ee546289SJens Wiklander KEEP_PAGER(rwp_save_page); 193ee546289SJens Wiklander 194ee546289SJens Wiklander static struct fobj_ops ops_rw_paged __rodata_unpaged = { 195ee546289SJens Wiklander .free = rwp_free, 196ee546289SJens Wiklander .load_page = rwp_load_page, 197ee546289SJens Wiklander .save_page = rwp_save_page, 198ee546289SJens Wiklander }; 199ee546289SJens Wiklander 200ee546289SJens Wiklander struct fobj_rop { 201ee546289SJens Wiklander uint8_t *hashes; 202ee546289SJens Wiklander uint8_t *store; 203ee546289SJens Wiklander struct fobj fobj; 204ee546289SJens Wiklander }; 205ee546289SJens Wiklander 206ee546289SJens Wiklander static struct fobj_ops ops_ro_paged; 207ee546289SJens Wiklander 208ee546289SJens Wiklander struct fobj *fobj_ro_paged_alloc(unsigned int num_pages, void *hashes, 209ee546289SJens Wiklander void *store) 210ee546289SJens Wiklander { 211ee546289SJens Wiklander struct fobj_rop *rop = NULL; 212ee546289SJens Wiklander 213ee546289SJens Wiklander assert(num_pages && hashes && store); 214ee546289SJens Wiklander 215ee546289SJens Wiklander rop = calloc(1, sizeof(*rop)); 216ee546289SJens Wiklander if (!rop) 217ee546289SJens Wiklander return NULL; 218ee546289SJens Wiklander 219ee546289SJens Wiklander rop->hashes = hashes; 220ee546289SJens Wiklander rop->store = store; 221ee546289SJens Wiklander fobj_init(&rop->fobj, &ops_ro_paged, num_pages); 222ee546289SJens Wiklander 223ee546289SJens Wiklander return &rop->fobj; 224ee546289SJens Wiklander } 225ee546289SJens Wiklander 226ee546289SJens Wiklander static struct fobj_rop *to_rop(struct fobj *fobj) 227ee546289SJens Wiklander { 228ee546289SJens Wiklander assert(fobj->ops == &ops_ro_paged); 229ee546289SJens Wiklander 230ee546289SJens Wiklander return container_of(fobj, struct fobj_rop, fobj); 231ee546289SJens Wiklander } 232ee546289SJens Wiklander 233ee546289SJens Wiklander static void rop_free(struct fobj *fobj) 234ee546289SJens Wiklander { 235ee546289SJens Wiklander struct fobj_rop *rop = to_rop(fobj); 236ee546289SJens Wiklander 237ee546289SJens Wiklander fobj_uninit(fobj); 238ee546289SJens Wiklander tee_mm_free(tee_mm_find(&tee_mm_sec_ddr, virt_to_phys(rop->store))); 239ee546289SJens Wiklander free(rop->hashes); 240ee546289SJens Wiklander free(rop); 241ee546289SJens Wiklander } 242ee546289SJens Wiklander 243ee546289SJens Wiklander static TEE_Result rop_load_page(struct fobj *fobj, unsigned int page_idx, 244ee546289SJens Wiklander void *va) 245ee546289SJens Wiklander { 246ee546289SJens Wiklander struct fobj_rop *rop = to_rop(fobj); 247ee546289SJens Wiklander const uint8_t *hash = rop->hashes + page_idx * TEE_SHA256_HASH_SIZE; 248ee546289SJens Wiklander const uint8_t *src = rop->store + page_idx * SMALL_PAGE_SIZE; 249ee546289SJens Wiklander 250ee546289SJens Wiklander assert(refcount_val(&fobj->refc)); 251ee546289SJens Wiklander assert(page_idx < fobj->num_pages); 252ee546289SJens Wiklander memcpy(va, src, SMALL_PAGE_SIZE); 253ee546289SJens Wiklander 254ee546289SJens Wiklander return hash_sha256_check(hash, va, SMALL_PAGE_SIZE); 255ee546289SJens Wiklander } 256ee546289SJens Wiklander KEEP_PAGER(rop_load_page); 257ee546289SJens Wiklander 258ee546289SJens Wiklander static TEE_Result rop_save_page(struct fobj *fobj __unused, 259ee546289SJens Wiklander unsigned int page_idx __unused, 260ee546289SJens Wiklander const void *va __unused) 261ee546289SJens Wiklander { 262ee546289SJens Wiklander return TEE_ERROR_GENERIC; 263ee546289SJens Wiklander } 264ee546289SJens Wiklander KEEP_PAGER(rop_save_page); 265ee546289SJens Wiklander 266ee546289SJens Wiklander static struct fobj_ops ops_ro_paged __rodata_unpaged = { 267ee546289SJens Wiklander .free = rop_free, 268ee546289SJens Wiklander .load_page = rop_load_page, 269ee546289SJens Wiklander .save_page = rop_save_page, 270ee546289SJens Wiklander }; 271ee546289SJens Wiklander 272ee546289SJens Wiklander static struct fobj_ops ops_locked_paged; 273ee546289SJens Wiklander 274ee546289SJens Wiklander struct fobj *fobj_locked_paged_alloc(unsigned int num_pages) 275ee546289SJens Wiklander { 276ee546289SJens Wiklander struct fobj *f = NULL; 277ee546289SJens Wiklander 278ee546289SJens Wiklander assert(num_pages); 279ee546289SJens Wiklander 280ee546289SJens Wiklander f = calloc(1, sizeof(*f)); 281ee546289SJens Wiklander if (!f) 282ee546289SJens Wiklander return NULL; 283ee546289SJens Wiklander 284ee546289SJens Wiklander fobj_init(f, &ops_locked_paged, num_pages); 285ee546289SJens Wiklander 286ee546289SJens Wiklander return f; 287ee546289SJens Wiklander } 288ee546289SJens Wiklander 289ee546289SJens Wiklander static void lop_free(struct fobj *fobj) 290ee546289SJens Wiklander { 291ee546289SJens Wiklander assert(fobj->ops == &ops_locked_paged); 292ee546289SJens Wiklander fobj_uninit(fobj); 293ee546289SJens Wiklander free(fobj); 294ee546289SJens Wiklander } 295ee546289SJens Wiklander 296ee546289SJens Wiklander static TEE_Result lop_load_page(struct fobj *fobj __maybe_unused, 297ee546289SJens Wiklander unsigned int page_idx __maybe_unused, 298ee546289SJens Wiklander void *va) 299ee546289SJens Wiklander { 300ee546289SJens Wiklander assert(fobj->ops == &ops_locked_paged); 301ee546289SJens Wiklander assert(refcount_val(&fobj->refc)); 302ee546289SJens Wiklander assert(page_idx < fobj->num_pages); 303ee546289SJens Wiklander 304ee546289SJens Wiklander memset(va, 0, SMALL_PAGE_SIZE); 305ee546289SJens Wiklander 306ee546289SJens Wiklander return TEE_SUCCESS; 307ee546289SJens Wiklander } 308ee546289SJens Wiklander KEEP_PAGER(lop_load_page); 309ee546289SJens Wiklander 310ee546289SJens Wiklander static TEE_Result lop_save_page(struct fobj *fobj __unused, 311ee546289SJens Wiklander unsigned int page_idx __unused, 312ee546289SJens Wiklander const void *va __unused) 313ee546289SJens Wiklander { 314ee546289SJens Wiklander return TEE_ERROR_GENERIC; 315ee546289SJens Wiklander } 316ee546289SJens Wiklander KEEP_PAGER(lop_save_page); 317ee546289SJens Wiklander 318ee546289SJens Wiklander static struct fobj_ops ops_locked_paged __rodata_unpaged = { 319ee546289SJens Wiklander .free = lop_free, 320ee546289SJens Wiklander .load_page = lop_load_page, 321ee546289SJens Wiklander .save_page = lop_save_page, 322ee546289SJens Wiklander }; 323ee546289SJens Wiklander #endif /*CFG_WITH_PAGER*/ 324fbcaa411SJens Wiklander 325fbcaa411SJens Wiklander #ifndef CFG_PAGED_USER_TA 326fbcaa411SJens Wiklander 327fbcaa411SJens Wiklander struct fobj_sec_mem { 328fbcaa411SJens Wiklander tee_mm_entry_t *mm; 329fbcaa411SJens Wiklander struct fobj fobj; 330fbcaa411SJens Wiklander }; 331fbcaa411SJens Wiklander 332fbcaa411SJens Wiklander static struct fobj_ops ops_sec_mem; 333fbcaa411SJens Wiklander 334fbcaa411SJens Wiklander struct fobj *fobj_sec_mem_alloc(unsigned int num_pages) 335fbcaa411SJens Wiklander { 336fbcaa411SJens Wiklander struct fobj_sec_mem *f = calloc(1, sizeof(*f)); 337fbcaa411SJens Wiklander size_t size = 0; 338fbcaa411SJens Wiklander void *va = NULL; 339fbcaa411SJens Wiklander 340fbcaa411SJens Wiklander if (!f) 341fbcaa411SJens Wiklander return NULL; 342fbcaa411SJens Wiklander 343fbcaa411SJens Wiklander if (MUL_OVERFLOW(num_pages, SMALL_PAGE_SIZE, &size)) 344fbcaa411SJens Wiklander goto err; 345fbcaa411SJens Wiklander 346fbcaa411SJens Wiklander f->mm = tee_mm_alloc(&tee_mm_sec_ddr, size); 347fbcaa411SJens Wiklander if (!f->mm) 348fbcaa411SJens Wiklander goto err; 349fbcaa411SJens Wiklander 350fbcaa411SJens Wiklander va = phys_to_virt(tee_mm_get_smem(f->mm), MEM_AREA_TA_RAM); 351fbcaa411SJens Wiklander if (!va) 352fbcaa411SJens Wiklander goto err; 353fbcaa411SJens Wiklander 354fbcaa411SJens Wiklander memset(va, 0, size); 355fbcaa411SJens Wiklander f->fobj.ops = &ops_sec_mem; 356fbcaa411SJens Wiklander f->fobj.num_pages = num_pages; 357fbcaa411SJens Wiklander refcount_set(&f->fobj.refc, 1); 358fbcaa411SJens Wiklander 359fbcaa411SJens Wiklander return &f->fobj; 360fbcaa411SJens Wiklander err: 361fbcaa411SJens Wiklander tee_mm_free(f->mm); 362fbcaa411SJens Wiklander free(f); 363fbcaa411SJens Wiklander 364fbcaa411SJens Wiklander return NULL; 365fbcaa411SJens Wiklander } 366fbcaa411SJens Wiklander 367fbcaa411SJens Wiklander static struct fobj_sec_mem *to_sec_mem(struct fobj *fobj) 368fbcaa411SJens Wiklander { 369fbcaa411SJens Wiklander assert(fobj->ops == &ops_sec_mem); 370fbcaa411SJens Wiklander 371fbcaa411SJens Wiklander return container_of(fobj, struct fobj_sec_mem, fobj); 372fbcaa411SJens Wiklander } 373fbcaa411SJens Wiklander 374fbcaa411SJens Wiklander static void sec_mem_free(struct fobj *fobj) 375fbcaa411SJens Wiklander { 376fbcaa411SJens Wiklander struct fobj_sec_mem *f = to_sec_mem(fobj); 377fbcaa411SJens Wiklander 378fbcaa411SJens Wiklander assert(!refcount_val(&fobj->refc)); 379fbcaa411SJens Wiklander tee_mm_free(f->mm); 380fbcaa411SJens Wiklander free(f); 381fbcaa411SJens Wiklander } 382fbcaa411SJens Wiklander 383fbcaa411SJens Wiklander static paddr_t sec_mem_get_pa(struct fobj *fobj, unsigned int page_idx) 384fbcaa411SJens Wiklander { 385fbcaa411SJens Wiklander struct fobj_sec_mem *f = to_sec_mem(fobj); 386fbcaa411SJens Wiklander 387fbcaa411SJens Wiklander assert(refcount_val(&fobj->refc)); 388fbcaa411SJens Wiklander assert(page_idx < fobj->num_pages); 389fbcaa411SJens Wiklander 390fbcaa411SJens Wiklander return tee_mm_get_smem(f->mm) + page_idx * SMALL_PAGE_SIZE; 391fbcaa411SJens Wiklander } 392fbcaa411SJens Wiklander 393fbcaa411SJens Wiklander static struct fobj_ops ops_sec_mem __rodata_unpaged = { 394fbcaa411SJens Wiklander .free = sec_mem_free, 395fbcaa411SJens Wiklander .get_pa = sec_mem_get_pa, 396fbcaa411SJens Wiklander }; 397fbcaa411SJens Wiklander 398fbcaa411SJens Wiklander #endif /*PAGED_USER_TA*/ 399