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