Received: by 2002:a05:6a10:2726:0:0:0:0 with SMTP id ib38csp945401pxb; Wed, 6 Apr 2022 05:02:18 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxHG8ZnQtFI3Vyi9IfXbJrAvaZIDMNewEhBNP/mz0OlNXC6A713acDRSGqEqKeKvM6Mk78E X-Received: by 2002:a17:902:db0e:b0:154:8682:c1db with SMTP id m14-20020a170902db0e00b001548682c1dbmr8288978plx.128.1649246537784; Wed, 06 Apr 2022 05:02:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1649246537; cv=none; d=google.com; s=arc-20160816; b=ee0jjeatk9Gt0YpYs92U35QVAGl83JVpsoakdPTCngnFvxdXpYoJuQFk6VXCYwshtB /FbS9b9n7Emu5bsBNoI0XvzpoY1K9Rjzf/HlSh8wgEgKEaDa1MrJpc62UiKACbsn+9lA kacSJvvmYtQ8/NPfSKWHpghFp4u1FOyS8je1PekSGRFuDqKlPWkqpg+QmVlwVLB9cboo Y3nmqs7MUaVaLG+cWKjvCcUsyWLDOdh/mQevZJtAL8fpA8yrm+N+9zcVGa6ojZtKibsC s/8x50EtCBY3zV1rM8XtvySCcEQIsq6qVl7AuAt6IwMKGqIIt+IsDXWQTGojQGmNZOkI NL9w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=2MiMFKhThC8FLuquIhStF5XYXCgoY1R0Op8w8o2o1ms=; b=VmIxseccP91ZGv/9/34kM5kWn024CsCbbtDIciG5qWlfd046EqBD0rOmwf2v3UR5h+ rHBPuX8p3Zq4EISgBvT8qYcH4sueCDs9p0xXBmvLgHmJt3DMAHmPS/KhjI9tvVshrqxf zyu6NpIBlG80SVB/ElwWZWKh9NoZDKIAegntOTDQWsUsWesbZGmQW9x4ZS1sw+ypgBfF 69wuqc1nDIjbquGPplayu1DnfsUvaDSrbUeig5qF8dHZYxiXZ02J3K8h2xGP9KTk3CZm KukjK3jxtQQYl+D3fUmGmwN1j/S5jDkN/AFRhBmVgbJ8rbEmCe9AkhuoAPZ95FF5l505 1mnw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=zMtrH3Wb; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id h6-20020aa796c6000000b004fa3a8e006fsi15066988pfq.294.2022.04.06.05.02.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 Apr 2022 05:02:17 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=zMtrH3Wb; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 3F3F8451775; Wed, 6 Apr 2022 03:28:53 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1391418AbiDEWSP (ORCPT + 99 others); Tue, 5 Apr 2022 18:18:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52344 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1353975AbiDEKKQ (ORCPT ); Tue, 5 Apr 2022 06:10:16 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 85C87C4E3A; Tue, 5 Apr 2022 02:56:02 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 1609D616D7; Tue, 5 Apr 2022 09:56:02 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 25859C385A1; Tue, 5 Apr 2022 09:56:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1649152561; bh=g+BIlF8aVqHMQOFVwronpp1v3eo4iKq0jRClRPv6cIg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=zMtrH3WbshfEJzOckV4BYePrkSOFzjt+4xNDSiiJ5CynqJAWLbSZo3aXNDscl+FZ5 UY+P8SADv0sauejqLRn96HATyGpd0hEqjfNiqakJ/og8ajyrrUsjF40qZj6qUu6GER +rFilZiwegn4KALMVSD7fDBzcg0ryCWfZvyohXCw= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Zhihao Cheng , Richard Weinberger Subject: [PATCH 5.15 820/913] ubifs: Fix ui->dirty race between do_tmpfile() and writeback work Date: Tue, 5 Apr 2022 09:31:22 +0200 Message-Id: <20220405070404.410883696@linuxfoundation.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220405070339.801210740@linuxfoundation.org> References: <20220405070339.801210740@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RDNS_NONE,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Zhihao Cheng commit 60eb3b9c9f11206996f57cb89521824304b305ad upstream. 'ui->dirty' is not protected by 'ui_mutex' in function do_tmpfile() which may race with ubifs_write_inode[wb_workfn] to access/update 'ui->dirty', finally dirty space is released twice. open(O_TMPFILE) wb_workfn do_tmpfile ubifs_budget_space(ino_req = { .dirtied_ino = 1}) d_tmpfile // mark inode(tmpfile) dirty ubifs_jnl_update // without holding tmpfile's ui_mutex mark_inode_clean(ui) if (ui->dirty) ubifs_release_dirty_inode_budget(ui) // release first time ubifs_write_inode mutex_lock(&ui->ui_mutex) ubifs_release_dirty_inode_budget(ui) // release second time mutex_unlock(&ui->ui_mutex) ui->dirty = 0 Run generic/476 can reproduce following message easily (See reproducer in [Link]): UBIFS error (ubi0:0 pid 2578): ubifs_assert_failed [ubifs]: UBIFS assert failed: c->bi.dd_growth >= 0, in fs/ubifs/budget.c:554 UBIFS warning (ubi0:0 pid 2578): ubifs_ro_mode [ubifs]: switched to read-only mode, error -22 Workqueue: writeback wb_workfn (flush-ubifs_0_0) Call Trace: ubifs_ro_mode+0x54/0x60 [ubifs] ubifs_assert_failed+0x4b/0x80 [ubifs] ubifs_release_budget+0x468/0x5a0 [ubifs] ubifs_release_dirty_inode_budget+0x53/0x80 [ubifs] ubifs_write_inode+0x121/0x1f0 [ubifs] ... wb_workfn+0x283/0x7b0 Fix it by holding tmpfile ubifs inode lock during ubifs_jnl_update(). Similar problem exists in whiteout renaming, but previous fix("ubifs: Rename whiteout atomically") has solved the problem. Fixes: 474b93704f32163 ("ubifs: Implement O_TMPFILE") Link: https://bugzilla.kernel.org/show_bug.cgi?id=214765 Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/dir.c | 60 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -397,6 +397,32 @@ out_free: return ERR_PTR(err); } +/** + * lock_2_inodes - a wrapper for locking two UBIFS inodes. + * @inode1: first inode + * @inode2: second inode + * + * We do not implement any tricks to guarantee strict lock ordering, because + * VFS has already done it for us on the @i_mutex. So this is just a simple + * wrapper function. + */ +static void lock_2_inodes(struct inode *inode1, struct inode *inode2) +{ + mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); + mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); +} + +/** + * unlock_2_inodes - a wrapper for unlocking two UBIFS inodes. + * @inode1: first inode + * @inode2: second inode + */ +static void unlock_2_inodes(struct inode *inode1, struct inode *inode2) +{ + mutex_unlock(&ubifs_inode(inode2)->ui_mutex); + mutex_unlock(&ubifs_inode(inode1)->ui_mutex); +} + static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, struct dentry *dentry, umode_t mode) { @@ -404,7 +430,7 @@ static int ubifs_tmpfile(struct user_nam struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1}; struct ubifs_budget_req ino_req = { .dirtied_ino = 1 }; - struct ubifs_inode *ui, *dir_ui = ubifs_inode(dir); + struct ubifs_inode *ui; int err, instantiated = 0; struct fscrypt_name nm; @@ -452,18 +478,18 @@ static int ubifs_tmpfile(struct user_nam instantiated = 1; mutex_unlock(&ui->ui_mutex); - mutex_lock(&dir_ui->ui_mutex); + lock_2_inodes(dir, inode); err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0); if (err) goto out_cancel; - mutex_unlock(&dir_ui->ui_mutex); + unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); return 0; out_cancel: - mutex_unlock(&dir_ui->ui_mutex); + unlock_2_inodes(dir, inode); out_inode: make_bad_inode(inode); if (!instantiated) @@ -690,32 +716,6 @@ static int ubifs_dir_release(struct inod return 0; } -/** - * lock_2_inodes - a wrapper for locking two UBIFS inodes. - * @inode1: first inode - * @inode2: second inode - * - * We do not implement any tricks to guarantee strict lock ordering, because - * VFS has already done it for us on the @i_mutex. So this is just a simple - * wrapper function. - */ -static void lock_2_inodes(struct inode *inode1, struct inode *inode2) -{ - mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); - mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); -} - -/** - * unlock_2_inodes - a wrapper for unlocking two UBIFS inodes. - * @inode1: first inode - * @inode2: second inode - */ -static void unlock_2_inodes(struct inode *inode1, struct inode *inode2) -{ - mutex_unlock(&ubifs_inode(inode2)->ui_mutex); - mutex_unlock(&ubifs_inode(inode1)->ui_mutex); -} - static int ubifs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) {