1bf215546Sopenharmony_ci/************************************************************************** 2bf215546Sopenharmony_ci * 3bf215546Sopenharmony_ci * Copyright 2021 Snap Inc. 4bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the 8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 10bf215546Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to 11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 12bf215546Sopenharmony_ci * the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included 15bf215546Sopenharmony_ci * in all copies or substantial portions of the Software. 16bf215546Sopenharmony_ci * 17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20bf215546Sopenharmony_ci * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21bf215546Sopenharmony_ci * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24bf215546Sopenharmony_ci * 25bf215546Sopenharmony_ci **************************************************************************/ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci/* 28bf215546Sopenharmony_ci * Memory fd wrappers. 29bf215546Sopenharmony_ci */ 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include "detect_os.h" 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci#if DETECT_OS_UNIX 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#include <string.h> 36bf215546Sopenharmony_ci#include <fcntl.h> 37bf215546Sopenharmony_ci#include <unistd.h> 38bf215546Sopenharmony_ci#include <sys/mman.h> 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci#include "anon_file.h" 41bf215546Sopenharmony_ci#include "mesa-sha1.h" 42bf215546Sopenharmony_ci#include "u_math.h" 43bf215546Sopenharmony_ci#include "os_memory.h" 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci/* (Re)define UUID_SIZE to avoid including vulkan.h (or p_defines.h) here. */ 46bf215546Sopenharmony_ci#define UUID_SIZE 16 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cistruct memory_header { 49bf215546Sopenharmony_ci size_t size; 50bf215546Sopenharmony_ci size_t offset; 51bf215546Sopenharmony_ci uint8_t uuid[UUID_SIZE]; 52bf215546Sopenharmony_ci}; 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistatic void 55bf215546Sopenharmony_ciget_driver_id_sha1_hash(uint8_t sha1[SHA1_DIGEST_LENGTH], const char *driver_id) { 56bf215546Sopenharmony_ci struct mesa_sha1 sha1_ctx; 57bf215546Sopenharmony_ci _mesa_sha1_init(&sha1_ctx); 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci _mesa_sha1_update(&sha1_ctx, driver_id, strlen(driver_id)); 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci _mesa_sha1_final(&sha1_ctx, sha1); 62bf215546Sopenharmony_ci} 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci/** 65bf215546Sopenharmony_ci * Imports memory from a file descriptor 66bf215546Sopenharmony_ci */ 67bf215546Sopenharmony_cibool 68bf215546Sopenharmony_cios_import_memory_fd(int fd, void **ptr, uint64_t *size, char const *driver_id) 69bf215546Sopenharmony_ci{ 70bf215546Sopenharmony_ci void *mapped_ptr; 71bf215546Sopenharmony_ci struct memory_header header; 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci lseek(fd, 0, SEEK_SET); 74bf215546Sopenharmony_ci int bytes_read = read(fd, &header, sizeof(header)); 75bf215546Sopenharmony_ci if(bytes_read != sizeof(header)) 76bf215546Sopenharmony_ci return false; 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci // Check the uuid we put after the sizes in order to verify that the fd 79bf215546Sopenharmony_ci // is a memfd that we created and not some random fd. 80bf215546Sopenharmony_ci uint8_t sha1[SHA1_DIGEST_LENGTH]; 81bf215546Sopenharmony_ci get_driver_id_sha1_hash(sha1, driver_id); 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci assert(SHA1_DIGEST_LENGTH >= UUID_SIZE); 84bf215546Sopenharmony_ci if (memcmp(header.uuid, sha1, UUID_SIZE)) { 85bf215546Sopenharmony_ci return false; 86bf215546Sopenharmony_ci } 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci mapped_ptr = mmap(NULL, header.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 89bf215546Sopenharmony_ci if (mapped_ptr == MAP_FAILED) { 90bf215546Sopenharmony_ci return false; 91bf215546Sopenharmony_ci } 92bf215546Sopenharmony_ci *ptr = (void*)((uintptr_t)mapped_ptr + header.offset); 93bf215546Sopenharmony_ci // the offset does not count as part of the size 94bf215546Sopenharmony_ci *size = header.size - header.offset; 95bf215546Sopenharmony_ci return true; 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci/** 99bf215546Sopenharmony_ci * Return memory on given byte alignment 100bf215546Sopenharmony_ci */ 101bf215546Sopenharmony_civoid * 102bf215546Sopenharmony_cios_malloc_aligned_fd(size_t size, size_t alignment, int *fd, char const *fd_name, char const *driver_id) 103bf215546Sopenharmony_ci{ 104bf215546Sopenharmony_ci void *ptr, *buf; 105bf215546Sopenharmony_ci int mem_fd; 106bf215546Sopenharmony_ci size_t alloc_size, offset; 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci *fd = -1; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci /* 111bf215546Sopenharmony_ci * Calculate 112bf215546Sopenharmony_ci * 113bf215546Sopenharmony_ci * alloc_size = size + alignment + sizeof(struct memory_header) + sizeof(size_t) 114bf215546Sopenharmony_ci * 115bf215546Sopenharmony_ci * while checking for overflow. 116bf215546Sopenharmony_ci */ 117bf215546Sopenharmony_ci const size_t header_size = sizeof(struct memory_header) + sizeof(size_t); 118bf215546Sopenharmony_ci if (add_overflow_size_t(size, alignment, &alloc_size) || 119bf215546Sopenharmony_ci add_overflow_size_t(alloc_size, header_size, &alloc_size)) 120bf215546Sopenharmony_ci return NULL; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci mem_fd = os_create_anonymous_file(alloc_size, fd_name); 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci if(mem_fd < 0) 125bf215546Sopenharmony_ci return NULL; 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci#if defined(HAVE_MEMFD_CREATE) || defined(ANDROID) 128bf215546Sopenharmony_ci // Seal fd, so no one can grow or shrink the memory. 129bf215546Sopenharmony_ci if (fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL) != 0) 130bf215546Sopenharmony_ci goto fail; 131bf215546Sopenharmony_ci#endif 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci ptr = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0); 134bf215546Sopenharmony_ci if (ptr == MAP_FAILED) 135bf215546Sopenharmony_ci goto fail; 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci // Save the size and offset at the start, so we have all we need to unmap the memory 138bf215546Sopenharmony_ci // and we are able to find the start of the actual data-section. Also save the 139bf215546Sopenharmony_ci // offset directly before the data-section, so we can find the start of the mapped memory. 140bf215546Sopenharmony_ci // | size | offset | ... padding ... | offset | ... data ... | 141bf215546Sopenharmony_ci // ^ ^ ^ 142bf215546Sopenharmony_ci // 0 offset size 143bf215546Sopenharmony_ci buf = (char *)(((uintptr_t)ptr + header_size + alignment - 1) & ~((uintptr_t)(alignment - 1))); 144bf215546Sopenharmony_ci offset = (size_t)((uintptr_t)buf - (uintptr_t)ptr); 145bf215546Sopenharmony_ci struct memory_header* header = (struct memory_header*)ptr; 146bf215546Sopenharmony_ci header->size = alloc_size; 147bf215546Sopenharmony_ci header->offset = offset; 148bf215546Sopenharmony_ci ((size_t*)buf)[-1] = offset; 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci // Add the hash of the driver_id as a uuid to the header in order to identify the memory 151bf215546Sopenharmony_ci // when importing. 152bf215546Sopenharmony_ci uint8_t sha1[SHA1_DIGEST_LENGTH]; 153bf215546Sopenharmony_ci get_driver_id_sha1_hash(sha1, driver_id); 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci assert(SHA1_DIGEST_LENGTH >= UUID_SIZE); 156bf215546Sopenharmony_ci memcpy(header->uuid, sha1, UUID_SIZE); 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci *fd = mem_fd; 159bf215546Sopenharmony_ci return buf; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_cifail: 162bf215546Sopenharmony_ci close(mem_fd); 163bf215546Sopenharmony_ci return NULL; 164bf215546Sopenharmony_ci} 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci/** 167bf215546Sopenharmony_ci * Free memory returned by os_malloc_aligned_fd(). 168bf215546Sopenharmony_ci */ 169bf215546Sopenharmony_civoid 170bf215546Sopenharmony_cios_free_fd(void *ptr) 171bf215546Sopenharmony_ci{ 172bf215546Sopenharmony_ci if (ptr) { 173bf215546Sopenharmony_ci size_t offset = ((size_t*)ptr)[-1]; 174bf215546Sopenharmony_ci struct memory_header* header = (struct memory_header*)((uintptr_t)ptr - offset); 175bf215546Sopenharmony_ci // check if the offset at the beginning of the memory 176bf215546Sopenharmony_ci // is the same as the one we saved directly before the data. 177bf215546Sopenharmony_ci assert(offset == header->offset); 178bf215546Sopenharmony_ci munmap(header, header->size); 179bf215546Sopenharmony_ci } 180bf215546Sopenharmony_ci} 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci#endif 183