Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp4026347ybl; Mon, 3 Feb 2020 11:06:25 -0800 (PST) X-Google-Smtp-Source: APXvYqw9GU+21Icfy/RJWfEz/H98GS+PoCGIF9sGtBMaxRKdlJ2PXdq6u86n1LfppswSMNIZ9c6g X-Received: by 2002:a9d:7f8d:: with SMTP id t13mr17703439otp.175.1580756785516; Mon, 03 Feb 2020 11:06:25 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1580756785; cv=none; d=google.com; s=arc-20160816; b=k5JYU8qGYL8xtsNYNLq8FhTCb76xChQcqYJHU7EZ9UYYzaFReA/CAwZX3rgfJcVM/R OSXFU9DbR3VxQmoUxYPjq9KSoeFjr9k4tu8QG7rmmJqpmkUcnsFNlcWpjDYp7N2MjC+P nYiRgqgCvbi4lmYGcGlkY75Ewtq447JQQ9X+LuB0/B8sQRlo48wAfKdvLrzmFv6r7g/H 3EAbukvUbM6+jGEufWx+jWI3x4b+QUt+B5SNowH9wffl7g3O2Z8qXWeZTZ2OBnuY3ooC YPvfInbZmc+VOcJUkAIyhy1vC9Fv/Z0dKHH2RiEGdtDmw7BJt2bVXAHy+VNSJTDNt8sw AcFA== 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:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=txNa1FuA50Tspy+Gs/9SCmn8fITaJBi3dPjk0D4Mp5s=; b=SaGDzzGuOnr45uK59oLC8/A4ya/wAy5tgef8PURwU2/gHH+JzS86byhVyizG9qqvYv oVorzXrpeOG7eepaBnOSdE1UCBV/jXsa8t80vdgegV+4kQKiv1s+82pkFRvpxyBZPzK0 zLIyqz7s2WHi8Ux7zem7qR/7x5fSSKuO/5xnnzhv8szEDVDJTfbl5i2y8dX6ZuwXkBDK HdJoefBlunido5dvnETnVVia5ybEZHxmzVa1dXO24vlScepEvx6FKd8Zv/vA9EpdeMIn L2JCUmtJ1oq5EIGljrXLLjMjYfKVW0A7jgYkacY5WWUPZaEVrRhnr7vTdN+1erm2Mow6 E5QA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=IhlTT6TY; 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 n11si9367730otk.290.2020.02.03.11.06.13; Mon, 03 Feb 2020 11:06:25 -0800 (PST) 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; dkim=pass header.i=@kernel.org header.s=default header.b=IhlTT6TY; 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 S1730102AbgBCQdC (ORCPT + 99 others); Mon, 3 Feb 2020 11:33:02 -0500 Received: from mail.kernel.org ([198.145.29.99]:46800 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730504AbgBCQc6 (ORCPT ); Mon, 3 Feb 2020 11:32:58 -0500 Received: from localhost (unknown [104.132.45.99]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 923A72051A; Mon, 3 Feb 2020 16:32:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1580747578; bh=s79AFNuWI6DuIPhPDSa54BwdoM9eLCk/ctOOg7bL6uQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IhlTT6TYAYiiW22e56YOyW17R9bsP7RWtv5fiy0y78+Utc//s4r+27uDQqbQIypcc rQECfynKfkl7zS5Mwqn0enYD6djoWEWEpgYTUfcyZOW+xMY7o2miIxo0kgwcDLjuOV JbBS4OtyeBCqtGn4dO8V8pF67yMWnPVv3s/M16D4= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, stable@kernel.org, Theodore Tso , Zubin Mithra , syzbot+4a39a025912b265cacef@syzkaller.appspotmail.com Subject: [PATCH 4.19 12/70] ext4: validate the debug_want_extra_isize mount option at parse time Date: Mon, 3 Feb 2020 16:19:24 +0000 Message-Id: <20200203161914.334164647@linuxfoundation.org> X-Mailer: git-send-email 2.25.0 In-Reply-To: <20200203161912.158976871@linuxfoundation.org> References: <20200203161912.158976871@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Theodore Ts'o commit 9803387c55f7d2ce69aa64340c5fdc6b3027dbc8 upstream. Instead of setting s_want_extra_size and then making sure that it is a valid value afterwards, validate the field before we set it. This avoids races and other problems when remounting the file system. Link: https://lore.kernel.org/r/20191215063020.GA11512@mit.edu Cc: stable@kernel.org Signed-off-by: Theodore Ts'o Reported-and-tested-by: syzbot+4a39a025912b265cacef@syzkaller.appspotmail.com Signed-off-by: Zubin Mithra Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 127 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 66 insertions(+), 61 deletions(-) --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1842,6 +1842,13 @@ static int handle_mount_opt(struct super arg = JBD2_DEFAULT_MAX_COMMIT_AGE; sbi->s_commit_interval = HZ * arg; } else if (token == Opt_debug_want_extra_isize) { + if ((arg & 1) || + (arg < 4) || + (arg > (sbi->s_inode_size - EXT4_GOOD_OLD_INODE_SIZE))) { + ext4_msg(sb, KERN_ERR, + "Invalid want_extra_isize %d", arg); + return -1; + } sbi->s_want_extra_isize = arg; } else if (token == Opt_max_batch_time) { sbi->s_max_batch_time = arg; @@ -3513,40 +3520,6 @@ int ext4_calculate_overhead(struct super return 0; } -static void ext4_clamp_want_extra_isize(struct super_block *sb) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - unsigned def_extra_isize = sizeof(struct ext4_inode) - - EXT4_GOOD_OLD_INODE_SIZE; - - if (sbi->s_inode_size == EXT4_GOOD_OLD_INODE_SIZE) { - sbi->s_want_extra_isize = 0; - return; - } - if (sbi->s_want_extra_isize < 4) { - sbi->s_want_extra_isize = def_extra_isize; - if (ext4_has_feature_extra_isize(sb)) { - if (sbi->s_want_extra_isize < - le16_to_cpu(es->s_want_extra_isize)) - sbi->s_want_extra_isize = - le16_to_cpu(es->s_want_extra_isize); - if (sbi->s_want_extra_isize < - le16_to_cpu(es->s_min_extra_isize)) - sbi->s_want_extra_isize = - le16_to_cpu(es->s_min_extra_isize); - } - } - /* Check if enough inode space is available */ - if ((sbi->s_want_extra_isize > sbi->s_inode_size) || - (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize > - sbi->s_inode_size)) { - sbi->s_want_extra_isize = def_extra_isize; - ext4_msg(sb, KERN_INFO, - "required extra inode space not available"); - } -} - static void ext4_set_resv_clusters(struct super_block *sb) { ext4_fsblk_t resv_clusters; @@ -3754,6 +3727,65 @@ static int ext4_fill_super(struct super_ */ sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT; + if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { + sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE; + sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO; + } else { + sbi->s_inode_size = le16_to_cpu(es->s_inode_size); + sbi->s_first_ino = le32_to_cpu(es->s_first_ino); + if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) { + ext4_msg(sb, KERN_ERR, "invalid first ino: %u", + sbi->s_first_ino); + goto failed_mount; + } + if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || + (!is_power_of_2(sbi->s_inode_size)) || + (sbi->s_inode_size > blocksize)) { + ext4_msg(sb, KERN_ERR, + "unsupported inode size: %d", + sbi->s_inode_size); + goto failed_mount; + } + /* + * i_atime_extra is the last extra field available for + * [acm]times in struct ext4_inode. Checking for that + * field should suffice to ensure we have extra space + * for all three. + */ + if (sbi->s_inode_size >= offsetof(struct ext4_inode, i_atime_extra) + + sizeof(((struct ext4_inode *)0)->i_atime_extra)) { + sb->s_time_gran = 1; + } else { + sb->s_time_gran = NSEC_PER_SEC; + } + } + if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { + sbi->s_want_extra_isize = sizeof(struct ext4_inode) - + EXT4_GOOD_OLD_INODE_SIZE; + if (ext4_has_feature_extra_isize(sb)) { + unsigned v, max = (sbi->s_inode_size - + EXT4_GOOD_OLD_INODE_SIZE); + + v = le16_to_cpu(es->s_want_extra_isize); + if (v > max) { + ext4_msg(sb, KERN_ERR, + "bad s_want_extra_isize: %d", v); + goto failed_mount; + } + if (sbi->s_want_extra_isize < v) + sbi->s_want_extra_isize = v; + + v = le16_to_cpu(es->s_min_extra_isize); + if (v > max) { + ext4_msg(sb, KERN_ERR, + "bad s_min_extra_isize: %d", v); + goto failed_mount; + } + if (sbi->s_want_extra_isize < v) + sbi->s_want_extra_isize = v; + } + } + if (sbi->s_es->s_mount_opts[0]) { char *s_mount_opts = kstrndup(sbi->s_es->s_mount_opts, sizeof(sbi->s_es->s_mount_opts), @@ -3955,29 +3987,6 @@ static int ext4_fill_super(struct super_ has_huge_files); sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files); - if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { - sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE; - sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO; - } else { - sbi->s_inode_size = le16_to_cpu(es->s_inode_size); - sbi->s_first_ino = le32_to_cpu(es->s_first_ino); - if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) { - ext4_msg(sb, KERN_ERR, "invalid first ino: %u", - sbi->s_first_ino); - goto failed_mount; - } - if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || - (!is_power_of_2(sbi->s_inode_size)) || - (sbi->s_inode_size > blocksize)) { - ext4_msg(sb, KERN_ERR, - "unsupported inode size: %d", - sbi->s_inode_size); - goto failed_mount; - } - if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) - sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2); - } - sbi->s_desc_size = le16_to_cpu(es->s_desc_size); if (ext4_has_feature_64bit(sb)) { if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT || @@ -4421,8 +4430,6 @@ no_journal: } else if (ret) goto failed_mount4a; - ext4_clamp_want_extra_isize(sb); - ext4_set_resv_clusters(sb); err = ext4_setup_system_zone(sb); @@ -5207,8 +5214,6 @@ static int ext4_remount(struct super_blo goto restore_opts; } - ext4_clamp_want_extra_isize(sb); - if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^ test_opt(sb, JOURNAL_CHECKSUM)) { ext4_msg(sb, KERN_ERR, "changing journal_checksum "