1 /* 2 * (MPSAFE) 3 * 4 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. 5 * 6 * This code is derived from software contributed to The DragonFly Project 7 * by Matthew Dillon <dillon@backplane.com> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 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 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 3. Neither the name of The DragonFly Project nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific, prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $DragonFly: src/sys/kern/imgact_resident.c,v 1.17 2007/04/30 07:18:53 dillon Exp $ 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/sysproto.h> 43 #include <sys/exec.h> 44 #include <sys/imgact.h> 45 #include <sys/imgact_aout.h> 46 #include <sys/mman.h> 47 #include <sys/proc.h> 48 #include <sys/priv.h> 49 #include <sys/resourcevar.h> 50 #include <sys/sysent.h> 51 #include <sys/systm.h> 52 #include <sys/stat.h> 53 #include <sys/vnode.h> 54 #include <sys/inflate.h> 55 #include <sys/sysctl.h> 56 #include <sys/lock.h> 57 #include <sys/resident.h> 58 59 #include <vm/vm.h> 60 #include <vm/vm_param.h> 61 #include <vm/pmap.h> 62 #include <vm/vm_map.h> 63 #include <vm/vm_kern.h> 64 #include <vm/vm_extern.h> 65 66 #include <sys/sysref2.h> 67 #include <sys/mplock2.h> 68 69 static int exec_res_id = 0; 70 71 static TAILQ_HEAD(,vmresident) exec_res_list; 72 73 static MALLOC_DEFINE(M_EXEC_RES, "vmresident", "resident execs"); 74 75 /* lockmgr lock for protecting the exec_res_list */ 76 static struct lock exec_list_lock; 77 78 static void 79 vm_resident_init(void *__dummy) 80 { 81 lockinit(&exec_list_lock, "vmres", 0, 0); 82 TAILQ_INIT(&exec_res_list); 83 } 84 SYSINIT(vmres, SI_BOOT1_LOCK, SI_ORDER_ANY, vm_resident_init, 0); 85 86 static int 87 fill_xresident(struct vmresident *vr, struct xresident *in, struct thread *td) 88 { 89 struct stat st; 90 struct vnode *vrtmp; 91 int error = 0; 92 93 vrtmp = vr->vr_vnode; 94 95 in->res_entry_addr = vr->vr_entry_addr; 96 in->res_id = vr->vr_id; 97 if (vrtmp) { 98 char *freepath, *fullpath; 99 error = vn_fullpath(td->td_proc, vrtmp, &fullpath, &freepath, 0); 100 if (error != 0) { 101 /* could not retrieve cached path, return zero'ed string */ 102 bzero(in->res_file, MAXPATHLEN); 103 error = 0; 104 } else { 105 strlcpy(in->res_file, fullpath, sizeof(in->res_file)); 106 kfree(freepath, M_TEMP); 107 } 108 109 /* indicate that we are using the vnode */ 110 error = vget(vrtmp, LK_EXCLUSIVE); 111 if (error) 112 goto done; 113 114 /* retrieve underlying stat information and release vnode */ 115 error = vn_stat(vrtmp, &st, td->td_ucred); 116 vput(vrtmp); 117 if (error) 118 goto done; 119 120 in->res_stat = st; 121 } 122 123 done: 124 if (error) 125 kprintf("fill_xresident, error = %d\n", error); 126 return (error); 127 } 128 129 static int 130 sysctl_vm_resident(SYSCTL_HANDLER_ARGS) 131 { 132 struct vmresident *vmres; 133 struct thread *td; 134 int error; 135 int count; 136 137 /* only super-user should call this sysctl */ 138 td = req->td; 139 if ((priv_check(td, PRIV_VM_RESIDENT)) != 0) 140 return EPERM; 141 142 error = count = 0; 143 144 if (exec_res_id == 0) 145 return error; 146 147 /* client queried for number of resident binaries */ 148 if (!req->oldptr) 149 return SYSCTL_OUT(req, 0, exec_res_id); 150 151 lockmgr(&exec_list_lock, LK_SHARED); 152 153 TAILQ_FOREACH(vmres, &exec_res_list, vr_link) { 154 struct xresident xres; 155 error = fill_xresident(vmres, &xres, td); 156 if (error != 0) 157 break; 158 159 error = SYSCTL_OUT(req, (void *)&xres, 160 sizeof(struct xresident)); 161 if (error != 0) 162 break; 163 } 164 lockmgr(&exec_list_lock, LK_RELEASE); 165 166 return (error); 167 } 168 SYSCTL_PROC(_vm, OID_AUTO, resident, CTLTYPE_OPAQUE|CTLFLAG_RD, 0, 0, 169 sysctl_vm_resident, "S,xresident", "resident executables (sys/resident.h)"); 170 171 int 172 exec_resident_imgact(struct image_params *imgp) 173 { 174 struct vmresident *vmres; 175 176 /* 177 * resident image activator 178 */ 179 lockmgr(&exec_list_lock, LK_SHARED); 180 if ((vmres = imgp->vp->v_resident) == NULL) { 181 lockmgr(&exec_list_lock, LK_RELEASE); 182 return(-1); 183 } 184 atomic_add_int(&vmres->vr_refs, 1); 185 lockmgr(&exec_list_lock, LK_RELEASE); 186 187 /* 188 * We want to exec the new vmspace without holding the lock to 189 * improve concurrency. 190 */ 191 exec_new_vmspace(imgp, vmres->vr_vmspace); 192 imgp->resident = 1; 193 imgp->interpreted = 0; 194 imgp->proc->p_sysent = vmres->vr_sysent; 195 imgp->entry_addr = vmres->vr_entry_addr; 196 atomic_subtract_int(&vmres->vr_refs, 1); 197 198 return(0); 199 } 200 201 /* 202 * exec_sys_register(entry) 203 * 204 * Register ourselves for resident execution. Only root (i.e. a process with 205 * PRIV_VM_RESIDENT credentials) can do this. This 206 * will snapshot the vmspace and cause future exec's of the specified binary 207 * to use the snapshot directly rather then load & relocate a new copy. 208 * 209 * MPALMOSTSAFE 210 */ 211 int 212 sys_exec_sys_register(struct exec_sys_register_args *uap) 213 { 214 struct thread *td = curthread; 215 struct vmresident *vmres; 216 struct vnode *vp; 217 struct proc *p; 218 int error; 219 220 p = td->td_proc; 221 error = priv_check_cred(td->td_ucred, PRIV_VM_RESIDENT, 0); 222 if (error) 223 return(error); 224 225 if ((vp = p->p_textvp) == NULL) 226 return(ENOENT); 227 228 lockmgr(&exec_list_lock, LK_EXCLUSIVE); 229 230 if (vp->v_resident) { 231 lockmgr(&exec_list_lock, LK_RELEASE); 232 return(EEXIST); 233 } 234 235 vhold(vp); 236 vmres = kmalloc(sizeof(*vmres), M_EXEC_RES, M_WAITOK | M_ZERO); 237 vmres->vr_vnode = vp; 238 vmres->vr_sysent = p->p_sysent; 239 vmres->vr_id = ++exec_res_id; 240 vmres->vr_entry_addr = (intptr_t)uap->entry; 241 vmres->vr_vmspace = vmspace_fork(p->p_vmspace); /* XXX order */ 242 pmap_pinit2(vmspace_pmap(vmres->vr_vmspace)); 243 vp->v_resident = vmres; 244 245 TAILQ_INSERT_TAIL(&exec_res_list, vmres, vr_link); 246 lockmgr(&exec_list_lock, LK_RELEASE); 247 248 return(0); 249 } 250 251 /* 252 * exec_sys_unregister(id) 253 * 254 * Unregister the specified id. If an id of -1 is used unregister 255 * the registration associated with the current process. An id of -2 256 * unregisters everything. 257 * 258 * MPALMOSTSAFE 259 */ 260 int 261 sys_exec_sys_unregister(struct exec_sys_unregister_args *uap) 262 { 263 struct thread *td = curthread; 264 struct vmresident *vmres; 265 struct proc *p; 266 int error; 267 int id; 268 int count; 269 270 p = td->td_proc; 271 error = priv_check_cred(td->td_ucred, PRIV_VM_RESIDENT, 0); 272 if (error) 273 return(error); 274 275 /* 276 * If id is -1, unregister ourselves 277 */ 278 lockmgr(&exec_list_lock, LK_EXCLUSIVE); 279 280 if ((id = uap->id) == -1 && p->p_textvp && p->p_textvp->v_resident) 281 id = p->p_textvp->v_resident->vr_id; 282 283 /* 284 * Look for the registration 285 */ 286 error = ENOENT; 287 count = 0; 288 289 restart: 290 TAILQ_FOREACH(vmres, &exec_res_list, vr_link) { 291 if (id == -2 || vmres->vr_id == id) { 292 /* 293 * Check race against exec 294 */ 295 if (vmres->vr_refs) { 296 lockmgr(&exec_list_lock, LK_RELEASE); 297 tsleep(vmres, 0, "vmres", 1); 298 lockmgr(&exec_list_lock, LK_EXCLUSIVE); 299 goto restart; 300 } 301 302 /* 303 * Remove it 304 */ 305 TAILQ_REMOVE(&exec_res_list, vmres, vr_link); 306 if (vmres->vr_vnode) { 307 vmres->vr_vnode->v_resident = NULL; 308 vdrop(vmres->vr_vnode); 309 vmres->vr_vnode = NULL; 310 } 311 if (vmres->vr_vmspace) { 312 sysref_put(&vmres->vr_vmspace->vm_sysref); 313 vmres->vr_vmspace = NULL; 314 } 315 kfree(vmres, M_EXEC_RES); 316 exec_res_id--; 317 error = 0; 318 ++count; 319 goto restart; 320 } 321 } 322 lockmgr(&exec_list_lock, LK_RELEASE); 323 324 if (error == 0) 325 uap->sysmsg_result = count; 326 return(error); 327 } 328 329