1/*- 2 * Copyright (c) 2015 Nuxi, https://nuxi.nl/ 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD$"); 28 29#include <sys/param.h> 30#include <sys/imgact.h> 31#include <sys/kernel.h> 32#include <sys/module.h> 33#include <sys/proc.h> 34#include <sys/smp.h> 35#include <sys/sysctl.h> 36#include <sys/sysent.h> 37#include <sys/systm.h> 38 39#include <contrib/cloudabi/cloudabi32_types.h> 40 41#include <compat/cloudabi/cloudabi_util.h> 42 43#include <compat/cloudabi32/cloudabi32_util.h> 44 45extern char _binary_cloudabi32_vdso_o_start[]; 46extern char _binary_cloudabi32_vdso_o_end[]; 47 48int 49cloudabi32_copyout_strings(struct image_params *imgp, uintptr_t *stack_base) 50{ 51 struct image_args *args; 52 uintptr_t begin; 53 size_t len; 54 55 /* Copy out program arguments. */ 56 args = imgp->args; 57 len = exec_args_get_begin_envv(args) - args->begin_argv; 58 begin = rounddown2(imgp->sysent->sv_usrstack - len, sizeof(register_t)); 59 *stack_base = begin; 60 return (copyout(args->begin_argv, (void *)begin, len)); 61} 62 63int 64cloudabi32_fixup(uintptr_t *stack_base, struct image_params *imgp) 65{ 66 char canarybuf[64], pidbuf[16]; 67 Elf32_Auxargs *args; 68 struct thread *td; 69 void *argdata, *canary, *pid; 70 size_t argdatalen; 71 int error; 72 73 /* 74 * CloudABI executables do not store the FreeBSD OS release 75 * number in their header. Set the OS release number to the 76 * latest version of FreeBSD, so that system calls behave as if 77 * called natively. 78 */ 79 td = curthread; 80 td->td_proc->p_osrel = __FreeBSD_version; 81 82 argdata = (void *)*stack_base; 83 84 /* Store canary for stack smashing protection. */ 85 arc4rand(canarybuf, sizeof(canarybuf), 0); 86 *stack_base -= roundup(sizeof(canarybuf), sizeof(register_t)); 87 canary = (void *)*stack_base; 88 error = copyout(canarybuf, canary, sizeof(canarybuf)); 89 if (error != 0) 90 return (error); 91 92 /* 93 * Generate a random UUID that identifies the process. Right now 94 * we don't store this UUID in the kernel. Ideally, it should be 95 * exposed through ps(1). 96 */ 97 arc4rand(pidbuf, sizeof(pidbuf), 0); 98 pidbuf[6] = (pidbuf[6] & 0x0f) | 0x40; 99 pidbuf[8] = (pidbuf[8] & 0x3f) | 0x80; 100 *stack_base -= roundup(sizeof(pidbuf), sizeof(register_t)); 101 pid = (void *)*stack_base; 102 error = copyout(pidbuf, pid, sizeof(pidbuf)); 103 if (error != 0) 104 return (error); 105 106 /* 107 * Compute length of program arguments. As the argument data is 108 * binary safe, we had to add a trailing null byte in 109 * exec_copyin_data_fds(). Undo this by reducing the length. 110 */ 111 args = (Elf32_Auxargs *)imgp->auxargs; 112 argdatalen = exec_args_get_begin_envv(imgp->args) - 113 imgp->args->begin_argv; 114 if (argdatalen > 0) 115 --argdatalen; 116 117 /* Write out an auxiliary vector. */ 118 cloudabi32_auxv_t auxv[] = { 119#define VAL(type, val) { .a_type = (type), .a_val = (val) } 120#define PTR(type, ptr) { .a_type = (type), .a_ptr = (uintptr_t)(ptr) } 121 PTR(CLOUDABI_AT_ARGDATA, argdata), 122 VAL(CLOUDABI_AT_ARGDATALEN, argdatalen), 123 VAL(CLOUDABI_AT_BASE, args->base), 124 PTR(CLOUDABI_AT_CANARY, canary), 125 VAL(CLOUDABI_AT_CANARYLEN, sizeof(canarybuf)), 126 VAL(CLOUDABI_AT_NCPUS, mp_ncpus), 127 VAL(CLOUDABI_AT_PAGESZ, args->pagesz), 128 PTR(CLOUDABI_AT_PHDR, args->phdr), 129 VAL(CLOUDABI_AT_PHNUM, args->phnum), 130 PTR(CLOUDABI_AT_PID, pid), 131 PTR(CLOUDABI_AT_SYSINFO_EHDR, 132 imgp->proc->p_sysent->sv_shared_page_base), 133 VAL(CLOUDABI_AT_TID, td->td_tid), 134#undef VAL 135#undef PTR 136 { .a_type = CLOUDABI_AT_NULL }, 137 }; 138 *stack_base -= roundup(sizeof(auxv), sizeof(register_t)); 139 error = copyout(auxv, (void *)*stack_base, sizeof(auxv)); 140 if (error != 0) 141 return (error); 142 143 /* Reserve space for storing the TCB. */ 144 *stack_base -= roundup(sizeof(cloudabi32_tcb_t), sizeof(register_t)); 145 return (0); 146} 147 148static int 149cloudabi32_modevent(module_t mod, int type, void *data) 150{ 151 152 switch (type) { 153 case MOD_LOAD: 154 cloudabi_vdso_init(cloudabi32_brand.sysvec, 155 _binary_cloudabi32_vdso_o_start, 156 _binary_cloudabi32_vdso_o_end); 157 if (elf32_insert_brand_entry(&cloudabi32_brand) < 0) { 158 printf("Failed to add CloudABI ELF brand handler\n"); 159 return (EINVAL); 160 } 161 return (0); 162 case MOD_UNLOAD: 163 if (elf32_brand_inuse(&cloudabi32_brand)) 164 return (EBUSY); 165 if (elf32_remove_brand_entry(&cloudabi32_brand) < 0) { 166 printf("Failed to remove CloudABI ELF brand handler\n"); 167 return (EINVAL); 168 } 169 cloudabi_vdso_destroy(cloudabi32_brand.sysvec); 170 return (0); 171 default: 172 return (EOPNOTSUPP); 173 } 174} 175 176static moduledata_t cloudabi32_module = { 177 "cloudabi32", 178 cloudabi32_modevent, 179 NULL 180}; 181 182DECLARE_MODULE_TIED(cloudabi32, cloudabi32_module, SI_SUB_EXEC, SI_ORDER_ANY); 183MODULE_DEPEND(cloudabi32, cloudabi, 1, 1, 1); 184FEATURE(cloudabi32, "CloudABI 32bit support"); 185