Received: by 2002:a05:6a10:f3d0:0:0:0:0 with SMTP id a16csp235542pxv; Wed, 30 Jun 2021 19:35:33 -0700 (PDT) X-Google-Smtp-Source: ABdhPJy7FpEL/YshbrdnhcRl8v0oJwKqZBniWzIiyjPdwy5FI7eGUpNBJDzwSRscn8TwgV7Ar2tW X-Received: by 2002:aa7:c782:: with SMTP id n2mr51231363eds.77.1625106933029; Wed, 30 Jun 2021 19:35:33 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1625106933; cv=none; d=google.com; s=arc-20160816; b=epyRlK6+686UJYqv+NSzD3nTBsIwQtOZAd7k587SLYI7Z6gFmd9Msn1ykujJ/UYNku I3dnMUfnS99JR1i82WTJJjSUzJU8H/nLRphIjH2b0FNuRQKZCIFz01JURi0QZZnjDhI0 bpjNUCgcacr6Bu3ig9Hafee9ycDMCGhtvWFHEXMbK8ji9IonOltEr/oOiNxA4woCkN6O ZHst3HxEtJmPqkxycm/jRov3/0zu1ni4XkSxXgwJ9vckv5XP/izgViq4HXcWupgdKQqQ OaTmwf7GNbo6WQ+/83w/LK42U+pdwtn5yD3saJ7ujw1WPOfQNRXc/2q3eLcgF2AGGqjD SWAQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-language:content-transfer-encoding :in-reply-to:mime-version:user-agent:date:message-id:from:references :cc:to:subject; bh=m9rWeti+S30w2HBDyXJ5pj84EYwEYBS2gtI4ptziluk=; b=V1wNvt4FXJYtiSaGt6s1ThTWAowbI01pe7/igULqmE3ccJswZncBMO9fkDJ9CspbcH tFSOnE4Wb5Croe0LW36TAT2hmp6JfJlnJELtV1qAG0gHyNyzByazldTveIRp+77o8T0A 8bMPk3bts2EjpBeF1yZ2sC4yxKxkLRYGyPtFjeoWBAt/+NXH8Ut+KGuudVMuFJu2eT3y MBpeLIYSDTrs4rFKeU3kNlJBIj7uwes2isFmzC07rS0ZY+DuW50ay08tzBkIkzcJOJIA dem5AZ8IDyu7zxdrpGOFqT/L/dY5ww9OcWKR8BAWPlKwXWksryGKufBV4qwHnKVgibFa nt3A== ARC-Authentication-Results: i=1; mx.google.com; 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=fail (p=NONE sp=NONE dis=NONE) header.from=huawei.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id 26si4588244ejk.553.2021.06.30.19.35.09; Wed, 30 Jun 2021 19:35:33 -0700 (PDT) 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; 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=fail (p=NONE sp=NONE dis=NONE) header.from=huawei.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238635AbhGACgs (ORCPT + 99 others); Wed, 30 Jun 2021 22:36:48 -0400 Received: from szxga02-in.huawei.com ([45.249.212.188]:9441 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238056AbhGACgs (ORCPT ); Wed, 30 Jun 2021 22:36:48 -0400 Received: from dggemv703-chm.china.huawei.com (unknown [172.30.72.55]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4GFhzK10bQzZlKP; Thu, 1 Jul 2021 10:31:09 +0800 (CST) Received: from dggpemm500021.china.huawei.com (7.185.36.109) by dggemv703-chm.china.huawei.com (10.3.19.46) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.2; Thu, 1 Jul 2021 10:34:16 +0800 Received: from [10.174.177.223] (10.174.177.223) by dggpemm500021.china.huawei.com (7.185.36.109) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) id 15.1.2176.2; Thu, 1 Jul 2021 10:34:15 +0800 Subject: Re: [PATCH] lz4: fixs use-after-free Read in LZ4_decompress_safe_partial To: Nick Terrell , Gao Xiang CC: Andrew Morton , Stephen Rothwell , Rajat Asthana , LKML , Yann Collet , "linux-erofs@lists.ozlabs.org" References: <20210630032358.949122-1-cy.fan@huawei.com> From: Chengyang Fan Message-ID: Date: Thu, 1 Jul 2021 10:34:14 +0800 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.6.1 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset="utf-8"; format=flowed Content-Transfer-Encoding: 8bit Content-Language: en-US X-Originating-IP: [10.174.177.223] X-ClientProxiedBy: dggeme715-chm.china.huawei.com (10.1.199.111) To dggpemm500021.china.huawei.com (7.185.36.109) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 2021/7/1 1:49, Nick Terrell wrote: > >> On Jun 30, 2021, at 4:42 AM, Gao Xiang wrote: >> >> (also +cc Yann as well as Nick..) >> >> Hi Chengyang, >> >> If I understand correctly, is this a manually produced fuzzed >> EROFS compressed data? If it's just a normal image, could you >> also share the original image? >> >> On Wed, Jun 30, 2021 at 11:23:58AM +0800, Chengyang Fan wrote: >>> ================================================================== >>> BUG: KASAN: use-after-free in get_unaligned_le16 include/linux/unaligned/access_ok.h:10 [inline] >>> BUG: KASAN: use-after-free in LZ4_readLE16 lib/lz4/lz4defs.h:132 [inline] >>> BUG: KASAN: use-after-free in LZ4_decompress_generic lib/lz4/lz4_decompress.c:281 [inline] >>> BUG: KASAN: use-after-free in LZ4_decompress_safe_partial+0xf50/0x1480 lib/lz4/lz4_decompress.c:465 >>> Read of size 2 at addr ffff888017851000 by task kworker/u12:0/2056 >>> >>> CPU: 0 PID: 2056 Comm: kworker/u12:0 Not tainted 5.10.40 #2 >>> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 >>> Workqueue: erofs_unzipd z_erofs_decompressqueue_work >>> Call Trace: >>> __dump_stack lib/dump_stack.c:77 [inline] >>> dump_stack+0x137/0x1be lib/dump_stack.c:118 >>> print_address_description+0x6c/0x640 mm/kasan/report.c:385 >>> __kasan_report mm/kasan/report.c:545 [inline] >>> kasan_report+0x13d/0x1e0 mm/kasan/report.c:562 >>> get_unaligned_le16 include/linux/unaligned/access_ok.h:10 [inline] >>> LZ4_readLE16 lib/lz4/lz4defs.h:132 [inline] >>> LZ4_decompress_generic lib/lz4/lz4_decompress.c:281 [inline] >>> LZ4_decompress_safe_partial+0xf50/0x1480 lib/lz4/lz4_decompress.c:465 >>> z_erofs_lz4_decompress+0x839/0xc90 fs/erofs/decompressor.c:162 >>> z_erofs_decompress_generic fs/erofs/decompressor.c:291 [inline] >>> z_erofs_decompress+0x57e/0xe10 fs/erofs/decompressor.c:344 >>> z_erofs_decompress_pcluster+0x13d1/0x2310 fs/erofs/zdata.c:880 >>> z_erofs_decompress_queue fs/erofs/zdata.c:958 [inline] >>> z_erofs_decompressqueue_work+0xde/0x140 fs/erofs/zdata.c:969 >>> process_one_work+0x780/0xfc0 kernel/workqueue.c:2269 >>> worker_thread+0xaa4/0x1460 kernel/workqueue.c:2415 >>> kthread+0x39a/0x3c0 kernel/kthread.c:292 >>> ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:296 >>> >>> The buggy address belongs to the page: >>> page:00000000a79b76f1 refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x17851 >>> flags: 0xfff00000000000() >>> raw: 00fff00000000000 ffffea000081b9c8 ffffea00006ac6c8 0000000000000000 >>> raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000 >>> page dumped because: kasan: bad access detected >>> >>> Memory state around the buggy address: >>> ffff888017850f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >>> ffff888017850f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >>>> ffff888017851000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff >>> ^ >>> ffff888017851080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff >>> ffff888017851100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff >>> ================================================================== >>> erofs: (device loop0): z_erofs_lz4_decompress: failed to decompress -4099 in[4096, 0] out[9000] >>> >>> Off-by-one error causes the above issue. In LZ4_decompress_generic(), >>> `iend = src + srcSize`. It means the valid address range should be >>> [src, iend - 1]. Therefore, when checking whether the reading is >>> out-of-bounds, it should be `>= iend` rather than `> iend`. > This isn’t correct. The bounds check is correct for the following memcpy(). > The problem is the LZ4_readLE16() on line 285 [1]. Yeah, it's my fault. This fix is incorrect. >>> Reported-by: Hulk Robot >>> Signed-off-by: Chengyang Fan >>> --- >>> lib/lz4/lz4_decompress.c | 2 +- >>> 1 file changed, 1 insertion(+), 1 deletion(-) >>> >>> diff --git a/lib/lz4/lz4_decompress.c b/lib/lz4/lz4_decompress.c >>> index 926f4823d5ea..ec51837cd31f 100644 >>> --- a/lib/lz4/lz4_decompress.c >>> +++ b/lib/lz4/lz4_decompress.c >>> @@ -234,7 +234,7 @@ static FORCE_INLINE int LZ4_decompress_generic( >>> length = oend - op; >>> } >>> if ((endOnInput) >>> - && (ip + length > iend)) { >>> + && (ip + length >= iend)) { >> I'm not sure it should be fixed as this. > Yeah, this is not the correct fix. `ip + length > iend` is correct for the > memcpy(). You would instead need to add another check after the > memcpy(). E.g. something like this, taken from upstream [2]. > > ``` > > LZ4_memmove(op, ip, length); > ip += length; > op += length; > > /* Necessarily EOF, due to parsing restrictions */ > - if (!partialDecoding || (cpy == oend)) > + if (!partialDecoding || (cpy == oend) || (ip >= (iend-2))) > break; > ``` > > This should be enough to fix the out of bounds read you reported. > However, I can’t guarantee that this will fix all the issues that have been > fixed upstream since v1.8.3. > > The safest and most robust course of action would be to update the version > of LZ4 in the kernel to the latest upstream, which is continuously fuzzed, and > doesn't have this issue. > > Best, > Nick Terrell Thanks for pointing this out. I ignored the modifications of LZ4 upstream before. So I'll recheck them and find the right way to fix this error. Thanks, Chengyang Fan >> The current lz4 decompression code was from lz4 1.8.3, and I saw >> several following up fixes for incomplete input partial decoding >> in recent LZ4 upstream, you could check them out together. However, >> EROFS should never pass incomplete lz4 compressed data to the LZ4 >> side unless it's somewhat a corrupted image on purpose. >> https://github.com/lz4/lz4/blame/dev/lib/lz4.c >> >> Thanks, >> Gao Xiang >> >>> /* >>> * Error : >>> * read attempt beyond >>> -- >>> 2.18.0.huawei.25 > [1] https://github.com/torvalds/linux/blob/007b350a58754a93ca9fe50c498cc27780171153/lib/lz4/lz4_decompress.c#L285 > [2] https://github.com/lz4/lz4/blob/11efc95c3f02b76ab40e7fbd605677ad6eb141d3/lib/lz4.c#L2059 > >