Commit 800c24dc authored by David Disseldorp's avatar David Disseldorp Committed by Andrew Morton
Browse files

initramfs: support cpio extraction with file checksums

Add support for extraction of checksum-enabled "070702" cpio archives,
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.

Link: https://lkml.kernel.org/r/20220404093429.27570-7-ddiss@suse.de


Signed-off-by: default avatarDavid Disseldorp <ddiss@suse.de>
Suggested-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christian Brauner <christian.brauner@ubuntu.com>
Cc: Martin Wilck <mwilck@suse.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent ea804871
Loading
Loading
Loading
Loading
+24 −5
Original line number Diff line number Diff line
@@ -17,8 +17,11 @@
#include <linux/init_syscalls.h>
#include <linux/umh.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;

@@ -33,6 +36,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;
@@ -176,15 +186,16 @@ static __initdata unsigned long body_len, name_len;
static __initdata uid_t uid;
static __initdata gid_t gid;
static __initdata unsigned rdev;
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);
	}
@@ -199,6 +210,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 */
@@ -267,7 +279,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
@@ -362,6 +378,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);
@@ -394,6 +411,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;