From nobody Thu Dec 18 00:47:17 2025 Received: from abb.hmeau.com (abb.hmeau.com [144.6.53.87]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3C0804414; Sun, 23 Feb 2025 06:55:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=144.6.53.87 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740293739; cv=none; b=Bzvvqo3HM+rfVQayJtBI+PlvPm8+ckzEYKtMo0OPrUVxyQhENmsFcDnP0M56g6gvcgzvh+K8ZoY/0DHKQGmQSEo4aneQQD7MlCq6Ty/1CUA0+4uIEDrSzfTQy7VJ2+qsVMpcXWyIj9/SCZd/RfzJshBcjgMxl99XaJdEu3akERI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1740293739; c=relaxed/simple; bh=QmOR/YrUzzwsYy7T54Gep40GJD5nY3nQaIVBiQTDYps=; h=Date:From:To:Cc:Subject:Message-ID:MIME-Version:Content-Type: Content-Disposition; b=jBdcAkegM1u2k3jY2QJFf5uiUWNyGvEMUinF+5L7LFlL0E51uYIW6HEAKBF+Qe+2RANYhOszvJALh4ZuaKgL4Mn3JbLtZbHF4/f5XKRccvEOFNd3tP9c2efdQpzENXHvtnh3Lq7Jiv+dLpqPKWj6nfHjg9lcXSACW8HwcnvEA+0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=gondor.apana.org.au; spf=pass smtp.mailfrom=gondor.apana.org.au; dkim=pass (2048-bit key) header.d=hmeau.com header.i=@hmeau.com header.b=JxEDmKei; arc=none smtp.client-ip=144.6.53.87 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=gondor.apana.org.au Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gondor.apana.org.au Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=hmeau.com header.i=@hmeau.com header.b="JxEDmKei" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=hmeau.com; s=formenos; h=Content-Type:MIME-Version:Message-ID:Subject:Cc:To:From:Date: Sender:Reply-To:Content-Transfer-Encoding:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=TrabOqtRhfI4L6MXAwrxdsN96HvSybcOUIqp0rTlZoc=; b=JxEDmKeiwKhrw9Z+o5YxLxPgBR HoAWaqs0VwTbUwWImyM85VEknbl3XBCiRR+CuNJC3et+XS4tr+jnqXLqK3yuAKrxLGqGckJdxuDfw 4IRxi8oaKf4lJlevnGmYIZfG8cn2dwTOWyaYWrNaRiTpcsY8MmQkfKvya6UjwAB6uQKfXo92f/goA sLaTQNN+AdfMQ+PyA8rVzBdTFF2tJZIztCcnQcU8XMga3T13zHS5Q0TEBLhCWkGazq6oR/IT3qESg t4HYM/FrZ2RWok66dvs2Vc+2n9iEaLKHn6YCf6GHE2tW1t1oY4qumB6/VDa7uQti4PaKmSw2vlTtF iL2+dx+w==; Received: from loth.rohan.me.apana.org.au ([192.168.167.2]) by formenos.hmeau.com with smtp (Exim 4.96 #2 (Debian)) id 1tm5tc-000ycI-0E; Sun, 23 Feb 2025 14:55:25 +0800 Received: by loth.rohan.me.apana.org.au (sSMTP sendmail emulation); Sun, 23 Feb 2025 14:55:24 +0800 Date: Sun, 23 Feb 2025 14:55:24 +0800 From: Herbert Xu To: Linux Crypto Mailing List Cc: Linux Kernel Mailing List , Nitin Gupta , Richard Purdie , Andrew Morton , Linus Torvalds , Sergey Senozhatsky , "Markus F.X.J. Oberhumer" , Dave Rodgman Subject: [PATCH] lib/lzo: Avoid output overruns when compressing Message-ID: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The compression code in LZO never checked for output overruns. Fix this by checking for end of buffer before each write. Fixes: 64c70b1cf43d ("Add LZO1X algorithm to the kernel") Signed-off-by: Herbert Xu diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c index 47d6d43ea957..5d2f2f851694 100644 --- a/lib/lzo/lzo1x_compress.c +++ b/lib/lzo/lzo1x_compress.c @@ -18,10 +18,10 @@ #include #include "lzodefs.h" =20 -static noinline size_t +static noinline int lzo1x_1_do_compress(const unsigned char *in, size_t in_len, - unsigned char *out, size_t *out_len, - size_t ti, void *wrkmem, signed char *state_offset, + unsigned char **out, unsigned char *op_end, + size_t *tp, void *wrkmem, signed char *state_offset, const unsigned char bitstream_version) { const unsigned char *ip; @@ -30,8 +30,9 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_le= n, const unsigned char * const ip_end =3D in + in_len - 20; const unsigned char *ii; lzo_dict_t * const dict =3D (lzo_dict_t *) wrkmem; + size_t ti =3D *tp; =20 - op =3D out; + op =3D *out; ip =3D in; ii =3D ip; ip +=3D ti < 4 ? 4 - ti : 0; @@ -116,25 +117,41 @@ lzo1x_1_do_compress(const unsigned char *in, size_t i= n_len, if (t !=3D 0) { if (t <=3D 3) { op[*state_offset] |=3D t; + if (!HAVE_OP(4)) + return LZO_E_OUTPUT_OVERRUN; COPY4(op, ii); op +=3D t; } else if (t <=3D 16) { + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D (t - 3); + if (!HAVE_OP(16)) + return LZO_E_OUTPUT_OVERRUN; COPY8(op, ii); COPY8(op + 8, ii + 8); op +=3D t; } else { if (t <=3D 18) { + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D (t - 3); } else { size_t tt =3D t - 18; + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D 0; while (unlikely(tt > 255)) { tt -=3D 255; + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D 0; } + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D tt; } + if (!HAVE_OP(t)) + return LZO_E_OUTPUT_OVERRUN; do { COPY8(op, ii); COPY8(op + 8, ii + 8); @@ -151,6 +168,8 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_= len, if (unlikely(run_length)) { ip +=3D run_length; run_length -=3D MIN_ZERO_RUN_LENGTH; + if (!HAVE_OP(4)) + return LZO_E_OUTPUT_OVERRUN; put_unaligned_le32((run_length << 21) | 0xfffc18 | (run_length & 0x7), op); op +=3D 4; @@ -243,10 +262,14 @@ lzo1x_1_do_compress(const unsigned char *in, size_t i= n_len, ip +=3D m_len; if (m_len <=3D M2_MAX_LEN && m_off <=3D M2_MAX_OFFSET) { m_off -=3D 1; + if (!HAVE_OP(2)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D (((m_len - 1) << 5) | ((m_off & 7) << 2)); *op++ =3D (m_off >> 3); } else if (m_off <=3D M3_MAX_OFFSET) { m_off -=3D 1; + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; if (m_len <=3D M3_MAX_LEN) *op++ =3D (M3_MARKER | (m_len - 2)); else { @@ -254,14 +277,22 @@ lzo1x_1_do_compress(const unsigned char *in, size_t i= n_len, *op++ =3D M3_MARKER | 0; while (unlikely(m_len > 255)) { m_len -=3D 255; + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D 0; } + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D (m_len); } + if (!HAVE_OP(2)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D (m_off << 2); *op++ =3D (m_off >> 6); } else { m_off -=3D 0x4000; + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; if (m_len <=3D M4_MAX_LEN) *op++ =3D (M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2)); @@ -282,11 +313,17 @@ lzo1x_1_do_compress(const unsigned char *in, size_t i= n_len, m_len -=3D M4_MAX_LEN; *op++ =3D (M4_MARKER | ((m_off >> 11) & 8)); while (unlikely(m_len > 255)) { + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; m_len -=3D 255; *op++ =3D 0; } + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D (m_len); } + if (!HAVE_OP(2)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D (m_off << 2); *op++ =3D (m_off >> 6); } @@ -295,14 +332,16 @@ lzo1x_1_do_compress(const unsigned char *in, size_t i= n_len, ii =3D ip; goto next; } - *out_len =3D op - out; - return in_end - (ii - ti); + *out =3D op; + *tp =3D in_end - (ii - ti); + return LZO_E_OK; } =20 static int lzogeneric1x_1_compress(const unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len, void *wrkmem, const unsigned char bitstream_version) { + unsigned char * const op_end =3D out + *out_len; const unsigned char *ip =3D in; unsigned char *op =3D out; unsigned char *data_start; @@ -326,14 +365,17 @@ static int lzogeneric1x_1_compress(const unsigned cha= r *in, size_t in_len, while (l > 20) { size_t ll =3D min_t(size_t, l, m4_max_offset + 1); uintptr_t ll_end =3D (uintptr_t) ip + ll; + int err; + if ((ll_end + ((t + ll) >> 5)) <=3D ll_end) break; BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS); memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t)); - t =3D lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem, - &state_offset, bitstream_version); + err =3D lzo1x_1_do_compress(ip, ll, &op, op_end, &t, wrkmem, + &state_offset, bitstream_version); + if (err !=3D LZO_E_OK) + return err; ip +=3D ll; - op +=3D *out_len; l -=3D ll; } t +=3D l; @@ -342,20 +384,32 @@ static int lzogeneric1x_1_compress(const unsigned cha= r *in, size_t in_len, const unsigned char *ii =3D in + in_len - t; =20 if (op =3D=3D data_start && t <=3D 238) { + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D (17 + t); } else if (t <=3D 3) { op[state_offset] |=3D t; } else if (t <=3D 18) { + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D (t - 3); } else { size_t tt =3D t - 18; + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D 0; while (tt > 255) { tt -=3D 255; + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D 0; } + if (!HAVE_OP(1)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D tt; } + if (!HAVE_OP(t)) + return LZO_E_OUTPUT_OVERRUN; if (t >=3D 16) do { COPY8(op, ii); COPY8(op + 8, ii + 8); @@ -368,6 +422,8 @@ static int lzogeneric1x_1_compress(const unsigned char = *in, size_t in_len, } while (--t > 0); } =20 + if (!HAVE_OP(3)) + return LZO_E_OUTPUT_OVERRUN; *op++ =3D M4_MARKER | 1; *op++ =3D 0; *op++ =3D 0; diff --git a/lib/lzo/lzo1x_decompress_safe.c b/lib/lzo/lzo1x_decompress_saf= e.c index c94f4928e188..4d5a1b58a4a0 100644 --- a/lib/lzo/lzo1x_decompress_safe.c +++ b/lib/lzo/lzo1x_decompress_safe.c @@ -21,7 +21,6 @@ #include "lzodefs.h" =20 #define HAVE_IP(x) ((size_t)(ip_end - ip) >=3D (size_t)(x)) -#define HAVE_OP(x) ((size_t)(op_end - op) >=3D (size_t)(x)) #define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun #define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun #define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun diff --git a/lib/lzo/lzodefs.h b/lib/lzo/lzodefs.h index b60851fcf6ce..8b1a46993acf 100644 --- a/lib/lzo/lzodefs.h +++ b/lib/lzo/lzodefs.h @@ -19,6 +19,7 @@ */ #define LZO_VERSION 1 =20 +#define HAVE_OP(x) ((size_t)(op_end - op) >=3D (size_t)(x)) #define COPY4(dst, src) \ put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst)) #if defined(CONFIG_X86_64) || defined(CONFIG_ARM64) --=20 Email: Herbert Xu Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt