Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp1420786imm; Sun, 15 Jul 2018 07:20:58 -0700 (PDT) X-Google-Smtp-Source: AAOMgpfgI1Zf2ao8b7zwdc4rLODJqT1phz/iz4dvXZRzGSxp/OlWdcwpc6Srl7AEoU74wLH89hHt X-Received: by 2002:a17:902:1081:: with SMTP id c1-v6mr13344601pla.153.1531664457978; Sun, 15 Jul 2018 07:20:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1531664457; cv=none; d=google.com; s=arc-20160816; b=azJjUBmia6/8a+BNn2ROqqHhvFLyaSyiPSNgw5rIMTLHdifWPyz+4oEYx8JjFu9L8f v4bYC+Np2TKTXZ+oge3D6WAcb2PdEDaPBv+flsyfWGR5RT5C5+x7/QKqR/m+kpiMkPrV felN/dUiiwTg3CfF8/H3Gdlkn+4IxgabK+1NYVgShovMv2AuLKjJ96WAs+kaW4iQkIC1 JPNOz6BQ74vlbx0PkPps6dR0VxvOaENsWYb3mpHSRwrxuiHT2x4+lB8WOanhNoJHrBN7 XuG2hgAQm5SuAPGtA95RYj/vrFL18mARnqwNiDl0/ykUyqwcPNm7yu3yAgrQnGm5Dh1a 6v/A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:message-id :in-reply-to:date:references:subject:cc:to:from :arc-authentication-results; bh=uzQyxARa0LXEvQFLHC3eNLxSLRmALhAeDx0m44Bq7YE=; b=hRaCXliPLPmWBDH8ZfKUgYv0H00ePj7lLa2XsTuv1bTAKcpSggTEq8nW1OGOswgE8a 4Sv+czUxjWsTET22pFfswirHfskf+KsMpyBLQuZSIG6+tSO8UzPidf2cr5xPDIqg01fK P7V9aGoF/p/gFaMjxNMlnMvgL9oDnOK7zBfR/zL04vLaItq43ivBX5auxCOdriReTCHM /TytJU/1bQk+FYJ+BKkES78oWTmeLHzBkRmAIrAepEPVepGxcdikDw8MHCMDqVgtjqBH gn07z02ThzK0Es1VP/Eqv79oFi0wazyIASrOCMXXXwbrhr/lJ8wHxaLdh+yZA24ikxBW 7X/A== 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 t9-v6si10821045plq.324.2018.07.15.07.20.42; Sun, 15 Jul 2018 07:20: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 S1726346AbeGOOnQ (ORCPT + 99 others); Sun, 15 Jul 2018 10:43:16 -0400 Received: from mail.parknet.co.jp ([210.171.160.6]:46020 "EHLO mail.parknet.co.jp" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726239AbeGOOnQ (ORCPT ); Sun, 15 Jul 2018 10:43:16 -0400 Received: from ibmpc.myhome.or.jp (server.parknet.ne.jp [210.171.168.39]) by mail.parknet.co.jp (Postfix) with ESMTPSA id D19F7197480; Sun, 15 Jul 2018 23:20:07 +0900 (JST) Received: from devron.myhome.or.jp (foobar@devron.myhome.or.jp [192.168.0.3]) by ibmpc.myhome.or.jp (8.15.2/8.15.2/Debian-11) with ESMTPS id w6FEK6o2007984 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 15 Jul 2018 23:20:07 +0900 Received: from devron.myhome.or.jp (foobar@localhost [127.0.0.1]) by devron.myhome.or.jp (8.15.2/8.15.2/Debian-11) with ESMTPS id w6FEK6YZ027459 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 15 Jul 2018 23:20:06 +0900 Received: (from hirofumi@localhost) by devron.myhome.or.jp (8.15.2/8.15.2/Submit) id w6FEK6IB027458; Sun, 15 Jul 2018 23:20:06 +0900 From: OGAWA Hirofumi To: Andrew Morton Cc: Anatoly Trosinenko , linux-kernel@vger.kernel.org Subject: Re: FAT: Operating on broken FAT FS causes the write syscall to return negative number not equal to -1 References: Date: Sun, 15 Jul 2018 23:20:06 +0900 In-Reply-To: (Anatoly Trosinenko's message of "Sat, 14 Jul 2018 15:24:17 +0300") Message-ID: <878t6c7f8p.fsf@mail.parknet.co.jp> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Anatoly Trosinenko writes: > How to reproduce: > 1) Compile v4.18-rc4 kernel with the attached config > 1) Unpack the attached FS image (128 Mb) and mount it as vfat to /mnt > 2) Compile and run vfat-bug.c > > What is expected: > `write` returns either -1 or small positive number. > > What happens: > The -13619152 aka 0xffffffffff303030 is returned. This patch returns better error (-EIO) for me. (But note, the corrupted FS image doesn't guarantee POSIX behavior.) Thanks. [PATCH] fat: Validate ->i_start before using On corrupted FATfs may have invalid ->i_start. To handle it, this checks ->i_start before using, and return proper error code. Signed-off-by: OGAWA Hirofumi --- fs/fat/cache.c | 19 ++++++++++++------- fs/fat/fat.h | 7 +++++++ fs/fat/fatent.c | 6 +++--- 3 files changed, 22 insertions(+), 10 deletions(-) diff -puN fs/fat/cache.c~fat-validate-i_start fs/fat/cache.c --- linux/fs/fat/cache.c~fat-validate-i_start 2018-07-15 23:03:25.167171670 +0900 +++ linux-hirofumi/fs/fat/cache.c 2018-07-15 23:03:25.171171666 +0900 @@ -225,7 +225,8 @@ static inline void cache_init(struct fat int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) { struct super_block *sb = inode->i_sb; - const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits; + struct msdos_sb_info *sbi = MSDOS_SB(sb); + const int limit = sb->s_maxbytes >> sbi->cluster_bits; struct fat_entry fatent; struct fat_cache_id cid; int nr; @@ -234,6 +235,12 @@ int fat_get_cluster(struct inode *inode, *fclus = 0; *dclus = MSDOS_I(inode)->i_start; + if (!fat_valid_entry(sbi, *dclus)) { + fat_fs_error_ratelimit(sb, + "%s: invalid start cluster (i_pos %lld, start %08x)", + __func__, MSDOS_I(inode)->i_pos, *dclus); + return -EIO; + } if (cluster == 0) return 0; @@ -250,9 +257,8 @@ int fat_get_cluster(struct inode *inode, /* prevent the infinite loop of cluster chain */ if (*fclus > limit) { fat_fs_error_ratelimit(sb, - "%s: detected the cluster chain loop" - " (i_pos %lld)", __func__, - MSDOS_I(inode)->i_pos); + "%s: detected the cluster chain loop (i_pos %lld)", + __func__, MSDOS_I(inode)->i_pos); nr = -EIO; goto out; } @@ -262,9 +268,8 @@ int fat_get_cluster(struct inode *inode, goto out; else if (nr == FAT_ENT_FREE) { fat_fs_error_ratelimit(sb, - "%s: invalid cluster chain (i_pos %lld)", - __func__, - MSDOS_I(inode)->i_pos); + "%s: invalid cluster chain (i_pos %lld)", + __func__, MSDOS_I(inode)->i_pos); nr = -EIO; goto out; } else if (nr == FAT_ENT_EOF) { diff -puN fs/fat/fat.h~fat-validate-i_start fs/fat/fat.h --- linux/fs/fat/fat.h~fat-validate-i_start 2018-07-15 23:03:25.168171670 +0900 +++ linux-hirofumi/fs/fat/fat.h 2018-07-15 23:03:25.171171666 +0900 @@ -348,6 +348,13 @@ static inline void fatent_brelse(struct fatent->fat_inode = NULL; } +static inline bool fat_valid_entry(struct msdos_sb_info *sbi, int entry) +{ + if (entry < FAT_START_ENT || sbi->max_cluster <= entry) + return false; + return true; +} + extern void fat_ent_access_init(struct super_block *sb); extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry); diff -puN fs/fat/fatent.c~fat-validate-i_start fs/fat/fatent.c --- linux/fs/fat/fatent.c~fat-validate-i_start 2018-07-15 23:03:25.169171668 +0900 +++ linux-hirofumi/fs/fat/fatent.c 2018-07-15 23:03:25.171171666 +0900 @@ -24,7 +24,7 @@ static void fat12_ent_blocknr(struct sup { struct msdos_sb_info *sbi = MSDOS_SB(sb); int bytes = entry + (entry >> 1); - WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry); + WARN_ON(!fat_valid_entry(sbi, entry)); *offset = bytes & (sb->s_blocksize - 1); *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits); } @@ -34,7 +34,7 @@ static void fat_ent_blocknr(struct super { struct msdos_sb_info *sbi = MSDOS_SB(sb); int bytes = (entry << sbi->fatent_shift); - WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry); + WARN_ON(!fat_valid_entry(sbi, entry)); *offset = bytes & (sb->s_blocksize - 1); *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits); } @@ -354,7 +354,7 @@ int fat_ent_read(struct inode *inode, st int err, offset; sector_t blocknr; - if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { + if (!fat_valid_entry(sbi, entry)) { fatent_brelse(fatent); fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry); return -EIO; _ -- OGAWA Hirofumi