summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/os
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/os')
-rw-r--r--usr/src/uts/common/os/exit.c10
-rw-r--r--usr/src/uts/common/os/sysent.c6
-rw-r--r--usr/src/uts/common/os/upanic.c92
3 files changed, 106 insertions, 2 deletions
diff --git a/usr/src/uts/common/os/exit.c b/usr/src/uts/common/os/exit.c
index 06e0117cd6..5563c0f4ab 100644
--- a/usr/src/uts/common/os/exit.c
+++ b/usr/src/uts/common/os/exit.c
@@ -22,6 +22,7 @@
/*
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2018 Joyent, Inc.
+ * Copyright 2020 Oxide Computer Company
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -71,6 +72,7 @@
#include <sys/pool.h>
#include <sys/sdt.h>
#include <sys/corectl.h>
+#include <sys/core.h>
#include <sys/brand.h>
#include <sys/libc_kernel.h>
@@ -600,6 +602,14 @@ proc_exit(int why, int what)
}
/*
+ * If we had generated any upanic(2) state, free that now.
+ */
+ if (p->p_upanic != NULL) {
+ kmem_free(p->p_upanic, PRUPANIC_BUFLEN);
+ p->p_upanic = NULL;
+ }
+
+ /*
* Remove any fpollinfo_t's for this (last) thread from our file
* descriptors so closeall() can ASSERT() that they're all gone.
*/
diff --git a/usr/src/uts/common/os/sysent.c b/usr/src/uts/common/os/sysent.c
index fb64000e4d..be45b7ad8f 100644
--- a/usr/src/uts/common/os/sysent.c
+++ b/usr/src/uts/common/os/sysent.c
@@ -25,6 +25,7 @@
* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
* Copyright 2016 Joyent, Inc.
* Copyright (c) 2018, Joyent, Inc.
+ * Copyright 2020 Oxide Computer Company
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
@@ -330,6 +331,7 @@ int setsockopt(int, int, int, void *, socklen_t *, int);
int sockconfig(int, void *, void *, void *, void *);
ssize_t sendfilev(int, int, const struct sendfilevec *, int, size_t *);
ssize_t getrandom(void *, size_t, unsigned int);
+void upanic(void *, size_t);
typedef int64_t (*llfcn_t)(); /* for casting one-word returns */
@@ -583,7 +585,7 @@ struct sysent sysent[NSYSCALL] =
/* 122 */ SYSENT_CL("writev", writev, 3),
/* 123 */ SYSENT_CL("preadv", preadv, 5),
/* 124 */ SYSENT_CL("pwritev", pwritev, 5),
- /* 125 */ SYSENT_LOADABLE(), /* (was fxstat) */
+ /* 125 */ SYSENT_CI("upanic", upanic, 2),
/* 126 */ SYSENT_CL("getrandom", getrandom, 3),
/* 127 */ SYSENT_CI("mmapobj", mmapobjsys, 5),
/* 128 */ IF_LP64(
@@ -948,7 +950,7 @@ struct sysent sysent32[NSYSCALL] =
/* 122 */ SYSENT_CI("writev", writev32, 3),
/* 123 */ SYSENT_CI("preadv", preadv, 5),
/* 124 */ SYSENT_CI("pwritev", pwritev, 5),
- /* 125 */ SYSENT_LOADABLE32(), /* was fxstat32 */
+ /* 125 */ SYSENT_CI("upanic", upanic, 2),
/* 126 */ SYSENT_CI("getrandom", getrandom, 3),
/* 127 */ SYSENT_CI("mmapobj", mmapobjsys, 5),
/* 128 */ SYSENT_CI("setrlimit", setrlimit32, 2),
diff --git a/usr/src/uts/common/os/upanic.c b/usr/src/uts/common/os/upanic.c
new file mode 100644
index 0000000000..8acb9440f2
--- /dev/null
+++ b/usr/src/uts/common/os/upanic.c
@@ -0,0 +1,92 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 Oxide Computer Company
+ */
+
+#include <sys/proc.h>
+#include <c2/audit.h>
+#include <sys/procfs.h>
+#include <sys/core.h>
+
+/*
+ * This function is meant to be a guaranteed abort that generates a core file
+ * that allows up to 1k of data to enter into an elfnote in the process. This is
+ * meant to insure that even in the face of other problems, this can get out.
+ */
+
+void
+upanic(void *addr, size_t len)
+{
+ kthread_t *t = curthread;
+ proc_t *p = curproc;
+ klwp_t *lwp = ttolwp(t);
+ uint32_t auditing = AU_AUDITING();
+ uint32_t upflag = P_UPF_PANICKED;
+ void *buf;
+ int code;
+
+ /*
+ * Before we worry about the data that the user has as a message, go
+ * ahead and make sure we try and get all the other threads stopped.
+ * That'll help us make sure that nothing else is going on and we don't
+ * lose a race.
+ */
+ mutex_enter(&p->p_lock);
+ lwp->lwp_cursig = SIGABRT;
+ mutex_exit(&p->p_lock);
+
+ proc_is_exiting(p);
+ if (exitlwps(1) != 0) {
+ mutex_enter(&p->p_lock);
+ lwp_exit();
+ }
+
+ /*
+ * Copy in the user data. We truncate it to PRUPANIC_BUFLEN no matter
+ * what and ensure that the last data was set to zero.
+ */
+ if (addr != NULL && len > 0) {
+ size_t copylen;
+
+ upflag |= P_UPF_HAVEMSG;
+
+ if (len >= PRUPANIC_BUFLEN) {
+ copylen = PRUPANIC_BUFLEN;
+ upflag |= P_UPF_TRUNCMSG;
+ } else {
+ copylen = len;
+ }
+
+ buf = kmem_zalloc(PRUPANIC_BUFLEN, KM_SLEEP);
+ if (copyin(addr, buf, copylen) != 0) {
+ upflag |= P_UPF_INVALMSG;
+ upflag &= ~P_UPF_HAVEMSG;
+ } else {
+ mutex_enter(&p->p_lock);
+ ASSERT3P(p->p_upanic, ==, NULL);
+ p->p_upanic = buf;
+ mutex_exit(&p->p_lock);
+ }
+ }
+
+ mutex_enter(&p->p_lock);
+ p->p_upanicflag = upflag;
+ mutex_exit(&p->p_lock);
+
+ if (auditing) /* audit core dump */
+ audit_core_start(SIGABRT);
+ code = core(SIGABRT, B_FALSE);
+ if (auditing) /* audit core dump */
+ audit_core_finish(code ? CLD_KILLED : CLD_DUMPED);
+ exit(code ? CLD_KILLED : CLD_DUMPED, SIGABRT);
+}