Newer
Older
}
static int __get_dumpable(unsigned long mm_flags)
{
int ret;
ret = mm_flags & MMF_DUMPABLE_MASK;
return (ret >= 2) ? 2 : ret;
}
int get_dumpable(struct mm_struct *mm)
{
return __get_dumpable(mm->flags);
}
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
static void wait_for_dump_helpers(struct file *file)
{
struct pipe_inode_info *pipe;
pipe = file->f_path.dentry->d_inode->i_pipe;
pipe_lock(pipe);
pipe->readers++;
pipe->writers--;
while ((pipe->readers > 1) && (!signal_pending(current))) {
wake_up_interruptible_sync(&pipe->wait);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
pipe_wait(pipe);
}
pipe->readers--;
pipe->writers++;
pipe_unlock(pipe);
}

Neil Horman
committed
/*

Neil Horman
committed
* helper function to customize the process used
* to collect the core in userspace. Specifically
* it sets up a pipe and installs it as fd 0 (stdin)
* for the process. Returns 0 on success, or
* PTR_ERR on failure.
* Note that it also sets the core limit to 1. This
* is a special value that we use to trap recursive
* core dumps
*/
static int umh_pipe_setup(struct subprocess_info *info, struct cred *new)

Neil Horman
committed
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
{
struct file *rp, *wp;
struct fdtable *fdt;
struct coredump_params *cp = (struct coredump_params *)info->data;
struct files_struct *cf = current->files;
wp = create_write_pipe(0);
if (IS_ERR(wp))
return PTR_ERR(wp);
rp = create_read_pipe(wp, 0);
if (IS_ERR(rp)) {
free_write_pipe(wp);
return PTR_ERR(rp);
}
cp->file = wp;
sys_close(0);
fd_install(0, rp);
spin_lock(&cf->file_lock);
fdt = files_fdtable(cf);
FD_SET(0, fdt->open_fds);
FD_CLR(0, fdt->close_on_exec);
spin_unlock(&cf->file_lock);
/* and disallow core files too */
current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1};
return 0;
}
void do_coredump(long signr, int exit_code, struct pt_regs *regs)
struct core_state core_state;
struct core_name cn;
struct mm_struct *mm = current->mm;
struct linux_binfmt * binfmt;
const struct cred *old_cred;
struct cred *cred;
static atomic_t core_dump_count = ATOMIC_INIT(0);
struct coredump_params cprm = {
.signr = signr,
.regs = regs,
/*
* We must use the same mm->flags while dumping core to avoid
* inconsistency of bit flags, since this flag is not protected
* by any locks.
*/
.mm_flags = mm->flags,
binfmt = mm->binfmt;
if (!__get_dumpable(cprm.mm_flags))
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(cprm.mm_flags) == 2) {
/* Setuid core dump mode */
cred->fsuid = 0; /* Dump root private */
retval = coredump_wait(exit_code, &core_state);
if (retval < 0)
goto fail_creds;
/*
* 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);
ispipe = format_corename(&cn, signr);
if (ispipe) {
int dump_count;
char **helper_argv;
if (ispipe < 0) {
printk(KERN_WARNING "format_corename failed\n");
printk(KERN_WARNING "Aborting core\n");
goto fail_corename;
}

Neil Horman
committed
if (cprm.limit == 1) {
/*
* Normally core limits are irrelevant to pipes, since
* we're not writing to the file system, but we use

Neil Horman
committed
* cprm.limit of 1 here as a speacial value. Any
* non-1 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

Neil Horman
committed
* if the core_pattern binary sets RLIM_CORE = !1
* 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

Neil Horman
committed
"Process %d(%s) has RLIMIT_CORE set to 1\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, cn.corename+1, NULL);
if (!helper_argv) {
printk(KERN_WARNING "%s failed to allocate memory\n",
__func__);
goto fail_dropcount;
retval = call_usermodehelper_fns(helper_argv[0], helper_argv,
NULL, UMH_WAIT_EXEC, umh_pipe_setup,
NULL, &cprm);
argv_free(helper_argv);
if (retval) {
printk(KERN_INFO "Core dump to %s pipe failed\n",
cn.corename);
} else {
struct inode *inode;
if (cprm.limit < binfmt->min_coredump)
goto fail_unlock;
cprm.file = filp_open(cn.corename,
O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
0600);
if (IS_ERR(cprm.file))
goto fail_unlock;
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
inode = cprm.file->f_path.dentry->d_inode;
if (inode->i_nlink > 1)
goto close_fail;
if (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 (!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 || !cprm.file->f_op->write)
goto close_fail;
if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file))
goto close_fail;
}
retval = binfmt->core_dump(&cprm);
if (retval)
current->signal->group_exit_code |= 0x80;
if (ispipe && core_pipe_limit)
wait_for_dump_helpers(cprm.file);
close_fail:
if (cprm.file)
filp_close(cprm.file, NULL);
fail_dropcount:
atomic_dec(&core_dump_count);
kfree(cn.corename);
fail_corename:
/*
* Core dumping helper functions. These are the only things you should
* do on a core-file: use only these functions to write out all the
* necessary info.
*/
int dump_write(struct file *file, const void *addr, int nr)
{
return access_ok(VERIFY_READ, addr, nr) && file->f_op->write(file, addr, nr, &file->f_pos) == nr;
}
EXPORT_SYMBOL(dump_write);
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
int dump_seek(struct file *file, loff_t off)
{
int ret = 1;
if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
if (file->f_op->llseek(file, off, SEEK_CUR) < 0)
return 0;
} else {
char *buf = (char *)get_zeroed_page(GFP_KERNEL);
if (!buf)
return 0;
while (off > 0) {
unsigned long n = off;
if (n > PAGE_SIZE)
n = PAGE_SIZE;
if (!dump_write(file, buf, n)) {
ret = 0;
break;
}
off -= n;
}
free_page((unsigned long)buf);
}
return ret;
}
EXPORT_SYMBOL(dump_seek);