1c21dee17SSøren Schmidt /*- 20ba1b365SEd Maste * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 383ef78beSPedro F. Giffuni * 49a14aa01SUlrich Spörlein * Copyright (c) 1994-1996 Søren Schmidt 5c21dee17SSøren Schmidt * All rights reserved. 6c21dee17SSøren Schmidt * 7c21dee17SSøren Schmidt * Based heavily on /sys/kern/imgact_aout.c which is: 8c21dee17SSøren Schmidt * Copyright (c) 1993, David Greenman 9c21dee17SSøren Schmidt * 10c21dee17SSøren Schmidt * Redistribution and use in source and binary forms, with or without 11c21dee17SSøren Schmidt * modification, are permitted provided that the following conditions 12c21dee17SSøren Schmidt * are met: 13c21dee17SSøren Schmidt * 1. Redistributions of source code must retain the above copyright 140ba1b365SEd Maste * notice, this list of conditions and the following disclaimer. 15c21dee17SSøren Schmidt * 2. Redistributions in binary form must reproduce the above copyright 16c21dee17SSøren Schmidt * notice, this list of conditions and the following disclaimer in the 17c21dee17SSøren Schmidt * documentation and/or other materials provided with the distribution. 18c21dee17SSøren Schmidt * 190ba1b365SEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 200ba1b365SEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 210ba1b365SEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 220ba1b365SEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 230ba1b365SEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 240ba1b365SEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 250ba1b365SEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 260ba1b365SEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 270ba1b365SEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 280ba1b365SEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 290ba1b365SEd Maste * SUCH DAMAGE. 30c21dee17SSøren Schmidt */ 31c21dee17SSøren Schmidt 3227e0099cSDavid E. O'Brien #include <sys/cdefs.h> 3327e0099cSDavid E. O'Brien __FBSDID("$FreeBSD$"); 3427e0099cSDavid E. O'Brien 35c21dee17SSøren Schmidt #include <sys/param.h> 36c21dee17SSøren Schmidt #include <sys/systm.h> 37c21dee17SSøren Schmidt #include <sys/exec.h> 38c21dee17SSøren Schmidt #include <sys/imgact.h> 39c21dee17SSøren Schmidt #include <sys/imgact_aout.h> 40c21dee17SSøren Schmidt #include <sys/kernel.h> 411cd52ec3SBruce Evans #include <sys/lock.h> 42fb919e4dSMark Murray #include <sys/mman.h> 43fb919e4dSMark Murray #include <sys/mutex.h> 44a794e791SBruce Evans #include <sys/proc.h> 451ba5ad42SEdward Tomasz Napierala #include <sys/racct.h> 46fb919e4dSMark Murray #include <sys/resourcevar.h> 47a794e791SBruce Evans #include <sys/vnode.h> 48c21dee17SSøren Schmidt 49c21dee17SSøren Schmidt #include <vm/vm.h> 50c21dee17SSøren Schmidt #include <vm/vm_kern.h> 51ac9a8f2fSPeter Wemm #include <vm/vm_param.h> 52ac9a8f2fSPeter Wemm #include <vm/pmap.h> 53ac9a8f2fSPeter Wemm #include <vm/vm_map.h> 54e0067d71SBruce Evans #include <vm/vm_extern.h> 55c21dee17SSøren Schmidt 56d66a5066SPeter Wemm #include <i386/linux/linux.h> 571f3dad5aSBruce Evans 5889c9a483SAlfred Perlstein static int exec_linux_imgact(struct image_params *iparams); 591f3dad5aSBruce Evans 60303b270bSEivind Eklund static int 61b07cd97eSMark Murray exec_linux_imgact(struct image_params *imgp) 62c21dee17SSøren Schmidt { 63f58609f0SBruce Evans const struct exec *a_out = (const struct exec *) imgp->image_header; 645856e12eSJohn Dyson struct vmspace *vmspace; 65ede8dc43SBruce Evans vm_offset_t vmaddr; 66ede8dc43SBruce Evans unsigned long virtual_offset, file_offset; 67ede8dc43SBruce Evans unsigned long bss_size; 683494f31aSKonstantin Belousov ssize_t aresid; 69c21dee17SSøren Schmidt int error; 70c21dee17SSøren Schmidt 71c21dee17SSøren Schmidt if (((a_out->a_magic >> 16) & 0xff) != 0x64) 72c21dee17SSøren Schmidt return -1; 73c21dee17SSøren Schmidt 74c21dee17SSøren Schmidt /* 75c21dee17SSøren Schmidt * Set file/virtual offset based on a.out variant. 76c21dee17SSøren Schmidt */ 77c21dee17SSøren Schmidt switch ((int)(a_out->a_magic & 0xffff)) { 78c21dee17SSøren Schmidt case 0413: 79c21dee17SSøren Schmidt virtual_offset = 0; 80c21dee17SSøren Schmidt file_offset = 1024; 81c21dee17SSøren Schmidt break; 82c21dee17SSøren Schmidt case 0314: 83c21dee17SSøren Schmidt virtual_offset = 4096; 84c21dee17SSøren Schmidt file_offset = 0; 85c21dee17SSøren Schmidt break; 86c21dee17SSøren Schmidt default: 87c21dee17SSøren Schmidt return (-1); 88c21dee17SSøren Schmidt } 89c21dee17SSøren Schmidt bss_size = round_page(a_out->a_bss); 90d66a5066SPeter Wemm #ifdef DEBUG 91e4e6ae13SBruce Evans printf("imgact: text: %08lx, data: %08lx, bss: %08lx\n", 92e4e6ae13SBruce Evans (u_long)a_out->a_text, (u_long)a_out->a_data, bss_size); 93d66a5066SPeter Wemm #endif 94c21dee17SSøren Schmidt 95c21dee17SSøren Schmidt /* 96c21dee17SSøren Schmidt * Check various fields in header for validity/bounds. 97c21dee17SSøren Schmidt */ 98c21dee17SSøren Schmidt if (a_out->a_entry < virtual_offset || 99c21dee17SSøren Schmidt a_out->a_entry >= virtual_offset + a_out->a_text || 100f8845af0SPoul-Henning Kamp a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) 101c21dee17SSøren Schmidt return (-1); 102c21dee17SSøren Schmidt 103c21dee17SSøren Schmidt /* text + data can't exceed file size */ 104c52007c2SDavid Greenman if (a_out->a_data + a_out->a_text > imgp->attr->va_size) 105c21dee17SSøren Schmidt return (EFAULT); 106c21dee17SSøren Schmidt /* 107c21dee17SSøren Schmidt * text/data/bss must not exceed limits 108c21dee17SSøren Schmidt */ 10991d5354aSJohn Baldwin PROC_LOCK(imgp->proc); 110cbc89bfbSPaul Saab if (a_out->a_text > maxtsiz || 111f6f6d240SMateusz Guzik a_out->a_data + bss_size > lim_cur_proc(imgp->proc, RLIMIT_DATA) || 1121ba5ad42SEdward Tomasz Napierala racct_set(imgp->proc, RACCT_DATA, a_out->a_data + bss_size) != 0) { 11391d5354aSJohn Baldwin PROC_UNLOCK(imgp->proc); 114c21dee17SSøren Schmidt return (ENOMEM); 11591d5354aSJohn Baldwin } 11691d5354aSJohn Baldwin PROC_UNLOCK(imgp->proc); 117c21dee17SSøren Schmidt 11822db15c0SAttilio Rao VOP_UNLOCK(imgp->vp, 0); 119619eb6e5SJeff Roberson 120c21dee17SSøren Schmidt /* 121c21dee17SSøren Schmidt * Destroy old process VM and create a new one (with a new stack) 122c21dee17SSøren Schmidt */ 12389b57fcfSKonstantin Belousov error = exec_new_vmspace(imgp, &linux_sysvec); 12489b57fcfSKonstantin Belousov if (error) 12589b57fcfSKonstantin Belousov goto fail; 1265856e12eSJohn Dyson vmspace = imgp->proc->p_vmspace; 127c21dee17SSøren Schmidt 128c21dee17SSøren Schmidt /* 129c21dee17SSøren Schmidt * Check if file_offset page aligned,. 130802e08a3SAlexander Leidinger * Currently we cannot handle misaligned file offsets, 131c21dee17SSøren Schmidt * and so we read in the entire image (what a waste). 132c21dee17SSøren Schmidt */ 133f8845af0SPoul-Henning Kamp if (file_offset & PAGE_MASK) { 134c21dee17SSøren Schmidt #ifdef DEBUG 135e4e6ae13SBruce Evans printf("imgact: Non page aligned binary %lu\n", file_offset); 136c21dee17SSøren Schmidt #endif 137c21dee17SSøren Schmidt /* 1385297fc55SPeter Wemm * Map text+data+bss read/write/execute 139c21dee17SSøren Schmidt */ 140c21dee17SSøren Schmidt vmaddr = virtual_offset; 141c21dee17SSøren Schmidt error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, 142edb572a3SJohn Baldwin a_out->a_text + a_out->a_data + bss_size, 0, VMFS_NO_SPACE, 143a4fc5c1aSJohn Dyson VM_PROT_ALL, VM_PROT_ALL, 0); 144c21dee17SSøren Schmidt if (error) 145619eb6e5SJeff Roberson goto fail; 146c21dee17SSøren Schmidt 1473494f31aSKonstantin Belousov error = vn_rdwr(UIO_READ, imgp->vp, (void *)vmaddr, file_offset, 1483494f31aSKonstantin Belousov a_out->a_text + a_out->a_data, UIO_USERSPACE, 0, 1493494f31aSKonstantin Belousov curthread->td_ucred, NOCRED, &aresid, curthread); 1503494f31aSKonstantin Belousov if (error != 0) 151619eb6e5SJeff Roberson goto fail; 1523494f31aSKonstantin Belousov if (aresid != 0) { 1533494f31aSKonstantin Belousov error = ENOEXEC; 154619eb6e5SJeff Roberson goto fail; 1553494f31aSKonstantin Belousov } 156c21dee17SSøren Schmidt 157c21dee17SSøren Schmidt /* 1585297fc55SPeter Wemm * remove write enable on the 'text' part 159c21dee17SSøren Schmidt */ 1600946c36cSPeter Wemm error = vm_map_protect(&vmspace->vm_map, 1610946c36cSPeter Wemm vmaddr, 1620946c36cSPeter Wemm vmaddr + a_out->a_text, 1630946c36cSPeter Wemm VM_PROT_EXECUTE|VM_PROT_READ, 1640946c36cSPeter Wemm TRUE); 165c21dee17SSøren Schmidt if (error) 166619eb6e5SJeff Roberson goto fail; 167c21dee17SSøren Schmidt } 168c21dee17SSøren Schmidt else { 169c21dee17SSøren Schmidt #ifdef DEBUG 170e4e6ae13SBruce Evans printf("imgact: Page aligned binary %lu\n", file_offset); 171c21dee17SSøren Schmidt #endif 172c21dee17SSøren Schmidt /* 1735297fc55SPeter Wemm * Map text+data read/execute 174c21dee17SSøren Schmidt */ 175c21dee17SSøren Schmidt vmaddr = virtual_offset; 1765297fc55SPeter Wemm error = vm_mmap(&vmspace->vm_map, &vmaddr, 1775297fc55SPeter Wemm a_out->a_text + a_out->a_data, 178c21dee17SSøren Schmidt VM_PROT_READ | VM_PROT_EXECUTE, 1795297fc55SPeter Wemm VM_PROT_ALL, 180c21dee17SSøren Schmidt MAP_PRIVATE | MAP_FIXED, 18198df9218SJohn Baldwin OBJT_VNODE, 18298df9218SJohn Baldwin imgp->vp, file_offset); 183c21dee17SSøren Schmidt if (error) 184619eb6e5SJeff Roberson goto fail; 185c21dee17SSøren Schmidt 186d66a5066SPeter Wemm #ifdef DEBUG 187e4e6ae13SBruce Evans printf("imgact: startaddr=%08lx, length=%08lx\n", 18813a0a973SDavid E. O'Brien (u_long)vmaddr, (u_long)a_out->a_text + (u_long)a_out->a_data); 189d66a5066SPeter Wemm #endif 190c21dee17SSøren Schmidt /* 1915297fc55SPeter Wemm * allow read/write of data 192c21dee17SSøren Schmidt */ 1935297fc55SPeter Wemm error = vm_map_protect(&vmspace->vm_map, 1945297fc55SPeter Wemm vmaddr + a_out->a_text, 1955297fc55SPeter Wemm vmaddr + a_out->a_text + a_out->a_data, 1965297fc55SPeter Wemm VM_PROT_ALL, 1975297fc55SPeter Wemm FALSE); 198c21dee17SSøren Schmidt if (error) 199619eb6e5SJeff Roberson goto fail; 200c21dee17SSøren Schmidt 201c21dee17SSøren Schmidt /* 2025297fc55SPeter Wemm * Allocate anon demand-zeroed area for uninitialized data 203c21dee17SSøren Schmidt */ 204c21dee17SSøren Schmidt if (bss_size != 0) { 205c21dee17SSøren Schmidt vmaddr = virtual_offset + a_out->a_text + a_out->a_data; 206c21dee17SSøren Schmidt error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, 207edb572a3SJohn Baldwin bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0); 208c21dee17SSøren Schmidt if (error) 209619eb6e5SJeff Roberson goto fail; 210d66a5066SPeter Wemm #ifdef DEBUG 211e4e6ae13SBruce Evans printf("imgact: bssaddr=%08lx, length=%08lx\n", 212e4e6ae13SBruce Evans (u_long)vmaddr, bss_size); 213d66a5066SPeter Wemm #endif 214d66a5066SPeter Wemm 215c21dee17SSøren Schmidt } 216c21dee17SSøren Schmidt } 217c21dee17SSøren Schmidt /* Fill in process VM information */ 218c21dee17SSøren Schmidt vmspace->vm_tsize = round_page(a_out->a_text) >> PAGE_SHIFT; 219c21dee17SSøren Schmidt vmspace->vm_dsize = round_page(a_out->a_data + bss_size) >> PAGE_SHIFT; 2202cf50c62SBruce Evans vmspace->vm_taddr = (caddr_t)(void *)(uintptr_t)virtual_offset; 2212cf50c62SBruce Evans vmspace->vm_daddr = (caddr_t)(void *)(uintptr_t) 2222cf50c62SBruce Evans (virtual_offset + a_out->a_text); 223c21dee17SSøren Schmidt 224c21dee17SSøren Schmidt /* Fill in image_params */ 225c52007c2SDavid Greenman imgp->interpreted = 0; 226c52007c2SDavid Greenman imgp->entry_addr = a_out->a_entry; 227c21dee17SSøren Schmidt 228c52007c2SDavid Greenman imgp->proc->p_sysent = &linux_sysvec; 229619eb6e5SJeff Roberson 230619eb6e5SJeff Roberson fail: 231cb05b60aSAttilio Rao vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY); 232619eb6e5SJeff Roberson return (error); 233c21dee17SSøren Schmidt } 234c21dee17SSøren Schmidt 235c21dee17SSøren Schmidt /* 236c21dee17SSøren Schmidt * Tell kern_execve.c about it, with a little help from the linker. 237c21dee17SSøren Schmidt */ 238*eae594f7SEd Maste static struct execsw linux_execsw = { exec_linux_imgact, "Linux a.out" }; 239aa855a59SPeter Wemm EXEC_SET(linuxaout, linux_execsw); 240