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/10.2/lib/libkvm/kvm_vnet.c 217744 2011-01-23 11:08:28Z uqs $"); 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 <nlist.h> 47195838Sbz#include <kvm.h> 48195838Sbz#include <limits.h> 49195838Sbz#include <stdlib.h> 50195838Sbz#include <unistd.h> 51195838Sbz 52195838Sbz#include "kvm_private.h" 53195838Sbz 54195838Sbz/* 55195838Sbz * Set up libkvm to handle virtual network stack symbols by selecting a 56195838Sbz * starting pid. 57195838Sbz */ 58195838Sbzint 59195838Sbz_kvm_vnet_selectpid(kvm_t *kd, pid_t pid) 60195838Sbz{ 61195838Sbz struct proc proc; 62195838Sbz struct ucred cred; 63195838Sbz struct prison prison; 64195838Sbz struct vnet vnet; 65195838Sbz struct nlist nl[] = { 66195838Sbz /* 67195838Sbz * Note: kvm_nlist strips the first '_' so add an extra one 68195838Sbz * here to __{start,stop}_set_vnet. 69195838Sbz */ 70195838Sbz#define NLIST_START_VNET 0 71195838Sbz { .n_name = "___start_" VNET_SETNAME }, 72195838Sbz#define NLIST_STOP_VNET 1 73195838Sbz { .n_name = "___stop_" VNET_SETNAME }, 74195838Sbz#define NLIST_VNET_HEAD 2 75195838Sbz { .n_name = "vnet_head" }, 76195838Sbz#define NLIST_ALLPROC 3 77195838Sbz { .n_name = "allproc" }, 78195838Sbz#define NLIST_DUMPTID 4 79195838Sbz { .n_name = "dumptid" }, 80195838Sbz#define NLIST_PROC0 5 81195838Sbz { .n_name = "proc0" }, 82195838Sbz { .n_name = NULL }, 83195838Sbz }; 84217744Suqs uintptr_t procp, credp; 85217744Suqs#define VMCORE_VNET_OF_PROC0 86217744Suqs#ifndef VMCORE_VNET_OF_PROC0 87217744Suqs struct thread td; 88217744Suqs uintptr_t tdp; 89217744Suqs#endif 90195838Sbz lwpid_t dumptid; 91195838Sbz 92195838Sbz /* 93195838Sbz * Locate and cache locations of important symbols 94195838Sbz * using the internal version of _kvm_nlist, turning 95195838Sbz * off initialization to avoid recursion in case of 96195838Sbz * unresolveable symbols. 97195838Sbz */ 98195838Sbz if (_kvm_nlist(kd, nl, 0) != 0) { 99195838Sbz /* 100195838Sbz * XXX-BZ: ___start_/___stop_VNET_SETNAME may fail. 101195838Sbz * For now do not report an error here as we are called 102195838Sbz * internally and in `void context' until we merge the 103195838Sbz * functionality to optionally activate this into programs. 104195838Sbz * By that time we can properly fail and let the callers 105195838Sbz * handle the error. 106195838Sbz */ 107195838Sbz /* _kvm_err(kd, kd->program, "%s: no namelist", __func__); */ 108195838Sbz return (-1); 109195838Sbz } 110195838Sbz 111195838Sbz /* 112195838Sbz * Auto-detect if this is a crashdump by reading dumptid. 113195838Sbz */ 114195838Sbz dumptid = 0; 115195838Sbz if (nl[NLIST_DUMPTID].n_value) { 116195838Sbz if (kvm_read(kd, nl[NLIST_DUMPTID].n_value, &dumptid, 117195838Sbz sizeof(dumptid)) != sizeof(dumptid)) { 118195838Sbz _kvm_err(kd, kd->program, "%s: dumptid", __func__); 119195838Sbz return (-1); 120195838Sbz } 121195838Sbz } 122195838Sbz 123195838Sbz /* 124204435Srwatson * First, find the process for this pid. If we are working on a 125204435Srwatson * dump, either locate the thread dumptid is refering to or proc0. 126195838Sbz * Based on either, take the address of the ucred. 127195838Sbz */ 128195838Sbz credp = 0; 129195838Sbz 130195838Sbz procp = nl[NLIST_ALLPROC].n_value; 131195838Sbz#ifdef VMCORE_VNET_OF_PROC0 132195838Sbz if (dumptid > 0) { 133195838Sbz procp = nl[NLIST_PROC0].n_value; 134195838Sbz pid = 0; 135195838Sbz } 136195838Sbz#endif 137195838Sbz while (procp != 0) { 138195838Sbz if (kvm_read(kd, procp, &proc, sizeof(proc)) != sizeof(proc)) { 139195838Sbz _kvm_err(kd, kd->program, "%s: proc", __func__); 140195838Sbz return (-1); 141195838Sbz } 142195838Sbz#ifndef VMCORE_VNET_OF_PROC0 143195838Sbz if (dumptid > 0) { 144195838Sbz tdp = (uintptr_t)TAILQ_FIRST(&proc.p_threads); 145195838Sbz while (tdp != 0) { 146195838Sbz if (kvm_read(kd, tdp, &td, sizeof(td)) != 147195838Sbz sizeof(td)) { 148195838Sbz _kvm_err(kd, kd->program, "%s: thread", 149195838Sbz __func__); 150195838Sbz return (-1); 151195838Sbz } 152195838Sbz if (td.td_tid == dumptid) { 153195838Sbz credp = (uintptr_t)td.td_ucred; 154195838Sbz break; 155195838Sbz } 156195838Sbz tdp = (uintptr_t)TAILQ_NEXT(&td, td_plist); 157195838Sbz } 158195838Sbz } else 159195838Sbz#endif 160195838Sbz if (proc.p_pid == pid) 161195838Sbz credp = (uintptr_t)proc.p_ucred; 162195838Sbz if (credp != 0) 163195838Sbz break; 164195838Sbz procp = (uintptr_t)LIST_NEXT(&proc, p_list); 165195838Sbz } 166195838Sbz if (credp == 0) { 167195838Sbz _kvm_err(kd, kd->program, "%s: pid/tid not found", __func__); 168195838Sbz return (-1); 169195838Sbz } 170195838Sbz if (kvm_read(kd, (uintptr_t)credp, &cred, sizeof(cred)) != 171195838Sbz sizeof(cred)) { 172195838Sbz _kvm_err(kd, kd->program, "%s: cred", __func__); 173195838Sbz return (-1); 174195838Sbz } 175195838Sbz if (cred.cr_prison == NULL) { 176195838Sbz _kvm_err(kd, kd->program, "%s: no jail", __func__); 177195838Sbz return (-1); 178195838Sbz } 179195838Sbz if (kvm_read(kd, (uintptr_t)cred.cr_prison, &prison, sizeof(prison)) != 180195838Sbz sizeof(prison)) { 181195838Sbz _kvm_err(kd, kd->program, "%s: prison", __func__); 182195838Sbz return (-1); 183195838Sbz } 184195838Sbz if (prison.pr_vnet == NULL) { 185195838Sbz _kvm_err(kd, kd->program, "%s: no vnet", __func__); 186195838Sbz return (-1); 187195838Sbz } 188195838Sbz if (kvm_read(kd, (uintptr_t)prison.pr_vnet, &vnet, sizeof(vnet)) != 189195838Sbz sizeof(vnet)) { 190195838Sbz _kvm_err(kd, kd->program, "%s: vnet", __func__); 191195838Sbz return (-1); 192195838Sbz } 193195838Sbz if (vnet.vnet_magic_n != VNET_MAGIC_N) { 194195838Sbz _kvm_err(kd, kd->program, "%s: invalid vnet magic#", __func__); 195195838Sbz return (-1); 196195838Sbz } 197195838Sbz kd->vnet_initialized = 1; 198195838Sbz kd->vnet_start = nl[NLIST_START_VNET].n_value; 199195838Sbz kd->vnet_stop = nl[NLIST_STOP_VNET].n_value; 200195838Sbz kd->vnet_current = (uintptr_t)prison.pr_vnet; 201196185Sbz kd->vnet_base = vnet.vnet_data_base; 202195838Sbz return (0); 203195838Sbz} 204195838Sbz 205195838Sbz/* 206195838Sbz * Check whether the vnet module has been initialized sucessfully 207195838Sbz * or not, intialize it if permitted. 208195838Sbz */ 209195838Sbzint 210195838Sbz_kvm_vnet_initialized(kvm_t *kd, int intialize) 211195838Sbz{ 212195838Sbz 213195838Sbz if (kd->vnet_initialized || !intialize) 214195838Sbz return (kd->vnet_initialized); 215195838Sbz 216195838Sbz (void) _kvm_vnet_selectpid(kd, getpid()); 217195838Sbz 218195838Sbz return (kd->vnet_initialized); 219195838Sbz} 220195838Sbz 221195838Sbz/* 222195838Sbz * Check whether the value is within the vnet symbol range and 223195838Sbz * only if so adjust the offset relative to the current base. 224195838Sbz */ 225195838Sbzuintptr_t 226195838Sbz_kvm_vnet_validaddr(kvm_t *kd, uintptr_t value) 227195838Sbz{ 228195838Sbz 229195838Sbz if (value == 0) 230195838Sbz return (value); 231195838Sbz 232195838Sbz if (!kd->vnet_initialized) 233195838Sbz return (value); 234195838Sbz 235195838Sbz if (value < kd->vnet_start || value >= kd->vnet_stop) 236195838Sbz return (value); 237195838Sbz 238195838Sbz return (kd->vnet_base + value); 239195838Sbz} 240