参照元

説明

引数

返り値

参考

実装

void do_coredump(long signr, int exit_code, struct pt_regs *regs)
{
	struct core_state core_state;
	char corename[CORENAME_MAX_SIZE + 1];
	struct mm_struct *mm = current->mm;
	struct linux_binfmt * binfmt;
	struct inode * inode;
	const struct cred *old_cred;
	struct cred *cred;
	int retval = 0;
	int flag = 0;
	int ispipe = 0;
	char **helper_argv = NULL;
	int helper_argc = 0;
	int dump_count = 0;
	static atomic_t core_dump_count = ATOMIC_INIT(0);
	struct coredump_params cprm = {
		.signr = signr,
		.regs = regs,
		.limit = current->signal->rlim[RLIMIT_CORE].rlim_cur,
	};

	audit_core_dumps(signr);

	binfmt = mm->binfmt;
	if (!binfmt || !binfmt->core_dump)
		goto fail;

	cred = prepare_creds();
	if (!cred) {
		retval = -ENOMEM;
		goto fail;
	}

	down_write(&mm->mmap_sem);
	/*
	 * If another thread got here first, or we are not dumpable, bail out.
	 */
	if (mm->core_state || !get_dumpable(mm)) {
		up_write(&mm->mmap_sem);
		put_cred(cred);
		goto fail;
	}

	/*
	 *	We cannot trust fsuid as being the "true" uid of the
	 *	process nor do we know its entire history. We only know it
	 *	was tainted so we dump it as root in mode 2.
	 */
	if (get_dumpable(mm) == 2) {	/* Setuid core dump mode */
		flag = O_EXCL;		/* Stop rewrite attacks */
		cred->fsuid = 0;	/* Dump root private */
	}

	retval = coredump_wait(exit_code, &core_state);
	if (retval < 0) {
		put_cred(cred);
		goto fail;
	}

	old_cred = override_creds(cred);

	/*
	 * Clear any false indication of pending signals that might
	 * be seen by the filesystem code called to write the core file.
	 */
	clear_thread_flag(TIF_SIGPENDING);

	/*
	 * lock_kernel() because format_corename() is controlled by sysctl, which
	 * uses lock_kernel()
	 */
 	lock_kernel();
	ispipe = format_corename(corename, signr);
	unlock_kernel();

	if ((!ispipe) && (cprm.limit < binfmt->min_coredump))
		goto fail_unlock;

 	if (ispipe) {
		if (cprm.limit == 0) {
			/*
			 * Normally core limits are irrelevant to pipes, since
			 * we're not writing to the file system, but we use
			 * cprm.limit of 0 here as a speacial value. Any
			 * non-zero limit gets set to RLIM_INFINITY below, but
			 * a limit of 0 skips the dump.  This is a consistent
			 * way to catch recursive crashes.  We can still crash
			 * if the core_pattern binary sets RLIM_CORE =  !0
			 * but it runs as root, and can do lots of stupid things
			 * Note that we use task_tgid_vnr here to grab the pid
			 * of the process group leader.  That way we get the
			 * right pid if a thread in a multi-threaded
			 * core_pattern process dies.
			 */
			printk(KERN_WARNING
				"Process %d(%s) has RLIMIT_CORE set to 0\n",
				task_tgid_vnr(current), current->comm);
			printk(KERN_WARNING "Aborting core\n");
			goto fail_unlock;
		}

		dump_count = atomic_inc_return(&core_dump_count);
		if (core_pipe_limit && (core_pipe_limit < dump_count)) {
			printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n",
			       task_tgid_vnr(current), current->comm);
			printk(KERN_WARNING "Skipping core dump\n");
			goto fail_dropcount;
		}

		helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc);
		if (!helper_argv) {
			printk(KERN_WARNING "%s failed to allocate memory\n",
			       __func__);
			goto fail_dropcount;
		}

		cprm.limit = RLIM_INFINITY;

		/* SIGPIPE can happen, but it's just never processed */
		if (call_usermodehelper_pipe(helper_argv[0], helper_argv, NULL,
				&cprm.file)) {
 			printk(KERN_INFO "Core dump to %s pipe failed\n",
			       corename);
			goto fail_dropcount;
 		}
 	} else
		cprm.file = filp_open(corename,
				 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
				 0600);
	if (IS_ERR(cprm.file))
		goto fail_dropcount;
	inode = cprm.file->f_path.dentry->d_inode;
	if (inode->i_nlink > 1)
		goto close_fail;	/* multiple links - don't dump */
	if (!ispipe && d_unhashed(cprm.file->f_path.dentry))
		goto close_fail;

	/* AK: actually i see no reason to not allow this for named pipes etc.,
	   but keep the previous behaviour for now. */
	if (!ispipe && !S_ISREG(inode->i_mode))
		goto close_fail;
	/*
	 * Dont allow local users get cute and trick others to coredump
	 * into their pre-created files:
	 */
	if (inode->i_uid != current_fsuid())
		goto close_fail;
	if (!cprm.file->f_op)
		goto close_fail;
	if (!cprm.file->f_op->write)
		goto close_fail;
	if (!ispipe &&
	    do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file) != 0)
		goto close_fail;

	retval = binfmt->core_dump(&cprm);

	if (retval)
		current->signal->group_exit_code |= 0x80;
close_fail:
	if (ispipe && core_pipe_limit)
		wait_for_dump_helpers(cprm.file);
	filp_close(cprm.file, NULL);
fail_dropcount:
	if (dump_count)
		atomic_dec(&core_dump_count);
fail_unlock:
	if (helper_argv)
		argv_free(helper_argv);

	revert_creds(old_cred);
	put_cred(cred);
	coredump_finish(mm);
fail:
	return;
}

コメント


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS