1cbe7e1b8SBalint Dobszay // SPDX-License-Identifier: BSD-2-Clause 2cbe7e1b8SBalint Dobszay /* 3cbe7e1b8SBalint Dobszay * Copyright (c) 2018-2019, Linaro Limited 4*c185655eSJelle 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; 49baa5161dSBalint Dobszay mobj = mobj_with_fobj_alloc(f, NULL); 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 139*c185655eSJelle Sels if (is_user_ta_ctx(sess->ctx) || is_stmm_ctx(sess->ctx)) { 140*c185655eSJelle Sels SCATTERED_ARRAY_FOREACH(binh->op, ta_stores, 141*c185655eSJelle 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 } 151*c185655eSJelle Sels } else if (is_sp_ctx(sess->ctx)) { 152*c185655eSJelle Sels SCATTERED_ARRAY_FOREACH(binh->op, sp_stores, 153*c185655eSJelle Sels struct ts_store_ops) { 154*c185655eSJelle Sels DMSG("Lookup user SP ELF %pUl (%s)", 155*c185655eSJelle Sels (void *)uuid, binh->op->description); 156*c185655eSJelle Sels 157*c185655eSJelle Sels res = binh->op->open(uuid, &binh->h); 158*c185655eSJelle Sels DMSG("res=%#"PRIx32, res); 159*c185655eSJelle Sels if (res != TEE_ERROR_ITEM_NOT_FOUND && 160*c185655eSJelle Sels res != TEE_ERROR_STORAGE_NOT_AVAILABLE) 161*c185655eSJelle Sels break; 162*c185655eSJelle Sels } 163*c185655eSJelle Sels } else { 164*c185655eSJelle Sels res = TEE_ERROR_ITEM_NOT_FOUND; 165*c185655eSJelle Sels } 166*c185655eSJelle 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) 209cbe7e1b8SBalint Dobszay res = binh->op->read(binh->h, 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 222cbe7e1b8SBalint Dobszay static TEE_Result binh_copy_to(struct bin_handle *binh, vaddr_t va, 223cbe7e1b8SBalint Dobszay size_t offs_bytes, size_t num_bytes) 224cbe7e1b8SBalint Dobszay { 225cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 226cbe7e1b8SBalint Dobszay size_t next_offs = 0; 227cbe7e1b8SBalint Dobszay 228cbe7e1b8SBalint Dobszay if (offs_bytes < binh->offs_bytes) 229cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_STATE; 230cbe7e1b8SBalint Dobszay 231cbe7e1b8SBalint Dobszay if (ADD_OVERFLOW(offs_bytes, num_bytes, &next_offs)) 232cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 233cbe7e1b8SBalint Dobszay 234cbe7e1b8SBalint Dobszay if (offs_bytes > binh->offs_bytes) { 235cbe7e1b8SBalint Dobszay res = binh->op->read(binh->h, NULL, 236cbe7e1b8SBalint Dobszay offs_bytes - binh->offs_bytes); 237cbe7e1b8SBalint Dobszay if (res) 238cbe7e1b8SBalint Dobszay return res; 239cbe7e1b8SBalint Dobszay binh->offs_bytes = offs_bytes; 240cbe7e1b8SBalint Dobszay } 241cbe7e1b8SBalint Dobszay 242cbe7e1b8SBalint Dobszay if (next_offs > binh->size_bytes) { 243cbe7e1b8SBalint Dobszay size_t rb = binh->size_bytes - binh->offs_bytes; 244cbe7e1b8SBalint Dobszay 245cbe7e1b8SBalint Dobszay res = binh->op->read(binh->h, (void *)va, rb); 246cbe7e1b8SBalint Dobszay if (res) 247cbe7e1b8SBalint Dobszay return res; 248cbe7e1b8SBalint Dobszay memset((uint8_t *)va + rb, 0, num_bytes - rb); 249cbe7e1b8SBalint Dobszay binh->offs_bytes = binh->size_bytes; 250cbe7e1b8SBalint Dobszay } else { 251cbe7e1b8SBalint Dobszay res = binh->op->read(binh->h, (void *)va, num_bytes); 252cbe7e1b8SBalint Dobszay if (res) 253cbe7e1b8SBalint Dobszay return res; 254cbe7e1b8SBalint Dobszay binh->offs_bytes = next_offs; 255cbe7e1b8SBalint Dobszay } 256cbe7e1b8SBalint Dobszay 257cbe7e1b8SBalint Dobszay return TEE_SUCCESS; 258cbe7e1b8SBalint Dobszay } 259cbe7e1b8SBalint Dobszay 260baa5161dSBalint Dobszay TEE_Result ldelf_syscall_map_bin(vaddr_t *va, size_t num_bytes, 261baa5161dSBalint Dobszay unsigned long handle, size_t offs_bytes, 262baa5161dSBalint Dobszay size_t pad_begin, size_t pad_end, 263baa5161dSBalint Dobszay unsigned long flags) 264cbe7e1b8SBalint Dobszay { 265baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS; 266baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 267baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 268baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx; 269cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL; 270cbe7e1b8SBalint Dobszay uint32_t num_rounded_bytes = 0; 271cbe7e1b8SBalint Dobszay struct file_slice *fs = NULL; 272cbe7e1b8SBalint Dobszay bool file_is_locked = false; 273cbe7e1b8SBalint Dobszay struct mobj *mobj = NULL; 274cbe7e1b8SBalint Dobszay uint32_t offs_pages = 0; 275cbe7e1b8SBalint Dobszay size_t num_pages = 0; 276cbe7e1b8SBalint Dobszay uint32_t prot = 0; 277baa5161dSBalint Dobszay const uint32_t accept_flags = LDELF_MAP_FLAG_SHAREABLE | 278baa5161dSBalint Dobszay LDELF_MAP_FLAG_WRITEABLE | 279baa5161dSBalint Dobszay LDELF_MAP_FLAG_EXECUTABLE; 280cbe7e1b8SBalint Dobszay 281baa5161dSBalint Dobszay if (!sys_ctx) 282cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 283cbe7e1b8SBalint Dobszay 284baa5161dSBalint Dobszay binh = handle_lookup(&sys_ctx->db, handle); 285cbe7e1b8SBalint Dobszay if (!binh) 286cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 287cbe7e1b8SBalint Dobszay 288cbe7e1b8SBalint Dobszay if ((flags & accept_flags) != flags) 289cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 290cbe7e1b8SBalint Dobszay 291baa5161dSBalint Dobszay if ((flags & LDELF_MAP_FLAG_SHAREABLE) && 292baa5161dSBalint Dobszay (flags & LDELF_MAP_FLAG_WRITEABLE)) 293cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 294cbe7e1b8SBalint Dobszay 295baa5161dSBalint Dobszay if ((flags & LDELF_MAP_FLAG_EXECUTABLE) && 296baa5161dSBalint Dobszay (flags & LDELF_MAP_FLAG_WRITEABLE)) 297cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 298cbe7e1b8SBalint Dobszay 299cbe7e1b8SBalint Dobszay if (offs_bytes & SMALL_PAGE_MASK) 300cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 301cbe7e1b8SBalint Dobszay 302cbe7e1b8SBalint Dobszay prot = TEE_MATTR_UR | TEE_MATTR_PR; 303baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_WRITEABLE) 304cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UW | TEE_MATTR_PW; 305baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_EXECUTABLE) 306cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UX; 307cbe7e1b8SBalint Dobszay 308cbe7e1b8SBalint Dobszay offs_pages = offs_bytes >> SMALL_PAGE_SHIFT; 309cbe7e1b8SBalint Dobszay if (ROUNDUP_OVERFLOW(num_bytes, SMALL_PAGE_SIZE, &num_rounded_bytes)) 310cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 311cbe7e1b8SBalint Dobszay num_pages = num_rounded_bytes / SMALL_PAGE_SIZE; 312cbe7e1b8SBalint Dobszay 313cbe7e1b8SBalint Dobszay if (!file_trylock(binh->f)) { 314cbe7e1b8SBalint Dobszay /* 315cbe7e1b8SBalint Dobszay * Before we can block on the file lock we must make all 316cbe7e1b8SBalint Dobszay * our page tables available for reclaiming in order to 317cbe7e1b8SBalint Dobszay * avoid a dead-lock with the other thread (which already 318cbe7e1b8SBalint Dobszay * is holding the file lock) mapping lots of memory below. 319cbe7e1b8SBalint Dobszay */ 320cbe7e1b8SBalint Dobszay vm_set_ctx(NULL); 321cbe7e1b8SBalint Dobszay file_lock(binh->f); 322cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx); 323cbe7e1b8SBalint Dobszay } 324cbe7e1b8SBalint Dobszay file_is_locked = true; 325cbe7e1b8SBalint Dobszay fs = file_find_slice(binh->f, offs_pages); 326cbe7e1b8SBalint Dobszay if (fs) { 327cbe7e1b8SBalint Dobszay /* If there's registered slice it has to match */ 328cbe7e1b8SBalint Dobszay if (fs->page_offset != offs_pages || 329cbe7e1b8SBalint Dobszay num_pages > fs->fobj->num_pages) { 330cbe7e1b8SBalint Dobszay res = TEE_ERROR_BAD_PARAMETERS; 331cbe7e1b8SBalint Dobszay goto err; 332cbe7e1b8SBalint Dobszay } 333cbe7e1b8SBalint Dobszay 334cbe7e1b8SBalint Dobszay /* If there's a slice we must be mapping shareable */ 335baa5161dSBalint Dobszay if (!(flags & LDELF_MAP_FLAG_SHAREABLE)) { 336cbe7e1b8SBalint Dobszay res = TEE_ERROR_BAD_PARAMETERS; 337cbe7e1b8SBalint Dobszay goto err; 338cbe7e1b8SBalint Dobszay } 339cbe7e1b8SBalint Dobszay 340cbe7e1b8SBalint Dobszay mobj = mobj_with_fobj_alloc(fs->fobj, binh->f); 341cbe7e1b8SBalint Dobszay if (!mobj) { 342cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY; 343cbe7e1b8SBalint Dobszay goto err; 344cbe7e1b8SBalint Dobszay } 345baa5161dSBalint Dobszay res = vm_map_pad(uctx, va, num_rounded_bytes, 346cbe7e1b8SBalint Dobszay prot, VM_FLAG_READONLY, 347cbe7e1b8SBalint Dobszay mobj, 0, pad_begin, pad_end, 0); 348cbe7e1b8SBalint Dobszay mobj_put(mobj); 349cbe7e1b8SBalint Dobszay if (res) 350cbe7e1b8SBalint Dobszay goto err; 351cbe7e1b8SBalint Dobszay } else { 352cbe7e1b8SBalint Dobszay struct fobj *f = fobj_ta_mem_alloc(num_pages); 353cbe7e1b8SBalint Dobszay struct file *file = NULL; 354cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0; 355cbe7e1b8SBalint Dobszay 356cbe7e1b8SBalint Dobszay if (!f) { 357cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY; 358cbe7e1b8SBalint Dobszay goto err; 359cbe7e1b8SBalint Dobszay } 360baa5161dSBalint Dobszay if (!(flags & LDELF_MAP_FLAG_WRITEABLE)) { 361cbe7e1b8SBalint Dobszay file = binh->f; 362cbe7e1b8SBalint Dobszay vm_flags |= VM_FLAG_READONLY; 363cbe7e1b8SBalint Dobszay } 364cbe7e1b8SBalint Dobszay 365cbe7e1b8SBalint Dobszay mobj = mobj_with_fobj_alloc(f, file); 366cbe7e1b8SBalint Dobszay fobj_put(f); 367cbe7e1b8SBalint Dobszay if (!mobj) { 368cbe7e1b8SBalint Dobszay res = TEE_ERROR_OUT_OF_MEMORY; 369cbe7e1b8SBalint Dobszay goto err; 370cbe7e1b8SBalint Dobszay } 371baa5161dSBalint Dobszay res = vm_map_pad(uctx, va, num_rounded_bytes, 372cbe7e1b8SBalint Dobszay TEE_MATTR_PRW, vm_flags, mobj, 0, 373cbe7e1b8SBalint Dobszay pad_begin, pad_end, 0); 374cbe7e1b8SBalint Dobszay mobj_put(mobj); 375cbe7e1b8SBalint Dobszay if (res) 376cbe7e1b8SBalint Dobszay goto err; 377baa5161dSBalint Dobszay res = binh_copy_to(binh, *va, offs_bytes, num_bytes); 378cbe7e1b8SBalint Dobszay if (res) 379cbe7e1b8SBalint Dobszay goto err_unmap_va; 380baa5161dSBalint Dobszay res = vm_set_prot(uctx, *va, num_rounded_bytes, 381cbe7e1b8SBalint Dobszay prot); 382cbe7e1b8SBalint Dobszay if (res) 383cbe7e1b8SBalint Dobszay goto err_unmap_va; 384cbe7e1b8SBalint Dobszay 385cbe7e1b8SBalint Dobszay /* 386cbe7e1b8SBalint Dobszay * The context currently is active set it again to update 387cbe7e1b8SBalint Dobszay * the mapping. 388cbe7e1b8SBalint Dobszay */ 389cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx); 390cbe7e1b8SBalint Dobszay 391baa5161dSBalint Dobszay if (!(flags & LDELF_MAP_FLAG_WRITEABLE)) { 392cbe7e1b8SBalint Dobszay res = file_add_slice(binh->f, f, offs_pages); 393cbe7e1b8SBalint Dobszay if (res) 394cbe7e1b8SBalint Dobszay goto err_unmap_va; 395cbe7e1b8SBalint Dobszay } 396cbe7e1b8SBalint Dobszay } 397cbe7e1b8SBalint Dobszay 398cbe7e1b8SBalint Dobszay file_unlock(binh->f); 399cbe7e1b8SBalint Dobszay 400cbe7e1b8SBalint Dobszay return TEE_SUCCESS; 401cbe7e1b8SBalint Dobszay 402cbe7e1b8SBalint Dobszay err_unmap_va: 403baa5161dSBalint Dobszay if (vm_unmap(uctx, *va, num_rounded_bytes)) 404cbe7e1b8SBalint Dobszay panic(); 405cbe7e1b8SBalint Dobszay 406cbe7e1b8SBalint Dobszay /* 407cbe7e1b8SBalint Dobszay * The context currently is active set it again to update 408cbe7e1b8SBalint Dobszay * the mapping. 409cbe7e1b8SBalint Dobszay */ 410cbe7e1b8SBalint Dobszay vm_set_ctx(uctx->ts_ctx); 411cbe7e1b8SBalint Dobszay 412cbe7e1b8SBalint Dobszay err: 413cbe7e1b8SBalint Dobszay if (file_is_locked) 414cbe7e1b8SBalint Dobszay file_unlock(binh->f); 415cbe7e1b8SBalint Dobszay 416cbe7e1b8SBalint Dobszay return res; 417cbe7e1b8SBalint Dobszay } 418cbe7e1b8SBalint Dobszay 419baa5161dSBalint Dobszay TEE_Result ldelf_syscall_copy_from_bin(void *dst, size_t offs, size_t num_bytes, 420baa5161dSBalint Dobszay unsigned long handle) 421cbe7e1b8SBalint Dobszay { 422baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS; 423baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 424baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 425baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx; 426cbe7e1b8SBalint Dobszay struct bin_handle *binh = NULL; 427cbe7e1b8SBalint Dobszay 428baa5161dSBalint Dobszay res = vm_check_access_rights(uctx, 429baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_WRITE | 430baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_ANY_OWNER, 431baa5161dSBalint Dobszay (uaddr_t)dst, num_bytes); 432baa5161dSBalint Dobszay if (res) 433baa5161dSBalint Dobszay return res; 434baa5161dSBalint Dobszay 435baa5161dSBalint Dobszay if (!sys_ctx) 436cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 437cbe7e1b8SBalint Dobszay 438baa5161dSBalint Dobszay binh = handle_lookup(&sys_ctx->db, handle); 439cbe7e1b8SBalint Dobszay if (!binh) 440cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 441cbe7e1b8SBalint Dobszay 442baa5161dSBalint Dobszay return binh_copy_to(binh, (vaddr_t)dst, offs, num_bytes); 443cbe7e1b8SBalint Dobszay } 444cbe7e1b8SBalint Dobszay 445baa5161dSBalint Dobszay TEE_Result ldelf_syscall_set_prot(unsigned long va, size_t num_bytes, 446baa5161dSBalint Dobszay unsigned long flags) 447cbe7e1b8SBalint Dobszay { 448cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 449baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 450baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 451baa5161dSBalint Dobszay size_t sz = ROUNDUP(num_bytes, SMALL_PAGE_SIZE); 452baa5161dSBalint Dobszay uint32_t prot = TEE_MATTR_UR | TEE_MATTR_PR; 453cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0; 454cbe7e1b8SBalint Dobszay vaddr_t end_va = 0; 455baa5161dSBalint Dobszay const uint32_t accept_flags = LDELF_MAP_FLAG_WRITEABLE | 456baa5161dSBalint Dobszay LDELF_MAP_FLAG_EXECUTABLE; 457cbe7e1b8SBalint Dobszay 458cbe7e1b8SBalint Dobszay if ((flags & accept_flags) != flags) 459cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 460baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_WRITEABLE) 461cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UW | TEE_MATTR_PW; 462baa5161dSBalint Dobszay if (flags & LDELF_MAP_FLAG_EXECUTABLE) 463cbe7e1b8SBalint Dobszay prot |= TEE_MATTR_UX; 464cbe7e1b8SBalint Dobszay 465cbe7e1b8SBalint Dobszay /* 466baa5161dSBalint Dobszay * The vm_get_flags() and vm_unmap() are supposed to detect or handle 467baa5161dSBalint Dobszay * overflow directly or indirectly. However, since this function is an 468baa5161dSBalint Dobszay * API function it's worth having an extra guard here. If nothing else, 469baa5161dSBalint Dobszay * to increase code clarity. 470cbe7e1b8SBalint Dobszay */ 471cbe7e1b8SBalint Dobszay if (ADD_OVERFLOW(va, sz, &end_va)) 472cbe7e1b8SBalint Dobszay return TEE_ERROR_BAD_PARAMETERS; 473cbe7e1b8SBalint Dobszay 474cbe7e1b8SBalint Dobszay res = vm_get_flags(uctx, va, sz, &vm_flags); 475cbe7e1b8SBalint Dobszay if (res) 476cbe7e1b8SBalint Dobszay return res; 477cbe7e1b8SBalint Dobszay if (vm_flags & VM_FLAG_PERMANENT) 478cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED; 479cbe7e1b8SBalint Dobszay 480cbe7e1b8SBalint Dobszay /* 481cbe7e1b8SBalint Dobszay * If the segment is a mapping of a part of a file (vm_flags & 482cbe7e1b8SBalint Dobszay * VM_FLAG_READONLY) it cannot be made writeable as all mapped 483cbe7e1b8SBalint Dobszay * files are mapped read-only. 484cbe7e1b8SBalint Dobszay */ 485cbe7e1b8SBalint Dobszay if ((vm_flags & VM_FLAG_READONLY) && 486cbe7e1b8SBalint Dobszay (prot & (TEE_MATTR_UW | TEE_MATTR_PW))) 487cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED; 488cbe7e1b8SBalint Dobszay 489cbe7e1b8SBalint Dobszay return vm_set_prot(uctx, va, sz, prot); 490cbe7e1b8SBalint Dobszay } 491cbe7e1b8SBalint Dobszay 492baa5161dSBalint Dobszay TEE_Result ldelf_syscall_remap(unsigned long old_va, vaddr_t *new_va, 493baa5161dSBalint Dobszay size_t num_bytes, size_t pad_begin, 494baa5161dSBalint Dobszay size_t pad_end) 495cbe7e1b8SBalint Dobszay { 496cbe7e1b8SBalint Dobszay TEE_Result res = TEE_SUCCESS; 497baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 498baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 499cbe7e1b8SBalint Dobszay uint32_t vm_flags = 0; 500cbe7e1b8SBalint Dobszay 501cbe7e1b8SBalint Dobszay res = vm_get_flags(uctx, old_va, num_bytes, &vm_flags); 502cbe7e1b8SBalint Dobszay if (res) 503cbe7e1b8SBalint Dobszay return res; 504cbe7e1b8SBalint Dobszay if (vm_flags & VM_FLAG_PERMANENT) 505cbe7e1b8SBalint Dobszay return TEE_ERROR_ACCESS_DENIED; 506cbe7e1b8SBalint Dobszay 507baa5161dSBalint Dobszay res = vm_remap(uctx, new_va, old_va, num_bytes, pad_begin, pad_end); 508cbe7e1b8SBalint Dobszay 509cbe7e1b8SBalint Dobszay return res; 510cbe7e1b8SBalint Dobszay } 511baa5161dSBalint Dobszay 512baa5161dSBalint Dobszay TEE_Result ldelf_syscall_gen_rnd_num(void *buf, size_t num_bytes) 513baa5161dSBalint Dobszay { 514baa5161dSBalint Dobszay TEE_Result res = TEE_SUCCESS; 515baa5161dSBalint Dobszay struct ts_session *sess = ts_get_current_session(); 516baa5161dSBalint Dobszay struct user_mode_ctx *uctx = to_user_mode_ctx(sess->ctx); 517baa5161dSBalint Dobszay 518baa5161dSBalint Dobszay res = vm_check_access_rights(uctx, 519baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_WRITE | 520baa5161dSBalint Dobszay TEE_MEMORY_ACCESS_ANY_OWNER, 521baa5161dSBalint Dobszay (uaddr_t)buf, num_bytes); 522baa5161dSBalint Dobszay if (res) 523baa5161dSBalint Dobszay return res; 524baa5161dSBalint Dobszay 525baa5161dSBalint Dobszay return crypto_rng_read(buf, num_bytes); 526baa5161dSBalint Dobszay } 527baa5161dSBalint Dobszay 528baa5161dSBalint Dobszay /* 529baa5161dSBalint Dobszay * Should be called after returning from ldelf. If user_ctx is not NULL means 530baa5161dSBalint Dobszay * that ldelf crashed or otherwise didn't complete properly. This function will 531baa5161dSBalint Dobszay * close the remaining handles and free the context structs allocated by ldelf. 532baa5161dSBalint Dobszay */ 533baa5161dSBalint Dobszay void ldelf_sess_cleanup(struct ts_session *sess) 534baa5161dSBalint Dobszay { 535baa5161dSBalint Dobszay struct system_ctx *sys_ctx = sess->user_ctx; 536baa5161dSBalint Dobszay 537baa5161dSBalint Dobszay if (sys_ctx) { 538baa5161dSBalint Dobszay handle_db_destroy(&sys_ctx->db, bin_close); 539baa5161dSBalint Dobszay free(sys_ctx); 540baa5161dSBalint Dobszay sess->user_ctx = NULL; 541baa5161dSBalint Dobszay } 542baa5161dSBalint Dobszay } 543