From patchwork Mon Dec 13 23:20:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Disseldorp X-Patchwork-Id: 12674825 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6D14BC433EF for ; Mon, 13 Dec 2021 23:27:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242172AbhLMX1r (ORCPT ); Mon, 13 Dec 2021 18:27:47 -0500 Received: from smtp-out2.suse.de ([195.135.220.29]:46204 "EHLO smtp-out2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237209AbhLMX1r (ORCPT ); Mon, 13 Dec 2021 18:27:47 -0500 Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out2.suse.de (Postfix) with ESMTP id 67D7C1F3C4; Mon, 13 Dec 2021 23:27:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1639438066; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1ly1qWDMyzaC9LSjWtQrvzZF4gUZP1qfdd/b/C0c1M4=; b=Z6pq6063Bn93u4jVS40eSlDsB4bwuLxRSjb9OeHXzsZ7dLd1RkFKdKTH4RfcFpSbmVlo8i wv8M7n8fAIuueQxw/IJpO807/FvI4eRkJo6R1NtBbxIjdVESXLoCt17O4mWdhOVy4MDYoN EFB1d4Q/yfG9NiwxO2Q6No4JWMvp7q0= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1639438066; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1ly1qWDMyzaC9LSjWtQrvzZF4gUZP1qfdd/b/C0c1M4=; b=qJeWp/qQ8ILoHU7oHdx/qqnBEl8ah9U3hv1hGTLLgZk0Tg53u+pQ1GT1HKuOSm3S4zp2Ik 3S8EdR7hTcsOhcDQ== Received: from echidna.suse.de (unknown [10.163.47.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id 3C6B2A3B83; Mon, 13 Dec 2021 23:27:46 +0000 (UTC) From: David Disseldorp To: linux-fsdevel@vger.kernel.org Cc: Martin Wilck , viro@zeniv.linux.org.uk, willy@infradead.org, David Disseldorp Subject: [PATCH v5 1/5] initramfs: refactor do_header() cpio magic checks Date: Tue, 14 Dec 2021 00:20:04 +0100 Message-Id: <20211213232007.26851-2-ddiss@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211213232007.26851-1-ddiss@suse.de> References: <20211213232007.26851-1-ddiss@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org do_header() is called for each cpio entry and fails if the first six bytes don't match "newc" magic. The magic check includes a special case error message if POSIX.1 ASCII (cpio -H odc) magic is detected. This special case POSIX.1 check can be nested under the "newc" mismatch code path to avoid calling memcmp() twice in a non-error case. Signed-off-by: David Disseldorp Reviewed-by: Martin Wilck --- init/initramfs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/init/initramfs.c b/init/initramfs.c index 2f3d96dc3db6..2f79b3ec0b40 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -257,12 +257,11 @@ static int __init do_collect(void) static int __init do_header(void) { - if (memcmp(collected, "070707", 6)==0) { - error("incorrect cpio method used: use -H newc option"); - return 1; - } if (memcmp(collected, "070701", 6)) { - error("no cpio magic"); + if (memcmp(collected, "070707", 6) == 0) + error("incorrect cpio method used: use -H newc option"); + else + error("no cpio magic"); return 1; } parse_header(collected); From patchwork Mon Dec 13 23:20:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Disseldorp X-Patchwork-Id: 12674827 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4360DC433FE for ; Mon, 13 Dec 2021 23:27:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242198AbhLMX1s (ORCPT ); Mon, 13 Dec 2021 18:27:48 -0500 Received: from smtp-out1.suse.de ([195.135.220.28]:38946 "EHLO smtp-out1.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242066AbhLMX1r (ORCPT ); Mon, 13 Dec 2021 18:27:47 -0500 Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out1.suse.de (Postfix) with ESMTP id 99CAD212BA; Mon, 13 Dec 2021 23:27:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1639438066; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DIt9ginl48PKy64MiddiDG2EUGisGKDxe5coRfLRgmI=; b=SMyP/SyKubOAb4vUXmne+gcyt0TG+od6KHHyosDPTmhie3QebkzYa+O05JmJzsbP6WXJp+ 4hFXupCDOfof2XYc+IOmGy7C308mIxnuYynKrqIL/lP3fAcFKlLeCXYWz0ES6v3T6pNdiD BzWUJQJtMFG0pyJep3U7GIBDuptjh/c= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1639438066; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DIt9ginl48PKy64MiddiDG2EUGisGKDxe5coRfLRgmI=; b=oa4mZS9aWZHqi7QbCRYVwplbAobGEaaxKJBLBPGRCyR8AGPb6R8OQW5HQ7Q59AH2ipmVsz WJ/v4WCS9jO/XKDg== Received: from echidna.suse.de (unknown [10.163.47.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id 6F0C5A3B87; Mon, 13 Dec 2021 23:27:46 +0000 (UTC) From: David Disseldorp To: linux-fsdevel@vger.kernel.org Cc: Martin Wilck , viro@zeniv.linux.org.uk, willy@infradead.org, David Disseldorp Subject: [PATCH v5 2/5] initramfs: add INITRAMFS_PRESERVE_MTIME Kconfig option Date: Tue, 14 Dec 2021 00:20:05 +0100 Message-Id: <20211213232007.26851-3-ddiss@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211213232007.26851-1-ddiss@suse.de> References: <20211213232007.26851-1-ddiss@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org initramfs cpio mtime preservation, as implemented in commit 889d51a10712 ("initramfs: add option to preserve mtime from initramfs cpio images"), uses a linked list to defer directory mtime processing until after all other items in the cpio archive have been processed. This is done to ensure that parent directory mtimes aren't overwritten via subsequent child creation. Contrary to the 889d51a10712 commit message, the mtime preservation behaviour is unconditional. This change adds a new INITRAMFS_PRESERVE_MTIME Kconfig option, which can be used to disable on-by-default mtime retention and in turn speed up initramfs extraction, particularly for cpio archives with large directory counts. Benchmarks with a one million directory cpio archive extracted 20 times demonstrated: mean extraction time (s) std dev INITRAMFS_PRESERVE_MTIME=y 3.808 0.006 INITRAMFS_PRESERVE_MTIME unset 3.056 0.004 The above extraction times were measured using ftrace (initcall_finish - initcall_start) values for populate_rootfs() with initramfs_async disabled. Signed-off-by: David Disseldorp Reviewed-by: Martin Wilck --- init/Kconfig | 10 +++++++++ init/initramfs.c | 48 +++------------------------------------- init/initramfs_mtime.h | 50 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 45 deletions(-) create mode 100644 init/initramfs_mtime.h diff --git a/init/Kconfig b/init/Kconfig index 4b7bac10c72d..a98f63d3c366 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1357,6 +1357,16 @@ config BOOT_CONFIG If unsure, say Y. +config INITRAMFS_PRESERVE_MTIME + bool "Preserve cpio archive mtimes in initramfs" + default y + help + Each entry in an initramfs cpio archive carries an mtime value. When + enabled, extracted cpio items take this mtime, with directory mtime + setting deferred until after creation of any child entries. + + If unsure, say Y. + choice prompt "Compiler optimization level" default CC_OPTIMIZE_FOR_PERFORMANCE diff --git a/init/initramfs.c b/init/initramfs.c index 2f79b3ec0b40..5b4ca8ecadb5 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -17,6 +17,8 @@ #include #include +#include "initramfs_mtime.h" + static ssize_t __init xwrite(struct file *file, const char *p, size_t count, loff_t *pos) { @@ -116,46 +118,6 @@ static void __init free_hash(void) } } -static long __init do_utime(char *filename, time64_t mtime) -{ - struct timespec64 t[2]; - - t[0].tv_sec = mtime; - t[0].tv_nsec = 0; - t[1].tv_sec = mtime; - t[1].tv_nsec = 0; - return init_utimes(filename, t); -} - -static __initdata LIST_HEAD(dir_list); -struct dir_entry { - struct list_head list; - char *name; - time64_t mtime; -}; - -static void __init dir_add(const char *name, time64_t mtime) -{ - struct dir_entry *de = kmalloc(sizeof(struct dir_entry), GFP_KERNEL); - if (!de) - panic_show_mem("can't allocate dir_entry buffer"); - INIT_LIST_HEAD(&de->list); - de->name = kstrdup(name, GFP_KERNEL); - de->mtime = mtime; - list_add(&de->list, &dir_list); -} - -static void __init dir_utime(void) -{ - struct dir_entry *de, *tmp; - list_for_each_entry_safe(de, tmp, &dir_list, list) { - list_del(&de->list); - do_utime(de->name, de->mtime); - kfree(de->name); - kfree(de); - } -} - static __initdata time64_t mtime; /* cpio header parsing */ @@ -379,14 +341,10 @@ static int __init do_name(void) static int __init do_copy(void) { if (byte_count >= body_len) { - struct timespec64 t[2] = { }; if (xwrite(wfile, victim, body_len, &wfile_pos) != body_len) error("write error"); - t[0].tv_sec = mtime; - t[1].tv_sec = mtime; - vfs_utimes(&wfile->f_path, t); - + do_utime_path(&wfile->f_path, mtime); fput(wfile); eat(body_len); state = SkipIt; diff --git a/init/initramfs_mtime.h b/init/initramfs_mtime.h new file mode 100644 index 000000000000..fbd8757b34a9 --- /dev/null +++ b/init/initramfs_mtime.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifdef CONFIG_INITRAMFS_PRESERVE_MTIME +static void __init do_utime(char *filename, time64_t mtime) +{ + struct timespec64 t[2] = { { .tv_sec = mtime }, { .tv_sec = mtime } }; + init_utimes(filename, t); +} + +static void __init do_utime_path(const struct path *path, time64_t mtime) +{ + struct timespec64 t[2] = { { .tv_sec = mtime }, { .tv_sec = mtime } }; + vfs_utimes(path, t); +} + +static __initdata LIST_HEAD(dir_list); +struct dir_entry { + struct list_head list; + char *name; + time64_t mtime; +}; + +static void __init dir_add(const char *name, time64_t mtime) +{ + struct dir_entry *de = kmalloc(sizeof(struct dir_entry), GFP_KERNEL); + if (!de) + panic("can't allocate dir_entry buffer"); + INIT_LIST_HEAD(&de->list); + de->name = kstrdup(name, GFP_KERNEL); + de->mtime = mtime; + list_add(&de->list, &dir_list); +} + +static void __init dir_utime(void) +{ + struct dir_entry *de, *tmp; + + list_for_each_entry_safe(de, tmp, &dir_list, list) { + list_del(&de->list); + do_utime(de->name, de->mtime); + kfree(de->name); + kfree(de); + } +} +#else +static void __init do_utime(char *filename, time64_t mtime) {} +static void __init do_utime_path(const struct path *path, time64_t mtime) {} +static void __init dir_add(const char *name, time64_t mtime) {} +static void __init dir_utime(void) {} +#endif From patchwork Mon Dec 13 23:20:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Disseldorp X-Patchwork-Id: 12674829 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5F000C4332F for ; Mon, 13 Dec 2021 23:27:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242322AbhLMX1t (ORCPT ); Mon, 13 Dec 2021 18:27:49 -0500 Received: from smtp-out1.suse.de ([195.135.220.28]:38954 "EHLO smtp-out1.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242126AbhLMX1r (ORCPT ); Mon, 13 Dec 2021 18:27:47 -0500 Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out1.suse.de (Postfix) with ESMTP id CC85E212BC; Mon, 13 Dec 2021 23:27:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1639438066; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dT3bNEkeoqlQtpJ1IGL9Z6s5aNZ4925QHeV43AShAkw=; b=bSLcemAhjJOK6Gbbt1CllS+aGdA4X7Wi7M5xc6DURRqJHvO7nH2tECE+1nE+usOVcCNOF8 zbRy1e5WE3k2y8gWTP8lMZNCOOIyHBI1EEwIC0w1gDVxVsxemDgXSETlvTizIRxebNoPaB kdpDmUw7aZlNrJ+qW3TyutBLnTAaLf8= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1639438066; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dT3bNEkeoqlQtpJ1IGL9Z6s5aNZ4925QHeV43AShAkw=; b=d8UezfwxW4jFOHA6oWXfXZcI/8ehasLqZnk4dRt83ER6ueZCqTtdgiijD5QUxhbNtomKYG LS9k9xA9LFVnpjDg== Received: from echidna.suse.de (unknown [10.163.47.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id A1F0BA3B88; Mon, 13 Dec 2021 23:27:46 +0000 (UTC) From: David Disseldorp To: linux-fsdevel@vger.kernel.org Cc: Martin Wilck , viro@zeniv.linux.org.uk, willy@infradead.org, David Disseldorp Subject: [PATCH v5 3/5] gen_init_cpio: fix short read file handling Date: Tue, 14 Dec 2021 00:20:06 +0100 Message-Id: <20211213232007.26851-4-ddiss@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211213232007.26851-1-ddiss@suse.de> References: <20211213232007.26851-1-ddiss@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org When processing a "file" entry, gen_init_cpio attempts to allocate a buffer large enough to stage the entire contents of the source file. It then attempts to fill the buffer via a single read() call and subsequently writes out the entire buffer length, without checking that read() returned the full length, potentially writing uninitialized buffer memory. Fix this by breaking up file I/O into 64k chunks and only writing the length returned by the prior read() call. Signed-off-by: David Disseldorp --- usr/gen_init_cpio.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index 0e2c8a5838b1..9a0f8c37273a 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -20,6 +20,7 @@ #define xstr(s) #s #define str(s) xstr(s) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) static unsigned int offset; static unsigned int ino = 721; @@ -297,9 +298,8 @@ static int cpio_mkfile(const char *name, const char *location, unsigned int nlinks) { char s[256]; - char *filebuf = NULL; struct stat buf; - long size; + unsigned long size; int file = -1; int retval; int rc = -1; @@ -326,22 +326,17 @@ static int cpio_mkfile(const char *name, const char *location, buf.st_mtime = 0xffffffff; } - filebuf = malloc(buf.st_size); - if (!filebuf) { - fprintf (stderr, "out of memory\n"); - goto error; - } - - retval = read (file, filebuf, buf.st_size); - if (retval < 0) { - fprintf (stderr, "Can not read %s file\n", location); + if (buf.st_size > 0xffffffff) { + fprintf(stderr, "%s: Size exceeds maximum cpio file size\n", + location); goto error; } size = 0; for (i = 1; i <= nlinks; i++) { /* data goes on last link */ - if (i == nlinks) size = buf.st_size; + if (i == nlinks) + size = buf.st_size; if (name[0] == '/') name++; @@ -366,23 +361,34 @@ static int cpio_mkfile(const char *name, const char *location, push_string(name); push_pad(); - if (size) { - if (fwrite(filebuf, size, 1, stdout) != 1) { + while (size) { + unsigned char filebuf[65536]; + ssize_t this_read; + size_t this_size = MIN(size, sizeof(filebuf)); + + this_read = read(file, filebuf, this_size); + if (this_read <= 0 || this_read > this_size) { + fprintf(stderr, "Can not read %s file\n", location); + goto error; + } + + if (fwrite(filebuf, this_read, 1, stdout) != 1) { fprintf(stderr, "writing filebuf failed\n"); goto error; } - offset += size; - push_pad(); + offset += this_read; + size -= this_read; } + push_pad(); name += namesize; } ino++; rc = 0; - + error: - if (filebuf) free(filebuf); - if (file >= 0) close(file); + if (file >= 0) + close(file); return rc; } From patchwork Mon Dec 13 23:20:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Disseldorp X-Patchwork-Id: 12674833 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E7B4EC433F5 for ; Mon, 13 Dec 2021 23:27:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242527AbhLMX1t (ORCPT ); Mon, 13 Dec 2021 18:27:49 -0500 Received: from smtp-out2.suse.de ([195.135.220.29]:46214 "EHLO smtp-out2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242134AbhLMX1s (ORCPT ); Mon, 13 Dec 2021 18:27:48 -0500 Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out2.suse.de (Postfix) with ESMTP id 0AFE91F3C5; Mon, 13 Dec 2021 23:27:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1639438067; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0olblKT4Lf6E/ZFGQoQz5l9ZkwgnLOqIstvu57MkJ2U=; b=PTuxRCaRjt2FrwBpe+b9kct6IUxhFo9PlMT5+OyFl79Op9zZQm0EgbXNUi628/HB03a5fO bLue+BJzqVcEpA0g9SJPkFPqRI6MG7mEiS5qbrchpAvBxjsgVMsYHcXZenDAST3htILEFv reZ2CfcZoXzwn5AmDBQG/4oG+XcMFIY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1639438067; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0olblKT4Lf6E/ZFGQoQz5l9ZkwgnLOqIstvu57MkJ2U=; b=Bbig+1ut6GBwMsfINuquG1qayqqdp63YWrZOJHGhkg5nq6YDz3wbKHjXxpjsxV/yH+U6av yYNsSVVUyvty1CBA== Received: from echidna.suse.de (unknown [10.163.47.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id D446AA3B83; Mon, 13 Dec 2021 23:27:46 +0000 (UTC) From: David Disseldorp To: linux-fsdevel@vger.kernel.org Cc: Martin Wilck , viro@zeniv.linux.org.uk, willy@infradead.org, David Disseldorp Subject: [PATCH v5 4/5] gen_init_cpio: support file checksum archiving Date: Tue, 14 Dec 2021 00:20:07 +0100 Message-Id: <20211213232007.26851-5-ddiss@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211213232007.26851-1-ddiss@suse.de> References: <20211213232007.26851-1-ddiss@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Documentation/driver-api/early-userspace/buffer-format.rst includes the specification for crc-enabled cpio archives. Implement support for this format in gen_init_cpio via a new '-c' parameter. Suggested-by: Matthew Wilcox (Oracle) Signed-off-by: David Disseldorp --- usr/gen_init_cpio.c | 54 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index 9a0f8c37273a..dc838e26a5b9 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include +#include #include #include #include @@ -25,6 +27,7 @@ static unsigned int offset; static unsigned int ino = 721; static time_t default_mtime; +static bool do_csum = false; struct file_handler { const char *type; @@ -78,7 +81,7 @@ static void cpio_trailer(void) sprintf(s, "%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", - "070701", /* magic */ + do_csum ? "070702" : "070701", /* magic */ 0, /* ino */ 0, /* mode */ (long) 0, /* uid */ @@ -110,7 +113,7 @@ static int cpio_mkslink(const char *name, const char *target, name++; sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", - "070701", /* magic */ + do_csum ? "070702" : "070701", /* magic */ ino++, /* ino */ S_IFLNK | mode, /* mode */ (long) uid, /* uid */ @@ -159,7 +162,7 @@ static int cpio_mkgeneric(const char *name, unsigned int mode, name++; sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", - "070701", /* magic */ + do_csum ? "070702" : "070701", /* magic */ ino++, /* ino */ mode, /* mode */ (long) uid, /* uid */ @@ -253,7 +256,7 @@ static int cpio_mknod(const char *name, unsigned int mode, name++; sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" "%08X%08X%08X%08X%08X%08X%08X", - "070701", /* magic */ + do_csum ? "070702" : "070701", /* magic */ ino++, /* ino */ mode, /* mode */ (long) uid, /* uid */ @@ -293,6 +296,29 @@ static int cpio_mknod_line(const char *line) return rc; } +static int cpio_mkfile_csum(int fd, unsigned long size, uint32_t *csum) +{ + while (size) { + unsigned char filebuf[65536]; + ssize_t this_read; + size_t i, this_size = MIN(size, sizeof(filebuf)); + + this_read = read(fd, filebuf, this_size); + if (this_read <= 0 || this_read > this_size) + return -1; + + for (i = 0; i < this_read; i++) + *csum += filebuf[i]; + + size -= this_read; + } + /* seek back to the start for data segment I/O */ + if (lseek(fd, 0, SEEK_SET) < 0) + return -1; + + return 0; +} + static int cpio_mkfile(const char *name, const char *location, unsigned int mode, uid_t uid, gid_t gid, unsigned int nlinks) @@ -305,6 +331,7 @@ static int cpio_mkfile(const char *name, const char *location, int rc = -1; int namesize; unsigned int i; + uint32_t csum = 0; mode |= S_IFREG; @@ -332,6 +359,11 @@ static int cpio_mkfile(const char *name, const char *location, goto error; } + if (do_csum && cpio_mkfile_csum(file, buf.st_size, &csum) < 0) { + fprintf(stderr, "Failed to checksum file %s\n", location); + goto error; + } + size = 0; for (i = 1; i <= nlinks; i++) { /* data goes on last link */ @@ -343,7 +375,7 @@ static int cpio_mkfile(const char *name, const char *location, namesize = strlen(name) + 1; sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX" "%08lX%08X%08X%08X%08X%08X%08X", - "070701", /* magic */ + do_csum ? "070702" : "070701", /* magic */ ino, /* ino */ mode, /* mode */ (long) uid, /* uid */ @@ -356,7 +388,7 @@ static int cpio_mkfile(const char *name, const char *location, 0, /* rmajor */ 0, /* rminor */ namesize, /* namesize */ - 0); /* chksum */ + size ? csum : 0); /* chksum */ push_hdr(s); push_string(name); push_pad(); @@ -464,7 +496,7 @@ static int cpio_mkfile_line(const char *line) static void usage(const char *prog) { fprintf(stderr, "Usage:\n" - "\t%s [-t ] \n" + "\t%s [-t ] [-c] \n" "\n" " is a file containing newline separated entries that\n" "describe the files to be included in the initramfs archive:\n" @@ -499,7 +531,8 @@ static void usage(const char *prog) "\n" " is time in seconds since Epoch that will be used\n" "as mtime for symlinks, special files and directories. The default\n" - "is to use the current time for these entries.\n", + "is to use the current time for these entries.\n" + "-c: calculate and store 32-bit checksums for file data.\n", prog); } @@ -541,7 +574,7 @@ int main (int argc, char *argv[]) default_mtime = time(NULL); while (1) { - int opt = getopt(argc, argv, "t:h"); + int opt = getopt(argc, argv, "t:ch"); char *invalid; if (opt == -1) @@ -556,6 +589,9 @@ int main (int argc, char *argv[]) exit(1); } break; + case 'c': + do_csum = true; + break; case 'h': case '?': usage(argv[0]); From patchwork Mon Dec 13 23:20:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Disseldorp X-Patchwork-Id: 12674831 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 78E31C433EF for ; Mon, 13 Dec 2021 23:27:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244154AbhLMX1u (ORCPT ); Mon, 13 Dec 2021 18:27:50 -0500 Received: from smtp-out2.suse.de ([195.135.220.29]:46226 "EHLO smtp-out2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242103AbhLMX1s (ORCPT ); Mon, 13 Dec 2021 18:27:48 -0500 Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out2.suse.de (Postfix) with ESMTP id 3DE0A1F3C6; Mon, 13 Dec 2021 23:27:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1639438067; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mDlw3+F/2XMD4uChHoYTT839HaCwSlUPxhDd/Rgnxpo=; b=TcemtsPrEEprKUEcJOdcVX8GhbsreAo9v8QDRhw+3p6jBHgR7Z+k0IkdIkwfyIHlXYkdio eOWl/WzYf8+OOPxyRpqXFPfgx+V+XuKrWJkYiU5738JYpE+nEQJOZrgNt6zIQHkgfnOB52 aeyBJGzHP59R+6+I7c05rsostFKoylQ= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1639438067; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mDlw3+F/2XMD4uChHoYTT839HaCwSlUPxhDd/Rgnxpo=; b=vCrOx8+8n1QopirrSKZG5j0TZZR5J02GlzgTT0h/tC6TTK2q9nZMBqBJdzZA5fm+MfMXWD TdcvnQwtNPizkqCg== Received: from echidna.suse.de (unknown [10.163.47.146]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by relay2.suse.de (Postfix) with ESMTPS id 12807A3B87; Mon, 13 Dec 2021 23:27:47 +0000 (UTC) From: David Disseldorp To: linux-fsdevel@vger.kernel.org Cc: Martin Wilck , viro@zeniv.linux.org.uk, willy@infradead.org, David Disseldorp Subject: [PATCH v5 5/5] initramfs: support cpio extraction with file checksums Date: Tue, 14 Dec 2021 00:20:08 +0100 Message-Id: <20211213232007.26851-6-ddiss@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211213232007.26851-1-ddiss@suse.de> References: <20211213232007.26851-1-ddiss@suse.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Add support for the extraction of crc-enabled "070702" cpio archives, as specified in Documentation/driver-api/early-userspace/buffer-format.rst. Fail extraction if the calculated file data checksum doesn't match the value carried in the header. Suggested-by: Matthew Wilcox (Oracle) Signed-off-by: David Disseldorp --- init/initramfs.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/init/initramfs.c b/init/initramfs.c index 5b4ca8ecadb5..ead3e2839f44 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -19,8 +19,11 @@ #include "initramfs_mtime.h" -static ssize_t __init xwrite(struct file *file, const char *p, size_t count, - loff_t *pos) +static __initdata bool csum_present; +static __initdata u32 io_csum; + +static ssize_t __init xwrite(struct file *file, const unsigned char *p, + size_t count, loff_t *pos) { ssize_t out = 0; @@ -35,6 +38,13 @@ static ssize_t __init xwrite(struct file *file, const char *p, size_t count, } else if (rv == 0) break; + if (csum_present) { + ssize_t i; + + for (i = 0; i < rv; i++) + io_csum += p[i]; + } + p += rv; out += rv; count -= rv; @@ -118,8 +128,6 @@ static void __init free_hash(void) } } -static __initdata time64_t mtime; - /* cpio header parsing */ static __initdata unsigned long ino, major, minor, nlink; @@ -128,15 +136,17 @@ static __initdata unsigned long body_len, name_len; static __initdata uid_t uid; static __initdata gid_t gid; static __initdata unsigned rdev; +static __initdata time64_t mtime; +static __initdata u32 hdr_csum; static void __init parse_header(char *s) { - unsigned long parsed[12]; + unsigned long parsed[13]; char buf[9]; int i; buf[8] = '\0'; - for (i = 0, s += 6; i < 12; i++, s += 8) { + for (i = 0, s += 6; i < 13; i++, s += 8) { memcpy(buf, s, 8); parsed[i] = simple_strtoul(buf, NULL, 16); } @@ -151,6 +161,7 @@ static void __init parse_header(char *s) minor = parsed[8]; rdev = new_encode_dev(MKDEV(parsed[9], parsed[10])); name_len = parsed[11]; + hdr_csum = parsed[12]; } /* FSM */ @@ -219,7 +230,11 @@ static int __init do_collect(void) static int __init do_header(void) { - if (memcmp(collected, "070701", 6)) { + if (!memcmp(collected, "070701", 6)) { + csum_present = false; + } else if (!memcmp(collected, "070702", 6)) { + csum_present = true; + } else { if (memcmp(collected, "070707", 6) == 0) error("incorrect cpio method used: use -H newc option"); else @@ -314,6 +329,7 @@ static int __init do_name(void) if (IS_ERR(wfile)) return 0; wfile_pos = 0; + io_csum = 0; vfs_fchown(wfile, uid, gid); vfs_fchmod(wfile, mode); @@ -346,6 +362,8 @@ static int __init do_copy(void) do_utime_path(&wfile->f_path, mtime); fput(wfile); + if (csum_present && io_csum != hdr_csum) + error("bad data checksum"); eat(body_len); state = SkipIt; return 0;