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