Page MenuHomeFreeBSD

D25230.id72979.diff
No OneTemporary

D25230.id72979.diff

Index: libexec/Makefile
===================================================================
--- libexec/Makefile
+++ libexec/Makefile
@@ -7,6 +7,7 @@
${_atrun} \
${_blacklistd-helper} \
${_comsat} \
+ corestop \
${_dma} \
flua \
getty \
Index: libexec/corestop/Makefile
===================================================================
--- /dev/null
+++ libexec/corestop/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+SCRIPTS= corestop.sh
+
+.include <bsd.prog.mk>
Index: libexec/corestop/corestop.sh
===================================================================
--- /dev/null
+++ libexec/corestop/corestop.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+die() {
+ echo "$*; exiting" 1>&2
+ exit 1
+}
+
+PID="$1"
+EUID="$2"
+
+if [ "$3" != "su-done" ]; then
+ # Reexecute ourselves as user $EUID.
+ LOGIN=$(getent passwd "${EUID}" | cut -f 1 -d ':')
+
+ if [ -z "${LOGIN}" ]; then
+ die "cannot retrieve login name for EUID ${EUID}"
+ exit 1
+ fi
+
+ exec su -l ${LOGIN} -c "${0} ${PID} ${EUID} su-done"
+
+ # This cannot happen, but hey, what if there's a bug in sh(1)?
+ exit 1
+fi
+
+# From this point on we're running as user $EUID.
+
+if [ "${EUID}" -ne $(id -u) ]; then
+ # Make extra sure it doesn't happen.
+ die "not running as EUID ${EUID}"
+fi
+
+# Get the process working directory.
+CWD=$(procstat -f "${PID}" | awk '$3 == "cwd" { print $10 }')
+[ -n "${CWD}" ] || die "unable to query working directory"
+
+# Get process name.
+COMM=$(procstat -b "${PID}" | awk 'NR == 2 { print $2 }')
+[ -n "${CWD}" ] || die "unable to query process name"
+
+CORETMP=$(mktemp -d -t corestop.XXXXXX)
+if [ $? -ne 0 -o -z "${CORETMP}" ]; then
+ die "mktemp failed"
+fi
+
+cd "${CORETMP}"
+
+show() {
+ echo "\$ $@"
+ $@
+ echo
+}
+
+{
+ echo bt | show /usr/bin/lldb -p "${PID}"
+ #echo bt | show /usr/local/bin/gdb -q -p "${PID}"
+
+ show procstat arguments "${PID}"
+ show procstat environment "${PID}"
+ show procstat vm "${PID}"
+ show procstat files "${PID}"
+ show procstat threads "${PID}"
+ show procstat basic "${PID}"
+ show procstat binary "${PID}"
+ show procstat credentials "${PID}"
+ show procstat auxv "${PID}"
+ show procstat signal "${PID}"
+ show procstat tsignal "${PID}"
+ show procstat kstack "${PID}"
+ show procstat rlimit "${PID}"
+ # XXX: The one below doesn't seem to work.
+ #show procstat ptlwpinfo "${PID}"
+ show procstat rusage "${PID}"
+ show procstat cpuset "${PID}"
+
+} > "${CORETMP}/core.txt" 2>&1
+
+# Get list of files mapped as executable into the process virtual memory,
+# ie the main executable and its shared libraries.
+FILES=$(procstat -v "${PID}" | awk '$4 ~ /x/ && $10 == "vn" {print $11 }' | sort -u | xargs)
+
+gcore -c "${COMM}.core" "${PID}"
+
+COREDIR="${COMM}.${PID}.coredir"
+CORETAR="${CWD}/${COREDIR}.tar.gz"
+tar -c -z -L -s ",^,${COREDIR}/," -f "${CORETAR}" * ${FILES}
+rc=$?
+rm -rf "${CORETMP}"
+
+if [ $rc -eq 0 ]; then
+ echo "${CORETAR} created for pid ${PID} (${COMM}), euid ${EUID}"
+fi
Index: sbin/devd/devd.conf
===================================================================
--- sbin/devd/devd.conf
+++ sbin/devd/devd.conf
@@ -263,6 +263,13 @@
action "/etc/rc.resume acpi $notify";
};
+notify 10 {
+ match "system" "kernel";
+ match "subsystem" "signal";
+ match "type" "corestop";
+ action "/usr/libexec/corestop $pid $euid 2>&1 | /usr/bin/logger -st corestop\(pid=$pid\); kill -KILL $pid";
+};
+
/* EXAMPLES TO END OF FILE
# An example of something that a vendor might install if you were to
Index: sbin/devd/devd.conf.5
===================================================================
--- sbin/devd/devd.conf.5
+++ sbin/devd/devd.conf.5
@@ -272,6 +272,8 @@
Name of attached/detached device.
.It Li endpoints
Endpoint count (USB).
+.It Li euid
+Effective UID (corestop).
.It Li function
Card functions.
.It Li interface
@@ -295,7 +297,8 @@
.It Li parent
Parent device.
.It Li pid
-PID of the process triggering the rule (RCTL).
+PID of the process triggering the rule (RCTL),
+or the process that crashed (corestop).
.It Li port
Hub port number (USB).
.It Li product
@@ -521,6 +524,9 @@
.It Sy Type
.It Li coredump
Notification that a process has crashed and dumped core.
+.It Li corestop
+Notification that a process would crash, but was stopped
+just before executing the offending instruction.
.El
.El
.Pp
Index: sys/compat/linux/linux_file.c
===================================================================
--- sys/compat/linux/linux_file.c
+++ sys/compat/linux/linux_file.c
@@ -1371,9 +1371,10 @@
case LINUX_F_DUPFD_CLOEXEC:
return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
+ default:
+ linux_msg(td, "unsupported fcntl cmd %d\n", args->cmd);
+ return (EINVAL);
}
-
- return (EINVAL);
}
int
Index: sys/compat/linux/linux_futex.c
===================================================================
--- sys/compat/linux/linux_futex.c
+++ sys/compat/linux/linux_futex.c
@@ -760,7 +760,8 @@
clockrt = args->op & LINUX_FUTEX_CLOCK_REALTIME;
args->op = args->op & ~LINUX_FUTEX_CLOCK_REALTIME;
if (clockrt && args->op != LINUX_FUTEX_WAIT_BITSET &&
- args->op != LINUX_FUTEX_WAIT_REQUEUE_PI) {
+ args->op != LINUX_FUTEX_WAIT_REQUEUE_PI &&
+ args->op != LINUX_FUTEX_WAIT) {
LIN_SDT_PROBE0(futex, linux_sys_futex,
unimplemented_clockswitch);
LIN_SDT_PROBE1(futex, linux_sys_futex, return, ENOSYS);
Index: sys/compat/linux/linux_mib.h
===================================================================
--- sys/compat/linux/linux_mib.h
+++ sys/compat/linux/linux_mib.h
@@ -62,6 +62,7 @@
#define linux_use26(t) (linux_kernver(t) >= LINUX_KERNVER_2006000)
+extern int linux_debug;
extern int linux_default_openfiles;
extern int linux_ignore_ip_recverr;
extern int linux_preserve_vstatus;
Index: sys/compat/linux/linux_mib.c
===================================================================
--- sys/compat/linux/linux_mib.c
+++ sys/compat/linux/linux_mib.c
@@ -63,6 +63,11 @@
SYSCTL_NODE(_compat, OID_AUTO, linux, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"Linux mode");
+int linux_debug = 1;
+SYSCTL_INT(_compat_linux, OID_AUTO, debug, CTLFLAG_RWTUN,
+ &linux_debug, 0,
+ "Log warnings from linux(4); or 0 to disable");
+
int linux_default_openfiles = 1024;
SYSCTL_INT(_compat_linux, OID_AUTO, default_openfiles, CTLFLAG_RWTUN,
&linux_default_openfiles, 0,
Index: sys/compat/linux/linux_socket.h
===================================================================
--- sys/compat/linux/linux_socket.h
+++ sys/compat/linux/linux_socket.h
@@ -170,12 +170,6 @@
/* Socket defines */
#define LINUX_SOL_SOCKET 1
-#define LINUX_SOL_IP 0
-#define LINUX_SOL_TCP 6
-#define LINUX_SOL_UDP 17
-#define LINUX_SOL_IPV6 41
-#define LINUX_SOL_IPX 256
-#define LINUX_SOL_AX25 257
#define LINUX_SO_DEBUG 1
#define LINUX_SO_REUSEADDR 2
Index: sys/compat/linux/linux_socket.c
===================================================================
--- sys/compat/linux/linux_socket.c
+++ sys/compat/linux/linux_socket.c
@@ -92,10 +92,9 @@
linux_to_bsd_sockopt_level(int level)
{
- switch (level) {
- case LINUX_SOL_SOCKET:
+ if (level == LINUX_SOL_SOCKET)
return (SOL_SOCKET);
- }
+ /* Remaining values are RFC-defined protocol numbers. */
return (level);
}
@@ -103,10 +102,8 @@
bsd_to_linux_sockopt_level(int level)
{
- switch (level) {
- case SOL_SOCKET:
+ if (level == SOL_SOCKET)
return (LINUX_SOL_SOCKET);
- }
return (level);
}
@@ -946,7 +943,7 @@
struct msghdr msg;
struct l_cmsghdr linux_cmsg;
struct l_cmsghdr *ptr_cmsg;
- struct l_msghdr linux_msg;
+ struct l_msghdr linux_msghdr;
struct iovec *iov;
socklen_t datalen;
struct sockaddr *sa;
@@ -958,7 +955,7 @@
l_size_t clen;
int error, fflag;
- error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
+ error = copyin(msghdr, &linux_msghdr, sizeof(linux_msghdr));
if (error != 0)
return (error);
@@ -969,10 +966,11 @@
* order to handle this case. This should be checked, but allows the
* Linux ping to work.
*/
- if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
- linux_msg.msg_control = PTROUT(NULL);
+ if (PTRIN(linux_msghdr.msg_control) != NULL &&
+ linux_msghdr.msg_controllen == 0)
+ linux_msghdr.msg_control = PTROUT(NULL);
- error = linux_to_bsd_msghdr(&msg, &linux_msg);
+ error = linux_to_bsd_msghdr(&msg, &linux_msghdr);
if (error != 0)
return (error);
@@ -1010,7 +1008,7 @@
goto bad;
}
- if (linux_msg.msg_controllen >= sizeof(struct l_cmsghdr)) {
+ if (linux_msghdr.msg_controllen >= sizeof(struct l_cmsghdr)) {
error = ENOBUFS;
control = m_get(M_WAITOK, MT_CONTROL);
@@ -1018,8 +1016,8 @@
data = mtod(control, void *);
datalen = 0;
- ptr_cmsg = PTRIN(linux_msg.msg_control);
- clen = linux_msg.msg_controllen;
+ ptr_cmsg = PTRIN(linux_msghdr.msg_control);
+ clen = linux_msghdr.msg_controllen;
do {
error = copyin(ptr_cmsg, &linux_cmsg,
sizeof(struct l_cmsghdr));
@@ -1154,7 +1152,7 @@
struct l_cmsghdr *linux_cmsg = NULL;
struct l_ucred linux_ucred;
socklen_t datalen, maxlen, outlen;
- struct l_msghdr linux_msg;
+ struct l_msghdr linux_msghdr;
struct iovec *iov, *uiov;
struct mbuf *control = NULL;
struct mbuf **controlp;
@@ -1166,11 +1164,11 @@
void *data;
int error, i, fd, fds, *fdp;
- error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
+ error = copyin(msghdr, &linux_msghdr, sizeof(linux_msghdr));
if (error != 0)
return (error);
- error = linux_to_bsd_msghdr(msg, &linux_msg);
+ error = linux_to_bsd_msghdr(msg, &linux_msghdr);
if (error != 0)
return (error);
@@ -1198,7 +1196,7 @@
goto bad;
if (msg->msg_name) {
- msg->msg_name = PTRIN(linux_msg.msg_name);
+ msg->msg_name = PTRIN(linux_msghdr.msg_name);
error = bsd_to_linux_sockaddr(sa, &lsa, msg->msg_namelen);
if (error == 0)
error = copyout(lsa, PTRIN(msg->msg_name),
@@ -1208,12 +1206,12 @@
goto bad;
}
- error = bsd_to_linux_msghdr(msg, &linux_msg);
+ error = bsd_to_linux_msghdr(msg, &linux_msghdr);
if (error != 0)
goto bad;
- maxlen = linux_msg.msg_controllen;
- linux_msg.msg_controllen = 0;
+ maxlen = linux_msghdr.msg_controllen;
+ linux_msghdr.msg_controllen = 0;
if (control) {
linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO);
@@ -1221,7 +1219,7 @@
msg->msg_controllen = control->m_len;
cm = CMSG_FIRSTHDR(msg);
- outbuf = PTRIN(linux_msg.msg_control);
+ outbuf = PTRIN(linux_msghdr.msg_control);
outlen = 0;
while (cm != NULL) {
linux_cmsg->cmsg_type =
@@ -1230,6 +1228,7 @@
bsd_to_linux_sockopt_level(cm->cmsg_level);
if (linux_cmsg->cmsg_type == -1 ||
cm->cmsg_level != SOL_SOCKET) {
+ linux_msg(curthread, "recvmsg: tukej; type %d level %d", linux_cmsg->cmsg_type, cm->cmsg_level);
error = EINVAL;
goto bad;
}
@@ -1287,7 +1286,7 @@
error = EMSGSIZE;
goto bad;
} else {
- linux_msg.msg_flags |= LINUX_MSG_CTRUNC;
+ linux_msghdr.msg_flags |= LINUX_MSG_CTRUNC;
m_dispose_extcontrolm(control);
goto out;
}
@@ -1309,11 +1308,11 @@
cm = CMSG_NXTHDR(msg, cm);
}
- linux_msg.msg_controllen = outlen;
+ linux_msghdr.msg_controllen = outlen;
}
out:
- error = copyout(&linux_msg, msghdr, sizeof(linux_msg));
+ error = copyout(&linux_msghdr, msghdr, sizeof(linux_msghdr));
bad:
if (control != NULL) {
@@ -1810,7 +1809,7 @@
return (linux_sendfile(td, arg));
}
- uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
+ linux_msg(td, "socket type %d not implemented", args->what);
return (ENOSYS);
}
#endif /* __i386__ || __arm__ || (__amd64__ && COMPAT_LINUX32) */
Index: sys/compat/linux/linux_util.c
===================================================================
--- sys/compat/linux/linux_util.c
+++ sys/compat/linux/linux_util.c
@@ -91,6 +91,9 @@
va_list ap;
struct proc *p;
+ if (linux_debug == 0)
+ return;
+
p = td->td_proc;
printf("linux: pid %d (%s): ", (int)p->p_pid, p->p_comm);
va_start(ap, fmt);
Index: sys/kern/kern_sig.c
===================================================================
--- sys/kern/kern_sig.c
+++ sys/kern/kern_sig.c
@@ -104,6 +104,7 @@
"struct thread *", "struct proc *", "int");
static int coredump(struct thread *);
+static void corestop(struct thread *, int sig);
static int killpg1(struct thread *td, int sig, int pgid, int all,
ksiginfo_t *ksi);
static int issignal(struct thread *td);
@@ -189,6 +190,10 @@
SYSCTL_INT(_kern, OID_AUTO, coredump, CTLFLAG_RW,
&do_coredump, 0, "Enable/Disable coredumps");
+static int do_corestop = 0;
+SYSCTL_INT(_kern, OID_AUTO, corestop, CTLFLAG_RW,
+ &do_corestop, 0, "Stop the process instead of dumping core");
+
static int set_core_nodump_flag = 0;
SYSCTL_INT(_kern, OID_AUTO, nodump_coredump, CTLFLAG_RW, &set_core_nodump_flag,
0, "Enable setting the NODUMP flag on coredump files");
@@ -3104,6 +3109,9 @@
* Default action, where the default is to kill
* the process. (Other cases were ignored above.)
*/
+ if (do_corestop && (sigprop(sig) & SIGPROP_CORE))
+ corestop(td, sig);
+
mtx_unlock(&ps->ps_mtx);
proc_td_siginfo_capture(td, &ksi.ksi_info);
sigexit(td, sig);
@@ -3769,6 +3777,81 @@
#endif
free(name, M_TEMP);
return (error);
+}
+
+/*
+ * Stop the crashed process, so it can be analyzed and then killed.
+ */
+static void
+corestop(struct thread *td, int sig)
+{
+ char strbuf[32];
+ struct proc *p;
+ struct sigacts *ps;
+ int must_exit, rv;
+
+ p = td->td_proc;
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ ps = p->p_sigacts;
+ mtx_assert(&ps->ps_mtx, MA_OWNED);
+
+ /*
+ * The policy here mimics the one from coredump().
+ */
+ if ((!sugid_coredump && (p->p_flag & P_SUGID) != 0) ||
+ (p->p_flag2 & P2_NOTRACE) != 0) {
+ return;
+ }
+
+ must_exit = thread_single(p, SINGLE_NO_EXIT);
+ if (must_exit)
+ return;
+
+ KASSERT((p->p_flag2 & P2_CORESTOPPED) == 0,
+ ("%s: P2_CORESTOPPED already set", __func__));
+
+ p->p_flag2 |= P2_CORESTOPPED;
+
+ log(LOG_INFO,
+ "pid %d (%s), jid %d, uid %d: would exit on "
+ "signal %d (core stopped)\n", p->p_pid, p->p_comm,
+ p->p_ucred->cr_prison->pr_id,
+ td->td_ucred->cr_uid,
+ sig &~ WCOREFLAG);
+ rv = snprintf(strbuf, sizeof(strbuf),
+ "pid=%d euid=%d", p->p_pid, p->p_ucred->cr_uid);
+ KASSERT(rv > 0 && rv < sizeof(strbuf),
+ ("%s: snprintf failed\n", __func__));
+ devctl_notify("kernel", "signal", "corestop", strbuf);
+
+again:
+ /*
+ * Actually stop executing now. The only caveat is that we need
+ * to provide a way for the debugger to attach and detach, more
+ * than once. This is somewhat complicated due to PT_ATTACH
+ * and PT_DETACH insisting on resuming the process.
+ */
+ mtx_unlock(&ps->ps_mtx);
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK,
+ &p->p_mtx.lock_object, "corestopping");
+ sigqueue_delete(&td->td_sigqueue, sig);
+ sigqueue_delete(&p->p_sigqueue, sig);
+ p->p_flag |= P_STOPPED_SIG;
+ p->p_xsig = sig;
+ PROC_SLOCK(p);
+ sig_suspend_threads(td, p, 0);
+ thread_suspend_switch(td, p);
+ PROC_SUNLOCK(p);
+ mtx_lock(&ps->ps_mtx);
+
+ /*
+ * Handle signals as long as we are being ptraced.
+ */
+ if (p->p_flag2 & P2_PTRACE_FSTP) {
+ while ((sig = cursig(td)) != 0)
+ postsig(sig);
+ goto again;
+ }
}
/*
Index: sys/kern/sys_process.c
===================================================================
--- sys/kern/sys_process.c
+++ sys/kern/sys_process.c
@@ -1089,11 +1089,18 @@
* Unsuspend all threads. To leave a thread
* suspended, use PT_SUSPEND to suspend it before
* continuing the process.
+ *
+ * Except for processes that are corestopped - those
+ * need to remain stopped, otherwise it wouldn't be
+ * possible to reattach to them.
*/
- PROC_SLOCK(p);
- p->p_flag &= ~(P_STOPPED_TRACE | P_STOPPED_SIG | P_WAITED);
- thread_unsuspend(p);
- PROC_SUNLOCK(p);
+ p->p_flag &= ~(P_STOPPED_TRACE | P_WAITED);
+ if ((p->p_flag2 & P2_CORESTOPPED) == 0 || data != 0) {
+ p->p_flag &= ~P_STOPPED_SIG;
+ PROC_SLOCK(p);
+ thread_unsuspend(p);
+ PROC_SUNLOCK(p);
+ }
break;
case PT_WRITE_I:
Index: sys/kern/tty_tty.c
===================================================================
--- sys/kern/tty_tty.c
+++ sys/kern/tty_tty.c
@@ -63,10 +63,14 @@
{
struct proc *p;
- if (*dev != NULL)
+ if (*dev != NULL) {
+ printf("%s: *dev != null, %d (%s)\n", __func__, curproc->p_pid, curproc->p_comm);
return;
- if (strcmp(name, "tty"))
+ }
+ if (strcmp(name, "tty")) {
+ printf("%s: bingo, name != tty, %d (%s)\n", __func__, curproc->p_pid, curproc->p_comm);
return;
+ }
p = curproc;
sx_sunlock(&clone_drain_lock);
sx_slock(&proctree_lock);
Index: sys/sys/proc.h
===================================================================
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -784,6 +784,7 @@
#define P2_PROTMAX_DISABLE 0x00000400 /* Force disable implied PROT_MAX. */
#define P2_STKGAP_DISABLE 0x00000800 /* Disable stack gap for MAP_STACK */
#define P2_STKGAP_DISABLE_EXEC 0x00001000 /* Stack gap disabled after exec */
+#define P2_CORESTOPPED 0x00002000 /* Stopped instead of dumping core */
/* Flags protected by proctree_lock, kept in p_treeflags. */
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
Index: tests/sys/audit/Makefile
===================================================================
--- tests/sys/audit/Makefile
+++ tests/sys/audit/Makefile
@@ -49,7 +49,7 @@
TEST_METADATA+= timeout="30"
TEST_METADATA+= required_user="root"
TEST_METADATA+= is_exclusive="true"
-TEST_METADATA+= required_files="/etc/rc.d/auditd"
+TEST_METADATA+= required_files="/etc/rc.d/auditd /dev/auditpipe"
WARNS?= 6

File Metadata

Mime Type
text/plain
Expires
Fri, Jun 19, 1:55 AM (5 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34064515
Default Alt Text
D25230.id72979.diff (17 KB)

Event Timeline