Received: by 2002:a25:6193:0:0:0:0:0 with SMTP id v141csp3204124ybb; Sun, 22 Mar 2020 18:17:57 -0700 (PDT) X-Google-Smtp-Source: ADFU+vuEiYWNERLwE2ooq4MU4fFuxUa22sqrxIKbsJSGngQRNXXfdlssMrT/B5iGE0iBwuWNR0Pc X-Received: by 2002:a54:4614:: with SMTP id p20mr917025oip.48.1584926277263; Sun, 22 Mar 2020 18:17:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1584926277; cv=none; d=google.com; s=arc-20160816; b=t1R5FdsLY/pQAsE+0Mu1RlYBvT4mFEkeHs/dUAuj0r6yA6FaDekq/TMyG8x/ze1kyR 36NDs8y+8EDqMx1J4oCmYg+u4ryupQlCueLsQz1qb2xF2OrQntxe0fMHkIL1Ay4gbu1Q f+iNhIYgOJwHZ3INMwbhnFoqY4zjepNqh7iO0UlpI79yL6HM9lUJwN2hNdWqcZo+IgZ4 V3A44913pgHZWaOvNAbw9f6NDA+G1evVgELcmGeocwMg1l3OM/G5lBCt6aqMIjNd7Jr4 gy+cYWqyvMn+beWIy3AiuGf/8Osrh0TXc+FJoWQ6rDa3BVOsqG2k0jKcldQ3LOG7nAyY 8NKw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:to:subject; bh=rR5apMUQEGlPoG7yU/zbq+LO60gsXTjpffYwxxSbhms=; b=E7BigVTI3Q7vAAxKt/Vz5ykWLY0nPM5PcbKqRte86dpkhDjfTiCkuIIFucOqpAGVSv q/mXp/omcmPzNbJdJLqD+kfX1RHkQU995tmc+qHl0Ov34hBdloMk5g20Q4HvJzFFCdi/ 8IduyzvKuH73vsmMdh7Kmmf7m/s6rc/lmboX5yxvw5N/m1u1ev03sAs2aXmM1+0sLVnX LTr0Xi05+471Wb5wzDQHUMWb2IdS0UgZ8EkU+rgun/k04Q4fxTdbesqxy0sjKMbjMIcz ej8/lOZxE6ssUm+IoGHQp6lVVjSaWaODsDTmfPu9dW95p6Z5HPwdK0aqfyHDfqpU1j1V ZlpA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j84si6836719oia.126.2020.03.22.18.17.44; Sun, 22 Mar 2020 18:17:57 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726946AbgCWBPo (ORCPT + 99 others); Sun, 22 Mar 2020 21:15:44 -0400 Received: from szxga05-in.huawei.com ([45.249.212.191]:12171 "EHLO huawei.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726843AbgCWBPo (ORCPT ); Sun, 22 Mar 2020 21:15:44 -0400 Received: from DGGEMS404-HUB.china.huawei.com (unknown [172.30.72.58]) by Forcepoint Email with ESMTP id 0FC0C8D054AAEDF270BF; Mon, 23 Mar 2020 09:15:41 +0800 (CST) Received: from [10.134.22.195] (10.134.22.195) by smtp.huawei.com (10.3.19.204) with Microsoft SMTP Server (TLS) id 14.3.487.0; Mon, 23 Mar 2020 09:15:40 +0800 Subject: Re: [PATCH] f2fs: fix potential .flags overflow on 32bit architecture To: =?UTF-8?Q?Ond=c5=99ej_Jirman?= , Chao Yu , , , References: <20200322101327.5979-1-chao@kernel.org> <20200322121434.i2jea6o5tzanip7z@core.my.home> <47c71fe9-e168-8080-d0ed-2cfaa9a77e5e@kernel.org> <20200322153014.czpca7ozhfy4ctdh@core.my.home> From: Chao Yu Message-ID: <70f992f5-54f7-bd09-2b27-f418da51341e@huawei.com> Date: Mon, 23 Mar 2020 09:15:39 +0800 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1 MIME-Version: 1.0 In-Reply-To: <20200322153014.czpca7ozhfy4ctdh@core.my.home> Content-Type: text/plain; charset="utf-8" Content-Language: en-US Content-Transfer-Encoding: 8bit X-Originating-IP: [10.134.22.195] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 2020/3/22 23:30, Ondřej Jirman wrote: > On Sun, Mar 22, 2020 at 09:18:56PM +0800, Chao Yu wrote: >> Hi, >> >> On 2020-3-22 20:14, Ondřej Jirman wrote: >>> Hello, >>> >>> On Sun, Mar 22, 2020 at 06:13:27PM +0800, Chao Yu wrote: >>>> From: Chao Yu >>>> >>>> f2fs_inode_info.flags is unsigned long variable, it has 32 bits >>>> in 32bit architecture, since we introduced FI_MMAP_FILE flag >>>> when we support data compression, we may access memory cross >>>> the border of .flags field, corrupting .i_sem field, result in >>>> below deadlock. >>>> >>>> To fix this issue, let's introduce .extra_flags to grab extra >>>> space to store those new flags. >>>> >>>> Call Trace: >>>> __schedule+0x8d0/0x13fc >>>> ? mark_held_locks+0xac/0x100 >>>> schedule+0xcc/0x260 >>>> rwsem_down_write_slowpath+0x3ab/0x65d >>>> down_write+0xc7/0xe0 >>>> f2fs_drop_nlink+0x3d/0x600 [f2fs] >>>> f2fs_delete_inline_entry+0x300/0x440 [f2fs] >>>> f2fs_delete_entry+0x3a1/0x7f0 [f2fs] >>>> f2fs_unlink+0x500/0x790 [f2fs] >>>> vfs_unlink+0x211/0x490 >>>> do_unlinkat+0x483/0x520 >>>> sys_unlink+0x4a/0x70 >>>> do_fast_syscall_32+0x12b/0x683 >>>> entry_SYSENTER_32+0xaa/0x102 >>>> >>>> Fixes: 4c8ff7095bef ("f2fs: support data compression") >>>> Signed-off-by: Chao Yu >>>> --- >>>> fs/f2fs/f2fs.h | 26 ++++++++++++++++++++------ >>>> fs/f2fs/inode.c | 1 + >>>> 2 files changed, 21 insertions(+), 6 deletions(-) >>>> >>>> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h >>>> index fcafa68212eb..fcd22df2e9ca 100644 >>>> --- a/fs/f2fs/f2fs.h >>>> +++ b/fs/f2fs/f2fs.h >>>> @@ -695,6 +695,7 @@ struct f2fs_inode_info { >>>> >>>> /* Use below internally in f2fs*/ >>>> unsigned long flags; /* use to pass per-file flags */ >>>> + unsigned long extra_flags; /* extra flags */ >>>> struct rw_semaphore i_sem; /* protect fi info */ >>>> atomic_t dirty_pages; /* # of dirty pages */ >>>> f2fs_hash_t chash; /* hash value of given file name */ >>>> @@ -2569,7 +2570,7 @@ enum { >>>> }; >>>> >>>> static inline void __mark_inode_dirty_flag(struct inode *inode, >>>> - int flag, bool set) >>>> + unsigned long long flag, bool set) >>>> { >>>> switch (flag) { >>>> case FI_INLINE_XATTR: >>>> @@ -2588,20 +2589,33 @@ static inline void __mark_inode_dirty_flag(struct inode *inode, >>>> >>>> static inline void set_inode_flag(struct inode *inode, int flag) >>>> { >>>> - if (!test_bit(flag, &F2FS_I(inode)->flags)) >>>> - set_bit(flag, &F2FS_I(inode)->flags); >>>> + if ((1 << flag) <= sizeof(unsigned long)) { >>> >>> ^ this is wrong. Maybe you meant flag <= BITS_PER_LONG >> >> Oh, my bad, I meant that, thanks for pointing out this. :) >> >>> >>> And ditto for the same checks below. Maybe you can make flags an array of >>> BIT_WORD(max_flag_value) + 1 and skip the branches altogether? > > I've found maybe a clearer macro for this: > > https://elixir.bootlin.com/linux/latest/source/include/linux/bitops.h#L15 > > BITS_TO_LONGS(nr) More clean, thanks, will send v3 soon. Thanks, > > But it takes the number of bits in the bitmap, which would be > "max_flag_value + 1". > > regards, > o. > >> That will be better, let me revise this patch. >> >> Thanks, >> >>> >>> thank you and regards, >>> o. >>> >>>> + if (!test_bit(flag, &F2FS_I(inode)->flags)) >>>> + set_bit(flag, &F2FS_I(inode)->flags); >>>> + } else { >>>> + if (!test_bit(flag - 32, &F2FS_I(inode)->extra_flags)) >>>> + set_bit(flag - 32, &F2FS_I(inode)->extra_flags); >>>> + } >>>> __mark_inode_dirty_flag(inode, flag, true); >>>> } >>>> >>>> static inline int is_inode_flag_set(struct inode *inode, int flag) >>>> { >>>> - return test_bit(flag, &F2FS_I(inode)->flags); >>>> + if ((1 << flag) <= sizeof(unsigned long)) >>>> + return test_bit(flag, &F2FS_I(inode)->flags); >>>> + else >>>> + return test_bit(flag - 32, &F2FS_I(inode)->extra_flags); >>>> } >>>> >>>> static inline void clear_inode_flag(struct inode *inode, int flag) >>>> { >>>> - if (test_bit(flag, &F2FS_I(inode)->flags)) >>>> - clear_bit(flag, &F2FS_I(inode)->flags); >>>> + if ((1 << flag) <= sizeof(unsigned long)) { >>>> + if (test_bit(flag, &F2FS_I(inode)->flags)) >>>> + clear_bit(flag, &F2FS_I(inode)->flags); >>>> + } else { >>>> + if (test_bit(flag - 32, &F2FS_I(inode)->extra_flags)) >>>> + clear_bit(flag - 32, &F2FS_I(inode)->extra_flags); >>>> + } >>>> __mark_inode_dirty_flag(inode, flag, false); >>>> } >>>> >>>> diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c >>>> index 44e08bf2e2b4..ca924d7e0e30 100644 >>>> --- a/fs/f2fs/inode.c >>>> +++ b/fs/f2fs/inode.c >>>> @@ -363,6 +363,7 @@ static int do_read_inode(struct inode *inode) >>>> if (S_ISREG(inode->i_mode)) >>>> fi->i_flags &= ~F2FS_PROJINHERIT_FL; >>>> fi->flags = 0; >>>> + fi->extra_flags = 0; >>>> fi->i_advise = ri->i_advise; >>>> fi->i_pino = le32_to_cpu(ri->i_pino); >>>> fi->i_dir_level = ri->i_dir_level; >>>> -- >>>> 2.22.0 >>>> > . >