xref: /illumos-gate/usr/src/uts/common/os/upanic.c (revision 88a8a2ff)
1350ffdd5SRobert Mustacchi /*
2350ffdd5SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3350ffdd5SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4350ffdd5SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5350ffdd5SRobert Mustacchi  * 1.0 of the CDDL.
6350ffdd5SRobert Mustacchi  *
7350ffdd5SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8350ffdd5SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9350ffdd5SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10350ffdd5SRobert Mustacchi  */
11350ffdd5SRobert Mustacchi 
12350ffdd5SRobert Mustacchi /*
13*88a8a2ffSRobert Mustacchi  * Copyright 2021 Oxide Computer Company
14350ffdd5SRobert Mustacchi  */
15350ffdd5SRobert Mustacchi 
16350ffdd5SRobert Mustacchi #include <sys/proc.h>
17350ffdd5SRobert Mustacchi #include <c2/audit.h>
18350ffdd5SRobert Mustacchi #include <sys/procfs.h>
19350ffdd5SRobert Mustacchi #include <sys/core.h>
20350ffdd5SRobert Mustacchi 
21350ffdd5SRobert Mustacchi /*
22350ffdd5SRobert Mustacchi  * This function is meant to be a guaranteed abort that generates a core file
23350ffdd5SRobert Mustacchi  * that allows up to 1k of data to enter into an elfnote in the process. This is
24350ffdd5SRobert Mustacchi  * meant to insure that even in the face of other problems, this can get out.
25350ffdd5SRobert Mustacchi  */
26350ffdd5SRobert Mustacchi 
27350ffdd5SRobert Mustacchi void
upanic(void * addr,size_t len)28350ffdd5SRobert Mustacchi upanic(void *addr, size_t len)
29350ffdd5SRobert Mustacchi {
30350ffdd5SRobert Mustacchi 	kthread_t *t = curthread;
31350ffdd5SRobert Mustacchi 	proc_t *p = curproc;
32350ffdd5SRobert Mustacchi 	klwp_t *lwp = ttolwp(t);
33350ffdd5SRobert Mustacchi 	uint32_t auditing = AU_AUDITING();
34350ffdd5SRobert Mustacchi 	uint32_t upflag = P_UPF_PANICKED;
35350ffdd5SRobert Mustacchi 	void *buf;
36350ffdd5SRobert Mustacchi 	int code;
37350ffdd5SRobert Mustacchi 
38350ffdd5SRobert Mustacchi 	/*
39350ffdd5SRobert Mustacchi 	 * Before we worry about the data that the user has as a message, go
40350ffdd5SRobert Mustacchi 	 * ahead and make sure we try and get all the other threads stopped.
41350ffdd5SRobert Mustacchi 	 * That'll help us make sure that nothing else is going on and we don't
42350ffdd5SRobert Mustacchi 	 * lose a race.
43350ffdd5SRobert Mustacchi 	 */
44350ffdd5SRobert Mustacchi 	mutex_enter(&p->p_lock);
45350ffdd5SRobert Mustacchi 	lwp->lwp_cursig = SIGABRT;
46350ffdd5SRobert Mustacchi 	mutex_exit(&p->p_lock);
47350ffdd5SRobert Mustacchi 
48350ffdd5SRobert Mustacchi 	proc_is_exiting(p);
49350ffdd5SRobert Mustacchi 	if (exitlwps(1) != 0) {
50350ffdd5SRobert Mustacchi 		mutex_enter(&p->p_lock);
51350ffdd5SRobert Mustacchi 		lwp_exit();
52350ffdd5SRobert Mustacchi 	}
53350ffdd5SRobert Mustacchi 
54350ffdd5SRobert Mustacchi 	/*
55350ffdd5SRobert Mustacchi 	 * Copy in the user data. We truncate it to PRUPANIC_BUFLEN no matter
56350ffdd5SRobert Mustacchi 	 * what and ensure that the last data was set to zero.
57350ffdd5SRobert Mustacchi 	 */
58350ffdd5SRobert Mustacchi 	if (addr != NULL && len > 0) {
59350ffdd5SRobert Mustacchi 		size_t copylen;
60350ffdd5SRobert Mustacchi 
61350ffdd5SRobert Mustacchi 		upflag |= P_UPF_HAVEMSG;
62350ffdd5SRobert Mustacchi 
63350ffdd5SRobert Mustacchi 		if (len >= PRUPANIC_BUFLEN) {
64350ffdd5SRobert Mustacchi 			copylen = PRUPANIC_BUFLEN;
65350ffdd5SRobert Mustacchi 			upflag |= P_UPF_TRUNCMSG;
66350ffdd5SRobert Mustacchi 		} else {
67350ffdd5SRobert Mustacchi 			copylen = len;
68350ffdd5SRobert Mustacchi 		}
69350ffdd5SRobert Mustacchi 
70350ffdd5SRobert Mustacchi 		buf = kmem_zalloc(PRUPANIC_BUFLEN, KM_SLEEP);
71350ffdd5SRobert Mustacchi 		if (copyin(addr, buf, copylen) != 0) {
72350ffdd5SRobert Mustacchi 			upflag |= P_UPF_INVALMSG;
73350ffdd5SRobert Mustacchi 			upflag &= ~P_UPF_HAVEMSG;
74350ffdd5SRobert Mustacchi 		} else {
75350ffdd5SRobert Mustacchi 			mutex_enter(&p->p_lock);
76350ffdd5SRobert Mustacchi 			ASSERT3P(p->p_upanic, ==, NULL);
77350ffdd5SRobert Mustacchi 			p->p_upanic = buf;
78350ffdd5SRobert Mustacchi 			mutex_exit(&p->p_lock);
79350ffdd5SRobert Mustacchi 		}
80350ffdd5SRobert Mustacchi 	}
81350ffdd5SRobert Mustacchi 
82350ffdd5SRobert Mustacchi 	mutex_enter(&p->p_lock);
83350ffdd5SRobert Mustacchi 	p->p_upanicflag = upflag;
84350ffdd5SRobert Mustacchi 	mutex_exit(&p->p_lock);
85350ffdd5SRobert Mustacchi 
86*88a8a2ffSRobert Mustacchi 	/*
87*88a8a2ffSRobert Mustacchi 	 * If we're auditing we need to finish the system call itself and then
88*88a8a2ffSRobert Mustacchi 	 * begin the core dump.
89*88a8a2ffSRobert Mustacchi 	 */
90*88a8a2ffSRobert Mustacchi 	if (auditing) {
91*88a8a2ffSRobert Mustacchi 		audit_finish(0, SYS_upanic, 0, NULL);
92350ffdd5SRobert Mustacchi 		audit_core_start(SIGABRT);
93*88a8a2ffSRobert Mustacchi 	}
94350ffdd5SRobert Mustacchi 	code = core(SIGABRT, B_FALSE);
95350ffdd5SRobert Mustacchi 	if (auditing)		/* audit core dump */
96350ffdd5SRobert Mustacchi 		audit_core_finish(code ? CLD_KILLED : CLD_DUMPED);
97350ffdd5SRobert Mustacchi 	exit(code ? CLD_KILLED : CLD_DUMPED, SIGABRT);
98350ffdd5SRobert Mustacchi }
99