Re: [PATCH 1/1] binfmt_elf, coredump: Log the reason of the failed core dumps

kernel test robot
2024-06-18T11:32:01Z

Hi Roman,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 831bcbcead6668ebf20b64fdb27518f1362ace3a]

url: https://github.com/intel-lab-lkp/linux/commits/Roman-Kisel/binfmt_elf-coredump-Log-the-reason-of-the-failed-core-dumps/20240618-074419
base: 831bcbcead6668ebf20b64fdb27518f1362ace3a
patch link: https://lore.kernel.org/r/20240617234133.1167523-2-romank%40linux.microsoft.com
patch subject: [PATCH 1/1] binfmt_elf, coredump: Log the reason of the failed core dumps
config: arm-allnoconfig (https://download.01.org/0day-ci/archive/20240618/202406181954.9Z65WD4Z-lkp@intel.com/config)
compiler: clang version 19.0.0git (https://github.com/llvm/llvm-project 78ee473784e5ef6f0b19ce4cb111fb6e4d23c6b2)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240618/202406181954.9Z65WD4Z-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202406181954.9Z65WD4Z-lkp@intel.com/

All warnings (new ones prefixed by >>):

In file included from fs/coredump.c:6:
In file included from include/linux/mm.h:2253:
include/linux/vmstat.h:514:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
514 | return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
| ~~~~~~~~~~~ ^ ~~~
>> fs/coredump.c:816:32: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat]
815 | pr_info("Core dump to |%s: vma_count %d, vma_data_size %lu, written %lld bytes, pos %lld\n",
| ~~~
| %zu
816 | cn.corename, cprm.vma_count, cprm.vma_data_size, cprm.written, cprm.pos);
| ^~~~~~~~~~~~~~~~~~
include/linux/printk.h:537:34: note: expanded from macro 'pr_info'
537 | printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/printk.h:464:60: note: expanded from macro 'printk'
464 | #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/printk.h:436:19: note: expanded from macro 'printk_index_wrap'
436 | _p_func(_fmt, ##__VA_ARGS__); \
| ~~~~ ^~~~~~~~~~~
2 warnings generated.

vim +816 fs/coredump.c

521
522 int do_coredump(const kernel_siginfo_t *siginfo)
523 {
524 struct core_state core_state;
525 struct core_name cn;
526 struct mm_struct *mm = current->mm;
527 struct linux_binfmt * binfmt;
528 const struct cred *old_cred;
529 struct cred *cred;
530 int retval;
531 int ispipe;
532 size_t *argv = NULL;
533 int argc = 0;
534 /* require nonrelative corefile path and be extra careful */
535 bool need_suid_safe = false;
536 bool core_dumped = false;
537 static atomic_t core_dump_count = ATOMIC_INIT(0);
538 struct coredump_params cprm = {
539 .siginfo = siginfo,
540 .limit = rlimit(RLIMIT_CORE),
541 /*
542 * We must use the same mm->flags while dumping core to avoid
543 * inconsistency of bit flags, since this flag is not protected
544 * by any locks.
545 */
546 .mm_flags = mm->flags,
547 .vma_meta = NULL,
548 .cpu = raw_smp_processor_id(),
549 };
550
551 audit_core_dumps(siginfo->si_signo);
552
553 binfmt = mm->binfmt;
554 if (!binfmt || !binfmt->core_dump) {
555 retval = -ENOEXEC;
556 goto fail;
557 }
558 if (!__get_dumpable(cprm.mm_flags)) {
559 retval = -EACCES;
560 goto fail;
561 }
562
563 cred = prepare_creds();
564 if (!cred) {
565 retval = -EPERM;
566 goto fail;
567 }
568 /*
569 * We cannot trust fsuid as being the "true" uid of the process
570 * nor do we know its entire history. We only know it was tainted
571 * so we dump it as root in mode 2, and only into a controlled
572 * environment (pipe handler or fully qualified path).
573 */
574 if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) {
575 /* Setuid core dump mode */
576 cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */
577 need_suid_safe = true;
578 }
579
580 retval = coredump_wait(siginfo->si_signo, &core_state);
581 if (retval < 0)
582 goto fail_creds;
583
584 old_cred = override_creds(cred);
585
586 ispipe = format_corename(&cn, &cprm, &argv, &argc);
587
588 if (ispipe) {
589 int argi;
590 int dump_count;
591 char **helper_argv;
592 struct subprocess_info *sub_info;
593
594 if (ispipe < 0) {
595 printk(KERN_WARNING "format_corename failed\n");
596 printk(KERN_WARNING "Aborting core\n");
597 retval = ispipe;
598 goto fail_unlock;
599 }
600
601 if (cprm.limit == 1) {
602 /* See umh_pipe_setup() which sets RLIMIT_CORE = 1.
603 *
604 * Normally core limits are irrelevant to pipes, since
605 * we're not writing to the file system, but we use
606 * cprm.limit of 1 here as a special value, this is a
607 * consistent way to catch recursive crashes.
608 * We can still crash if the core_pattern binary sets
609 * RLIM_CORE = !1, but it runs as root, and can do
610 * lots of stupid things.
611 *
612 * Note that we use task_tgid_vnr here to grab the pid
613 * of the process group leader. That way we get the
614 * right pid if a thread in a multi-threaded
615 * core_pattern process dies.
616 */
617 printk(KERN_WARNING
618 "Process %d(%s) has RLIMIT_CORE set to 1\n",
619 task_tgid_vnr(current), current->comm);
620 printk(KERN_WARNING "Aborting core\n");
621 retval = -EPERM;
622 goto fail_unlock;
623 }
624 cprm.limit = RLIM_INFINITY;
625
626 dump_count = atomic_inc_return(&core_dump_count);
627 if (core_pipe_limit && (core_pipe_limit < dump_count)) {
628 printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n",
629 task_tgid_vnr(current), current->comm);
630 printk(KERN_WARNING "Skipping core dump\n");
631 retval = -E2BIG;
632 goto fail_dropcount;
633 }
634
635 helper_argv = kmalloc_array(argc + 1, sizeof(*helper_argv),
636 GFP_KERNEL);
637 if (!helper_argv) {
638 printk(KERN_WARNING "%s failed to allocate memory\n",
639 __func__);
640 retval = -ENOMEM;
641 goto fail_dropcount;
642 }
643 for (argi = 0; argi < argc; argi++)
644 helper_argv[argi] = cn.corename + argv[argi];
645 helper_argv[argi] = NULL;
646
647 retval = -ENOMEM;
648 sub_info = call_usermodehelper_setup(helper_argv[0],
649 helper_argv, NULL, GFP_KERNEL,
650 umh_pipe_setup, NULL, &cprm);
651 if (sub_info)
652 retval = call_usermodehelper_exec(sub_info,
653 UMH_WAIT_EXEC);
654
655 kfree(helper_argv);
656 if (retval) {
657 printk(KERN_INFO "Core dump to |%s pipe failed\n",
658 cn.corename);
659 goto close_fail;
660 }
661 } else {
662 struct mnt_idmap *idmap;
663 struct inode *inode;
664 int open_flags = O_CREAT | O_WRONLY | O_NOFOLLOW |
665 O_LARGEFILE | O_EXCL;
666
667 if (cprm.limit < binfmt->min_coredump) {
668 retval = -E2BIG;
669 goto fail_unlock;
670 }
671
672 if (need_suid_safe && cn.corename[0] != '/') {
673 printk(KERN_WARNING "Pid %d(%s) can only dump core "\
674 "to fully qualified path!\n",
675 task_tgid_vnr(current), current->comm);
676 printk(KERN_WARNING "Skipping core dump\n");
677 retval = -EPERM;
678 goto fail_unlock;
679 }
680
681 /*
682 * Unlink the file if it exists unless this is a SUID
683 * binary - in that case, we're running around with root
684 * privs and don't want to unlink another user's coredump.
685 */
686 if (!need_suid_safe) {
687 /*
688 * If it doesn't exist, that's fine. If there's some
689 * other problem, we'll catch it at the filp_open().
690 */
691 do_unlinkat(AT_FDCWD, getname_kernel(cn.corename));
692 }
693
694 /*
695 * There is a race between unlinking and creating the
696 * file, but if that causes an EEXIST here, that's
697 * fine - another process raced with us while creating
698 * the corefile, and the other process won. To userspace,
699 * what matters is that at least one of the two processes
700 * writes its coredump successfully, not which one.
701 */
702 if (need_suid_safe) {
703 /*
704 * Using user namespaces, normal user tasks can change
705 * their current->fs->root to point to arbitrary
706 * directories. Since the intention of the "only dump
707 * with a fully qualified path" rule is to control where
708 * coredumps may be placed using root privileges,
709 * current->fs->root must not be used. Instead, use the
710 * root directory of init_task.
711 */
712 struct path root;
713
714 task_lock(&init_task);
715 get_fs_root(init_task.fs, &root);
716 task_unlock(&init_task);
717 cprm.file = file_open_root(&root, cn.corename,
718 open_flags, 0600);
719 path_put(&root);
720 } else {
721 cprm.file = filp_open(cn.corename, open_flags, 0600);
722 }
723 if (IS_ERR(cprm.file)) {
724 retval = PTR_ERR(cprm.file);
725 goto fail_unlock;
726 }
727
728 inode = file_inode(cprm.file);
729 if (inode->i_nlink > 1) {
730 retval = -EMLINK;
731 goto close_fail;
732 }
733 if (d_unhashed(cprm.file->f_path.dentry)) {
734 retval = -EEXIST;
735 goto close_fail;
736 }
737 /*
738 * AK: actually i see no reason to not allow this for named
739 * pipes etc, but keep the previous behaviour for now.
740 */
741 if (!S_ISREG(inode->i_mode)) {
742 retval = -EISDIR;
743 goto close_fail;
744 }
745 /*
746 * Don't dump core if the filesystem changed owner or mode
747 * of the file during file creation. This is an issue when
748 * a process dumps core while its cwd is e.g. on a vfat
749 * filesystem.
750 */
751 idmap = file_mnt_idmap(cprm.file);
752 if (!vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, inode),
753 current_fsuid())) {
754 pr_info_ratelimited("Core dump to %s aborted: cannot preserve file owner\n",
755 cn.corename);
756 retval = -EPERM;
757 goto close_fail;
758 }
759 if ((inode->i_mode & 0677) != 0600) {
760 pr_info_ratelimited("Core dump to %s aborted: cannot preserve file permissions\n",
761 cn.corename);
762 retval = -EPERM;
763 goto close_fail;
764 }
765 if (!(cprm.file->f_mode & FMODE_CAN_WRITE)) {
766 retval = -EACCES;
767 goto close_fail;
768 }
769 retval = do_truncate(idmap, cprm.file->f_path.dentry,
770 0, 0, cprm.file);
771 if (retval)
772 goto close_fail;
773 }
774
775 /* get us an unshared descriptor table; almost always a no-op */
776 /* The cell spufs coredump code reads the file descriptor tables */
777 retval = unshare_files();
778 if (retval)
779 goto close_fail;
780 if (!dump_interrupted()) {
781 /*
782 * umh disabled with CONFIG_STATIC_USERMODEHELPER_PATH="" would
783 * have this set to NULL.
784 */
785 if (!cprm.file) {
786 pr_info("Core dump to |%s disabled\n", cn.corename);
787 retval = -EPERM;
788 goto close_fail;
789 }
790 if (!dump_vma_snapshot(&cprm)) {
791 pr_err("Can't get VMA snapshot for core dump |%s\n", cn.corename);
792 retval = -EACCES;
793 goto close_fail;
794 }
795
796 file_start_write(cprm.file);
797 core_dumped = binfmt->core_dump(&cprm);
798 /*
799 * Ensures that file size is big enough to contain the current
800 * file postion. This prevents gdb from complaining about
801 * a truncated file if the last "write" to the file was
802 * dump_skip.
803 */
804 if (cprm.to_skip) {
805 cprm.to_skip--;
806 dump_emit(&cprm, "", 1);
807 }
808 file_end_write(cprm.file);
809 free_vma_snapshot(&cprm);
810 } else {
811 pr_err("Core dump to |%s has been interrupted\n", cn.corename);
812 retval = -EAGAIN;
813 goto fail;
814 }
815 pr_info("Core dump to |%s: vma_count %d, vma_data_size %lu, written %lld bytes, pos %lld\n",
> 816 cn.corename, cprm.vma_count, cprm.vma_data_size, cprm.written, cprm.pos);
817 if (ispipe && core_pipe_limit)
818 wait_for_dump_helpers(cprm.file);
819
820 retval = 0;
821
822 close_fail:
823 if (cprm.file)
824 filp_close(cprm.file, NULL);
825 fail_dropcount:
826 if (ispipe)
827 atomic_dec(&core_dump_count);
828 fail_unlock:
829 kfree(argv);
830 kfree(cn.corename);
831 coredump_finish(core_dumped);
832 revert_creds(old_cred);
833 fail_creds:
834 put_cred(cred);
835 fail:
836 return retval;
837 }
838

--
0-DAY CI Kernel Test Service