From 5fafdb664484e7c25e024a96678da89f625542f6 Mon Sep 17 00:00:00 2001 From: Cheng Lingfei Date: Sat, 10 Oct 2026 03:24:42 +0000 Subject: [PATCH] lkl: mmu: fix shm leak and add shmem_cleanup host operation In MMU mode, shmem_init() allocates POSIX shared memory via shm_open() to back LKL physical memory. Two issues currently exist: 1. Because POSIX shared memory has kernel persistence, /dev/shm/lkl_phys_mem_ remains alive after the process exits or crashes, leading to SHM exhaustion under automated testing or fuzzing. Fix this by unlinking the shm object immediately after shm_open(). 2. shared_mem_fd is currently never closed. If an application repeatedly boots and halts LKL within the same host process, each subsequent shmem_init() overwrites shared_mem_fd without closing the previous one, leaking both host file descriptors and physical memory across LKL restarts. Furthermore, missing FD_CLOEXEC causes child processes spawned via fork/exec to inherit the memory backing descriptor. Fix these by: - Calling shm_unlink() right after shm_open() and setting FD_CLOEXEC. - Defensively closing any existing shared_mem_fd in shmem_init(). - Adding a shmem_cleanup() host operation in lkl_host_operations, called from free_mem() during lkl_sys_halt(), to properly close shared_mem_fd when LKL shuts down. Closes: https://github.com/lkl/linux/issues/629 Signed-off-by: Cheng Lingfei --- arch/lkl/include/uapi/asm/host_ops.h | 5 +++++ arch/lkl/mm/bootmem.c | 4 ++++ tools/lkl/lib/posix-host.c | 10 ++++++++++ 3 files changed, 19 insertions(+) diff --git a/arch/lkl/include/uapi/asm/host_ops.h b/arch/lkl/include/uapi/asm/host_ops.h index 673a059512108a..0d4887974115b7 100644 --- a/arch/lkl/include/uapi/asm/host_ops.h +++ b/arch/lkl/include/uapi/asm/host_ops.h @@ -140,6 +140,10 @@ enum lkl_prot { * protection * @munmap - unmap previously mapped memory * + * @shmem_init - initialize host shared memory for MMU physical memory + * @shmem_mmap - map host shared memory into address space + * @shmem_cleanup - cleanup host shared memory resources + * * @pci_ops - pointer to PCI host operations */ struct lkl_host_operations { @@ -199,6 +203,7 @@ struct lkl_host_operations { void (*shmem_init)(unsigned long size); void *(*shmem_mmap)(void *addr, unsigned long pg_off, unsigned long size, enum lkl_prot prot); + void (*shmem_cleanup)(void); struct lkl_dev_pci_ops *pci_ops; }; diff --git a/arch/lkl/mm/bootmem.c b/arch/lkl/mm/bootmem.c index 79958137971b48..8734a24c94c2a5 100644 --- a/arch/lkl/mm/bootmem.c +++ b/arch/lkl/mm/bootmem.c @@ -78,4 +78,8 @@ void free_mem(void) lkl_ops->page_free(_memory_start, mem_size); else lkl_ops->mem_free(_memory_start); +#ifdef CONFIG_MMU + if (lkl_ops->shmem_cleanup) + lkl_ops->shmem_cleanup(); +#endif } diff --git a/tools/lkl/lib/posix-host.c b/tools/lkl/lib/posix-host.c index 2f4e0191dd78a7..5f3060558afd8a 100644 --- a/tools/lkl/lib/posix-host.c +++ b/tools/lkl/lib/posix-host.c @@ -531,6 +531,7 @@ static void shmem_init(unsigned long size) snprintf(lkl_shmem_id, sizeof(lkl_shmem_id), "/lkl_phys_mem_%d", getpid()); shared_mem_fd = shm_open(lkl_shmem_id, O_RDWR | O_CREAT, rwx); assert(shared_mem_fd >= 0); + assert(shm_unlink(lkl_shmem_id) == 0); shared_mem_size = size; assert(ftruncate(shared_mem_fd, shared_mem_size) == 0); } @@ -546,6 +547,14 @@ static void *lkl_shmem_mmap(void *addr, unsigned long pg_off, return NULL; return ret; } + +static void shmem_cleanup(void) +{ + if (shared_mem_fd >= 0) { + close(shared_mem_fd); + shared_mem_fd = -1; + } +} #endif // LKL_HOST_CONFIG_MMU static void *posix_malloc(unsigned long size) @@ -611,6 +620,7 @@ struct lkl_host_operations lkl_host_ops = { #ifdef LKL_HOST_CONFIG_MMU .shmem_init = shmem_init, .shmem_mmap = lkl_shmem_mmap, + .shmem_cleanup = shmem_cleanup, #endif #ifdef LKL_HOST_CONFIG_VFIO_PCI .pci_ops = &vfio_pci_ops,