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