Received: by 2002:a05:7412:3210:b0:e2:908c:2ebd with SMTP id eu16csp797883rdb; Fri, 1 Sep 2023 04:45:39 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGPgmc8tjNmbA2HyaBtQTFN+TIf80vxMXFG3TZ+l80kZJOhJK58OV8s5+JgLT4CS42dVbnX X-Received: by 2002:a17:907:7616:b0:9a2:86a:f9c0 with SMTP id jx22-20020a170907761600b009a2086af9c0mr2969397ejc.1.1693568738886; Fri, 01 Sep 2023 04:45:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1693568738; cv=none; d=google.com; s=arc-20160816; b=qcJZ8k0CyPoiR29YTFDHX+0fPv/8lwPHih33pyMr0qBh0WaJAaiK4HtP302s/BZDiC tCeEjlc2t9RLUNK7EqceKTVNbKGfpCuJK1Ng3VL9st9LZUq1h9ldPbtQ0C3KPwPKd39A /PwrYTkavLYFzWDKRyq5nz7tvF7Mvo2+ZbNyIm7CPYSPpePDjVOb3FJ+LmOTRg4a4UYq t6aSVlBKhj1ZijIUk7pSbajLjI9L60m7QXVKFCfwYCr0EcEivRHy2XH/pRArsErUKcC+ DMNGp5ledL9rMiHAfoXjETrQKizNbTz9QqRqnrCtFnvKeZxoCFXIHJrXY0tTk/6F3Xe/ f8GA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:subject:message-id:date:from:in-reply-to :references:mime-version:dkim-signature; bh=8lU6YO+z4Xic+wL488cXXSGPplUA1jXI9U8PP+ZKs9w=; fh=NXBUqmPvDCeFOqt4rI83+0nHWZgrVCDgsWCtPGuxbKM=; b=vH/ENTxez9hRerNkS01172L4SrA2RjABRy66xRoBmqEvAiIkjXN4GoqlFX8/8c0M59 rysaisoLJsMifVaYfKq1EoCKSpvME4nkc6Qm55rvIkTBOHyJFhSMweM69Tck8gnK53s7 55oDjDICh+ml8P70L4B6e0rZnjnG41c+ZBSTV1dHifhZfuu+Z/1+RIN1QBDxHyFxlBqF R9hNAwIaSkkf9FCNpoCdZDgFzIy+uJ/wFSQfqEqtkSaLgh8E1De8ZpLzF72ucmoKSQs8 q0C1k1c65RoLrPDtWH4GT48ToT8SYiJLYDzT6JMjgXiHedpD33gVS+m7wiXmlaUbySOa Lt8w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b="hiPGhd/3"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 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 out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id d2-20020a1709064c4200b0099b46fc04f6si2201368ejw.1006.2023.09.01.04.45.12; Fri, 01 Sep 2023 04:45:38 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b="hiPGhd/3"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 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 S241133AbjHaVei (ORCPT + 99 others); Thu, 31 Aug 2023 17:34:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41274 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229795AbjHaVeh (ORCPT ); Thu, 31 Aug 2023 17:34:37 -0400 Received: from sin.source.kernel.org (sin.source.kernel.org [145.40.73.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B2971107; Thu, 31 Aug 2023 14:34:34 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by sin.source.kernel.org (Postfix) with ESMTPS id DD6B4CE223C; Thu, 31 Aug 2023 21:34:32 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1AFB9C433CB; Thu, 31 Aug 2023 21:34:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1693517671; bh=Pgd2Yocptj9793lIYLqngAmH9TmBoivbfYxnZc7PBrQ=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=hiPGhd/3c0qNhHdmi69L4PA7g+37wO5CLgwhhcFP5vKqw1scF+yKPrkw1O8ZCIgxB 5mCv6ZQSCorvCihaDTfGlfkzApaMZjD0CgCbgyJkLlxL36XFFYfMi/vhpNFLUrqzKD ZUjks1TgN+bvuuZ1ecy7bfJfx7iI8OCKlO0sMOUN+YljqGPJjpBWaSwL/68EVf54DN 5z2H/udtRhNY5WJXAUv47YFHb4wu04iA68+4teyLcWal9V1ob9wLN220ljo5F3nApG Z1vw324n6PoFB5fRINXbVN/SoG9APZPdQ5BNQjmvf1Scm53HJznhNaC7mkPGKkNaSw 4v8/4TgrclThA== Received: by mail-lf1-f50.google.com with SMTP id 2adb3069b0e04-500760b296aso1539461e87.0; Thu, 31 Aug 2023 14:34:30 -0700 (PDT) X-Gm-Message-State: AOJu0YyCBL3S99U+N31adkR0LOT79bJpz/eTKUsnYIA7+r5wTU0SUdXB BAU5WtWCnXBPsIa6bHY6WCsmipy/FNXZvCy2jRQ= X-Received: by 2002:a05:6512:2347:b0:4f9:6adf:3981 with SMTP id p7-20020a056512234700b004f96adf3981mr1297313lfu.33.1693517669059; Thu, 31 Aug 2023 14:34:29 -0700 (PDT) MIME-Version: 1.0 References: <20230831210125.gonna.173-kees@kernel.org> In-Reply-To: <20230831210125.gonna.173-kees@kernel.org> From: Ard Biesheuvel Date: Thu, 31 Aug 2023 23:34:17 +0200 X-Gmail-Original-Message-ID: Message-ID: Subject: Re: [PATCH v2] pstore: Base compression input buffer size on estimated compressed size To: Kees Cook Cc: Linus Torvalds , Eric Biggers , Herbert Xu , Tony Luck , "Guilherme G. Piccoli" , linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Thu, 31 Aug 2023 at 23:01, Kees Cook wrote: > > From: Ard Biesheuvel > > Commit 1756ddea6916 ("pstore: Remove worst-case compression size logic") > removed some clunky per-algorithm worst case size estimation routines on > the basis that we can always store pstore records uncompressed, and > these worst case estimations are about how much the size might > inadvertently *increase* due to encapsulation overhead when the input > cannot be compressed at all. So if compression results in a size > increase, we just store the original data instead. > > However, it seems that the original code was misinterpreting these > calculations as an estimation of how much uncompressed data might fit > into a compressed buffer of a given size, and it was using the results > to consume the input data in larger chunks than the pstore record size, > relying on the compression to ensure that what ultimately gets stored > fits into the available space. > > One result of this, as observed and reported by Linus, is that upgrading > to a newer kernel that includes the given commit may result in pstore > decompression errors reported in the kernel log. This is due to the fact > that the existing records may unexpectedly decompress to a size that is > larger than the pstore record size. > > Another potential problem caused by this change is that we may > underutilize the fixed sized records on pstore backends such as ramoops. > And on pstore backends with variable sized records such as EFI, we will > end up creating many more entries than before to store the same amount > of compressed data. > > So let's fix both issues, by bringing back the typical case estimation of > how much ASCII text captured from the dmesg log might fit into a pstore > record of a given size after compression. The original implementation > used the computation given below for zlib: > > switch (size) { > /* buffer range for efivars */ > case 1000 ... 2000: > cmpr = 56; > break; > case 2001 ... 3000: > cmpr = 54; > break; > case 3001 ... 3999: > cmpr = 52; > break; > /* buffer range for nvram, erst */ > case 4000 ... 10000: > cmpr = 45; > break; > default: > cmpr = 60; > break; > } > > return (size * 100) / cmpr; > > We will use the previous worst-case of 60% for compression. For > decompression go extra large (3x) so we make sure there's enough space > for anything. > > While at it, rate limit the error message so we don't flood the log > unnecessarily on systems that have accumulated a lot of pstore history. > > Cc: Linus Torvalds > Cc: Eric Biggers > Cc: Kees Cook > Cc: Herbert Xu > Signed-off-by: Ard Biesheuvel > Link: https://lore.kernel.org/r/20230830212238.135900-1-ardb@kernel.org > Co-developed-by: Kees Cook > Signed-off-by: Kees Cook > --- > v2: > - reduce compression buffer size to 1.67x from 2x > - raise decompression buffer size to 3x LGTM Thanks for picking this up. > v1: https://lore.kernel.org/all/20230830212238.135900-1-ardb@kernel.org > --- > fs/pstore/platform.c | 34 +++++++++++++++++++++++++++------- > 1 file changed, 27 insertions(+), 7 deletions(-) > > diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c > index 62356d542ef6..e5bca9a004cc 100644 > --- a/fs/pstore/platform.c > +++ b/fs/pstore/platform.c > @@ -98,7 +98,14 @@ MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)"); > > static void *compress_workspace; > > +/* > + * Compression is only used for dmesg output, which consists of low-entropy > + * ASCII text, and so we can assume worst-case 60%. > + */ > +#define DMESG_COMP_PERCENT 60 > + > static char *big_oops_buf; > +static size_t max_compressed_size; > > void pstore_set_kmsg_bytes(int bytes) > { > @@ -196,6 +203,7 @@ static int pstore_compress(const void *in, void *out, > > static void allocate_buf_for_compression(void) > { > + size_t compressed_size; > char *buf; > > /* Skip if not built-in or compression disabled. */ > @@ -216,7 +224,8 @@ static void allocate_buf_for_compression(void) > * uncompressed record size, since any record that would be expanded by > * compression is just stored uncompressed. > */ > - buf = kvzalloc(psinfo->bufsize, GFP_KERNEL); > + compressed_size = (psinfo->bufsize * 100) / DMESG_COMP_PERCENT; > + buf = kvzalloc(compressed_size, GFP_KERNEL); > if (!buf) { > pr_err("Failed %zu byte compression buffer allocation for: %s\n", > psinfo->bufsize, compress); > @@ -233,6 +242,7 @@ static void allocate_buf_for_compression(void) > > /* A non-NULL big_oops_buf indicates compression is available. */ > big_oops_buf = buf; > + max_compressed_size = compressed_size; > > pr_info("Using crash dump compression: %s\n", compress); > } > @@ -246,6 +256,7 @@ static void free_buf_for_compression(void) > > kvfree(big_oops_buf); > big_oops_buf = NULL; > + max_compressed_size = 0; > } > > void pstore_record_init(struct pstore_record *record, > @@ -305,7 +316,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, > record.buf = psinfo->buf; > > dst = big_oops_buf ?: psinfo->buf; > - dst_size = psinfo->bufsize; > + dst_size = max_compressed_size ?: psinfo->bufsize; > > /* Write dump header. */ > header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why, > @@ -326,8 +337,15 @@ static void pstore_dump(struct kmsg_dumper *dumper, > record.compressed = true; > record.size = zipped_len; > } else { > - record.size = header_size + dump_size; > - memcpy(psinfo->buf, dst, record.size); > + /* > + * Compression failed, so the buffer is most > + * likely filled with binary data that does not > + * compress as well as ASCII text. Copy as much > + * of the uncompressed data as possible into > + * the pstore record, and discard the rest. > + */ > + record.size = psinfo->bufsize; > + memcpy(psinfo->buf, dst, psinfo->bufsize); > } > } else { > record.size = header_size + dump_size; > @@ -560,6 +578,7 @@ static void decompress_record(struct pstore_record *record, > int ret; > int unzipped_len; > char *unzipped, *workspace; > + size_t max_uncompressed_size; > > if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !record->compressed) > return; > @@ -583,7 +602,8 @@ static void decompress_record(struct pstore_record *record, > } > > /* Allocate enough space to hold max decompression and ECC. */ > - workspace = kvzalloc(psinfo->bufsize + record->ecc_notice_size, > + max_uncompressed_size = 3 * psinfo->bufsize; > + workspace = kvzalloc(max_uncompressed_size + record->ecc_notice_size, > GFP_KERNEL); > if (!workspace) > return; > @@ -591,11 +611,11 @@ static void decompress_record(struct pstore_record *record, > zstream->next_in = record->buf; > zstream->avail_in = record->size; > zstream->next_out = workspace; > - zstream->avail_out = psinfo->bufsize; > + zstream->avail_out = max_uncompressed_size; > > ret = zlib_inflate(zstream, Z_FINISH); > if (ret != Z_STREAM_END) { > - pr_err("zlib_inflate() failed, ret = %d!\n", ret); > + pr_err_ratelimited("zlib_inflate() failed, ret = %d!\n", ret); > kvfree(workspace); > return; > } > -- > 2.34.1 >