Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp2292906pxb; Thu, 11 Feb 2021 08:50:16 -0800 (PST) X-Google-Smtp-Source: ABdhPJzQzKkN2RX8xAP9hh9BNZdNTkn9ZrJPdwIVKoTS5ACUMW0Q3ugysxgJOna1j0o7NMz/MYjY X-Received: by 2002:a05:6402:2694:: with SMTP id w20mr9244068edd.200.1613062216395; Thu, 11 Feb 2021 08:50:16 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1613062216; cv=none; d=google.com; s=arc-20160816; b=YcA+q3i3Xsk/zQj/UNQ5Ffy9q9YweR7mj6AjCb7AKO2varG4+XJMJwhYwWx2oonfgM djHDsAZd6JmdopRmr9+xsi4qw5QeNmGY9z8wVODp5qYJvQ5LybV3e3U5F3Z+5MWAunFX bAdYs6MLvbx/kUERhvzHbY6U2XqVl4RqbbnlBvi95Sa2e0Qbq/RgxY3YNz5b+KH1C3Vx fMVwXBLAzjKJxiUV6mid7g0beFjwIrZMLgPGdpEsIVVWHj1iFJx/AdDKpOZGBCxUoCxL VuqDXY9adHDU/h3ZXnn/oBTWPWiUswBZ+2fZ1n/RHWqyZaIH2qa7d/s0hR1wymPTG/oR QqfA== 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=eGLEAu0OeX6JZtuTQwyzKs7BlJNQ9135TMX9wNyQ8kA=; b=EWuhJdjt7vZnCgTkDV/IP08jBHq3x1BovqSNZiar0sOX0gxcfA2c4UjxiQ4hnDiCPf niQlT+PhpRl1REBgBr9c3jbrk0oZFGjAI+rWmVDUt30eYGmsPmGFeehGSSBJZieuNmh5 w5T8UL45RIO1QCLrNSjeaeVlHLLRFMl37poYbvBMQQUL07/mfaPnvK/kiLLwzgu/pH7h cfu8VBcWsgsmnc41IhKcqk94lqjp7g9ThNhJe/4/Ajja4dIht81NdiE41F3628ZjN2/Z 69EM7L4qEyibHeco4AbC3zMke2fuokQCcmxrEg7DsfjCHtgVhn8ftlUb1dJZEKsk2noF nPfw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=1p3k6+Kt; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.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 vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id i17si4262976ejf.482.2021.02.11.08.49.52; Thu, 11 Feb 2021 08:50:16 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=1p3k6+Kt; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.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: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231209AbhBKQtA (ORCPT + 99 others); Thu, 11 Feb 2021 11:49:00 -0500 Received: from mail.kernel.org ([198.145.29.99]:57468 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229978AbhBKPjl (ORCPT ); Thu, 11 Feb 2021 10:39:41 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 7EBB364EF9; Thu, 11 Feb 2021 15:05:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1613055903; bh=z8VsTENTcOYY9ghCuzRmLxfRNzh7gODxzfRycroZV3g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=1p3k6+KtV24eg8JWpx1mWkJ8f/qShbg+5+TcRND0NXbvvOcpSq3+zmV2rlhDefvqE wji3eJ8vUqdr/ZYNGFapsEtOHJ/13NwniFcQH6zHOQKcuWJgrLQpqlKF25nQkExU7y LQwRk/ICG3vRes/YMTk8YIWa1SXDq2OIO+Ov+1hY= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Phillip Lougher , syzbot+b06d57ba83f604522af2@syzkaller.appspotmail.com, syzbot+c021ba012da41ee9807c@syzkaller.appspotmail.com, syzbot+5024636e8b5fd19f0f19@syzkaller.appspotmail.com, syzbot+bcbc661df46657d0fa4f@syzkaller.appspotmail.com, Andrew Morton , Linus Torvalds Subject: [PATCH 5.10 52/54] squashfs: add more sanity checks in id lookup Date: Thu, 11 Feb 2021 16:02:36 +0100 Message-Id: <20210211150155.143838798@linuxfoundation.org> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210211150152.885701259@linuxfoundation.org> References: <20210211150152.885701259@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Phillip Lougher commit f37aa4c7366e23f91b81d00bafd6a7ab54e4a381 upstream. Sysbot has reported a number of "slab-out-of-bounds reads" and "use-after-free read" errors which has been identified as being caused by a corrupted index value read from the inode. This could be because the metadata block is uncompressed, or because the "compression" bit has been corrupted (turning a compressed block into an uncompressed block). This patch adds additional sanity checks to detect this, and the following corruption. 1. It checks against corruption of the ids count. This can either lead to a larger table to be read, or a smaller than expected table to be read. In the case of a too large ids count, this would often have been trapped by the existing sanity checks, but this patch introduces a more exact check, which can identify too small values. 2. It checks the contents of the index table for corruption. Link: https://lkml.kernel.org/r/20210204130249.4495-3-phillip@squashfs.org.uk Signed-off-by: Phillip Lougher Reported-by: syzbot+b06d57ba83f604522af2@syzkaller.appspotmail.com Reported-by: syzbot+c021ba012da41ee9807c@syzkaller.appspotmail.com Reported-by: syzbot+5024636e8b5fd19f0f19@syzkaller.appspotmail.com Reported-by: syzbot+bcbc661df46657d0fa4f@syzkaller.appspotmail.com Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/squashfs/id.c | 40 ++++++++++++++++++++++++++++++++-------- fs/squashfs/squashfs_fs_sb.h | 1 + fs/squashfs/super.c | 6 +++--- fs/squashfs/xattr.h | 10 +++++++++- 4 files changed, 45 insertions(+), 12 deletions(-) --- a/fs/squashfs/id.c +++ b/fs/squashfs/id.c @@ -35,10 +35,15 @@ int squashfs_get_id(struct super_block * struct squashfs_sb_info *msblk = sb->s_fs_info; int block = SQUASHFS_ID_BLOCK(index); int offset = SQUASHFS_ID_BLOCK_OFFSET(index); - u64 start_block = le64_to_cpu(msblk->id_table[block]); + u64 start_block; __le32 disk_id; int err; + if (index >= msblk->ids) + return -EINVAL; + + start_block = le64_to_cpu(msblk->id_table[block]); + err = squashfs_read_metadata(sb, &disk_id, &start_block, &offset, sizeof(disk_id)); if (err < 0) @@ -56,7 +61,10 @@ __le64 *squashfs_read_id_index_table(str u64 id_table_start, u64 next_table, unsigned short no_ids) { unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids); + unsigned int indexes = SQUASHFS_ID_BLOCKS(no_ids); + int n; __le64 *table; + u64 start, end; TRACE("In read_id_index_table, length %d\n", length); @@ -67,20 +75,36 @@ __le64 *squashfs_read_id_index_table(str return ERR_PTR(-EINVAL); /* - * length bytes should not extend into the next table - this check - * also traps instances where id_table_start is incorrectly larger - * than the next table start + * The computed size of the index table (length bytes) should exactly + * match the table start and end points */ - if (id_table_start + length > next_table) + if (length != (next_table - id_table_start)) return ERR_PTR(-EINVAL); table = squashfs_read_table(sb, id_table_start, length); + if (IS_ERR(table)) + return table; /* - * table[0] points to the first id lookup table metadata block, this - * should be less than id_table_start + * table[0], table[1], ... table[indexes - 1] store the locations + * of the compressed id blocks. Each entry should be less than + * the next (i.e. table[0] < table[1]), and the difference between them + * should be SQUASHFS_METADATA_SIZE or less. table[indexes - 1] + * should be less than id_table_start, and again the difference + * should be SQUASHFS_METADATA_SIZE or less */ - if (!IS_ERR(table) && le64_to_cpu(table[0]) >= id_table_start) { + for (n = 0; n < (indexes - 1); n++) { + start = le64_to_cpu(table[n]); + end = le64_to_cpu(table[n + 1]); + + if (start >= end || (end - start) > SQUASHFS_METADATA_SIZE) { + kfree(table); + return ERR_PTR(-EINVAL); + } + } + + start = le64_to_cpu(table[indexes - 1]); + if (start >= id_table_start || (id_table_start - start) > SQUASHFS_METADATA_SIZE) { kfree(table); return ERR_PTR(-EINVAL); } --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h @@ -64,5 +64,6 @@ struct squashfs_sb_info { unsigned int inodes; unsigned int fragments; int xattr_ids; + unsigned int ids; }; #endif --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -166,6 +166,7 @@ static int squashfs_fill_super(struct su msblk->directory_table = le64_to_cpu(sblk->directory_table_start); msblk->inodes = le32_to_cpu(sblk->inodes); msblk->fragments = le32_to_cpu(sblk->fragments); + msblk->ids = le16_to_cpu(sblk->no_ids); flags = le16_to_cpu(sblk->flags); TRACE("Found valid superblock on %pg\n", sb->s_bdev); @@ -177,7 +178,7 @@ static int squashfs_fill_super(struct su TRACE("Block size %d\n", msblk->block_size); TRACE("Number of inodes %d\n", msblk->inodes); TRACE("Number of fragments %d\n", msblk->fragments); - TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids)); + TRACE("Number of ids %d\n", msblk->ids); TRACE("sblk->inode_table_start %llx\n", msblk->inode_table); TRACE("sblk->directory_table_start %llx\n", msblk->directory_table); TRACE("sblk->fragment_table_start %llx\n", @@ -236,8 +237,7 @@ static int squashfs_fill_super(struct su allocate_id_index_table: /* Allocate and read id index table */ msblk->id_table = squashfs_read_id_index_table(sb, - le64_to_cpu(sblk->id_table_start), next_table, - le16_to_cpu(sblk->no_ids)); + le64_to_cpu(sblk->id_table_start), next_table, msblk->ids); if (IS_ERR(msblk->id_table)) { errorf(fc, "unable to read id index table"); err = PTR_ERR(msblk->id_table); --- a/fs/squashfs/xattr.h +++ b/fs/squashfs/xattr.h @@ -17,8 +17,16 @@ extern int squashfs_xattr_lookup(struct static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, u64 *xattr_table_start, int *xattr_ids) { + struct squashfs_xattr_id_table *id_table; + + id_table = squashfs_read_table(sb, start, sizeof(*id_table)); + if (IS_ERR(id_table)) + return (__le64 *) id_table; + + *xattr_table_start = le64_to_cpu(id_table->xattr_table_start); + kfree(id_table); + ERROR("Xattrs in filesystem, these will be ignored\n"); - *xattr_table_start = start; return ERR_PTR(-ENOTSUPP); }