xref: /freebsd/lib/libkvm/kvm_vnet.c (revision a2f733abcff64628b7771a47089628b7327a88bd)
17cf8b4b9SBjoern A. Zeeb /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni  *
47cf8b4b9SBjoern A. Zeeb  * Copyright (c) 2009 Robert N. M. Watson
57cf8b4b9SBjoern A. Zeeb  * Copyright (c) 2009 Bjoern A. Zeeb <bz@FreeBSD.org>
67cf8b4b9SBjoern A. Zeeb  * All rights reserved.
77cf8b4b9SBjoern A. Zeeb  *
87cf8b4b9SBjoern A. Zeeb  * Redistribution and use in source and binary forms, with or without
97cf8b4b9SBjoern A. Zeeb  * modification, are permitted provided that the following conditions
107cf8b4b9SBjoern A. Zeeb  * are met:
117cf8b4b9SBjoern A. Zeeb  * 1. Redistributions of source code must retain the above copyright
127cf8b4b9SBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer.
137cf8b4b9SBjoern A. Zeeb  * 2. Redistributions in binary form must reproduce the above copyright
147cf8b4b9SBjoern A. Zeeb  *    notice, this list of conditions and the following disclaimer in the
157cf8b4b9SBjoern A. Zeeb  *    documentation and/or other materials provided with the distribution.
167cf8b4b9SBjoern A. Zeeb  *
177cf8b4b9SBjoern A. Zeeb  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
187cf8b4b9SBjoern A. Zeeb  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
197cf8b4b9SBjoern A. Zeeb  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
207cf8b4b9SBjoern A. Zeeb  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
217cf8b4b9SBjoern A. Zeeb  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
227cf8b4b9SBjoern A. Zeeb  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
237cf8b4b9SBjoern A. Zeeb  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
247cf8b4b9SBjoern A. Zeeb  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
257cf8b4b9SBjoern A. Zeeb  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
267cf8b4b9SBjoern A. Zeeb  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
277cf8b4b9SBjoern A. Zeeb  * SUCH DAMAGE.
287cf8b4b9SBjoern A. Zeeb  */
297cf8b4b9SBjoern A. Zeeb 
307cf8b4b9SBjoern A. Zeeb #include <sys/param.h>
317cf8b4b9SBjoern A. Zeeb 
327cf8b4b9SBjoern A. Zeeb #define	_WANT_PRISON
337cf8b4b9SBjoern A. Zeeb #define	_WANT_UCRED
347cf8b4b9SBjoern A. Zeeb #define	_WANT_VNET
357cf8b4b9SBjoern A. Zeeb 
367cf8b4b9SBjoern A. Zeeb #include <sys/_lock.h>
377cf8b4b9SBjoern A. Zeeb #include <sys/_mutex.h>
387cf8b4b9SBjoern A. Zeeb #include <sys/_task.h>
397cf8b4b9SBjoern A. Zeeb #include <sys/jail.h>
407cf8b4b9SBjoern A. Zeeb #include <sys/proc.h>
417cf8b4b9SBjoern A. Zeeb #include <sys/types.h>
427cf8b4b9SBjoern A. Zeeb 
4310108cb6SBjoern A. Zeeb #include <stdbool.h>
447cf8b4b9SBjoern A. Zeeb #include <net/vnet.h>
457cf8b4b9SBjoern A. Zeeb 
467cf8b4b9SBjoern A. Zeeb #include <kvm.h>
477cf8b4b9SBjoern A. Zeeb #include <limits.h>
487cf8b4b9SBjoern A. Zeeb #include <stdlib.h>
497cf8b4b9SBjoern A. Zeeb #include <unistd.h>
507cf8b4b9SBjoern A. Zeeb 
517cf8b4b9SBjoern A. Zeeb #include "kvm_private.h"
527cf8b4b9SBjoern A. Zeeb 
537cf8b4b9SBjoern A. Zeeb /*
547cf8b4b9SBjoern A. Zeeb  * Set up libkvm to handle virtual network stack symbols by selecting a
557cf8b4b9SBjoern A. Zeeb  * starting pid.
567cf8b4b9SBjoern A. Zeeb  */
577cf8b4b9SBjoern A. Zeeb int
_kvm_vnet_selectpid(kvm_t * kd,pid_t pid)587cf8b4b9SBjoern A. Zeeb _kvm_vnet_selectpid(kvm_t *kd, pid_t pid)
597cf8b4b9SBjoern A. Zeeb {
607cf8b4b9SBjoern A. Zeeb 	struct proc proc;
617cf8b4b9SBjoern A. Zeeb 	struct ucred cred;
627cf8b4b9SBjoern A. Zeeb 	struct prison prison;
637cf8b4b9SBjoern A. Zeeb 	struct vnet vnet;
647f911abeSJohn Baldwin 	struct kvm_nlist nl[] = {
657cf8b4b9SBjoern A. Zeeb 		/*
667cf8b4b9SBjoern A. Zeeb 		 * Note: kvm_nlist strips the first '_' so add an extra one
677cf8b4b9SBjoern A. Zeeb 		 * here to __{start,stop}_set_vnet.
687cf8b4b9SBjoern A. Zeeb 		 */
697cf8b4b9SBjoern A. Zeeb #define	NLIST_START_VNET	0
707cf8b4b9SBjoern A. Zeeb 		{ .n_name = "___start_" VNET_SETNAME },
717cf8b4b9SBjoern A. Zeeb #define	NLIST_STOP_VNET		1
727cf8b4b9SBjoern A. Zeeb 		{ .n_name = "___stop_" VNET_SETNAME },
737cf8b4b9SBjoern A. Zeeb #define	NLIST_VNET_HEAD		2
747cf8b4b9SBjoern A. Zeeb 		{ .n_name = "vnet_head" },
757cf8b4b9SBjoern A. Zeeb #define	NLIST_ALLPROC		3
767cf8b4b9SBjoern A. Zeeb 		{ .n_name = "allproc" },
777cf8b4b9SBjoern A. Zeeb #define	NLIST_DUMPTID		4
787cf8b4b9SBjoern A. Zeeb 		{ .n_name = "dumptid" },
797cf8b4b9SBjoern A. Zeeb #define	NLIST_PROC0		5
807cf8b4b9SBjoern A. Zeeb 		{ .n_name = "proc0" },
817cf8b4b9SBjoern A. Zeeb 		{ .n_name = NULL },
827cf8b4b9SBjoern A. Zeeb 	};
83c10970ddSUlrich Spörlein 	uintptr_t procp, credp;
84c10970ddSUlrich Spörlein #define	VMCORE_VNET_OF_PROC0
85c10970ddSUlrich Spörlein #ifndef VMCORE_VNET_OF_PROC0
86c10970ddSUlrich Spörlein 	struct thread td;
87c10970ddSUlrich Spörlein 	uintptr_t tdp;
88c10970ddSUlrich Spörlein #endif
897cf8b4b9SBjoern A. Zeeb 	lwpid_t dumptid;
907cf8b4b9SBjoern A. Zeeb 
917cf8b4b9SBjoern A. Zeeb 	/*
927f911abeSJohn Baldwin 	 * XXX: This only works for native kernels for now.
937f911abeSJohn Baldwin 	 */
947f911abeSJohn Baldwin 	if (!kvm_native(kd))
957f911abeSJohn Baldwin 		return (-1);
967f911abeSJohn Baldwin 
977f911abeSJohn Baldwin 	/*
987cf8b4b9SBjoern A. Zeeb 	 * Locate and cache locations of important symbols
997cf8b4b9SBjoern A. Zeeb 	 * using the internal version of _kvm_nlist, turning
1007cf8b4b9SBjoern A. Zeeb 	 * off initialization to avoid recursion in case of
1017cf8b4b9SBjoern A. Zeeb 	 * unresolveable symbols.
1027cf8b4b9SBjoern A. Zeeb 	 */
1037cf8b4b9SBjoern A. Zeeb 	if (_kvm_nlist(kd, nl, 0) != 0) {
1047cf8b4b9SBjoern A. Zeeb 		/*
1057cf8b4b9SBjoern A. Zeeb 		 * XXX-BZ: ___start_/___stop_VNET_SETNAME may fail.
1067cf8b4b9SBjoern A. Zeeb 		 * For now do not report an error here as we are called
1077cf8b4b9SBjoern A. Zeeb 		 * internally and in `void context' until we merge the
1087cf8b4b9SBjoern A. Zeeb 		 * functionality to optionally activate this into programs.
1097cf8b4b9SBjoern A. Zeeb 		 * By that time we can properly fail and let the callers
1107cf8b4b9SBjoern A. Zeeb 		 * handle the error.
1117cf8b4b9SBjoern A. Zeeb 		 */
1127cf8b4b9SBjoern A. Zeeb 		/* _kvm_err(kd, kd->program, "%s: no namelist", __func__); */
1137cf8b4b9SBjoern A. Zeeb 		return (-1);
1147cf8b4b9SBjoern A. Zeeb 	}
1157cf8b4b9SBjoern A. Zeeb 
1167cf8b4b9SBjoern A. Zeeb 	/*
1177cf8b4b9SBjoern A. Zeeb 	 * Auto-detect if this is a crashdump by reading dumptid.
1187cf8b4b9SBjoern A. Zeeb 	 */
1197cf8b4b9SBjoern A. Zeeb 	dumptid = 0;
1207cf8b4b9SBjoern A. Zeeb 	if (nl[NLIST_DUMPTID].n_value) {
1217cf8b4b9SBjoern A. Zeeb 		if (kvm_read(kd, nl[NLIST_DUMPTID].n_value, &dumptid,
1227cf8b4b9SBjoern A. Zeeb 		    sizeof(dumptid)) != sizeof(dumptid)) {
1237cf8b4b9SBjoern A. Zeeb 			_kvm_err(kd, kd->program, "%s: dumptid", __func__);
1247cf8b4b9SBjoern A. Zeeb 			return (-1);
1257cf8b4b9SBjoern A. Zeeb 		}
1267cf8b4b9SBjoern A. Zeeb 	}
1277cf8b4b9SBjoern A. Zeeb 
1287cf8b4b9SBjoern A. Zeeb 	/*
129f0506e89SRobert Watson 	 * First, find the process for this pid.  If we are working on a
13075f46cf6SPedro F. Giffuni 	 * dump, either locate the thread dumptid is referring to or proc0.
1317cf8b4b9SBjoern A. Zeeb 	 * Based on either, take the address of the ucred.
1327cf8b4b9SBjoern A. Zeeb 	 */
1337cf8b4b9SBjoern A. Zeeb 	credp = 0;
1347cf8b4b9SBjoern A. Zeeb 
1357cf8b4b9SBjoern A. Zeeb 	procp = nl[NLIST_ALLPROC].n_value;
1367cf8b4b9SBjoern A. Zeeb #ifdef VMCORE_VNET_OF_PROC0
1377cf8b4b9SBjoern A. Zeeb 	if (dumptid > 0) {
1387cf8b4b9SBjoern A. Zeeb 		procp = nl[NLIST_PROC0].n_value;
1397cf8b4b9SBjoern A. Zeeb 		pid = 0;
1407cf8b4b9SBjoern A. Zeeb 	}
1417cf8b4b9SBjoern A. Zeeb #endif
1427cf8b4b9SBjoern A. Zeeb 	while (procp != 0) {
1437cf8b4b9SBjoern A. Zeeb 		if (kvm_read(kd, procp, &proc, sizeof(proc)) != sizeof(proc)) {
1447cf8b4b9SBjoern A. Zeeb 			_kvm_err(kd, kd->program, "%s: proc", __func__);
1457cf8b4b9SBjoern A. Zeeb 			return (-1);
1467cf8b4b9SBjoern A. Zeeb 		}
1477cf8b4b9SBjoern A. Zeeb #ifndef VMCORE_VNET_OF_PROC0
1487cf8b4b9SBjoern A. Zeeb 		if (dumptid > 0) {
1497cf8b4b9SBjoern A. Zeeb 			tdp = (uintptr_t)TAILQ_FIRST(&proc.p_threads);
1507cf8b4b9SBjoern A. Zeeb 			while (tdp != 0) {
1517cf8b4b9SBjoern A. Zeeb 				if (kvm_read(kd, tdp, &td, sizeof(td)) !=
1527cf8b4b9SBjoern A. Zeeb 				    sizeof(td)) {
1537cf8b4b9SBjoern A. Zeeb 					_kvm_err(kd, kd->program, "%s: thread",
1547cf8b4b9SBjoern A. Zeeb 					    __func__);
1557cf8b4b9SBjoern A. Zeeb 					return (-1);
1567cf8b4b9SBjoern A. Zeeb 				}
1577cf8b4b9SBjoern A. Zeeb 				if (td.td_tid == dumptid) {
1587cf8b4b9SBjoern A. Zeeb 					credp = (uintptr_t)td.td_ucred;
1597cf8b4b9SBjoern A. Zeeb 					break;
1607cf8b4b9SBjoern A. Zeeb 				}
1617cf8b4b9SBjoern A. Zeeb 				tdp = (uintptr_t)TAILQ_NEXT(&td, td_plist);
1627cf8b4b9SBjoern A. Zeeb 			}
1637cf8b4b9SBjoern A. Zeeb 		} else
1647cf8b4b9SBjoern A. Zeeb #endif
1657cf8b4b9SBjoern A. Zeeb 		if (proc.p_pid == pid)
1667cf8b4b9SBjoern A. Zeeb 			credp = (uintptr_t)proc.p_ucred;
1677cf8b4b9SBjoern A. Zeeb 		if (credp != 0)
1687cf8b4b9SBjoern A. Zeeb 			break;
1697cf8b4b9SBjoern A. Zeeb 		procp = (uintptr_t)LIST_NEXT(&proc, p_list);
1707cf8b4b9SBjoern A. Zeeb 	}
1717cf8b4b9SBjoern A. Zeeb 	if (credp == 0) {
1727cf8b4b9SBjoern A. Zeeb 		_kvm_err(kd, kd->program, "%s: pid/tid not found", __func__);
1737cf8b4b9SBjoern A. Zeeb 		return (-1);
1747cf8b4b9SBjoern A. Zeeb 	}
1757cf8b4b9SBjoern A. Zeeb 	if (kvm_read(kd, (uintptr_t)credp, &cred, sizeof(cred)) !=
1767cf8b4b9SBjoern A. Zeeb 	    sizeof(cred)) {
1777cf8b4b9SBjoern A. Zeeb 		_kvm_err(kd, kd->program, "%s: cred", __func__);
1787cf8b4b9SBjoern A. Zeeb 		return (-1);
1797cf8b4b9SBjoern A. Zeeb 	}
1807cf8b4b9SBjoern A. Zeeb 	if (cred.cr_prison == NULL) {
1817cf8b4b9SBjoern A. Zeeb 		_kvm_err(kd, kd->program, "%s: no jail", __func__);
1827cf8b4b9SBjoern A. Zeeb 		return (-1);
1837cf8b4b9SBjoern A. Zeeb 	}
1847cf8b4b9SBjoern A. Zeeb 	if (kvm_read(kd, (uintptr_t)cred.cr_prison, &prison, sizeof(prison)) !=
1857cf8b4b9SBjoern A. Zeeb 	    sizeof(prison)) {
1867cf8b4b9SBjoern A. Zeeb 		_kvm_err(kd, kd->program, "%s: prison", __func__);
1877cf8b4b9SBjoern A. Zeeb 		return (-1);
1887cf8b4b9SBjoern A. Zeeb 	}
1897cf8b4b9SBjoern A. Zeeb 	if (prison.pr_vnet == NULL) {
1907cf8b4b9SBjoern A. Zeeb 		_kvm_err(kd, kd->program, "%s: no vnet", __func__);
1917cf8b4b9SBjoern A. Zeeb 		return (-1);
1927cf8b4b9SBjoern A. Zeeb 	}
1937cf8b4b9SBjoern A. Zeeb 	if (kvm_read(kd, (uintptr_t)prison.pr_vnet, &vnet, sizeof(vnet)) !=
1947cf8b4b9SBjoern A. Zeeb 	    sizeof(vnet)) {
1957cf8b4b9SBjoern A. Zeeb 		_kvm_err(kd, kd->program, "%s: vnet", __func__);
1967cf8b4b9SBjoern A. Zeeb 		return (-1);
1977cf8b4b9SBjoern A. Zeeb 	}
1987cf8b4b9SBjoern A. Zeeb 	if (vnet.vnet_magic_n != VNET_MAGIC_N) {
1997cf8b4b9SBjoern A. Zeeb 		_kvm_err(kd, kd->program, "%s: invalid vnet magic#", __func__);
2007cf8b4b9SBjoern A. Zeeb 		return (-1);
2017cf8b4b9SBjoern A. Zeeb 	}
2027cf8b4b9SBjoern A. Zeeb 	kd->vnet_initialized = 1;
2037cf8b4b9SBjoern A. Zeeb 	kd->vnet_start = nl[NLIST_START_VNET].n_value;
2047cf8b4b9SBjoern A. Zeeb 	kd->vnet_stop = nl[NLIST_STOP_VNET].n_value;
2057cf8b4b9SBjoern A. Zeeb 	kd->vnet_current = (uintptr_t)prison.pr_vnet;
20687a61ebdSBjoern A. Zeeb 	kd->vnet_base = vnet.vnet_data_base;
2077cf8b4b9SBjoern A. Zeeb 	return (0);
2087cf8b4b9SBjoern A. Zeeb }
2097cf8b4b9SBjoern A. Zeeb 
2107cf8b4b9SBjoern A. Zeeb /*
21175f46cf6SPedro F. Giffuni  * Check whether the vnet module has been initialized successfully
2127f911abeSJohn Baldwin  * or not, initialize it if permitted.
2137cf8b4b9SBjoern A. Zeeb  */
2147cf8b4b9SBjoern A. Zeeb int
_kvm_vnet_initialized(kvm_t * kd,int intialize)2157cf8b4b9SBjoern A. Zeeb _kvm_vnet_initialized(kvm_t *kd, int intialize)
2167cf8b4b9SBjoern A. Zeeb {
2177cf8b4b9SBjoern A. Zeeb 
2187cf8b4b9SBjoern A. Zeeb 	if (kd->vnet_initialized || !intialize)
2197cf8b4b9SBjoern A. Zeeb 		return (kd->vnet_initialized);
2207cf8b4b9SBjoern A. Zeeb 
2217cf8b4b9SBjoern A. Zeeb 	(void) _kvm_vnet_selectpid(kd, getpid());
2227cf8b4b9SBjoern A. Zeeb 
2237cf8b4b9SBjoern A. Zeeb 	return (kd->vnet_initialized);
2247cf8b4b9SBjoern A. Zeeb }
2257cf8b4b9SBjoern A. Zeeb 
2267cf8b4b9SBjoern A. Zeeb /*
2277cf8b4b9SBjoern A. Zeeb  * Check whether the value is within the vnet symbol range and
2287cf8b4b9SBjoern A. Zeeb  * only if so adjust the offset relative to the current base.
2297cf8b4b9SBjoern A. Zeeb  */
2307f911abeSJohn Baldwin kvaddr_t
_kvm_vnet_validaddr(kvm_t * kd,kvaddr_t value)2317f911abeSJohn Baldwin _kvm_vnet_validaddr(kvm_t *kd, kvaddr_t value)
2327cf8b4b9SBjoern A. Zeeb {
2337cf8b4b9SBjoern A. Zeeb 
2347cf8b4b9SBjoern A. Zeeb 	if (value == 0)
2357cf8b4b9SBjoern A. Zeeb 		return (value);
2367cf8b4b9SBjoern A. Zeeb 
2377cf8b4b9SBjoern A. Zeeb 	if (!kd->vnet_initialized)
2387cf8b4b9SBjoern A. Zeeb 		return (value);
2397cf8b4b9SBjoern A. Zeeb 
2407cf8b4b9SBjoern A. Zeeb 	if (value < kd->vnet_start || value >= kd->vnet_stop)
2417cf8b4b9SBjoern A. Zeeb 		return (value);
2427cf8b4b9SBjoern A. Zeeb 
2437cf8b4b9SBjoern A. Zeeb 	return (kd->vnet_base + value);
2447cf8b4b9SBjoern A. Zeeb }
245