1f04cf923SMarc-André Lureau /* 2f04cf923SMarc-André Lureau * memfd.c 3f04cf923SMarc-André Lureau * 4f04cf923SMarc-André Lureau * Copyright (c) 2015 Red Hat, Inc. 5f04cf923SMarc-André Lureau * 6f04cf923SMarc-André Lureau * QEMU library functions on POSIX which are shared between QEMU and 7f04cf923SMarc-André Lureau * the QEMU tools. 8f04cf923SMarc-André Lureau * 9f04cf923SMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy 10f04cf923SMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal 11f04cf923SMarc-André Lureau * in the Software without restriction, including without limitation the rights 12f04cf923SMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13f04cf923SMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is 14f04cf923SMarc-André Lureau * furnished to do so, subject to the following conditions: 15f04cf923SMarc-André Lureau * 16f04cf923SMarc-André Lureau * The above copyright notice and this permission notice shall be included in 17f04cf923SMarc-André Lureau * all copies or substantial portions of the Software. 18f04cf923SMarc-André Lureau * 19f04cf923SMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20f04cf923SMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21f04cf923SMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22f04cf923SMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23f04cf923SMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24f04cf923SMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25f04cf923SMarc-André Lureau * THE SOFTWARE. 26f04cf923SMarc-André Lureau */ 27f04cf923SMarc-André Lureau 28f04cf923SMarc-André Lureau #include "qemu/osdep.h" 29f04cf923SMarc-André Lureau 30*d3592199SMarc-André Lureau #include <glib.h> 31*d3592199SMarc-André Lureau #include <glib/gprintf.h> 32*d3592199SMarc-André Lureau 33*d3592199SMarc-André Lureau #include <sys/mman.h> 34*d3592199SMarc-André Lureau 35f04cf923SMarc-André Lureau #include "qemu/memfd.h" 36f04cf923SMarc-André Lureau 37f04cf923SMarc-André Lureau #ifdef CONFIG_MEMFD 38f04cf923SMarc-André Lureau #include <sys/memfd.h> 39f04cf923SMarc-André Lureau #elif defined CONFIG_LINUX 40f04cf923SMarc-André Lureau #include <sys/syscall.h> 41f04cf923SMarc-André Lureau #include <asm/unistd.h> 42f04cf923SMarc-André Lureau 43*d3592199SMarc-André Lureau static int memfd_create(const char *name, unsigned int flags) 44f04cf923SMarc-André Lureau { 45f04cf923SMarc-André Lureau #ifdef __NR_memfd_create 46f04cf923SMarc-André Lureau return syscall(__NR_memfd_create, name, flags); 47f04cf923SMarc-André Lureau #else 48f04cf923SMarc-André Lureau return -1; 49f04cf923SMarc-André Lureau #endif 50f04cf923SMarc-André Lureau } 51f04cf923SMarc-André Lureau #endif 52f04cf923SMarc-André Lureau 53f04cf923SMarc-André Lureau #ifndef MFD_CLOEXEC 54f04cf923SMarc-André Lureau #define MFD_CLOEXEC 0x0001U 55f04cf923SMarc-André Lureau #endif 56f04cf923SMarc-André Lureau 57f04cf923SMarc-André Lureau #ifndef MFD_ALLOW_SEALING 58f04cf923SMarc-André Lureau #define MFD_ALLOW_SEALING 0x0002U 59f04cf923SMarc-André Lureau #endif 60*d3592199SMarc-André Lureau 61*d3592199SMarc-André Lureau /* 62*d3592199SMarc-André Lureau * This is a best-effort helper for shared memory allocation, with 63*d3592199SMarc-André Lureau * optional sealing. The helper will do his best to allocate using 64*d3592199SMarc-André Lureau * memfd with sealing, but may fallback on other methods without 65*d3592199SMarc-André Lureau * sealing. 66*d3592199SMarc-André Lureau */ 67*d3592199SMarc-André Lureau void *qemu_memfd_alloc(const char *name, size_t size, unsigned int seals, 68*d3592199SMarc-André Lureau int *fd) 69*d3592199SMarc-André Lureau { 70*d3592199SMarc-André Lureau void *ptr; 71*d3592199SMarc-André Lureau int mfd = -1; 72*d3592199SMarc-André Lureau 73*d3592199SMarc-André Lureau *fd = -1; 74*d3592199SMarc-André Lureau 75*d3592199SMarc-André Lureau #ifdef CONFIG_LINUX 76*d3592199SMarc-André Lureau if (seals) { 77*d3592199SMarc-André Lureau mfd = memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC); 78*d3592199SMarc-André Lureau } 79*d3592199SMarc-André Lureau 80*d3592199SMarc-André Lureau if (mfd == -1) { 81*d3592199SMarc-André Lureau /* some systems have memfd without sealing */ 82*d3592199SMarc-André Lureau mfd = memfd_create(name, MFD_CLOEXEC); 83*d3592199SMarc-André Lureau seals = 0; 84*d3592199SMarc-André Lureau } 85*d3592199SMarc-André Lureau #endif 86*d3592199SMarc-André Lureau 87*d3592199SMarc-André Lureau if (mfd != -1) { 88*d3592199SMarc-André Lureau if (ftruncate(mfd, size) == -1) { 89*d3592199SMarc-André Lureau perror("ftruncate"); 90*d3592199SMarc-André Lureau close(mfd); 91*d3592199SMarc-André Lureau return NULL; 92*d3592199SMarc-André Lureau } 93*d3592199SMarc-André Lureau 94*d3592199SMarc-André Lureau if (seals && fcntl(mfd, F_ADD_SEALS, seals) == -1) { 95*d3592199SMarc-André Lureau perror("fcntl"); 96*d3592199SMarc-André Lureau close(mfd); 97*d3592199SMarc-André Lureau return NULL; 98*d3592199SMarc-André Lureau } 99*d3592199SMarc-André Lureau } else { 100*d3592199SMarc-André Lureau perror("memfd"); 101*d3592199SMarc-André Lureau return NULL; 102*d3592199SMarc-André Lureau } 103*d3592199SMarc-André Lureau 104*d3592199SMarc-André Lureau ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, 0); 105*d3592199SMarc-André Lureau if (ptr == MAP_FAILED) { 106*d3592199SMarc-André Lureau perror("mmap"); 107*d3592199SMarc-André Lureau close(mfd); 108*d3592199SMarc-André Lureau return NULL; 109*d3592199SMarc-André Lureau } 110*d3592199SMarc-André Lureau 111*d3592199SMarc-André Lureau *fd = mfd; 112*d3592199SMarc-André Lureau return ptr; 113*d3592199SMarc-André Lureau } 114*d3592199SMarc-André Lureau 115*d3592199SMarc-André Lureau void qemu_memfd_free(void *ptr, size_t size, int fd) 116*d3592199SMarc-André Lureau { 117*d3592199SMarc-André Lureau if (ptr) { 118*d3592199SMarc-André Lureau munmap(ptr, size); 119*d3592199SMarc-André Lureau } 120*d3592199SMarc-André Lureau 121*d3592199SMarc-André Lureau if (fd != -1) { 122*d3592199SMarc-André Lureau close(fd); 123*d3592199SMarc-André Lureau } 124*d3592199SMarc-André Lureau } 125