From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm1-f41.google.com (mail-wm1-f41.google.com [209.85.128.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 09C0935AC32 for ; Sat, 18 Jul 2026 12:34:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.41 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784378087; cv=none; b=OIh9y8JSaFE1yEfoQKi/g6lLDIuSchXfUPk2WjEeAeB1toX3nK+eTcwJ6ZylbDV/wbfsUXhrJbuGb12kJq+Hb5L2fKH1k+tMrQPKuY/oyI02hAqyJ9HFWlWrSJYL5dsB5J69qIOsG3bQ2sjoHJ68feIqCE8/NK6oHRb3k/yEY6k= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784378087; c=relaxed/simple; bh=bQ5YNOnX4209Wpz8kOSi35oIqwZK26TqnoQyCmPqWNM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AXRNppOh6fmMpx4WNYlzANdXeNJaQfqRtN5oTljUoWDKOW9p/txTU6h7DofXccAKhU72sPXMxhMoBRm8oTh5YAInRMmBDJkIcGDRJGzrjTPIKPy2fZqQxnp+Bt0i90zbKMAkRdTmVlvczZwj3KLX1Mo6sgxSnjsE+nqjeomUFgE= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=BlYiguqS; arc=none smtp.client-ip=209.85.128.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BlYiguqS" Received: by mail-wm1-f41.google.com with SMTP id 5b1f17b1804b1-4921eed3fa2so67792925e9.0 for ; Sat, 18 Jul 2026 05:34:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784378084; x=1784982884; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=fyK9obKyx21C+ZaaJV9CzkRR6fotaVHFrnIZl4e1n9w=; b=BlYiguqS048O/ksjaPkECRg1/0Gf7WX92Kx8zYMsKIoToxX4PsWSwh4Wah35FZOdqi W7XpHvP6TlDEpJ3JluryppikNeLjOgE6qXAyUegHlUGNhuZY50rIbIJmtC3dnvqRqkh7 3Ql6CEKw7Ks6K9FkB/fvBDqM0f7vMp+8qi0kgcKjuO7T07YVw9W+hmn8fk+WuKW5xlSA HNjrjkE4d7eAlgMuzFiihHlWdF8ln4wO026RBk4tsn2l4iqtXzsUS/yj6Z3xwe09cd9l I00uYPUohF1TiMut5vwWm/W5w5+8OxUFAMfgAhpXtoBDcbljfOU1ymNjm0s8XzjsujGA EvOw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784378084; x=1784982884; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=fyK9obKyx21C+ZaaJV9CzkRR6fotaVHFrnIZl4e1n9w=; b=ZqDnLbsLt9NVAMHs1oSSYKVhmPOCJpBMOKD+F8pY/T89BLAb/M9GbapRfUEBVtooQg zWpLJgrlsjRot5d20rHQkJIjES78gigLwom+f1yvHrPo5ccX1G6M11qmfjhWR73oCB/2 Hxknq7YXwv307CUv4MGt2fbDgTYbnNo+lY4KSRw6MSdDxbzyoRww2durtjmSgnz8m23K /nFgT99d6Kj4u493LlHMKbdPxFaiSX0Y7lCPYsidkT064RxqiqudiB3Y5sLXdAVcZLNa UWxDErzm/ZaF3+xz6p0G83i+a/Jf/tvyL9UsfMR4DZ4UC01xtW0myekytudvjlq1I1/K JEHA== X-Forwarded-Encrypted: i=1; AHgh+RoEYdqcH5Lmn872vLVNxU+zfjCDFIIOMql36Y3uW3edkllxGEwFkBY6s1TSk+wgfYB9bDCam4n5CWeW5g8=@vger.kernel.org X-Gm-Message-State: AOJu0YyLWx0294nqEku+K4b5UZeyR4tiaBYYD1Kv9Lz3shjaAJzmDSx9 2mP879MU1MoIzCeodyQ54O/vEDDdQVKQepdBlXJRkthtONmenNGlmNrP X-Gm-Gg: AfdE7cnRpGaMxZhw8TSOS2gDsCEFAwWyh3gTp8ZDaNo2KuiJGXMT0XylrN5CUwx1uoh No9DeME/XuJ013vDOtvw3Q/0y6u08jDuLizHXxTajrvX+4nweG/1Y9dYrEOSqX4Y+unBTCTpdN4 +NmN6NvsgR0JUb28gPhJ7xPOI/OlGRCh9/W4ythToYAfiv2FY/bs77jGBNWxij0SYusLke+w5c6 ghghsXkhtIPs1+TYjqGznpXDP/P7DiKLYR1WOJ4QDV62All07dwbi53BVjw61UrJSZsxkz1wLcC YiKXraYcnww69HOKPn+GpQrVDgW3IE8S38aUpx7uFmrGMgulB54RPJy8oh4gJFpux38FWdJ2Czu PvQnnNvJxaRxs2W3eFHq6jS9F4GeuamiCVxxLBz2tJhaRlrOOcUCisHGH6DdW6/nKOLXJuqgLLj BPD3YBw5h4WlvW X-Received: by 2002:a05:600c:c0c3:10b0:493:72d3:4a81 with SMTP id 5b1f17b1804b1-4954a3dc87bmr55989155e9.16.1784378084218; Sat, 18 Jul 2026 05:34:44 -0700 (PDT) Received: from liavpc.localdomain ([2a06:c701:4900:1700:d578:12e4:b9d6:6e36]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49549a35830sm129041165e9.3.2026.07.18.05.34.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 18 Jul 2026 05:34:43 -0700 (PDT) From: Liav Albani To: akpm@linux-foundation.org Cc: david@kernel.org, ljs@kernel.org, liam@infradead.org, vbabka@kernel.org, rppt@kernel.org, surenb@google.com, mhocko@suse.com, jannh@google.com, pfalcato@suse.de, linux-mm@kvack.org, linux-kernel@vger.kernel.org, Liav Albani Subject: [PATCH] mm/vma: fix imbalanced file reference count, properly abort mmap_prepare Date: Sat, 18 Jul 2026 15:34:17 +0300 Message-ID: <20260718123417.16339-2-liavalb@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260718123417.16339-1-liavalb@gmail.com> References: <20260718123417.16339-1-liavalb@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Under the new `vm_area_desc` struct, a driver may change the vm_file to provide a different backing VM file. In such case, it became apparent during testing of this capability, that a remove_vma() may drop a refcount on a VM file that we didn't call get_file() upon. In addition to that, calling vms_abort_munmap_vmas when we didn't do actual work is wrong, because mmap_prepare hook is about preparing the mmap state and not performing any actual mapping (yet). A kernel stack (before of this patch) could look like this: imbalanced put on file reference count WARNING: fs/file.c:36 at __file_ref_put_badval.isra.0+0x3f/0x60, CPU#1: test_proxy_mmap/116 Modules linked in: ufedm(OE) virtio_net net_failover failover nandsim nand nandcore bch mtd CPU: 1 UID: 0 PID: 116 Comm: test_proxy_mmap Tainted: G OE 7.2.0-rc3-gaf5e34a41cd6 #1 PREEMPT(full) bdadc55b51524b311c430c1536a97e7071150fd3 Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.17.0-2-2 04/01/2014 RIP: 0010:__file_ref_put_badval.isra.0+0x3f/0x60 Code: 85 f6 78 05 c3 cc cc cc cc 48 b8 00 00 00 00 00 00 00 a0 48 89 07 c3 cc cc cc cc 48 83 ec 08 48 89 3c 24 48 8d 3d 61 bc 30 02 <67> 48 0f b9 3a 48 ba 00 00 00 00 00 00 00 e0 48 8b 04 24 48 89 10 RSP: 0018:ffffc900006bbae8 EFLAGS: 00010296 RAX: bfffffffffffffff RBX: ffff88810409a180 RCX: 0000000038748000 RDX: ffff888100a44480 RSI: dfffffffffffffff RDI: ffffffff83b12730 RBP: ffffc900006bbbf8 R08: 0000000000000000 R09: 00007f8b49f8f000 R10: ffffc900006bbba0 R11: ffff88810409a208 R12: ffffc900006bbba0 R13: 00007f8b4a179000 R14: ffff888102222440 R15: 0000000000015040 FS: 0000000038726400(0000) GS:ffff8881b77d1000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000038728618 CR3: 0000000104a1c006 CR4: 0000000000370ef0 Call Trace: __file_ref_put+0x30/0x40 fput+0x4f/0x80 remove_vma+0x42/0x60 vms_complete_munmap_vmas+0x179/0x230 do_vmi_align_munmap+0x225/0x2a0 do_vmi_munmap+0xe6/0x1c0 __vm_munmap+0x113/0x200 __x64_sys_munmap+0x1b/0x30 do_syscall_64+0xaa/0x660 ? ksys_mmap_pgoff+0x168/0x200 ? do_syscall_64+0xaa/0x660 ? vfs_write+0x281/0x560 ? ksys_write+0x7b/0x110 ? do_syscall_64+0xaa/0x660 ? do_syscall_64+0x5f/0x660 ? clear_bhb_loop+0x30/0x80 ? clear_bhb_loop+0x30/0x80 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x440bcb Signed-off-by: Liav Albani --- include/linux/mm_types.h | 1 + mm/vma.c | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index b18c2b2e7d2c..5db0894e6064 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -981,6 +981,7 @@ struct vm_area_struct { unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE units */ struct file * vm_file; /* File we map to (can be NULL). */ + bool vm_file_doesnt_need_put; /* Do fput only if we did get_file... */ void * vm_private_data; /* was vm_pte (shared mem) */ #ifdef CONFIG_SWAP diff --git a/mm/vma.c b/mm/vma.c index 9eea2850818a..0c2e71fc09be 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -467,7 +467,7 @@ void remove_vma(struct vm_area_struct *vma) { might_sleep(); vma_close(vma); - if (vma->vm_file) + if (vma->vm_file && !vma->vm_file_doesnt_need_put) fput(vma->vm_file); mpol_put(vma_policy(vma)); vm_area_free(vma); @@ -2487,6 +2487,7 @@ static int __mmap_new_file_vma(struct mmap_state *map, int error; vma->vm_file = map->file; + vma->vm_file_doesnt_need_put = map->file_doesnt_need_get; if (!map->file_doesnt_need_get) get_file(map->file); @@ -2497,7 +2498,14 @@ static int __mmap_new_file_vma(struct mmap_state *map, if (error) { UNMAP_STATE(unmap, vmi, vma, vma->vm_start, vma->vm_end, map->prev, map->next); - fput(vma->vm_file); + + /* + * We set vma->vm_file to map->file, so if we didn't increase + * the refcount, don't decrease it in this path. + */ + if (!map->file_doesnt_need_get) + fput(vma->vm_file); + vma->vm_file = NULL; vma_iter_set(vmi, vma->vm_end); @@ -2757,7 +2765,7 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, if (!error && have_mmap_prepare) error = call_mmap_prepare(&map, &desc); if (error) - goto abort_munmap; + goto abort_mmap_prepare; if (map.check_ksm_early) update_ksm_flags(&map); @@ -2795,15 +2803,9 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, unacct_error: if (map.charged) vm_unacct_memory(map.charged); -abort_munmap: - /* - * This indicates that .mmap_prepare has set a new file, differing from - * desc->vm_file. But since we're aborting the operation, only the - * original file will be cleaned up. Ensure we clean up both. - */ - if (map.file_doesnt_need_get) - fput(map.file); + vms_abort_munmap_vmas(&map.vms, &map.mas_detach); +abort_mmap_prepare: return error; } -- 2.55.0