procfs_mem.c revision 79224
1127474Stjr/* 2127474Stjr * Copyright (c) 1993 Jan-Simon Pendry 3127474Stjr * Copyright (c) 1993 Sean Eric Fagan 4127474Stjr * Copyright (c) 1993 5127474Stjr * The Regents of the University of California. All rights reserved. 6174990Sache * 7127474Stjr * This code is derived from software contributed to Berkeley by 8127474Stjr * Jan-Simon Pendry and Sean Eric Fagan. 9127474Stjr * 10127474Stjr * Redistribution and use in source and binary forms, with or without 11127474Stjr * modification, are permitted provided that the following conditions 12127474Stjr * are met: 13127474Stjr * 1. Redistributions of source code must retain the above copyright 14127474Stjr * notice, this list of conditions and the following disclaimer. 15127474Stjr * 2. Redistributions in binary form must reproduce the above copyright 16127474Stjr * notice, this list of conditions and the following disclaimer in the 17127474Stjr * documentation and/or other materials provided with the distribution. 18127474Stjr * 3. All advertising materials mentioning features or use of this software 19127474Stjr * must display the following acknowledgement: 20127474Stjr * This product includes software developed by the University of 21174990Sache * California, Berkeley and its contributors. 22127474Stjr * 4. Neither the name of the University nor the names of its contributors 23127474Stjr * may be used to endorse or promote products derived from this software 24127474Stjr * without specific prior written permission. 25127474Stjr * 26127474Stjr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27127474Stjr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28127474Stjr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29127474Stjr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30127474Stjr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31127474Stjr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32127474Stjr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33127474Stjr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34127474Stjr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35127474Stjr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36174990Sache * SUCH DAMAGE. 37127474Stjr * 38127474Stjr * @(#)procfs_mem.c 8.5 (Berkeley) 6/15/94 39127474Stjr * 40127474Stjr * $FreeBSD: head/sys/fs/procfs/procfs_mem.c 79224 2001-07-04 16:20:28Z dillon $ 41127474Stjr */ 42127474Stjr 43127474Stjr/* 44127474Stjr * This is a lightly hacked and merged version 45127474Stjr * of sef's pread/pwrite functions 46174990Sache */ 47127474Stjr 48127474Stjr#include <sys/param.h> 49127474Stjr#include <sys/systm.h> 50127474Stjr#include <sys/lock.h> 51127474Stjr#include <sys/mutex.h> 52127474Stjr#include <sys/proc.h> 53127474Stjr#include <sys/ptrace.h> 54127474Stjr#include <sys/user.h> 55127474Stjr#include <sys/vnode.h> 56127474Stjr 57127474Stjr#include <fs/procfs/procfs.h> 58127474Stjr 59127474Stjr#include <vm/vm.h> 60127474Stjr#include <vm/vm_param.h> 61127474Stjr#include <vm/pmap.h> 62127474Stjr#include <vm/vm_extern.h> 63127474Stjr#include <vm/vm_map.h> 64127474Stjr#include <vm/vm_kern.h> 65127474Stjr#include <vm/vm_object.h> 66127474Stjr#include <vm/vm_page.h> 67127474Stjr 68127474Stjrstatic int procfs_rwmem __P((struct proc *curp, 69127474Stjr struct proc *p, struct uio *uio)); 70127474Stjr 71127474Stjrstatic int 72127474Stjrprocfs_rwmem(curp, p, uio) 73127474Stjr struct proc *curp; 74127474Stjr struct proc *p; 75127474Stjr struct uio *uio; 76127474Stjr{ 77127474Stjr int error; 78127474Stjr int writing; 79127474Stjr struct vmspace *vm; 80174990Sache vm_map_t map; 81127474Stjr vm_object_t object = NULL; 82127474Stjr vm_offset_t pageno = 0; /* page number */ 83127474Stjr vm_prot_t reqprot; 84127474Stjr vm_offset_t kva; 85127474Stjr 86127474Stjr GIANT_REQUIRED; 87127474Stjr 88127474Stjr /* 89127474Stjr * if the vmspace is in the midst of being deallocated or the 90127474Stjr * process is exiting, don't try to grab anything. The page table 91127474Stjr * usage in that process can be messed up. 92127474Stjr */ 93127474Stjr vm = p->p_vmspace; 94127474Stjr if ((p->p_flag & P_WEXIT)) 95127474Stjr return EFAULT; 96127474Stjr if (vm->vm_refcnt < 1) 97127474Stjr return EFAULT; 98127474Stjr ++vm->vm_refcnt; 99127474Stjr /* 100127474Stjr * The map we want... 101127474Stjr */ 102127474Stjr map = &vm->vm_map; 103 104 writing = uio->uio_rw == UIO_WRITE; 105 reqprot = writing ? (VM_PROT_WRITE | VM_PROT_OVERRIDE_WRITE) : VM_PROT_READ; 106 107 kva = kmem_alloc_pageable(kernel_map, PAGE_SIZE); 108 109 /* 110 * Only map in one page at a time. We don't have to, but it 111 * makes things easier. This way is trivial - right? 112 */ 113 do { 114 vm_map_t tmap; 115 vm_offset_t uva; 116 int page_offset; /* offset into page */ 117 vm_map_entry_t out_entry; 118 vm_prot_t out_prot; 119 boolean_t wired; 120 vm_pindex_t pindex; 121 u_int len; 122 vm_page_t m; 123 124 object = NULL; 125 126 uva = (vm_offset_t) uio->uio_offset; 127 128 /* 129 * Get the page number of this segment. 130 */ 131 pageno = trunc_page(uva); 132 page_offset = uva - pageno; 133 134 /* 135 * How many bytes to copy 136 */ 137 len = min(PAGE_SIZE - page_offset, uio->uio_resid); 138 139 /* 140 * Fault the page on behalf of the process 141 */ 142 error = vm_fault(map, pageno, reqprot, VM_FAULT_NORMAL); 143 if (error) { 144 error = EFAULT; 145 break; 146 } 147 148 /* 149 * Now we need to get the page. out_entry, out_prot, wired, 150 * and single_use aren't used. One would think the vm code 151 * would be a *bit* nicer... We use tmap because 152 * vm_map_lookup() can change the map argument. 153 */ 154 tmap = map; 155 error = vm_map_lookup(&tmap, pageno, reqprot, 156 &out_entry, &object, &pindex, &out_prot, 157 &wired); 158 159 if (error) { 160 error = EFAULT; 161 162 /* 163 * Make sure that there is no residue in 'object' from 164 * an error return on vm_map_lookup. 165 */ 166 object = NULL; 167 168 break; 169 } 170 171 m = vm_page_lookup(object, pindex); 172 173 /* Allow fallback to backing objects if we are reading */ 174 175 while (m == NULL && !writing && object->backing_object) { 176 177 pindex += OFF_TO_IDX(object->backing_object_offset); 178 object = object->backing_object; 179 180 m = vm_page_lookup(object, pindex); 181 } 182 183 if (m == NULL) { 184 error = EFAULT; 185 186 /* 187 * Make sure that there is no residue in 'object' from 188 * an error return on vm_map_lookup. 189 */ 190 object = NULL; 191 192 vm_map_lookup_done(tmap, out_entry); 193 194 break; 195 } 196 197 /* 198 * Wire the page into memory 199 */ 200 vm_page_wire(m); 201 202 /* 203 * We're done with tmap now. 204 * But reference the object first, so that we won't loose 205 * it. 206 */ 207 vm_object_reference(object); 208 vm_map_lookup_done(tmap, out_entry); 209 210 pmap_kenter(kva, VM_PAGE_TO_PHYS(m)); 211 212 /* 213 * Now do the i/o move. 214 */ 215 error = uiomove((caddr_t)(kva + page_offset), len, uio); 216 217 pmap_kremove(kva); 218 219 /* 220 * release the page and the object 221 */ 222 vm_page_unwire(m, 1); 223 vm_object_deallocate(object); 224 225 object = NULL; 226 227 } while (error == 0 && uio->uio_resid > 0); 228 229 if (object) 230 vm_object_deallocate(object); 231 232 kmem_free(kernel_map, kva, PAGE_SIZE); 233 vmspace_free(vm); 234 return (error); 235} 236 237/* 238 * Copy data in and out of the target process. 239 * We do this by mapping the process's page into 240 * the kernel and then doing a uiomove direct 241 * from the kernel address space. 242 */ 243int 244procfs_domem(curp, p, pfs, uio) 245 struct proc *curp; 246 struct proc *p; 247 struct pfsnode *pfs; 248 struct uio *uio; 249{ 250 251 if (uio->uio_resid == 0) 252 return (0); 253 254 /* 255 * XXX 256 * We need to check for KMEM_GROUP because ps is sgid kmem; 257 * not allowing it here causes ps to not work properly. Arguably, 258 * this is a bug with what ps does. We only need to do this 259 * for Pmem nodes, and only if it's reading. This is still not 260 * good, as it may still be possible to grab illicit data if 261 * a process somehow gets to be KMEM_GROUP. Note that this also 262 * means that KMEM_GROUP can't change without editing procfs.h! 263 * All in all, quite yucky. 264 */ 265 266 if (p_can(curp, p, P_CAN_DEBUG, NULL) && 267 !(uio->uio_rw == UIO_READ && 268 procfs_kmemaccess(curp))) 269 return EPERM; 270 271 return (procfs_rwmem(curp, p, uio)); 272} 273 274/* 275 * Given process (p), find the vnode from which 276 * its text segment is being executed. 277 * 278 * It would be nice to grab this information from 279 * the VM system, however, there is no sure-fire 280 * way of doing that. Instead, fork(), exec() and 281 * wait() all maintain the p_textvp field in the 282 * process proc structure which contains a held 283 * reference to the exec'ed vnode. 284 * 285 * XXX - Currently, this is not not used, as the 286 * /proc/pid/file object exposes an information leak 287 * that shouldn't happen. Using a mount option would 288 * make it configurable on a per-system (or, at least, 289 * per-mount) basis; however, that's not really best. 290 * The best way to do it, I think, would be as an 291 * ioctl; this would restrict it to the uid running 292 * program, or root, which seems a reasonable compromise. 293 * However, the number of applications for this is 294 * minimal, if it can't be seen in the filesytem space, 295 * and doint it as an ioctl makes it somewhat less 296 * useful due to the, well, inelegance. 297 * 298 */ 299struct vnode * 300procfs_findtextvp(p) 301 struct proc *p; 302{ 303 304 return (p->p_textvp); 305} 306 307int procfs_kmemaccess(curp) 308 struct proc *curp; 309{ 310 int i; 311 struct ucred *cred; 312 313 cred = curp->p_ucred; 314 if (suser(curp)) 315 return 1; 316 317 /* XXX: Why isn't this done with file-perms ??? */ 318 for (i = 0; i < cred->cr_ngroups; i++) 319 if (cred->cr_groups[i] == KMEM_GROUP) 320 return 1; 321 322 return 0; 323} 324