xref: /illumos-gate/usr/src/uts/common/os/upanic.c (revision d9529689937cca41f8af4b28094109ebe366870d)
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 2020 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
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 	if (auditing)		/* audit core dump */
87 		audit_core_start(SIGABRT);
88 	code = core(SIGABRT, B_FALSE);
89 	if (auditing)		/* audit core dump */
90 		audit_core_finish(code ? CLD_KILLED : CLD_DUMPED);
91 	exit(code ? CLD_KILLED : CLD_DUMPED, SIGABRT);
92 }
93