1 /* 2 * Copyright (c) 1993 Jan-Simon Pendry 3 * Copyright (c) 1993 Sean Eric Fagan 4 * Copyright (c) 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Jan-Simon Pendry and Sean Eric Fagan. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)procfs_mem.c 8.5 (Berkeley) 6/15/94 39 * 40 * $FreeBSD$ 41 */ 42 43 /* 44 * This is a lightly hacked and merged version 45 * of sef's pread/pwrite functions 46 */ 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/lock.h> 51 #include <sys/mutex.h> 52 #include <sys/proc.h> 53 #include <sys/ptrace.h> 54 #include <sys/user.h> 55 #include <sys/vnode.h> 56 57 #include <fs/procfs/procfs.h> 58 59 #include <vm/vm.h> 60 #include <vm/vm_param.h> 61 #include <vm/pmap.h> 62 #include <vm/vm_extern.h> 63 #include <vm/vm_map.h> 64 #include <vm/vm_kern.h> 65 #include <vm/vm_object.h> 66 #include <vm/vm_page.h> 67 68 static int procfs_rwmem __P((struct proc *curp, 69 struct proc *p, struct uio *uio)); 70 71 static int 72 procfs_rwmem(curp, p, uio) 73 struct proc *curp; 74 struct proc *p; 75 struct uio *uio; 76 { 77 int error; 78 int writing; 79 struct vmspace *vm; 80 vm_map_t map; 81 vm_object_t object = NULL; 82 vm_offset_t pageno = 0; /* page number */ 83 vm_prot_t reqprot; 84 vm_offset_t kva; 85 86 GIANT_REQUIRED; 87 88 /* 89 * if the vmspace is in the midst of being deallocated or the 90 * process is exiting, don't try to grab anything. The page table 91 * usage in that process can be messed up. 92 */ 93 vm = p->p_vmspace; 94 if ((p->p_flag & P_WEXIT)) 95 return EFAULT; 96 if (vm->vm_refcnt < 1) 97 return EFAULT; 98 ++vm->vm_refcnt; 99 /* 100 * The map we want... 101 */ 102 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 */ 243 int 244 procfs_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_candebug(curp, p) && 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 */ 299 struct vnode * 300 procfs_findtextvp(p) 301 struct proc *p; 302 { 303 304 return (p->p_textvp); 305 } 306 307 int 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