From patchwork Mon Nov 11 00:52:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 13870106 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id B8633D12D5E for ; Mon, 11 Nov 2024 00:53:24 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 3F0246B0098; Sun, 10 Nov 2024 19:53:24 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 37A606B0099; Sun, 10 Nov 2024 19:53:24 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 1F3456B009A; Sun, 10 Nov 2024 19:53:24 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id F24ED6B0098 for ; Sun, 10 Nov 2024 19:53:23 -0500 (EST) Received: from smtpin30.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id 9C2DC1A140A for ; Mon, 11 Nov 2024 00:53:23 +0000 (UTC) X-FDA: 82771989510.30.855E934 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by imf05.hostedemail.com (Postfix) with ESMTP id AC3BF100003 for ; Mon, 11 Nov 2024 00:52:06 +0000 (UTC) Authentication-Results: imf05.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=SS71cagn; spf=pass (imf05.hostedemail.com: domain of cel@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=cel@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1731286348; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=FGLo83jrDngw/CAuOddHFvlwBshrpzVUuM0qMcpgloY=; b=5/VD+T6/9J6a1sTkTUj0mM/9XrmYQm64LvjPgtXUhPL/RSpv9qcBkNpRch6iBgJDbm7OzJ QlL1BY1aq/nnPUoHPv8Q8ZSyacMg+DZViNORB9+/z9epagdM1DxQqUba/JOgJ29rsZ4JxR lDMERMpblqgVtoVmmG8FX3b9LpLr2OM= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1731286348; a=rsa-sha256; cv=none; b=PoHsJlsW/Y5zq/izpbtu/MXbx3Wz3toE3jAV17hjLHqSEmknQQYcSimOhsccMAjkKKXqoI ClY0u03jWnKy6wrCIH5cUyF1Q9LqxgZsvmFdAs59Gp0Zof4Od4GjGorKntS+/bz8fO92rK yW0Hby42Y8zAZjY1qMJq46G5nLfaAtw= ARC-Authentication-Results: i=1; imf05.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=SS71cagn; spf=pass (imf05.hostedemail.com: domain of cel@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=cel@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id C155F5C54D1; Mon, 11 Nov 2024 00:52:36 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 381A7C4CEDF; Mon, 11 Nov 2024 00:53:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1731286400; bh=FdkkHjJkV4S0+kVcTYwQw7JAo4gJep4aQ3vPEJrklpk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SS71cagn0Y7k0khmPTRSNE2WIHD+UznGHwyeGjN6di6DA1sirkflrguuVTZfxJuMc /G9xzd1SKB6D9RdV9mg/kKdTh3Fb8Uw0YfA3G5UjeH1P9ZO52x1CzgadU77Vyy7HgZ FnPM9QJ6/Fd2xvc9b3aTmANUab2ekRv5H7VCSTVNS+VumwqsVLVOWs39LyhE+bh+4h e1ygJE+h9xbhHDwrinkdWVXPXG1QA19rUN38dxI6I8sqZEE74fYpYwrkIBq7TR74w7 Rn6PjpDnyEgXK2ddOoeB3QHYdnXmUkLTtda17feUFfBEaG5aHTbfsQgcZVzOpWvud7 +nuLxfO5dEEMg== From: cel@kernel.org To: Cc: yukuai1@huaweicloud.com, harry.wentland@amd.com, sunpeng.li@amd.com, Rodrigo.Siqueira@amd.com, alexander.deucher@amd.com, christian.koenig@amd.com, Xinhui.Pan@amd.com, airlied@gmail.com, daniel@ffwll.ch, viro@zeniv.linux.org.uk, brauner@kernel.org, Liam.Howlett@oracle.com, akpm@linux-foundation.org, hughd@google.com, willy@infradead.org, gregkh@linuxfoundation.org, sashal@kernel.org, srinivasan.shanmugam@amd.com, chiahsuan.chung@amd.com, mingo@kernel.org, mgorman@techsingularity.net, yukuai3@huawei.com, chengming.zhou@linux.dev, zhangpeng.00@bytedance.com, amd-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, , linux-fsdevel@vger.kernel.org, maple-tree@lists.infradead.org, linux-mm@kvack.org, yi.zhang@huawei.com, yangerkun@huawei.com, Chuck Lever Subject: [RFC PATCH 6/6 6.6] libfs: fix infinite directory reads for offset dir Date: Sun, 10 Nov 2024 19:52:42 -0500 Message-ID: <20241111005242.34654-7-cel@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241111005242.34654-1-cel@kernel.org> References: <20241111005242.34654-1-cel@kernel.org> MIME-Version: 1.0 X-Stat-Signature: 93uyx1a815b16ysru57o7fmmppgocyd9 X-Rspam-User: X-Rspamd-Queue-Id: AC3BF100003 X-Rspamd-Server: rspam02 X-HE-Tag: 1731286326-614355 X-HE-Meta: U2FsdGVkX1+uDmIOZGFgffazdgto0Lkvx4sJhv+IvSb0AFTsRQs8bT6gk7O49SCQ0n3SHYWywqe7Xtd0tmQ6ZGOrZzfvU38B1PIGT2NZ6WpXjXGo1mqSlt20WovUHem6DUloUBqCXSuN7QQFu09okPmSR9PVW8of3uKugdnYdFehN9/9GqfF/df5KzykZxyT4c6YAWxlbAYXWkqLQe3PFFA0K9WliP9WObVI25mGmhYaapoEohgQhZ3FzwxWAnpoJ6PTPVzGJ+etk0IUvns30OR69mCwOIHBeFFiWbb9giNBl1nxmNKdaOeV9R2lyn37f+JD7nz4mpN8+apPTdkurtk9HSbQAnfOa33YepI5ZENBVpiabwJDPmTKImKcHYiHv5+UY27+9T3RYZgNfhkoBGaQVkJUdwfA4oLvUeIoTbdBgBeb9fKanZFFsAH1HV+M3O2Q8FvIrtjs41FnGeBZ95CD5VT/zKssfCF1SYfBIN4YMzalQIxzRAqzmss3rj/DvPygjBgvxflIjXyjJy0IMcChUcLM5vFMQHl+S9c0gjhQv27HPdYkF7LUjS3qtrnIvJ4vg0Aj/muLcyQWQIvyvC0Rc+UOgYW1fsTFQed1p4p+OM7MMSEFeYwwKNrgoOQfvBwc7YAh+j0ISBiU8Gx4ZzO74VLgVV9vhxywBiggncoz4G7msJL5cwCCYIuDNA7BKT+WaL8dSHBMe8zTJro/oZD4Bgq6a0hsrRPPX/RbEsSDDLbxQ8/n/cKhSylhvbjw45SCDMagTGMv/zITdDuTF0Kuhy+RhPyYX59A8/WULj+iWrLn/bGLzHRWMMvNwH7qF7H1/M1Cjmyt9UFnC8tUNGhcw+Dz3wlOPwknBjOtjhZn6LiWixpeuayGOa1PDIqJWm0EJwJO2ANaFTj99FArwnRnYdUH7k0RRYip0GOPBj7yO9ev+HlDmJE1/TdS88eHQ9fdt1wyFp8xYU6d4Oq 6Hbj6vl6 gYuhBw2cvUQDorH91Uh1kg+yWDkk041BfKSpvmCstVO4QSJs2vUtOZnDaGq+74Cf/5aquMPvDfnT+Vtr49CFPew8kkBOr4w4haDy6Hb7PiR4hmVMPSRPKEbSDyDToWWUKIxA28zxl1ZKaGR+N1V0rt5IaJZvBM5+B1yOCdy2Saq/wml+f8tfNo7iAqarKk05ktwUaiSaBjXV3ZcsrbZmNcs/6sx62HYJfSuZ19Ygg1KlEHRkSv2Zmv3VsN7n2go2CoQbj/vby+iyMQVj6/1W46BgafmWf0Hjwlf8x0iLkWc7HJUk= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: yangerkun [ Upstream commit 64a7ce76fb901bf9f9c36cf5d681328fc0fd4b5a ] After we switch tmpfs dir operations from simple_dir_operations to simple_offset_dir_operations, every rename happened will fill new dentry to dest dir's maple tree(&SHMEM_I(inode)->dir_offsets->mt) with a free key starting with octx->newx_offset, and then set newx_offset equals to free key + 1. This will lead to infinite readdir combine with rename happened at the same time, which fail generic/736 in xfstests(detail show as below). 1. create 5000 files(1 2 3...) under one dir 2. call readdir(man 3 readdir) once, and get one entry 3. rename(entry, "TEMPFILE"), then rename("TEMPFILE", entry) 4. loop 2~3, until readdir return nothing or we loop too many times(tmpfs break test with the second condition) We choose the same logic what commit 9b378f6ad48cf ("btrfs: fix infinite directory reads") to fix it, record the last_index when we open dir, and do not emit the entry which index >= last_index. The file->private_data now used in offset dir can use directly to do this, and we also update the last_index when we llseek the dir file. Fixes: a2e459555c5f ("shmem: stable directory offsets") Signed-off-by: yangerkun Link: https://lore.kernel.org/r/20240731043835.1828697-1-yangerkun@huawei.com Reviewed-by: Chuck Lever [brauner: only update last_index after seek when offset is zero like Jan suggested] Signed-off-by: Christian Brauner Link: https://nvd.nist.gov/vuln/detail/CVE-2024-46701 [ cel: adjusted to apply to origin/linux-6.6.y ] Signed-off-by: Chuck Lever --- fs/libfs.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/fs/libfs.c b/fs/libfs.c index a87005c89534..b59ff0dfea1f 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -449,6 +449,14 @@ void simple_offset_destroy(struct offset_ctx *octx) xa_destroy(&octx->xa); } +static int offset_dir_open(struct inode *inode, struct file *file) +{ + struct offset_ctx *ctx = inode->i_op->get_offset_ctx(inode); + + file->private_data = (void *)ctx->next_offset; + return 0; +} + /** * offset_dir_llseek - Advance the read position of a directory descriptor * @file: an open directory whose position is to be updated @@ -462,6 +470,9 @@ void simple_offset_destroy(struct offset_ctx *octx) */ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence) { + struct inode *inode = file->f_inode; + struct offset_ctx *ctx = inode->i_op->get_offset_ctx(inode); + switch (whence) { case SEEK_CUR: offset += file->f_pos; @@ -475,8 +486,9 @@ static loff_t offset_dir_llseek(struct file *file, loff_t offset, int whence) } /* In this case, ->private_data is protected by f_pos_lock */ - file->private_data = NULL; - return vfs_setpos(file, offset, U32_MAX); + if (!offset) + file->private_data = (void *)ctx->next_offset; + return vfs_setpos(file, offset, LONG_MAX); } static struct dentry *offset_find_next(struct xa_state *xas) @@ -505,7 +517,7 @@ static bool offset_dir_emit(struct dir_context *ctx, struct dentry *dentry) inode->i_ino, fs_umode_to_dtype(inode->i_mode)); } -static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx) +static void offset_iterate_dir(struct inode *inode, struct dir_context *ctx, long last_index) { struct offset_ctx *so_ctx = inode->i_op->get_offset_ctx(inode); XA_STATE(xas, &so_ctx->xa, ctx->pos); @@ -514,17 +526,21 @@ static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx) while (true) { dentry = offset_find_next(&xas); if (!dentry) - return ERR_PTR(-ENOENT); + return; + + if (dentry2offset(dentry) >= last_index) { + dput(dentry); + return; + } if (!offset_dir_emit(ctx, dentry)) { dput(dentry); - break; + return; } dput(dentry); ctx->pos = xas.xa_index + 1; } - return NULL; } /** @@ -551,22 +567,19 @@ static void *offset_iterate_dir(struct inode *inode, struct dir_context *ctx) static int offset_readdir(struct file *file, struct dir_context *ctx) { struct dentry *dir = file->f_path.dentry; + long last_index = (long)file->private_data; lockdep_assert_held(&d_inode(dir)->i_rwsem); if (!dir_emit_dots(file, ctx)) return 0; - /* In this case, ->private_data is protected by f_pos_lock */ - if (ctx->pos == DIR_OFFSET_MIN) - file->private_data = NULL; - else if (file->private_data == ERR_PTR(-ENOENT)) - return 0; - file->private_data = offset_iterate_dir(d_inode(dir), ctx); + offset_iterate_dir(d_inode(dir), ctx, last_index); return 0; } const struct file_operations simple_offset_dir_operations = { + .open = offset_dir_open, .llseek = offset_dir_llseek, .iterate_shared = offset_readdir, .read = generic_read_dir,