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