1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2021 Oxide Computer Company
14 */
15
16 #include <sys/proc.h>
17 #include <c2/audit.h>
18 #include <sys/procfs.h>
19 #include <sys/core.h>
20
21 /*
22 * This function is meant to be a guaranteed abort that generates a core file
23 * that allows up to 1k of data to enter into an elfnote in the process. This is
24 * meant to insure that even in the face of other problems, this can get out.
25 */
26
27 void
upanic(void * addr,size_t len)28 upanic(void *addr, size_t len)
29 {
30 kthread_t *t = curthread;
31 proc_t *p = curproc;
32 klwp_t *lwp = ttolwp(t);
33 uint32_t auditing = AU_AUDITING();
34 uint32_t upflag = P_UPF_PANICKED;
35 void *buf;
36 int code;
37
38 /*
39 * Before we worry about the data that the user has as a message, go
40 * ahead and make sure we try and get all the other threads stopped.
41 * That'll help us make sure that nothing else is going on and we don't
42 * lose a race.
43 */
44 mutex_enter(&p->p_lock);
45 lwp->lwp_cursig = SIGABRT;
46 mutex_exit(&p->p_lock);
47
48 proc_is_exiting(p);
49 if (exitlwps(1) != 0) {
50 mutex_enter(&p->p_lock);
51 lwp_exit();
52 }
53
54 /*
55 * Copy in the user data. We truncate it to PRUPANIC_BUFLEN no matter
56 * what and ensure that the last data was set to zero.
57 */
58 if (addr != NULL && len > 0) {
59 size_t copylen;
60
61 upflag |= P_UPF_HAVEMSG;
62
63 if (len >= PRUPANIC_BUFLEN) {
64 copylen = PRUPANIC_BUFLEN;
65 upflag |= P_UPF_TRUNCMSG;
66 } else {
67 copylen = len;
68 }
69
70 buf = kmem_zalloc(PRUPANIC_BUFLEN, KM_SLEEP);
71 if (copyin(addr, buf, copylen) != 0) {
72 upflag |= P_UPF_INVALMSG;
73 upflag &= ~P_UPF_HAVEMSG;
74 } else {
75 mutex_enter(&p->p_lock);
76 ASSERT3P(p->p_upanic, ==, NULL);
77 p->p_upanic = buf;
78 mutex_exit(&p->p_lock);
79 }
80 }
81
82 mutex_enter(&p->p_lock);
83 p->p_upanicflag = upflag;
84 mutex_exit(&p->p_lock);
85
86 /*
87 * If we're auditing we need to finish the system call itself and then
88 * begin the core dump.
89 */
90 if (auditing) {
91 audit_finish(0, SYS_upanic, 0, NULL);
92 audit_core_start(SIGABRT);
93 }
94 code = core(SIGABRT, B_FALSE);
95 if (auditing) /* audit core dump */
96 audit_core_finish(code ? CLD_KILLED : CLD_DUMPED);
97 exit(code ? CLD_KILLED : CLD_DUMPED, SIGABRT);
98 }
99