1195838Sbz/*- 2195838Sbz * Copyright (c) 2009 Robert N. M. Watson 3195838Sbz * Copyright (c) 2009 Bjoern A. Zeeb <bz@FreeBSD.org> 4195838Sbz * All rights reserved. 5195838Sbz * 6195838Sbz * Redistribution and use in source and binary forms, with or without 7195838Sbz * modification, are permitted provided that the following conditions 8195838Sbz * are met: 9195838Sbz * 1. Redistributions of source code must retain the above copyright 10195838Sbz * notice, this list of conditions and the following disclaimer. 11195838Sbz * 2. Redistributions in binary form must reproduce the above copyright 12195838Sbz * notice, this list of conditions and the following disclaimer in the 13195838Sbz * documentation and/or other materials provided with the distribution. 14195838Sbz * 15195838Sbz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16195838Sbz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17195838Sbz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18195838Sbz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19195838Sbz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20195838Sbz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21195838Sbz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22195838Sbz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23195838Sbz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24195838Sbz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25195838Sbz * SUCH DAMAGE. 26195838Sbz */ 27195838Sbz 28195838Sbz#include <sys/cdefs.h> 29195838Sbz__FBSDID("$FreeBSD: releng/11.0/lib/libkvm/kvm_vnet.c 298896 2016-05-01 19:37:33Z pfg $"); 30195838Sbz 31195838Sbz#include <sys/param.h> 32195838Sbz 33195838Sbz#define _WANT_PRISON 34195838Sbz#define _WANT_UCRED 35195838Sbz#define _WANT_VNET 36195838Sbz 37195838Sbz#include <sys/_lock.h> 38195838Sbz#include <sys/_mutex.h> 39195838Sbz#include <sys/_task.h> 40195838Sbz#include <sys/jail.h> 41195838Sbz#include <sys/proc.h> 42195838Sbz#include <sys/types.h> 43195838Sbz 44195838Sbz#include <net/vnet.h> 45195838Sbz 46195838Sbz#include <kvm.h> 47195838Sbz#include <limits.h> 48195838Sbz#include <stdlib.h> 49195838Sbz#include <unistd.h> 50195838Sbz 51195838Sbz#include "kvm_private.h" 52195838Sbz 53195838Sbz/* 54195838Sbz * Set up libkvm to handle virtual network stack symbols by selecting a 55195838Sbz * starting pid. 56195838Sbz */ 57195838Sbzint 58195838Sbz_kvm_vnet_selectpid(kvm_t *kd, pid_t pid) 59195838Sbz{ 60195838Sbz struct proc proc; 61195838Sbz struct ucred cred; 62195838Sbz struct prison prison; 63195838Sbz struct vnet vnet; 64291406Sjhb struct kvm_nlist nl[] = { 65195838Sbz /* 66195838Sbz * Note: kvm_nlist strips the first '_' so add an extra one 67195838Sbz * here to __{start,stop}_set_vnet. 68195838Sbz */ 69195838Sbz#define NLIST_START_VNET 0 70195838Sbz { .n_name = "___start_" VNET_SETNAME }, 71195838Sbz#define NLIST_STOP_VNET 1 72195838Sbz { .n_name = "___stop_" VNET_SETNAME }, 73195838Sbz#define NLIST_VNET_HEAD 2 74195838Sbz { .n_name = "vnet_head" }, 75195838Sbz#define NLIST_ALLPROC 3 76195838Sbz { .n_name = "allproc" }, 77195838Sbz#define NLIST_DUMPTID 4 78195838Sbz { .n_name = "dumptid" }, 79195838Sbz#define NLIST_PROC0 5 80195838Sbz { .n_name = "proc0" }, 81195838Sbz { .n_name = NULL }, 82195838Sbz }; 83217744Suqs uintptr_t procp, credp; 84217744Suqs#define VMCORE_VNET_OF_PROC0 85217744Suqs#ifndef VMCORE_VNET_OF_PROC0 86217744Suqs struct thread td; 87217744Suqs uintptr_t tdp; 88217744Suqs#endif 89195838Sbz lwpid_t dumptid; 90195838Sbz 91195838Sbz /* 92291406Sjhb * XXX: This only works for native kernels for now. 93291406Sjhb */ 94291406Sjhb if (!kvm_native(kd)) 95291406Sjhb return (-1); 96291406Sjhb 97291406Sjhb /* 98195838Sbz * Locate and cache locations of important symbols 99195838Sbz * using the internal version of _kvm_nlist, turning 100195838Sbz * off initialization to avoid recursion in case of 101195838Sbz * unresolveable symbols. 102195838Sbz */ 103195838Sbz if (_kvm_nlist(kd, nl, 0) != 0) { 104195838Sbz /* 105195838Sbz * XXX-BZ: ___start_/___stop_VNET_SETNAME may fail. 106195838Sbz * For now do not report an error here as we are called 107195838Sbz * internally and in `void context' until we merge the 108195838Sbz * functionality to optionally activate this into programs. 109195838Sbz * By that time we can properly fail and let the callers 110195838Sbz * handle the error. 111195838Sbz */ 112195838Sbz /* _kvm_err(kd, kd->program, "%s: no namelist", __func__); */ 113195838Sbz return (-1); 114195838Sbz } 115195838Sbz 116195838Sbz /* 117195838Sbz * Auto-detect if this is a crashdump by reading dumptid. 118195838Sbz */ 119195838Sbz dumptid = 0; 120195838Sbz if (nl[NLIST_DUMPTID].n_value) { 121195838Sbz if (kvm_read(kd, nl[NLIST_DUMPTID].n_value, &dumptid, 122195838Sbz sizeof(dumptid)) != sizeof(dumptid)) { 123195838Sbz _kvm_err(kd, kd->program, "%s: dumptid", __func__); 124195838Sbz return (-1); 125195838Sbz } 126195838Sbz } 127195838Sbz 128195838Sbz /* 129204435Srwatson * First, find the process for this pid. If we are working on a 130298896Spfg * dump, either locate the thread dumptid is referring to or proc0. 131195838Sbz * Based on either, take the address of the ucred. 132195838Sbz */ 133195838Sbz credp = 0; 134195838Sbz 135195838Sbz procp = nl[NLIST_ALLPROC].n_value; 136195838Sbz#ifdef VMCORE_VNET_OF_PROC0 137195838Sbz if (dumptid > 0) { 138195838Sbz procp = nl[NLIST_PROC0].n_value; 139195838Sbz pid = 0; 140195838Sbz } 141195838Sbz#endif 142195838Sbz while (procp != 0) { 143195838Sbz if (kvm_read(kd, procp, &proc, sizeof(proc)) != sizeof(proc)) { 144195838Sbz _kvm_err(kd, kd->program, "%s: proc", __func__); 145195838Sbz return (-1); 146195838Sbz } 147195838Sbz#ifndef VMCORE_VNET_OF_PROC0 148195838Sbz if (dumptid > 0) { 149195838Sbz tdp = (uintptr_t)TAILQ_FIRST(&proc.p_threads); 150195838Sbz while (tdp != 0) { 151195838Sbz if (kvm_read(kd, tdp, &td, sizeof(td)) != 152195838Sbz sizeof(td)) { 153195838Sbz _kvm_err(kd, kd->program, "%s: thread", 154195838Sbz __func__); 155195838Sbz return (-1); 156195838Sbz } 157195838Sbz if (td.td_tid == dumptid) { 158195838Sbz credp = (uintptr_t)td.td_ucred; 159195838Sbz break; 160195838Sbz } 161195838Sbz tdp = (uintptr_t)TAILQ_NEXT(&td, td_plist); 162195838Sbz } 163195838Sbz } else 164195838Sbz#endif 165195838Sbz if (proc.p_pid == pid) 166195838Sbz credp = (uintptr_t)proc.p_ucred; 167195838Sbz if (credp != 0) 168195838Sbz break; 169195838Sbz procp = (uintptr_t)LIST_NEXT(&proc, p_list); 170195838Sbz } 171195838Sbz if (credp == 0) { 172195838Sbz _kvm_err(kd, kd->program, "%s: pid/tid not found", __func__); 173195838Sbz return (-1); 174195838Sbz } 175195838Sbz if (kvm_read(kd, (uintptr_t)credp, &cred, sizeof(cred)) != 176195838Sbz sizeof(cred)) { 177195838Sbz _kvm_err(kd, kd->program, "%s: cred", __func__); 178195838Sbz return (-1); 179195838Sbz } 180195838Sbz if (cred.cr_prison == NULL) { 181195838Sbz _kvm_err(kd, kd->program, "%s: no jail", __func__); 182195838Sbz return (-1); 183195838Sbz } 184195838Sbz if (kvm_read(kd, (uintptr_t)cred.cr_prison, &prison, sizeof(prison)) != 185195838Sbz sizeof(prison)) { 186195838Sbz _kvm_err(kd, kd->program, "%s: prison", __func__); 187195838Sbz return (-1); 188195838Sbz } 189195838Sbz if (prison.pr_vnet == NULL) { 190195838Sbz _kvm_err(kd, kd->program, "%s: no vnet", __func__); 191195838Sbz return (-1); 192195838Sbz } 193195838Sbz if (kvm_read(kd, (uintptr_t)prison.pr_vnet, &vnet, sizeof(vnet)) != 194195838Sbz sizeof(vnet)) { 195195838Sbz _kvm_err(kd, kd->program, "%s: vnet", __func__); 196195838Sbz return (-1); 197195838Sbz } 198195838Sbz if (vnet.vnet_magic_n != VNET_MAGIC_N) { 199195838Sbz _kvm_err(kd, kd->program, "%s: invalid vnet magic#", __func__); 200195838Sbz return (-1); 201195838Sbz } 202195838Sbz kd->vnet_initialized = 1; 203195838Sbz kd->vnet_start = nl[NLIST_START_VNET].n_value; 204195838Sbz kd->vnet_stop = nl[NLIST_STOP_VNET].n_value; 205195838Sbz kd->vnet_current = (uintptr_t)prison.pr_vnet; 206196185Sbz kd->vnet_base = vnet.vnet_data_base; 207195838Sbz return (0); 208195838Sbz} 209195838Sbz 210195838Sbz/* 211298896Spfg * Check whether the vnet module has been initialized successfully 212291406Sjhb * or not, initialize it if permitted. 213195838Sbz */ 214195838Sbzint 215195838Sbz_kvm_vnet_initialized(kvm_t *kd, int intialize) 216195838Sbz{ 217195838Sbz 218195838Sbz if (kd->vnet_initialized || !intialize) 219195838Sbz return (kd->vnet_initialized); 220195838Sbz 221195838Sbz (void) _kvm_vnet_selectpid(kd, getpid()); 222195838Sbz 223195838Sbz return (kd->vnet_initialized); 224195838Sbz} 225195838Sbz 226195838Sbz/* 227195838Sbz * Check whether the value is within the vnet symbol range and 228195838Sbz * only if so adjust the offset relative to the current base. 229195838Sbz */ 230291406Sjhbkvaddr_t 231291406Sjhb_kvm_vnet_validaddr(kvm_t *kd, kvaddr_t value) 232195838Sbz{ 233195838Sbz 234195838Sbz if (value == 0) 235195838Sbz return (value); 236195838Sbz 237195838Sbz if (!kd->vnet_initialized) 238195838Sbz return (value); 239195838Sbz 240195838Sbz if (value < kd->vnet_start || value >= kd->vnet_stop) 241195838Sbz return (value); 242195838Sbz 243195838Sbz return (kd->vnet_base + value); 244195838Sbz} 245