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