Received: by 2002:a05:6a10:5bc5:0:0:0:0 with SMTP id os5csp908201pxb; Sun, 10 Oct 2021 14:57:57 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwkekQp1s13JxI0Nda3VvtMOSU7S9rRrf12uik4CD8ViAKNJ0p3umMXGZAiKG19s7WRBVjp X-Received: by 2002:a63:d40b:: with SMTP id a11mr15356177pgh.456.1633903077698; Sun, 10 Oct 2021 14:57:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1633903077; cv=none; d=google.com; s=arc-20160816; b=XyGP3pFATJFnbUHcvlbAnjsNJDorZcexj5rBGyBtDnljA3L9hdMWkTXTTcbnI+m3CN /0QOW3EOd8razntDwgH85atLdUY8vhxegdgDx7Yk80+hN533dNr8RZtXiG+bTwwpVIOo tRRqaAnbhrEevsyMBP7Lz+zFII+wOFLgTBwtk14QJxoKHnZVb6ir7ZJbtpmsal7eFU09 Dh8znohSa7hPDQFuoeflrReALbtOicxx2PmDN6B27huKH66AIuk3DgP4PRL/TOZm0KEF PP/SGIqOnwiRXDgNCQZb6uxLYinzUbC9D4g1YKJSpLRhvZFv2Ia/ZO0FgIsjrGP2nvIe jgYg== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=PfKQhJtko7f5i4Mjg+9VHlOtMXDIbQCZjBch7kzpDow=; b=ZLSO3mY+RUCc46EQGzDQVTkR2Mk/7NH8Iunpz3tLuusQISImBi5Dg45UhPAHDPTDHY m5eMor72azixCerPEa8zYobqVaCq+s2twmFC+Qz8RF7S60WeeWg86pxNu0s7dXe4WEAW WSp01gHmjO+zZjMJlny5uDqTL/azlQU/k1UUyG7zl7UHIphxo8dAYw31caVJuPpVsqvs WdyJearS7tTsbbLkrburrbieJ6SUAy+Cg1+nxrt/8JtWumB2RuoqU5kgludwDPb2k8uM I/yn4I8LmCRmPWTd+PHn9L4U9BQ0ZBCwiNfG908mmkxIlVJGBflFPEcPkxqfhQc0aQw3 6SQA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=KVwHcDz+; 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=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id s30si9083903pgo.362.2021.10.10.14.57.45; Sun, 10 Oct 2021 14:57:57 -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; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=KVwHcDz+; 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=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233084AbhJJVeE (ORCPT + 99 others); Sun, 10 Oct 2021 17:34:04 -0400 Received: from mail.kernel.org ([198.145.29.99]:58272 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233097AbhJJVeE (ORCPT ); Sun, 10 Oct 2021 17:34:04 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 3A14C60F23; Sun, 10 Oct 2021 21:32:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1633901525; bh=npnSU4nb33fksWbkboptClZqb5ckMMSYa0HSCr/9huI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KVwHcDz+zpa+qmVOZOLTbMQO0SxIZ5TqzekqxEc3xa2s8bLa4l945wmqDjknHWQoc qoqe5Cj20tzeECtjxQN7aEAUUgVQLFmA9+5S+V6q0/Hckuox16k6BvCH7vrwip1Cge U6OBmlD9pJbMq+X8RYnWGMB4UsNZG6mtGslP0JQtWCultrW/vXGyMXaADsXP3F3/pZ mS7HJD1SIWwC8yyQebyPMfyMADKG3nV7k0dEiDCLGfig65fkyb+x6++IgqzsXsy7Vn N00VB6y+1dbtkEsWbrnb2Iq5ZiJd+MT7lx7JyUWnx9A/TYP40I/2IhIKGrDnP4o+fO Cp9t7HrAYjVvw== From: Gao Xiang To: linux-erofs@lists.ozlabs.org, LKML Cc: Lasse Collin , Chao Yu , Andrew Morton , Greg KH , Linus Torvalds , Gao Xiang Subject: [PATCH 1/7] lib/xz: Avoid overlapping memcpy() with invalid input with in-place decompression Date: Mon, 11 Oct 2021 05:31:39 +0800 Message-Id: <20211010213145.17462-2-xiang@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20211010213145.17462-1-xiang@kernel.org> References: <20211010213145.17462-1-xiang@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Lasse Collin With valid files, the safety margin described in lib/decompress_unxz.c ensures that these buffers cannot overlap. But if the uncompressed size of the input is larger than the caller thought, which is possible when the input file is invalid/corrupt, the buffers can overlap. Obviously the result will then be garbage (and usually the decoder will return an error too) but no other harm will happen when such an over-run occurs. This change only affects uncompressed LZMA2 chunks and so this should have no effect on performance. Signed-off-by: Lasse Collin Signed-off-by: Gao Xiang --- lib/decompress_unxz.c | 2 +- lib/xz/xz_dec_lzma2.c | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/decompress_unxz.c b/lib/decompress_unxz.c index a2f38e23004a..f7a3dc13316a 100644 --- a/lib/decompress_unxz.c +++ b/lib/decompress_unxz.c @@ -167,7 +167,7 @@ * memeq and memzero are not used much and any remotely sane implementation * is fast enough. memcpy/memmove speed matters in multi-call mode, but * the kernel image is decompressed in single-call mode, in which only - * memcpy speed can matter and only if there is a lot of uncompressible data + * memmove speed can matter and only if there is a lot of uncompressible data * (LZMA2 stores uncompressible chunks in uncompressed form). Thus, the * functions below should just be kept small; it's probably not worth * optimizing for speed. diff --git a/lib/xz/xz_dec_lzma2.c b/lib/xz/xz_dec_lzma2.c index 7a6781e3f47b..d548cf0e59fe 100644 --- a/lib/xz/xz_dec_lzma2.c +++ b/lib/xz/xz_dec_lzma2.c @@ -387,7 +387,14 @@ static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b, *left -= copy_size; - memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size); + /* + * If doing in-place decompression in single-call mode and the + * uncompressed size of the file is larger than the caller + * thought (i.e. it is invalid input!), the buffers below may + * overlap and cause undefined behavior with memcpy(). + * With valid inputs memcpy() would be fine here. + */ + memmove(dict->buf + dict->pos, b->in + b->in_pos, copy_size); dict->pos += copy_size; if (dict->full < dict->pos) @@ -397,7 +404,11 @@ static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b, if (dict->pos == dict->end) dict->pos = 0; - memcpy(b->out + b->out_pos, b->in + b->in_pos, + /* + * Like above but for multi-call mode: use memmove() + * to avoid undefined behavior with invalid input. + */ + memmove(b->out + b->out_pos, b->in + b->in_pos, copy_size); } @@ -421,6 +432,12 @@ static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b) if (dict->pos == dict->end) dict->pos = 0; + /* + * These buffers cannot overlap even if doing in-place + * decompression because in multi-call mode dict->buf + * has been allocated by us in this file; it's not + * provided by the caller like in single-call mode. + */ memcpy(b->out + b->out_pos, dict->buf + dict->start, copy_size); } -- 2.20.1