1cbe7e1b8SBalint Dobszay // SPDX-License-Identifier: BSD-2-Clause 2cbe7e1b8SBalint Dobszay /* 36105aa86SJens Wiklander * Copyright (c) 2018-2019, 2022 Linaro Limited 4c185655eSJelle Sels * Copyright (c) 2020-2021, Arm Limited 5cbe7e1b8SBalint Dobszay */ 6cbe7e1b8SBalint Dobszay 7cbe7e1b8SBalint Dobszay #include <assert.h> 8baa5161dSBalint Dobszay #include <crypto/crypto.h> 9cbe7e1b8SBalint Dobszay #include <kernel/ldelf_syscalls.h> 10cbe7e1b8SBalint Dobszay #include <kernel/user_mode_ctx.h> 11cbe7e1b8SBalint Dobszay #include <ldelf.h> 12cbe7e1b8SBalint Dobszay #include <mm/file.h> 13cbe7e1b8SBalint Dobszay #include <mm/fobj.h> 14cbe7e1b8SBalint Dobszay #include <mm/mobj.h> 15cbe7e1b8SBalint Dobszay #include <mm/vm.h> 16cbe7e1b8SBalint Dobszay #include <stdlib.h> 17cbe7e1b8SBalint Dobszay #include <string.h> 18cbe7e1b8SBalint Dobszay #include <trace.h> 19cbe7e1b8SBalint Dobszay #include <util.h> 20cbe7e1b8SBalint Dobszay 21cbe7e1b8SBalint Dobszay struct bin_handle { 22cbe7e1b8SBalint Dobszay const struct ts_store_ops *op; 23cbe7e1b8SBalint Dobszay struct ts_store_handle *h; 24cbe7e1b8SBalint Dobszay struct file *f; 25cbe7e1b8SBalint Dobszay size_t offs_bytes; 26cbe7e1b8SBalint Dobszay size_t size_bytes; 27cbe7e1b8SBalint Dobszay }; 28cbe7e1b8SBalint Dobszay 29baa5161dSBalint Dobszay TEE_Result ldelf_syscall_map_zi(vaddr_t *va, size_t num_bytes, size_t pad_begin, 30baa5161dSBalint Dobszay size_t pad_end, unsigned long flags) 31baa5161dSBalint Dobszay { 32baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS; 33baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 34baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 35baa5161dSBalint Dobszay struct fobj *f = NULL; 36baa5161dSBalint Dobszay struct mobj *mobj = NULL; 37baa5161dSBalint Dobszay uint32_t prot = TEE_MATTR_URW | TEE_MATTR_PRW; 38baa5161dSBalint Dobszay uint32_t vm_flags = 0; 39baa5161dSBalint Dobszay 40baa5161dSBalint Dobszay if (flags & ~LDELF_MAP_FLAG_SHAREABLE) 41baa5161dSBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 42baa5161dSBalint Dobszay 43baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_SHAREABLE) 44baa5161dSBalint Dobszay vm_flags |= VM_FLAG_SHAREABLE; 45baa5161dSBalint Dobszay 46baa5161dSBalint Dobszay f = fobj_ta_mem_alloc(ROUNDUP_DIV(num_bytes, SMALL_PAGE_SIZE)); 47baa5161dSBalint Dobszay if (!f) 48baa5161dSBalint Dobszay return TEE_ERROR_OUT_OF_MEMORY; 496105aa86SJens Wiklander mobj = mobj_with_fobj_alloc(f, NULL, TEE_MATTR_MEM_TYPE_TAGGED); 50baa5161dSBalint Dobszay fobj_put(f); 51baa5161dSBalint Dobszay if (!mobj) 52baa5161dSBalint Dobszay return TEE_ERROR_OUT_OF_MEMORY; 53baa5161dSBalint Dobszay res = vm_map_pad(uctx, va, num_bytes, prot, vm_flags, 54baa5161dSBalint Dobszay mobj, 0, pad_begin, pad_end, 0); 55baa5161dSBalint Dobszay mobj_put(mobj); 56baa5161dSBalint Dobszay 57baa5161dSBalint Dobszay return res; 58baa5161dSBalint Dobszay } 59baa5161dSBalint Dobszay 60baa5161dSBalint Dobszay TEE_Result ldelf_syscall_unmap(vaddr_t va, size_t num_bytes) 61baa5161dSBalint Dobszay { 62baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS; 63baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 64baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 65baa5161dSBalint Dobszay size_t sz = ROUNDUP(num_bytes, SMALL_PAGE_SIZE); 66baa5161dSBalint Dobszay uint32_t vm_flags = 0; 67baa5161dSBalint Dobszay vaddr_t end_va = 0; 68baa5161dSBalint Dobszay 69baa5161dSBalint Dobszay /* 70baa5161dSBalint Dobszay * The vm_get_flags() and vm_unmap() are supposed to detect or handle 71baa5161dSBalint Dobszay * overflow directly or indirectly. However, since this function is an 72baa5161dSBalint Dobszay * API function it's worth having an extra guard here. If nothing else, 73baa5161dSBalint Dobszay * to increase code clarity. 74baa5161dSBalint Dobszay */ 75baa5161dSBalint Dobszay if (ADD_OVERFLOW(va, sz, &end_va)) 76baa5161dSBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 77baa5161dSBalint Dobszay 78baa5161dSBalint Dobszay res = vm_get_flags(uctx, va, sz, &vm_flags); 79baa5161dSBalint Dobszay if (res) 80baa5161dSBalint Dobszay return res; 81baa5161dSBalint Dobszay if (vm_flags & VM_FLAG_PERMANENT) 82baa5161dSBalint Dobszay return TEE_ERROR_ACCESS_DENIED; 83baa5161dSBalint Dobszay 84baa5161dSBalint Dobszay return vm_unmap(uctx, va, sz); 85baa5161dSBalint Dobszay } 86baa5161dSBalint Dobszay 87baa5161dSBalint Dobszay static void bin_close(void *ptr) 88cbe7e1b8SBalint Dobszay { 89cbe7e1b8SBalint Dobszay struct bin_handle *binh = ptr; 90cbe7e1b8SBalint Dobszay 91cbe7e1b8SBalint Dobszay if (binh) { 92cbe7e1b8SBalint Dobszay if (binh->op && binh->h) 93cbe7e1b8SBalint Dobszay binh->op->close(binh->h); 94cbe7e1b8SBalint Dobszay file_put(binh->f); 95cbe7e1b8SBalint Dobszay } 96cbe7e1b8SBalint Dobszay free(binh); 97cbe7e1b8SBalint Dobszay } 98cbe7e1b8SBalint Dobszay 99baa5161dSBalint Dobszay TEE_Result ldelf_syscall_open_bin(const TEE_UUID *uuid, size_t uuid_size, 100baa5161dSBalint Dobszay uint32_t *handle) 101cbe7e1b8SBalint Dobszay { 102cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 103baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 104baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 105baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx; 106cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL; 107cbe7e1b8SBalint Dobszay uint8_t tag[FILE_TAG_SIZE] = { 0 }; 108cbe7e1b8SBalint Dobszay unsigned int tag_len = sizeof(tag); 109baa5161dSBalint Dobszay int h = 0; 110cbe7e1b8SBalint Dobszay 111baa5161dSBalint Dobszay res = vm_check_access_rights(uctx, 112baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_READ | 113baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_ANY_OWNER, 114baa5161dSBalint Dobszay (uaddr_t)uuid, sizeof(TEE_UUID)); 115baa5161dSBalint Dobszay if (res) 116baa5161dSBalint Dobszay return res; 117baa5161dSBalint Dobszay 118baa5161dSBalint Dobszay res = vm_check_access_rights(uctx, 119baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_WRITE | 120baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_ANY_OWNER, 121baa5161dSBalint Dobszay (uaddr_t)handle, sizeof(uint32_t)); 122baa5161dSBalint Dobszay if (res) 123baa5161dSBalint Dobszay return res; 124baa5161dSBalint Dobszay 125baa5161dSBalint Dobszay if (uuid_size != sizeof(*uuid)) 126cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 127cbe7e1b8SBalint Dobszay 128baa5161dSBalint Dobszay if (!sys_ctx) { 129baa5161dSBalint Dobszay sys_ctx = calloc(1, sizeof(*sys_ctx)); 130baa5161dSBalint Dobszay if (!sys_ctx) 131baa5161dSBalint Dobszay return TEE_ERROR_OUT_OF_MEMORY; 132baa5161dSBalint Dobszay sess->user_ctx = sys_ctx; 133baa5161dSBalint Dobszay } 134cbe7e1b8SBalint Dobszay 135cbe7e1b8SBalint Dobszay binh = calloc(1, sizeof(*binh)); 136cbe7e1b8SBalint Dobszay if (!binh) 137cbe7e1b8SBalint Dobszay return TEE_ERROR_OUT_OF_MEMORY; 138cbe7e1b8SBalint Dobszay 139c185655eSJelle Sels if (is_user_ta_ctx(sess->ctx) || is_stmm_ctx(sess->ctx)) { 140c185655eSJelle Sels SCATTERED_ARRAY_FOREACH(binh->op, ta_stores, 141c185655eSJelle Sels struct ts_store_ops) { 142cbe7e1b8SBalint Dobszay DMSG("Lookup user TA ELF %pUl (%s)", 143cbe7e1b8SBalint Dobszay (void *)uuid, binh->op->description); 144cbe7e1b8SBalint Dobszay 145cbe7e1b8SBalint Dobszay res = binh->op->open(uuid, &binh->h); 146baa5161dSBalint Dobszay DMSG("res=%#"PRIx32, res); 147cbe7e1b8SBalint Dobszay if (res != TEE_ERROR_ITEM_NOT_FOUND && 148cbe7e1b8SBalint Dobszay res != TEE_ERROR_STORAGE_NOT_AVAILABLE) 149cbe7e1b8SBalint Dobszay break; 150cbe7e1b8SBalint Dobszay } 151c185655eSJelle Sels } else if (is_sp_ctx(sess->ctx)) { 152c185655eSJelle Sels SCATTERED_ARRAY_FOREACH(binh->op, sp_stores, 153c185655eSJelle Sels struct ts_store_ops) { 154c185655eSJelle Sels DMSG("Lookup user SP ELF %pUl (%s)", 155c185655eSJelle Sels (void *)uuid, binh->op->description); 156c185655eSJelle Sels 157c185655eSJelle Sels res = binh->op->open(uuid, &binh->h); 158c185655eSJelle Sels DMSG("res=%#"PRIx32, res); 159c185655eSJelle Sels if (res != TEE_ERROR_ITEM_NOT_FOUND && 160c185655eSJelle Sels res != TEE_ERROR_STORAGE_NOT_AVAILABLE) 161c185655eSJelle Sels break; 162c185655eSJelle Sels } 163c185655eSJelle Sels } else { 164c185655eSJelle Sels res = TEE_ERROR_ITEM_NOT_FOUND; 165c185655eSJelle Sels } 166c185655eSJelle Sels 167cbe7e1b8SBalint Dobszay if (res) 168cbe7e1b8SBalint Dobszay goto err; 169cbe7e1b8SBalint Dobszay 170cbe7e1b8SBalint Dobszay res = binh->op->get_size(binh->h, &binh->size_bytes); 171cbe7e1b8SBalint Dobszay if (res) 172cbe7e1b8SBalint Dobszay goto err; 173cbe7e1b8SBalint Dobszay res = binh->op->get_tag(binh->h, tag, &tag_len); 174cbe7e1b8SBalint Dobszay if (res) 175cbe7e1b8SBalint Dobszay goto err; 176cbe7e1b8SBalint Dobszay binh->f = file_get_by_tag(tag, tag_len); 177cbe7e1b8SBalint Dobszay if (!binh->f) 178cbe7e1b8SBalint Dobszay goto err_oom; 179cbe7e1b8SBalint Dobszay 180baa5161dSBalint Dobszay h = handle_get(&sys_ctx->db, binh); 181cbe7e1b8SBalint Dobszay if (h < 0) 182cbe7e1b8SBalint Dobszay goto err_oom; 183baa5161dSBalint Dobszay *handle = h; 184cbe7e1b8SBalint Dobszay 185cbe7e1b8SBalint Dobszay return TEE_SUCCESS; 186baa5161dSBalint Dobszay 187cbe7e1b8SBalint Dobszay err_oom: 188cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY; 189cbe7e1b8SBalint Dobszay err: 190baa5161dSBalint Dobszay bin_close(binh); 191cbe7e1b8SBalint Dobszay return res; 192cbe7e1b8SBalint Dobszay } 193cbe7e1b8SBalint Dobszay 194baa5161dSBalint Dobszay TEE_Result ldelf_syscall_close_bin(unsigned long handle) 195cbe7e1b8SBalint Dobszay { 196cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 197baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 198baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx; 199cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL; 200cbe7e1b8SBalint Dobszay 201baa5161dSBalint Dobszay if (!sys_ctx) 202cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 203cbe7e1b8SBalint Dobszay 204baa5161dSBalint Dobszay binh = handle_put(&sys_ctx->db, handle); 205cbe7e1b8SBalint Dobszay if (!binh) 206cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 207cbe7e1b8SBalint Dobszay 208cbe7e1b8SBalint Dobszay if (binh->offs_bytes < binh->size_bytes) 209*ef44161fSJens Wiklander res = binh->op->read(binh->h, NULL, NULL, 210cbe7e1b8SBalint Dobszay binh->size_bytes - binh->offs_bytes); 211cbe7e1b8SBalint Dobszay 212baa5161dSBalint Dobszay bin_close(binh); 213baa5161dSBalint Dobszay if (handle_db_is_empty(&sys_ctx->db)) { 214baa5161dSBalint Dobszay handle_db_destroy(&sys_ctx->db, bin_close); 215baa5161dSBalint Dobszay free(sys_ctx); 216baa5161dSBalint Dobszay sess->user_ctx = NULL; 217baa5161dSBalint Dobszay } 218cbe7e1b8SBalint Dobszay 219cbe7e1b8SBalint Dobszay return res; 220cbe7e1b8SBalint Dobszay } 221cbe7e1b8SBalint Dobszay 222*ef44161fSJens Wiklander static TEE_Result binh_copy_to(struct bin_handle *binh, vaddr_t va_core, 223*ef44161fSJens Wiklander vaddr_t va_user, size_t offs_bytes, 224*ef44161fSJens Wiklander size_t num_bytes) 225cbe7e1b8SBalint Dobszay { 226cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 227cbe7e1b8SBalint Dobszay size_t next_offs = 0; 228cbe7e1b8SBalint Dobszay 229cbe7e1b8SBalint Dobszay if (offs_bytes < binh->offs_bytes) 230cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_STATE; 231cbe7e1b8SBalint Dobszay 232cbe7e1b8SBalint Dobszay if (ADD_OVERFLOW(offs_bytes, num_bytes, &next_offs)) 233cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 234cbe7e1b8SBalint Dobszay 235cbe7e1b8SBalint Dobszay if (offs_bytes > binh->offs_bytes) { 236*ef44161fSJens Wiklander res = binh->op->read(binh->h, NULL, NULL, 237cbe7e1b8SBalint Dobszay offs_bytes - binh->offs_bytes); 238cbe7e1b8SBalint Dobszay if (res) 239cbe7e1b8SBalint Dobszay return res; 240cbe7e1b8SBalint Dobszay binh->offs_bytes = offs_bytes; 241cbe7e1b8SBalint Dobszay } 242cbe7e1b8SBalint Dobszay 243cbe7e1b8SBalint Dobszay if (next_offs > binh->size_bytes) { 244cbe7e1b8SBalint Dobszay size_t rb = binh->size_bytes - binh->offs_bytes; 245cbe7e1b8SBalint Dobszay 246*ef44161fSJens Wiklander res = binh->op->read(binh->h, (void *)va_core, 247*ef44161fSJens Wiklander (void *)va_user, rb); 248cbe7e1b8SBalint Dobszay if (res) 249cbe7e1b8SBalint Dobszay return res; 250*ef44161fSJens Wiklander if (va_core) 251*ef44161fSJens Wiklander memset((uint8_t *)va_core + rb, 0, num_bytes - rb); 252*ef44161fSJens Wiklander if (va_user) { 253*ef44161fSJens Wiklander res = clear_user((uint8_t *)va_user + rb, 254*ef44161fSJens Wiklander num_bytes - rb); 255*ef44161fSJens Wiklander if (res) 256*ef44161fSJens Wiklander return res; 257*ef44161fSJens Wiklander } 258cbe7e1b8SBalint Dobszay binh->offs_bytes = binh->size_bytes; 259cbe7e1b8SBalint Dobszay } else { 260*ef44161fSJens Wiklander res = binh->op->read(binh->h, (void *)va_core, 261*ef44161fSJens Wiklander (void *)va_user, num_bytes); 262cbe7e1b8SBalint Dobszay if (res) 263cbe7e1b8SBalint Dobszay return res; 264cbe7e1b8SBalint Dobszay binh->offs_bytes = next_offs; 265cbe7e1b8SBalint Dobszay } 266cbe7e1b8SBalint Dobszay 267cbe7e1b8SBalint Dobszay return TEE_SUCCESS; 268cbe7e1b8SBalint Dobszay } 269cbe7e1b8SBalint Dobszay 270baa5161dSBalint Dobszay TEE_Result ldelf_syscall_map_bin(vaddr_t *va, size_t num_bytes, 271baa5161dSBalint Dobszay unsigned long handle, size_t offs_bytes, 272baa5161dSBalint Dobszay size_t pad_begin, size_t pad_end, 273baa5161dSBalint Dobszay unsigned long flags) 274cbe7e1b8SBalint Dobszay { 275baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS; 276baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 277baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 278baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx; 279cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL; 280cbe7e1b8SBalint Dobszay uint32_t num_rounded_bytes = 0; 281cbe7e1b8SBalint Dobszay struct file_slice *fs = NULL; 282cbe7e1b8SBalint Dobszay bool file_is_locked = false; 283cbe7e1b8SBalint Dobszay struct mobj *mobj = NULL; 284cbe7e1b8SBalint Dobszay uint32_t offs_pages = 0; 285cbe7e1b8SBalint Dobszay size_t num_pages = 0; 286cbe7e1b8SBalint Dobszay uint32_t prot = 0; 287baa5161dSBalint Dobszay const uint32_t accept_flags = LDELF_MAP_FLAG_SHAREABLE | 288baa5161dSBalint Dobszay LDELF_MAP_FLAG_WRITEABLE | 2890d482f82SRuchika Gupta LDELF_MAP_FLAG_BTI | 290baa5161dSBalint Dobszay LDELF_MAP_FLAG_EXECUTABLE; 291cbe7e1b8SBalint Dobszay 292baa5161dSBalint Dobszay if (!sys_ctx) 293cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 294cbe7e1b8SBalint Dobszay 295baa5161dSBalint Dobszay binh = handle_lookup(&sys_ctx->db, handle); 296cbe7e1b8SBalint Dobszay if (!binh) 297cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 298cbe7e1b8SBalint Dobszay 299cbe7e1b8SBalint Dobszay if ((flags & accept_flags) != flags) 300cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 301cbe7e1b8SBalint Dobszay 302baa5161dSBalint Dobszay if ((flags & LDELF_MAP_FLAG_SHAREABLE) && 303baa5161dSBalint Dobszay (flags & LDELF_MAP_FLAG_WRITEABLE)) 304cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 305cbe7e1b8SBalint Dobszay 306baa5161dSBalint Dobszay if ((flags & LDELF_MAP_FLAG_EXECUTABLE) && 307baa5161dSBalint Dobszay (flags & LDELF_MAP_FLAG_WRITEABLE)) 308cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 309cbe7e1b8SBalint Dobszay 310cbe7e1b8SBalint Dobszay if (offs_bytes & SMALL_PAGE_MASK) 311cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 312cbe7e1b8SBalint Dobszay 313cbe7e1b8SBalint Dobszay prot = TEE_MATTR_UR | TEE_MATTR_PR; 314baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_WRITEABLE) 315cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UW | TEE_MATTR_PW; 316baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_EXECUTABLE) 317cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UX; 3180d482f82SRuchika Gupta if (flags & LDELF_MAP_FLAG_BTI) 3190d482f82SRuchika Gupta prot |= TEE_MATTR_GUARDED; 320cbe7e1b8SBalint Dobszay 321cbe7e1b8SBalint Dobszay offs_pages = offs_bytes >> SMALL_PAGE_SHIFT; 322cbe7e1b8SBalint Dobszay if (ROUNDUP_OVERFLOW(num_bytes, SMALL_PAGE_SIZE, &num_rounded_bytes)) 323cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 324cbe7e1b8SBalint Dobszay num_pages = num_rounded_bytes / SMALL_PAGE_SIZE; 325cbe7e1b8SBalint Dobszay 326cbe7e1b8SBalint Dobszay if (!file_trylock(binh->f)) { 327cbe7e1b8SBalint Dobszay /* 328cbe7e1b8SBalint Dobszay * Before we can block on the file lock we must make all 329cbe7e1b8SBalint Dobszay * our page tables available for reclaiming in order to 330cbe7e1b8SBalint Dobszay * avoid a dead-lock with the other thread (which already 331cbe7e1b8SBalint Dobszay * is holding the file lock) mapping lots of memory below. 332cbe7e1b8SBalint Dobszay */ 333cbe7e1b8SBalint Dobszay vm_set_ctx(NULL); 334cbe7e1b8SBalint Dobszay file_lock(binh->f); 335cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx); 336cbe7e1b8SBalint Dobszay } 337cbe7e1b8SBalint Dobszay file_is_locked = true; 338cbe7e1b8SBalint Dobszay fs = file_find_slice(binh->f, offs_pages); 339cbe7e1b8SBalint Dobszay if (fs) { 340cbe7e1b8SBalint Dobszay /* If there's registered slice it has to match */ 341cbe7e1b8SBalint Dobszay if (fs->page_offset != offs_pages || 342cbe7e1b8SBalint Dobszay num_pages > fs->fobj->num_pages) { 343cbe7e1b8SBalint Dobszay res = TEE_ERROR_BAD_PARAMETERS; 344cbe7e1b8SBalint Dobszay goto err; 345cbe7e1b8SBalint Dobszay } 346cbe7e1b8SBalint Dobszay 347cbe7e1b8SBalint Dobszay /* If there's a slice we must be mapping shareable */ 348baa5161dSBalint Dobszay if (!(flags & LDELF_MAP_FLAG_SHAREABLE)) { 349cbe7e1b8SBalint Dobszay res = TEE_ERROR_BAD_PARAMETERS; 350cbe7e1b8SBalint Dobszay goto err; 351cbe7e1b8SBalint Dobszay } 352cbe7e1b8SBalint Dobszay 3536105aa86SJens Wiklander mobj = mobj_with_fobj_alloc(fs->fobj, binh->f, 3546105aa86SJens Wiklander TEE_MATTR_MEM_TYPE_TAGGED); 355cbe7e1b8SBalint Dobszay if (!mobj) { 356cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY; 357cbe7e1b8SBalint Dobszay goto err; 358cbe7e1b8SBalint Dobszay } 359baa5161dSBalint Dobszay res = vm_map_pad(uctx, va, num_rounded_bytes, 360cbe7e1b8SBalint Dobszay prot, VM_FLAG_READONLY, 361cbe7e1b8SBalint Dobszay mobj, 0, pad_begin, pad_end, 0); 362cbe7e1b8SBalint Dobszay mobj_put(mobj); 363cbe7e1b8SBalint Dobszay if (res) 364cbe7e1b8SBalint Dobszay goto err; 365cbe7e1b8SBalint Dobszay } else { 366cbe7e1b8SBalint Dobszay struct fobj *f = fobj_ta_mem_alloc(num_pages); 367cbe7e1b8SBalint Dobszay struct file *file = NULL; 368cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0; 369cbe7e1b8SBalint Dobszay 370cbe7e1b8SBalint Dobszay if (!f) { 371cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY; 372cbe7e1b8SBalint Dobszay goto err; 373cbe7e1b8SBalint Dobszay } 374baa5161dSBalint Dobszay if (!(flags & LDELF_MAP_FLAG_WRITEABLE)) { 375cbe7e1b8SBalint Dobszay file = binh->f; 376cbe7e1b8SBalint Dobszay vm_flags |= VM_FLAG_READONLY; 377cbe7e1b8SBalint Dobszay } 378cbe7e1b8SBalint Dobszay 3796105aa86SJens Wiklander mobj = mobj_with_fobj_alloc(f, file, TEE_MATTR_MEM_TYPE_TAGGED); 380cbe7e1b8SBalint Dobszay fobj_put(f); 381cbe7e1b8SBalint Dobszay if (!mobj) { 382cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY; 383cbe7e1b8SBalint Dobszay goto err; 384cbe7e1b8SBalint Dobszay } 385baa5161dSBalint Dobszay res = vm_map_pad(uctx, va, num_rounded_bytes, 386cbe7e1b8SBalint Dobszay TEE_MATTR_PRW, vm_flags, mobj, 0, 387cbe7e1b8SBalint Dobszay pad_begin, pad_end, 0); 388cbe7e1b8SBalint Dobszay mobj_put(mobj); 389cbe7e1b8SBalint Dobszay if (res) 390cbe7e1b8SBalint Dobszay goto err; 391*ef44161fSJens Wiklander res = binh_copy_to(binh, *va, 0, offs_bytes, num_bytes); 392cbe7e1b8SBalint Dobszay if (res) 393cbe7e1b8SBalint Dobszay goto err_unmap_va; 394baa5161dSBalint Dobszay res = vm_set_prot(uctx, *va, num_rounded_bytes, 395cbe7e1b8SBalint Dobszay prot); 396cbe7e1b8SBalint Dobszay if (res) 397cbe7e1b8SBalint Dobszay goto err_unmap_va; 398cbe7e1b8SBalint Dobszay 399cbe7e1b8SBalint Dobszay /* 400cbe7e1b8SBalint Dobszay * The context currently is active set it again to update 401cbe7e1b8SBalint Dobszay * the mapping. 402cbe7e1b8SBalint Dobszay */ 403cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx); 404cbe7e1b8SBalint Dobszay 405baa5161dSBalint Dobszay if (!(flags & LDELF_MAP_FLAG_WRITEABLE)) { 406cbe7e1b8SBalint Dobszay res = file_add_slice(binh->f, f, offs_pages); 407cbe7e1b8SBalint Dobszay if (res) 408cbe7e1b8SBalint Dobszay goto err_unmap_va; 409cbe7e1b8SBalint Dobszay } 410cbe7e1b8SBalint Dobszay } 411cbe7e1b8SBalint Dobszay 412cbe7e1b8SBalint Dobszay file_unlock(binh->f); 413cbe7e1b8SBalint Dobszay 414cbe7e1b8SBalint Dobszay return TEE_SUCCESS; 415cbe7e1b8SBalint Dobszay 416cbe7e1b8SBalint Dobszay err_unmap_va: 417baa5161dSBalint Dobszay if (vm_unmap(uctx, *va, num_rounded_bytes)) 418cbe7e1b8SBalint Dobszay panic(); 419cbe7e1b8SBalint Dobszay 420cbe7e1b8SBalint Dobszay /* 421cbe7e1b8SBalint Dobszay * The context currently is active set it again to update 422cbe7e1b8SBalint Dobszay * the mapping. 423cbe7e1b8SBalint Dobszay */ 424cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx); 425cbe7e1b8SBalint Dobszay 426cbe7e1b8SBalint Dobszay err: 427cbe7e1b8SBalint Dobszay if (file_is_locked) 428cbe7e1b8SBalint Dobszay file_unlock(binh->f); 429cbe7e1b8SBalint Dobszay 430cbe7e1b8SBalint Dobszay return res; 431cbe7e1b8SBalint Dobszay } 432cbe7e1b8SBalint Dobszay 433baa5161dSBalint Dobszay TEE_Result ldelf_syscall_copy_from_bin(void *dst, size_t offs, size_t num_bytes, 434baa5161dSBalint Dobszay unsigned long handle) 435cbe7e1b8SBalint Dobszay { 436baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS; 437baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 438baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 439baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx; 440cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL; 441cbe7e1b8SBalint Dobszay 442baa5161dSBalint Dobszay res = vm_check_access_rights(uctx, 443baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_WRITE | 444baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_ANY_OWNER, 445baa5161dSBalint Dobszay (uaddr_t)dst, num_bytes); 446baa5161dSBalint Dobszay if (res) 447baa5161dSBalint Dobszay return res; 448baa5161dSBalint Dobszay 449baa5161dSBalint Dobszay if (!sys_ctx) 450cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 451cbe7e1b8SBalint Dobszay 452baa5161dSBalint Dobszay binh = handle_lookup(&sys_ctx->db, handle); 453cbe7e1b8SBalint Dobszay if (!binh) 454cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 455cbe7e1b8SBalint Dobszay 456*ef44161fSJens Wiklander return binh_copy_to(binh, 0, (vaddr_t)dst, offs, num_bytes); 457cbe7e1b8SBalint Dobszay } 458cbe7e1b8SBalint Dobszay 459baa5161dSBalint Dobszay TEE_Result ldelf_syscall_set_prot(unsigned long va, size_t num_bytes, 460baa5161dSBalint Dobszay unsigned long flags) 461cbe7e1b8SBalint Dobszay { 462cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 463baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 464baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 465baa5161dSBalint Dobszay size_t sz = ROUNDUP(num_bytes, SMALL_PAGE_SIZE); 466baa5161dSBalint Dobszay uint32_t prot = TEE_MATTR_UR | TEE_MATTR_PR; 467cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0; 468cbe7e1b8SBalint Dobszay vaddr_t end_va = 0; 469baa5161dSBalint Dobszay const uint32_t accept_flags = LDELF_MAP_FLAG_WRITEABLE | 4700d482f82SRuchika Gupta LDELF_MAP_FLAG_BTI | 471baa5161dSBalint Dobszay LDELF_MAP_FLAG_EXECUTABLE; 472cbe7e1b8SBalint Dobszay 473cbe7e1b8SBalint Dobszay if ((flags & accept_flags) != flags) 474cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 475baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_WRITEABLE) 476cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UW | TEE_MATTR_PW; 477baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_EXECUTABLE) 478cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UX; 4790d482f82SRuchika Gupta if (flags & LDELF_MAP_FLAG_BTI) 4800d482f82SRuchika Gupta prot |= TEE_MATTR_GUARDED; 481cbe7e1b8SBalint Dobszay 482cbe7e1b8SBalint Dobszay /* 483baa5161dSBalint Dobszay * The vm_get_flags() and vm_unmap() are supposed to detect or handle 484baa5161dSBalint Dobszay * overflow directly or indirectly. However, since this function is an 485baa5161dSBalint Dobszay * API function it's worth having an extra guard here. If nothing else, 486baa5161dSBalint Dobszay * to increase code clarity. 487cbe7e1b8SBalint Dobszay */ 488cbe7e1b8SBalint Dobszay if (ADD_OVERFLOW(va, sz, &end_va)) 489cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 490cbe7e1b8SBalint Dobszay 491cbe7e1b8SBalint Dobszay res = vm_get_flags(uctx, va, sz, &vm_flags); 492cbe7e1b8SBalint Dobszay if (res) 493cbe7e1b8SBalint Dobszay return res; 494cbe7e1b8SBalint Dobszay if (vm_flags & VM_FLAG_PERMANENT) 495cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED; 496cbe7e1b8SBalint Dobszay 497cbe7e1b8SBalint Dobszay /* 498cbe7e1b8SBalint Dobszay * If the segment is a mapping of a part of a file (vm_flags & 499cbe7e1b8SBalint Dobszay * VM_FLAG_READONLY) it cannot be made writeable as all mapped 500cbe7e1b8SBalint Dobszay * files are mapped read-only. 501cbe7e1b8SBalint Dobszay */ 502cbe7e1b8SBalint Dobszay if ((vm_flags & VM_FLAG_READONLY) && 503cbe7e1b8SBalint Dobszay (prot & (TEE_MATTR_UW | TEE_MATTR_PW))) 504cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED; 505cbe7e1b8SBalint Dobszay 506cbe7e1b8SBalint Dobszay return vm_set_prot(uctx, va, sz, prot); 507cbe7e1b8SBalint Dobszay } 508cbe7e1b8SBalint Dobszay 509baa5161dSBalint Dobszay TEE_Result ldelf_syscall_remap(unsigned long old_va, vaddr_t *new_va, 510baa5161dSBalint Dobszay size_t num_bytes, size_t pad_begin, 511baa5161dSBalint Dobszay size_t pad_end) 512cbe7e1b8SBalint Dobszay { 513cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 514baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 515baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 516cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0; 517cbe7e1b8SBalint Dobszay 518cbe7e1b8SBalint Dobszay res = vm_get_flags(uctx, old_va, num_bytes, &vm_flags); 519cbe7e1b8SBalint Dobszay if (res) 520cbe7e1b8SBalint Dobszay return res; 521cbe7e1b8SBalint Dobszay if (vm_flags & VM_FLAG_PERMANENT) 522cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED; 523cbe7e1b8SBalint Dobszay 524baa5161dSBalint Dobszay res = vm_remap(uctx, new_va, old_va, num_bytes, pad_begin, pad_end); 525cbe7e1b8SBalint Dobszay 526cbe7e1b8SBalint Dobszay return res; 527cbe7e1b8SBalint Dobszay } 528baa5161dSBalint Dobszay 529baa5161dSBalint Dobszay TEE_Result ldelf_syscall_gen_rnd_num(void *buf, size_t num_bytes) 530baa5161dSBalint Dobszay { 531baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS; 532baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 533baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 534baa5161dSBalint Dobszay 535baa5161dSBalint Dobszay res = vm_check_access_rights(uctx, 536baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_WRITE | 537baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_ANY_OWNER, 538baa5161dSBalint Dobszay (uaddr_t)buf, num_bytes); 539baa5161dSBalint Dobszay if (res) 540baa5161dSBalint Dobszay return res; 541baa5161dSBalint Dobszay 542baa5161dSBalint Dobszay return crypto_rng_read(buf, num_bytes); 543baa5161dSBalint Dobszay } 544baa5161dSBalint Dobszay 545baa5161dSBalint Dobszay /* 546baa5161dSBalint Dobszay * Should be called after returning from ldelf. If user_ctx is not NULL means 547baa5161dSBalint Dobszay * that ldelf crashed or otherwise didn't complete properly. This function will 548baa5161dSBalint Dobszay * close the remaining handles and free the context structs allocated by ldelf. 549baa5161dSBalint Dobszay */ 550baa5161dSBalint Dobszay void ldelf_sess_cleanup(struct ts_session *sess) 551baa5161dSBalint Dobszay { 552baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx; 553baa5161dSBalint Dobszay 554baa5161dSBalint Dobszay if (sys_ctx) { 555baa5161dSBalint Dobszay handle_db_destroy(&sys_ctx->db, bin_close); 556baa5161dSBalint Dobszay free(sys_ctx); 557baa5161dSBalint Dobszay sess->user_ctx = NULL; 558baa5161dSBalint Dobszay } 559baa5161dSBalint Dobszay } 560