17ec681f3Smrg/************************************************************************** 27ec681f3Smrg * 37ec681f3Smrg * Copyright 2021 Snap Inc. 47ec681f3Smrg * SPDX-License-Identifier: MIT 57ec681f3Smrg * 67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77ec681f3Smrg * copy of this software and associated documentation files (the 87ec681f3Smrg * "Software"), to deal in the Software without restriction, including 97ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish, 107ec681f3Smrg * distribute, sublicense, and/or sell copies of the Software, and to 117ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to 127ec681f3Smrg * the following conditions: 137ec681f3Smrg * 147ec681f3Smrg * The above copyright notice and this permission notice shall be included 157ec681f3Smrg * in all copies or substantial portions of the Software. 167ec681f3Smrg * 177ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 187ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 197ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 207ec681f3Smrg * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 217ec681f3Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 227ec681f3Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 237ec681f3Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 247ec681f3Smrg * 257ec681f3Smrg **************************************************************************/ 267ec681f3Smrg 277ec681f3Smrg/* 287ec681f3Smrg * Memory fd wrappers. 297ec681f3Smrg */ 307ec681f3Smrg 317ec681f3Smrg#include "detect_os.h" 327ec681f3Smrg 337ec681f3Smrg#if DETECT_OS_UNIX 347ec681f3Smrg 357ec681f3Smrg#include <string.h> 367ec681f3Smrg#include <fcntl.h> 377ec681f3Smrg#include <unistd.h> 387ec681f3Smrg#include <sys/mman.h> 397ec681f3Smrg 407ec681f3Smrg#include "anon_file.h" 417ec681f3Smrg#include "mesa-sha1.h" 427ec681f3Smrg#include "u_math.h" 437ec681f3Smrg#include "os_memory.h" 447ec681f3Smrg 457ec681f3Smrg/* (Re)define UUID_SIZE to avoid including vulkan.h (or p_defines.h) here. */ 467ec681f3Smrg#define UUID_SIZE 16 477ec681f3Smrg 487ec681f3Smrgstruct memory_header { 497ec681f3Smrg size_t size; 507ec681f3Smrg size_t offset; 517ec681f3Smrg uint8_t uuid[UUID_SIZE]; 527ec681f3Smrg}; 537ec681f3Smrg 547ec681f3Smrgstatic void 557ec681f3Smrgget_driver_id_sha1_hash(uint8_t sha1[SHA1_DIGEST_LENGTH], const char *driver_id) { 567ec681f3Smrg struct mesa_sha1 sha1_ctx; 577ec681f3Smrg _mesa_sha1_init(&sha1_ctx); 587ec681f3Smrg 597ec681f3Smrg _mesa_sha1_update(&sha1_ctx, driver_id, strlen(driver_id)); 607ec681f3Smrg 617ec681f3Smrg _mesa_sha1_final(&sha1_ctx, sha1); 627ec681f3Smrg} 637ec681f3Smrg 647ec681f3Smrg/** 657ec681f3Smrg * Imports memory from a file descriptor 667ec681f3Smrg */ 677ec681f3Smrgbool 687ec681f3Smrgos_import_memory_fd(int fd, void **ptr, uint64_t *size, char const *driver_id) 697ec681f3Smrg{ 707ec681f3Smrg void *mapped_ptr; 717ec681f3Smrg struct memory_header header; 727ec681f3Smrg 737ec681f3Smrg lseek(fd, 0, SEEK_SET); 747ec681f3Smrg int bytes_read = read(fd, &header, sizeof(header)); 757ec681f3Smrg if(bytes_read != sizeof(header)) 767ec681f3Smrg return false; 777ec681f3Smrg 787ec681f3Smrg // Check the uuid we put after the sizes in order to verify that the fd 797ec681f3Smrg // is a memfd that we created and not some random fd. 807ec681f3Smrg uint8_t sha1[SHA1_DIGEST_LENGTH]; 817ec681f3Smrg get_driver_id_sha1_hash(sha1, driver_id); 827ec681f3Smrg 837ec681f3Smrg assert(SHA1_DIGEST_LENGTH >= UUID_SIZE); 847ec681f3Smrg if (memcmp(header.uuid, sha1, UUID_SIZE)) { 857ec681f3Smrg return false; 867ec681f3Smrg } 877ec681f3Smrg 887ec681f3Smrg mapped_ptr = mmap(NULL, header.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 897ec681f3Smrg if (mapped_ptr == MAP_FAILED) { 907ec681f3Smrg return false; 917ec681f3Smrg } 927ec681f3Smrg *ptr = (void*)((uintptr_t)mapped_ptr + header.offset); 937ec681f3Smrg // the offset does not count as part of the size 947ec681f3Smrg *size = header.size - header.offset; 957ec681f3Smrg return true; 967ec681f3Smrg} 977ec681f3Smrg 987ec681f3Smrg/** 997ec681f3Smrg * Return memory on given byte alignment 1007ec681f3Smrg */ 1017ec681f3Smrgvoid * 1027ec681f3Smrgos_malloc_aligned_fd(size_t size, size_t alignment, int *fd, char const *fd_name, char const *driver_id) 1037ec681f3Smrg{ 1047ec681f3Smrg void *ptr, *buf; 1057ec681f3Smrg int mem_fd; 1067ec681f3Smrg size_t alloc_size, offset; 1077ec681f3Smrg 1087ec681f3Smrg *fd = -1; 1097ec681f3Smrg 1107ec681f3Smrg /* 1117ec681f3Smrg * Calculate 1127ec681f3Smrg * 1137ec681f3Smrg * alloc_size = size + alignment + sizeof(struct memory_header) + sizeof(size_t) 1147ec681f3Smrg * 1157ec681f3Smrg * while checking for overflow. 1167ec681f3Smrg */ 1177ec681f3Smrg const size_t header_size = sizeof(struct memory_header) + sizeof(size_t); 1187ec681f3Smrg if (add_overflow_size_t(size, alignment, &alloc_size) || 1197ec681f3Smrg add_overflow_size_t(alloc_size, header_size, &alloc_size)) 1207ec681f3Smrg return NULL; 1217ec681f3Smrg 1227ec681f3Smrg mem_fd = os_create_anonymous_file(alloc_size, fd_name); 1237ec681f3Smrg 1247ec681f3Smrg if(mem_fd < 0) 1257ec681f3Smrg return NULL; 1267ec681f3Smrg 1277ec681f3Smrg#if defined(HAVE_MEMFD_CREATE) || defined(ANDROID) 1287ec681f3Smrg // Seal fd, so no one can grow or shrink the memory. 1297ec681f3Smrg if (fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL) != 0) 1307ec681f3Smrg goto fail; 1317ec681f3Smrg#endif 1327ec681f3Smrg 1337ec681f3Smrg ptr = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0); 1347ec681f3Smrg if (ptr == MAP_FAILED) 1357ec681f3Smrg goto fail; 1367ec681f3Smrg 1377ec681f3Smrg // Save the size and offset at the start, so we have all we need to unmap the memory 1387ec681f3Smrg // and we are able to find the start of the actual data-section. Also save the 1397ec681f3Smrg // offset directly before the data-section, so we can find the start of the mapped memory. 1407ec681f3Smrg // | size | offset | ... padding ... | offset | ... data ... | 1417ec681f3Smrg // ^ ^ ^ 1427ec681f3Smrg // 0 offset size 1437ec681f3Smrg buf = (char *)(((uintptr_t)ptr + header_size + alignment - 1) & ~((uintptr_t)(alignment - 1))); 1447ec681f3Smrg offset = (size_t)((uintptr_t)buf - (uintptr_t)ptr); 1457ec681f3Smrg struct memory_header* header = (struct memory_header*)ptr; 1467ec681f3Smrg header->size = alloc_size; 1477ec681f3Smrg header->offset = offset; 1487ec681f3Smrg ((size_t*)buf)[-1] = offset; 1497ec681f3Smrg 1507ec681f3Smrg // Add the hash of the driver_id as a uuid to the header in order to identify the memory 1517ec681f3Smrg // when importing. 1527ec681f3Smrg uint8_t sha1[SHA1_DIGEST_LENGTH]; 1537ec681f3Smrg get_driver_id_sha1_hash(sha1, driver_id); 1547ec681f3Smrg 1557ec681f3Smrg assert(SHA1_DIGEST_LENGTH >= UUID_SIZE); 1567ec681f3Smrg memcpy(header->uuid, sha1, UUID_SIZE); 1577ec681f3Smrg 1587ec681f3Smrg *fd = mem_fd; 1597ec681f3Smrg return buf; 1607ec681f3Smrg 1617ec681f3Smrgfail: 1627ec681f3Smrg close(mem_fd); 1637ec681f3Smrg return NULL; 1647ec681f3Smrg} 1657ec681f3Smrg 1667ec681f3Smrg/** 1677ec681f3Smrg * Free memory returned by os_malloc_aligned_fd(). 1687ec681f3Smrg */ 1697ec681f3Smrgvoid 1707ec681f3Smrgos_free_fd(void *ptr) 1717ec681f3Smrg{ 1727ec681f3Smrg if (ptr) { 1737ec681f3Smrg size_t offset = ((size_t*)ptr)[-1]; 1747ec681f3Smrg struct memory_header* header = (struct memory_header*)((uintptr_t)ptr - offset); 1757ec681f3Smrg // check if the offset at the beginning of the memory 1767ec681f3Smrg // is the same as the one we saved directly before the data. 1777ec681f3Smrg assert(offset == header->offset); 1787ec681f3Smrg munmap(header, header->size); 1797ec681f3Smrg } 1807ec681f3Smrg} 1817ec681f3Smrg 1827ec681f3Smrg#endif 183