projects/linux·blob assoc-array-fixes · refs

798 lines · 18.4 KiB

1// SPDX-License-Identifier: GPL-2.0
2#include <linux/async.h>
3#include <linux/delay.h>
4#include <linux/dirent.h>
5#include <linux/export.h>
6#include <linux/fcntl.h>
7#include <linux/file.h>
8#include <linux/fs.h>
9#include <linux/fs_struct.h>
10#include <linux/hex.h>
11#include <linux/init.h>
12#include <linux/init_syscalls.h>
13#include <linux/kstrtox.h>
14#include <linux/memblock.h>
15#include <linux/mm.h>
16#include <linux/namei.h>
17#include <linux/overflow.h>
18#include <linux/security.h>
19#include <linux/slab.h>
20#include <linux/string.h>
21#include <linux/syscalls.h>
22#include <linux/types.h>
23#include <linux/umh.h>
24#include <linux/utime.h>
25
26#include <asm/byteorder.h>
27
28#include "do_mounts.h"
29#include "initramfs_internal.h"
30
31static __initdata bool csum_present;
32static __initdata u32 io_csum;
33
34static ssize_t __init xwrite(struct file *file, const unsigned char *p,
35 size_t count, loff_t *pos)
36{
37 ssize_t out = 0;
38
39 /* sys_write only can write MAX_RW_COUNT aka 2G-4K bytes at most */
40 while (count) {
41 ssize_t rv = kernel_write(file, p, count, pos);
42
43 if (rv < 0) {
44 if (rv == -EINTR || rv == -EAGAIN)
45 continue;
46 return out ? out : rv;
47 } else if (rv == 0)
48 break;
49
50 if (csum_present) {
51 ssize_t i;
52
53 for (i = 0; i < rv; i++)
54 io_csum += p[i];
55 }
56
57 p += rv;
58 out += rv;
59 count -= rv;
60 }
61
62 return out;
63}
64
65static __initdata char *message;
66static void __init error(char *x)
67{
68 if (!message)
69 message = x;
70}
71
72#define panic_show_mem(fmt, ...) \
73 ({ show_mem(); panic(fmt, ##__VA_ARGS__); })
74
75/* link hash */
76
77#define N_ALIGN(len) ((((len) + 1) & ~3) + 2)
78
79static __initdata struct hash {
80 int ino, minor, major;
81 umode_t mode;
82 struct hash *next;
83 char name[N_ALIGN(PATH_MAX)];
84} *head[32];
85static __initdata bool hardlink_seen;
86
87static inline int hash(int major, int minor, int ino)
88{
89 unsigned long tmp = ino + minor + (major << 3);
90 tmp += tmp >> 5;
91 return tmp & 31;
92}
93
94static char __init *find_link(int major, int minor, int ino,
95 umode_t mode, char *name)
96{
97 struct hash **p, *q;
98 for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) {
99 if ((*p)->ino != ino)
100 continue;
101 if ((*p)->minor != minor)
102 continue;
103 if ((*p)->major != major)
104 continue;
105 if (((*p)->mode ^ mode) & S_IFMT)
106 continue;
107 return (*p)->name;
108 }
109 q = kmalloc_obj(struct hash);
110 if (!q)
111 panic_show_mem("can't allocate link hash entry");
112 q->major = major;
113 q->minor = minor;
114 q->ino = ino;
115 q->mode = mode;
116 strscpy(q->name, name);
117 q->next = NULL;
118 *p = q;
119 hardlink_seen = true;
120 return NULL;
121}
122
123static void __init free_hash(void)
124{
125 struct hash **p, *q;
126 for (p = head; hardlink_seen && p < head + 32; p++) {
127 while (*p) {
128 q = *p;
129 *p = q->next;
130 kfree(q);
131 }
132 }
133 hardlink_seen = false;
134}
135
136#ifdef CONFIG_INITRAMFS_PRESERVE_MTIME
137static void __init do_utime(char *filename, time64_t mtime)
138{
139 struct timespec64 t[2] = { { .tv_sec = mtime }, { .tv_sec = mtime } };
140 init_utimes(filename, t);
141}
142
143static void __init do_utime_path(const struct path *path, time64_t mtime)
144{
145 struct timespec64 t[2] = { { .tv_sec = mtime }, { .tv_sec = mtime } };
146 vfs_utimes(path, t);
147}
148
149static __initdata LIST_HEAD(dir_list);
150struct dir_entry {
151 struct list_head list;
152 time64_t mtime;
153 char name[];
154};
155
156static void __init dir_add(const char *name, size_t nlen, time64_t mtime)
157{
158 struct dir_entry *de;
159
160 de = kmalloc_flex(*de, name, nlen);
161 if (!de)
162 panic_show_mem("can't allocate dir_entry buffer");
163 INIT_LIST_HEAD(&de->list);
164 strscpy(de->name, name, nlen);
165 de->mtime = mtime;
166 list_add(&de->list, &dir_list);
167}
168
169static void __init dir_utime(void)
170{
171 struct dir_entry *de, *tmp;
172 list_for_each_entry_safe(de, tmp, &dir_list, list) {
173 list_del(&de->list);
174 do_utime(de->name, de->mtime);
175 kfree(de);
176 }
177}
178#else
179static void __init do_utime(char *filename, time64_t mtime) {}
180static void __init do_utime_path(const struct path *path, time64_t mtime) {}
181static void __init dir_add(const char *name, size_t nlen, time64_t mtime) {}
182static void __init dir_utime(void) {}
183#endif
184
185static __initdata time64_t mtime;
186
187/* cpio header parsing */
188
189static __initdata unsigned long ino, major, minor, nlink;
190static __initdata umode_t mode;
191static __initdata unsigned long body_len, name_len;
192static __initdata uid_t uid;
193static __initdata gid_t gid;
194static __initdata unsigned rdev;
195static __initdata u32 hdr_csum;
196
197static int __init parse_header(char *s)
198{
199 __be32 header[13];
200 int ret;
201
202 ret = hex2bin((u8 *)header, s + 6, sizeof(header));
203 if (ret) {
204 error("damaged header");
205 return ret;
206 }
207
208 ino = be32_to_cpu(header[0]);
209 mode = be32_to_cpu(header[1]);
210 uid = be32_to_cpu(header[2]);
211 gid = be32_to_cpu(header[3]);
212 nlink = be32_to_cpu(header[4]);
213 mtime = be32_to_cpu(header[5]); /* breaks in y2106 */
214 body_len = be32_to_cpu(header[6]);
215 major = be32_to_cpu(header[7]);
216 minor = be32_to_cpu(header[8]);
217 rdev = new_encode_dev(MKDEV(be32_to_cpu(header[9]), be32_to_cpu(header[10])));
218 name_len = be32_to_cpu(header[11]);
219 hdr_csum = be32_to_cpu(header[12]);
220 return 0;
221}
222
223/* Finite-state machine */
224
225static __initdata enum state {
226 Start,
227 Collect,
228 GotHeader,
229 SkipIt,
230 GotName,
231 CopyFile,
232 GotSymlink,
233 Reset
234} state, next_state;
235
236static __initdata char *victim;
237static unsigned long byte_count __initdata;
238static __initdata loff_t this_header, next_header;
239
240static inline void __init eat(unsigned n)
241{
242 victim += n;
243 this_header += n;
244 byte_count -= n;
245}
246
247static __initdata char *collected;
248static long remains __initdata;
249static __initdata char *collect;
250
251static void __init read_into(char *buf, unsigned size, enum state next)
252{
253 if (byte_count >= size) {
254 collected = victim;
255 eat(size);
256 state = next;
257 } else {
258 collect = collected = buf;
259 remains = size;
260 next_state = next;
261 state = Collect;
262 }
263}
264
265static __initdata char *header_buf, *symlink_buf, *name_buf;
266
267static int __init do_start(void)
268{
269 read_into(header_buf, CPIO_HDRLEN, GotHeader);
270 return 0;
271}
272
273static int __init do_collect(void)
274{
275 unsigned long n = remains;
276 if (byte_count < n)
277 n = byte_count;
278 memcpy(collect, victim, n);
279 eat(n);
280 collect += n;
281 if ((remains -= n) != 0)
282 return 1;
283 state = next_state;
284 return 0;
285}
286
287static int __init do_header(void)
288{
289 if (!memcmp(collected, "070701", 6)) {
290 csum_present = false;
291 } else if (!memcmp(collected, "070702", 6)) {
292 csum_present = true;
293 } else {
294 if (memcmp(collected, "070707", 6) == 0)
295 error("incorrect cpio method used: use -H newc option");
296 else
297 error("no cpio magic");
298 return 1;
299 }
300 if (parse_header(collected))
301 return 1;
302 next_header = this_header + N_ALIGN(name_len) + body_len;
303 next_header = (next_header + 3) & ~3;
304 state = SkipIt;
305 if (name_len <= 0 || name_len > PATH_MAX)
306 return 0;
307 if (S_ISLNK(mode)) {
308 if (body_len > PATH_MAX)
309 return 0;
310 collect = collected = symlink_buf;
311 remains = N_ALIGN(name_len) + body_len;
312 next_state = GotSymlink;
313 state = Collect;
314 return 0;
315 }
316 if (S_ISREG(mode) || !body_len)
317 read_into(name_buf, N_ALIGN(name_len), GotName);
318 return 0;
319}
320
321static int __init do_skip(void)
322{
323 if (this_header + byte_count < next_header) {
324 eat(byte_count);
325 return 1;
326 } else {
327 eat(next_header - this_header);
328 state = next_state;
329 return 0;
330 }
331}
332
333static int __init do_reset(void)
334{
335 while (byte_count && *victim == '\0')
336 eat(1);
337 if (byte_count && (this_header & 3))
338 error("broken padding");
339 return 1;
340}
341
342static void __init clean_path(char *path, umode_t fmode)
343{
344 struct kstat st;
345
346 if (!init_stat(path, &st, AT_SYMLINK_NOFOLLOW) &&
347 (st.mode ^ fmode) & S_IFMT) {
348 if (S_ISDIR(st.mode))
349 init_rmdir(path);
350 else
351 init_unlink(path);
352 }
353}
354
355static int __init maybe_link(void)
356{
357 if (nlink >= 2) {
358 char *old = find_link(major, minor, ino, mode, collected);
359 if (old) {
360 clean_path(collected, 0);
361 return (init_link(old, collected) < 0) ? -1 : 1;
362 }
363 }
364 return 0;
365}
366
367static __initdata struct file *wfile;
368static __initdata loff_t wfile_pos;
369
370static int __init do_name(void)
371{
372 state = SkipIt;
373 next_state = Reset;
374
375 /* name_len > 0 && name_len <= PATH_MAX checked in do_header */
376 if (collected[name_len - 1] != '\0') {
377 pr_err("initramfs name without nulterm: %.*s\n",
378 (int)name_len, collected);
379 error("malformed archive");
380 return 1;
381 }
382
383 if (strcmp(collected, "TRAILER!!!") == 0) {
384 free_hash();
385 return 0;
386 }
387 clean_path(collected, mode);
388 if (S_ISREG(mode)) {
389 int ml = maybe_link();
390 if (ml >= 0) {
391 int openflags = O_WRONLY|O_CREAT|O_LARGEFILE;
392 if (ml != 1)
393 openflags |= O_TRUNC;
394 wfile = filp_open(collected, openflags, mode);
395 if (IS_ERR(wfile))
396 return 0;
397 wfile_pos = 0;
398 io_csum = 0;
399
400 vfs_fchown(wfile, uid, gid);
401 vfs_fchmod(wfile, mode);
402 if (body_len)
403 vfs_truncate(&wfile->f_path, body_len);
404 state = CopyFile;
405 }
406 } else if (S_ISDIR(mode)) {
407 init_mkdir(collected, mode);
408 init_chown(collected, uid, gid, 0);
409 init_chmod(collected, mode);
410 dir_add(collected, name_len, mtime);
411 } else if (S_ISBLK(mode) || S_ISCHR(mode) ||
412 S_ISFIFO(mode) || S_ISSOCK(mode)) {
413 if (maybe_link() == 0) {
414 init_mknod(collected, mode, rdev);
415 init_chown(collected, uid, gid, 0);
416 init_chmod(collected, mode);
417 do_utime(collected, mtime);
418 }
419 }
420 return 0;
421}
422
423static int __init do_copy(void)
424{
425 if (byte_count >= body_len) {
426 if (xwrite(wfile, victim, body_len, &wfile_pos) != body_len)
427 error("write error");
428
429 do_utime_path(&wfile->f_path, mtime);
430 fput(wfile);
431 if (csum_present && io_csum != hdr_csum)
432 error("bad data checksum");
433 eat(body_len);
434 state = SkipIt;
435 return 0;
436 } else {
437 if (xwrite(wfile, victim, byte_count, &wfile_pos) != byte_count)
438 error("write error");
439 body_len -= byte_count;
440 eat(byte_count);
441 return 1;
442 }
443}
444
445static int __init do_symlink(void)
446{
447 if (collected[name_len - 1] != '\0') {
448 pr_err("initramfs symlink without nulterm: %.*s\n",
449 (int)name_len, collected);
450 error("malformed archive");
451 return 1;
452 }
453 collected[N_ALIGN(name_len) + body_len] = '\0';
454 clean_path(collected, 0);
455 init_symlink(collected + N_ALIGN(name_len), collected);
456 init_chown(collected, uid, gid, AT_SYMLINK_NOFOLLOW);
457 do_utime(collected, mtime);
458 state = SkipIt;
459 next_state = Reset;
460 return 0;
461}
462
463static __initdata int (*actions[])(void) = {
464 [Start] = do_start,
465 [Collect] = do_collect,
466 [GotHeader] = do_header,
467 [SkipIt] = do_skip,
468 [GotName] = do_name,
469 [CopyFile] = do_copy,
470 [GotSymlink] = do_symlink,
471 [Reset] = do_reset,
472};
473
474static long __init write_buffer(char *buf, unsigned long len)
475{
476 byte_count = len;
477 victim = buf;
478
479 while (!actions[state]())
480 ;
481 return len - byte_count;
482}
483
484static long __init flush_buffer(void *bufv, unsigned long len)
485{
486 char *buf = bufv;
487 long written;
488 long origLen = len;
489 if (message)
490 return -1;
491 while ((written = write_buffer(buf, len)) < len && !message) {
492 char c = buf[written];
493 if (c == '0') {
494 buf += written;
495 len -= written;
496 state = Start;
497 } else if (c == 0) {
498 buf += written;
499 len -= written;
500 state = Reset;
501 } else
502 error("junk within compressed archive");
503 }
504 return origLen;
505}
506
507static unsigned long my_inptr __initdata; /* index of next byte to be processed in inbuf */
508
509#include <linux/decompress/generic.h>
510
511/**
512 * unpack_to_rootfs - decompress and extract an initramfs archive
513 * @buf: input initramfs archive to extract
514 * @len: length of initramfs data to process
515 *
516 * Returns: NULL for success or an error message string
517 *
518 * This symbol shouldn't be used externally. It's available for unit tests.
519 */
520char * __init unpack_to_rootfs(char *buf, unsigned long len)
521{
522 long written;
523 decompress_fn decompress;
524 const char *compress_name;
525 struct {
526 char header[CPIO_HDRLEN];
527 char symlink[PATH_MAX + N_ALIGN(PATH_MAX) + 1];
528 char name[N_ALIGN(PATH_MAX)];
529 } *bufs = kmalloc_obj(*bufs);
530
531 if (!bufs)
532 panic_show_mem("can't allocate buffers");
533
534 header_buf = bufs->header;
535 symlink_buf = bufs->symlink;
536 name_buf = bufs->name;
537
538 state = Start;
539 this_header = 0;
540 message = NULL;
541 while (!message && len) {
542 loff_t saved_offset = this_header;
543 if (*buf == '0' && !(this_header & 3)) {
544 state = Start;
545 written = write_buffer(buf, len);
546 buf += written;
547 len -= written;
548 continue;
549 }
550 if (!*buf) {
551 buf++;
552 len--;
553 this_header++;
554 continue;
555 }
556 this_header = 0;
557 decompress = decompress_method(buf, len, &compress_name);
558 pr_debug("Detected %s compressed data\n", compress_name);
559 if (decompress) {
560 int res = decompress(buf, len, NULL, flush_buffer, NULL,
561 &my_inptr, error);
562 if (res)
563 error("decompressor failed");
564 } else if (compress_name) {
565 pr_err("compression method %s not configured\n",
566 compress_name);
567 error("decompressor failed");
568 } else
569 error("invalid magic at start of compressed archive");
570 if (state != Reset)
571 error("junk at the end of compressed archive");
572 this_header = saved_offset + my_inptr;
573 buf += my_inptr;
574 len -= my_inptr;
575 }
576 dir_utime();
577 /* free any hardlink state collected without optional TRAILER!!! */
578 free_hash();
579 kfree(bufs);
580 return message;
581}
582
583static int __initdata do_retain_initrd;
584
585static int __init retain_initrd_param(char *str)
586{
587 if (*str)
588 return 0;
589 do_retain_initrd = 1;
590 return 1;
591}
592__setup("retain_initrd", retain_initrd_param);
593
594#ifdef CONFIG_ARCH_HAS_KEEPINITRD
595static int __init keepinitrd_setup(char *__unused)
596{
597 do_retain_initrd = 1;
598 return 1;
599}
600__setup("keepinitrd", keepinitrd_setup);
601#endif
602
603static bool __initdata initramfs_async = true;
604static int __init initramfs_async_setup(char *str)
605{
606 return kstrtobool(str, &initramfs_async) == 0;
607}
608__setup("initramfs_async=", initramfs_async_setup);
609
610extern char __initramfs_start[];
611extern unsigned long __initramfs_size;
612#include <linux/initrd.h>
613#include <linux/kexec.h>
614
615static BIN_ATTR(initrd, 0440, sysfs_bin_attr_simple_read, NULL, 0);
616
617void __init reserve_initrd_mem(void)
618{
619 phys_addr_t start;
620 unsigned long size;
621
622 /* Ignore the virtual address computed during device tree parsing */
623 initrd_start = initrd_end = 0;
624
625 if (!phys_initrd_size)
626 return;
627 /*
628 * Round the memory region to page boundaries as per free_initrd_mem()
629 * This allows us to detect whether the pages overlapping the initrd
630 * are in use, but more importantly, reserves the entire set of pages
631 * as we don't want these pages allocated for other purposes.
632 */
633 start = round_down(phys_initrd_start, PAGE_SIZE);
634 size = phys_initrd_size + (phys_initrd_start - start);
635 size = round_up(size, PAGE_SIZE);
636
637 if (!memblock_is_region_memory(start, size)) {
638 pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region",
639 (u64)start, size);
640 goto disable;
641 }
642
643 if (memblock_is_region_reserved(start, size)) {
644 pr_err("INITRD: 0x%08llx+0x%08lx overlaps in-use memory region\n",
645 (u64)start, size);
646 goto disable;
647 }
648
649 memblock_reserve(start, size);
650 /* Now convert initrd to virtual addresses */
651 initrd_start = (unsigned long)__va(phys_initrd_start);
652 initrd_end = initrd_start + phys_initrd_size;
653 initrd_below_start_ok = 1;
654
655 return;
656disable:
657 pr_cont(" - disabling initrd\n");
658 initrd_start = 0;
659 initrd_end = 0;
660}
661
662void __weak __init free_initrd_mem(unsigned long start, unsigned long end)
663{
664 free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
665 "initrd");
666}
667
668#ifdef CONFIG_CRASH_RESERVE
669static bool __init kexec_free_initrd(void)
670{
671 unsigned long crashk_start = (unsigned long)__va(crashk_res.start);
672 unsigned long crashk_end = (unsigned long)__va(crashk_res.end);
673
674 /*
675 * If the initrd region is overlapped with crashkernel reserved region,
676 * free only memory that is not part of crashkernel region.
677 */
678 if (initrd_start >= crashk_end || initrd_end <= crashk_start)
679 return false;
680
681 /*
682 * Initialize initrd memory region since the kexec boot does not do.
683 */
684 memset((void *)initrd_start, 0, initrd_end - initrd_start);
685 if (initrd_start < crashk_start)
686 free_initrd_mem(initrd_start, crashk_start);
687 if (initrd_end > crashk_end)
688 free_initrd_mem(crashk_end, initrd_end);
689 return true;
690}
691#else
692static inline bool kexec_free_initrd(void)
693{
694 return false;
695}
696#endif /* CONFIG_KEXEC_CORE */
697
698#ifdef CONFIG_BLK_DEV_RAM
699static void __init populate_initrd_image(char *err)
700{
701 ssize_t written;
702 struct file *file;
703 loff_t pos = 0;
704
705 printk(KERN_INFO "rootfs image is not initramfs (%s); looks like an initrd\n",
706 err);
707 file = filp_open("/initrd.image", O_WRONLY|O_CREAT|O_LARGEFILE, 0700);
708 if (IS_ERR(file))
709 return;
710
711 written = xwrite(file, (char *)initrd_start, initrd_end - initrd_start,
712 &pos);
713 if (written != initrd_end - initrd_start)
714 pr_err("/initrd.image: incomplete write (%zd != %ld)\n",
715 written, initrd_end - initrd_start);
716 fput(file);
717}
718#endif /* CONFIG_BLK_DEV_RAM */
719
720static void __init unpack_initramfs(async_cookie_t cookie)
721{
722 /* Load the built in initramfs */
723 char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
724 if (err)
725 panic_show_mem("%s", err); /* Failed to decompress INTERNAL initramfs */
726
727 if (!initrd_start || IS_ENABLED(CONFIG_INITRAMFS_FORCE))
728 return;
729
730 if (IS_ENABLED(CONFIG_BLK_DEV_RAM))
731 printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");
732 else
733 printk(KERN_INFO "Unpacking initramfs...\n");
734
735 err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start);
736 if (err) {
737#ifdef CONFIG_BLK_DEV_RAM
738 populate_initrd_image(err);
739#else
740 printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
741#endif
742 }
743}
744
745static void __init do_populate_rootfs(void *unused, async_cookie_t cookie)
746{
747 scoped_with_init_fs() {
748 unpack_initramfs(cookie);
749 security_initramfs_populated();
750 }
751
752 /*
753 * If the initrd region is overlapped with crashkernel reserved region,
754 * free only memory that is not part of crashkernel region.
755 */
756 if (!do_retain_initrd && initrd_start && !kexec_free_initrd()) {
757 free_initrd_mem(initrd_start, initrd_end);
758 } else if (do_retain_initrd && initrd_start) {
759 bin_attr_initrd.size = initrd_end - initrd_start;
760 bin_attr_initrd.private = (void *)initrd_start;
761 if (sysfs_create_bin_file(firmware_kobj, &bin_attr_initrd))
762 pr_err("Failed to create initrd sysfs file");
763 }
764 initrd_start = 0;
765 initrd_end = 0;
766
767 init_flush_fput();
768}
769
770static ASYNC_DOMAIN_EXCLUSIVE(initramfs_domain);
771static async_cookie_t initramfs_cookie;
772
773void wait_for_initramfs(void)
774{
775 if (!initramfs_cookie) {
776 /*
777 * Something before rootfs_initcall wants to access
778 * the filesystem/initramfs. Probably a bug. Make a
779 * note, avoid deadlocking the machine, and let the
780 * caller's access fail as it used to.
781 */
782 pr_warn_once("wait_for_initramfs() called before rootfs_initcalls\n");
783 return;
784 }
785 async_synchronize_cookie_domain(initramfs_cookie + 1, &initramfs_domain);
786}
787EXPORT_SYMBOL_GPL(wait_for_initramfs);
788
789static int __init populate_rootfs(void)
790{
791 initramfs_cookie = async_schedule_domain(do_populate_rootfs, NULL,
792 &initramfs_domain);
793 usermodehelper_enable();
794 if (!initramfs_async)
795 wait_for_initramfs();
796 return 0;
797}
798rootfs_initcall(populate_rootfs);