Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_sig.c
Show All 38 Lines | |||||
#include "opt_compat.h" | #include "opt_compat.h" | ||||
#include "opt_kdtrace.h" | #include "opt_kdtrace.h" | ||||
#include "opt_ktrace.h" | #include "opt_ktrace.h" | ||||
#include "opt_core.h" | #include "opt_core.h" | ||||
#include "opt_procdesc.h" | #include "opt_procdesc.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/ctype.h> | |||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/signalvar.h> | #include <sys/signalvar.h> | ||||
#include <sys/vnode.h> | #include <sys/vnode.h> | ||||
#include <sys/acct.h> | #include <sys/acct.h> | ||||
#include <sys/bus.h> | |||||
#include <sys/capsicum.h> | #include <sys/capsicum.h> | ||||
#include <sys/condvar.h> | #include <sys/condvar.h> | ||||
#include <sys/event.h> | #include <sys/event.h> | ||||
#include <sys/fcntl.h> | #include <sys/fcntl.h> | ||||
#include <sys/imgact.h> | #include <sys/imgact.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/ktr.h> | #include <sys/ktr.h> | ||||
#include <sys/ktrace.h> | #include <sys/ktrace.h> | ||||
▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | |||||
static int do_coredump = 1; | static int do_coredump = 1; | ||||
SYSCTL_INT(_kern, OID_AUTO, coredump, CTLFLAG_RW, | SYSCTL_INT(_kern, OID_AUTO, coredump, CTLFLAG_RW, | ||||
&do_coredump, 0, "Enable/Disable coredumps"); | &do_coredump, 0, "Enable/Disable coredumps"); | ||||
static int set_core_nodump_flag = 0; | static int set_core_nodump_flag = 0; | ||||
SYSCTL_INT(_kern, OID_AUTO, nodump_coredump, CTLFLAG_RW, &set_core_nodump_flag, | SYSCTL_INT(_kern, OID_AUTO, nodump_coredump, CTLFLAG_RW, &set_core_nodump_flag, | ||||
0, "Enable setting the NODUMP flag on coredump files"); | 0, "Enable setting the NODUMP flag on coredump files"); | ||||
static int coredump_devctl = 0; | |||||
SYSCTL_INT(_kern, OID_AUTO, coredump_devctl, CTLFLAG_RW, &coredump_devctl, | |||||
0, "Generate a devctl notification when processes coredump"); | |||||
/* | /* | ||||
* Signal properties and actions. | * Signal properties and actions. | ||||
* The array below categorizes the signals and their default actions | * The array below categorizes the signals and their default actions | ||||
* according to the following properties: | * according to the following properties: | ||||
*/ | */ | ||||
#define SA_KILL 0x01 /* terminates process by default */ | #define SA_KILL 0x01 /* terminates process by default */ | ||||
#define SA_CORE 0x02 /* ditto and coredumps */ | #define SA_CORE 0x02 /* ditto and coredumps */ | ||||
#define SA_STOP 0x04 /* suspend process */ | #define SA_STOP 0x04 /* suspend process */ | ||||
▲ Show 20 Lines • Show All 3,118 Lines • ▼ Show 20 Lines | #endif | ||||
return (error); | return (error); | ||||
} | } | ||||
NDFREE(&nd, NDF_ONLY_PNBUF); | NDFREE(&nd, NDF_ONLY_PNBUF); | ||||
*vpp = nd.ni_vp; | *vpp = nd.ni_vp; | ||||
*namep = name; | *namep = name; | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | |||||
coredump_sanitise_path(const char *path) | |||||
{ | |||||
size_t i; | |||||
/* | /* | ||||
* Only send a subset of ASCII to devd(8) because it | |||||
* might pass these strings to sh -c. | |||||
*/ | |||||
for (i = 0; path[i]; i++) | |||||
if (!(isalpha(path[i]) || isdigit(path[i])) && | |||||
path[i] != '/' && path[i] != '.' && | |||||
path[i] != '-') | |||||
return (0); | |||||
return (1); | |||||
} | |||||
/* | |||||
* Dump a process' core. The main routine does some | * Dump a process' core. The main routine does some | ||||
* policy checking, and creates the name of the coredump; | * policy checking, and creates the name of the coredump; | ||||
* then it passes on a vnode and a size limit to the process-specific | * then it passes on a vnode and a size limit to the process-specific | ||||
* coredump routine if there is one; if there _is not_ one, it returns | * coredump routine if there is one; if there _is not_ one, it returns | ||||
* ENOSYS; otherwise it returns the error from the process-specific routine. | * ENOSYS; otherwise it returns the error from the process-specific routine. | ||||
*/ | */ | ||||
static int | static int | ||||
coredump(struct thread *td) | coredump(struct thread *td) | ||||
{ | { | ||||
struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||
struct ucred *cred = td->td_ucred; | struct ucred *cred = td->td_ucred; | ||||
struct vnode *vp; | struct vnode *vp; | ||||
struct flock lf; | struct flock lf; | ||||
struct vattr vattr; | struct vattr vattr; | ||||
int error, error1, locked; | int error, error1, locked; | ||||
struct mount *mp; | struct mount *mp; | ||||
char *name; /* name of corefile */ | char *name; /* name of corefile */ | ||||
off_t limit; | off_t limit; | ||||
int compress; | int compress; | ||||
char *data = NULL; | |||||
char *fullpath, *freepath = NULL; | |||||
size_t len; | |||||
static const char comm_name[] = "comm="; | |||||
static const char core_name[] = "core="; | |||||
#ifdef COMPRESS_USER_CORES | #ifdef COMPRESS_USER_CORES | ||||
compress = compress_user_cores; | compress = compress_user_cores; | ||||
#else | #else | ||||
compress = 0; | compress = 0; | ||||
#endif | #endif | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td); | MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td); | ||||
Show All 26 Lines | restart: | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
/* Don't dump to non-regular files or files with links. */ | /* Don't dump to non-regular files or files with links. */ | ||||
if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 || | if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 || | ||||
vattr.va_nlink != 1) { | vattr.va_nlink != 1) { | ||||
VOP_UNLOCK(vp, 0); | VOP_UNLOCK(vp, 0); | ||||
error = EFAULT; | error = EFAULT; | ||||
goto close; | goto out; | ||||
} | } | ||||
VOP_UNLOCK(vp, 0); | VOP_UNLOCK(vp, 0); | ||||
lf.l_whence = SEEK_SET; | lf.l_whence = SEEK_SET; | ||||
lf.l_start = 0; | lf.l_start = 0; | ||||
lf.l_len = 0; | lf.l_len = 0; | ||||
lf.l_type = F_WRLCK; | lf.l_type = F_WRLCK; | ||||
locked = (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &lf, F_FLOCK) == 0); | locked = (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &lf, F_FLOCK) == 0); | ||||
Show All 28 Lines | restart: | ||||
} else { | } else { | ||||
error = ENOSYS; | error = ENOSYS; | ||||
} | } | ||||
if (locked) { | if (locked) { | ||||
lf.l_type = F_UNLCK; | lf.l_type = F_UNLCK; | ||||
VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_FLOCK); | VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_FLOCK); | ||||
} | } | ||||
close: | |||||
/* | |||||
* Notify the userland helper that a process triggered a core dump. | |||||
* This allows the helper to run an automated debugging session. | |||||
*/ | |||||
if (error != 0 || coredump_devctl == 0) | |||||
goto out; | |||||
len = MAXPATHLEN * 2 + sizeof(comm_name) - 1 + | |||||
sizeof(' ') + sizeof(core_name) - 1; | |||||
data = malloc(len, M_TEMP, M_WAITOK); | |||||
if (vn_fullpath_global(td, p->p_textvp, &fullpath, &freepath) != 0) | |||||
goto out; | |||||
if (!coredump_sanitise_path(fullpath)) | |||||
goto out; | |||||
snprintf(data, len, "%s%s ", comm_name, fullpath); | |||||
free(freepath, M_TEMP); | |||||
freepath = NULL; | |||||
if (vn_fullpath_global(td, vp, &fullpath, &freepath) != 0) | |||||
goto out; | |||||
if (!coredump_sanitise_path(fullpath)) | |||||
goto out; | |||||
strlcat(data, core_name, len); | |||||
strlcat(data, fullpath, len); | |||||
devctl_notify("kernel", "signal", "coredump", data); | |||||
out: | |||||
error1 = vn_close(vp, FWRITE, cred, td); | error1 = vn_close(vp, FWRITE, cred, td); | ||||
if (error == 0) | if (error == 0) | ||||
error = error1; | error = error1; | ||||
out: | |||||
#ifdef AUDIT | #ifdef AUDIT | ||||
audit_proc_coredump(td, name, error); | audit_proc_coredump(td, name, error); | ||||
#endif | #endif | ||||
free(freepath, M_TEMP); | |||||
free(data, M_TEMP); | |||||
free(name, M_TEMP); | free(name, M_TEMP); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Nonexistent system call-- signal process (may want to handle it). Flag | * Nonexistent system call-- signal process (may want to handle it). Flag | ||||
* error in case process won't see signal immediately (blocked or ignored). | * error in case process won't see signal immediately (blocked or ignored). | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 148 Lines • Show Last 20 Lines |