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