| From: David Disseldorp <ddiss@suse.de> |
| Subject: 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: David Disseldorp <ddiss@suse.de> |
| Suggested-by: Matthew 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: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| init/initramfs.c | 29 ++++++++++++++++++++++++----- |
| 1 file changed, 24 insertions(+), 5 deletions(-) |
| |
| --- a/init/initramfs.c~initramfs-support-cpio-extraction-with-file-checksums |
| +++ a/init/initramfs.c |
| @@ -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 |
| } 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 |
| 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; |
| _ |