| 1 | /* |
| 2 | * Copyright (c) 1998 Mark Newton |
| 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 | * 3. All advertising materials mentioning features or use of this software |
| 14 | * must display the following acknowledgement: |
| 15 | * This product includes software developed by Christos Zoulas. |
| 16 | * 4. The name of the author may not be used to endorse or promote products |
| 17 | * derived from this software without specific prior written permission. |
| 18 | * |
| 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 | * |
| 30 | * $FreeBSD: src/sys/svr4/svr4_sysvec.c,v 1.10.2.2 2002/07/09 14:12:43 robert Exp $ |
| 31 | * $DragonFly: src/sys/emulation/svr4/Attic/svr4_sysvec.c,v 1.4 2003/06/25 03:56:10 dillon Exp $ |
| 32 | */ |
| 33 | |
| 34 | /* XXX we use functions that might not exist. */ |
| 35 | #include "opt_compat.h" |
| 36 | |
| 37 | #ifndef COMPAT_43 |
| 38 | #error "Unable to compile SVR4-emulator due to missing COMPAT_43 option!" |
| 39 | #endif |
| 40 | |
| 41 | #include <sys/param.h> |
| 42 | #include <sys/systm.h> |
| 43 | #include <sys/buf.h> |
| 44 | #include <sys/proc.h> |
| 45 | #include <sys/sysent.h> |
| 46 | #include <sys/imgact.h> |
| 47 | #include <sys/imgact_elf.h> |
| 48 | #include <sys/socket.h> |
| 49 | #include <sys/malloc.h> |
| 50 | #include <sys/namei.h> |
| 51 | #include <sys/vnode.h> |
| 52 | #include <sys/module.h> |
| 53 | #include <vm/vm.h> |
| 54 | #include <vm/vm_zone.h> |
| 55 | #include <sys/exec.h> |
| 56 | #include <sys/kernel.h> |
| 57 | #include <machine/cpu.h> |
| 58 | #include <netinet/in.h> |
| 59 | |
| 60 | #include <svr4/svr4.h> |
| 61 | #include <svr4/svr4_types.h> |
| 62 | #include <svr4/svr4_syscall.h> |
| 63 | #include <svr4/svr4_signal.h> |
| 64 | #include <svr4/svr4_sockio.h> |
| 65 | #include <svr4/svr4_socket.h> |
| 66 | #include <svr4/svr4_errno.h> |
| 67 | #include <svr4/svr4_proto.h> |
| 68 | #include <svr4/svr4_siginfo.h> |
| 69 | #include <svr4/svr4_util.h> |
| 70 | |
| 71 | int bsd_to_svr4_errno[ELAST+1] = { |
| 72 | 0, |
| 73 | SVR4_EPERM, |
| 74 | SVR4_ENOENT, |
| 75 | SVR4_ESRCH, |
| 76 | SVR4_EINTR, |
| 77 | SVR4_EIO, |
| 78 | SVR4_ENXIO, |
| 79 | SVR4_E2BIG, |
| 80 | SVR4_ENOEXEC, |
| 81 | SVR4_EBADF, |
| 82 | SVR4_ECHILD, |
| 83 | SVR4_EDEADLK, |
| 84 | SVR4_ENOMEM, |
| 85 | SVR4_EACCES, |
| 86 | SVR4_EFAULT, |
| 87 | SVR4_ENOTBLK, |
| 88 | SVR4_EBUSY, |
| 89 | SVR4_EEXIST, |
| 90 | SVR4_EXDEV, |
| 91 | SVR4_ENODEV, |
| 92 | SVR4_ENOTDIR, |
| 93 | SVR4_EISDIR, |
| 94 | SVR4_EINVAL, |
| 95 | SVR4_ENFILE, |
| 96 | SVR4_EMFILE, |
| 97 | SVR4_ENOTTY, |
| 98 | SVR4_ETXTBSY, |
| 99 | SVR4_EFBIG, |
| 100 | SVR4_ENOSPC, |
| 101 | SVR4_ESPIPE, |
| 102 | SVR4_EROFS, |
| 103 | SVR4_EMLINK, |
| 104 | SVR4_EPIPE, |
| 105 | SVR4_EDOM, |
| 106 | SVR4_ERANGE, |
| 107 | SVR4_EAGAIN, |
| 108 | SVR4_EINPROGRESS, |
| 109 | SVR4_EALREADY, |
| 110 | SVR4_ENOTSOCK, |
| 111 | SVR4_EDESTADDRREQ, |
| 112 | SVR4_EMSGSIZE, |
| 113 | SVR4_EPROTOTYPE, |
| 114 | SVR4_ENOPROTOOPT, |
| 115 | SVR4_EPROTONOSUPPORT, |
| 116 | SVR4_ESOCKTNOSUPPORT, |
| 117 | SVR4_EOPNOTSUPP, |
| 118 | SVR4_EPFNOSUPPORT, |
| 119 | SVR4_EAFNOSUPPORT, |
| 120 | SVR4_EADDRINUSE, |
| 121 | SVR4_EADDRNOTAVAIL, |
| 122 | SVR4_ENETDOWN, |
| 123 | SVR4_ENETUNREACH, |
| 124 | SVR4_ENETRESET, |
| 125 | SVR4_ECONNABORTED, |
| 126 | SVR4_ECONNRESET, |
| 127 | SVR4_ENOBUFS, |
| 128 | SVR4_EISCONN, |
| 129 | SVR4_ENOTCONN, |
| 130 | SVR4_ESHUTDOWN, |
| 131 | SVR4_ETOOMANYREFS, |
| 132 | SVR4_ETIMEDOUT, |
| 133 | SVR4_ECONNREFUSED, |
| 134 | SVR4_ELOOP, |
| 135 | SVR4_ENAMETOOLONG, |
| 136 | SVR4_EHOSTDOWN, |
| 137 | SVR4_EHOSTUNREACH, |
| 138 | SVR4_ENOTEMPTY, |
| 139 | SVR4_EPROCLIM, |
| 140 | SVR4_EUSERS, |
| 141 | SVR4_EDQUOT, |
| 142 | SVR4_ESTALE, |
| 143 | SVR4_EREMOTE, |
| 144 | SVR4_EBADRPC, |
| 145 | SVR4_ERPCMISMATCH, |
| 146 | SVR4_EPROGUNAVAIL, |
| 147 | SVR4_EPROGMISMATCH, |
| 148 | SVR4_EPROCUNAVAIL, |
| 149 | SVR4_ENOLCK, |
| 150 | SVR4_ENOSYS, |
| 151 | SVR4_EFTYPE, |
| 152 | SVR4_EAUTH, |
| 153 | SVR4_ENEEDAUTH, |
| 154 | SVR4_EIDRM, |
| 155 | SVR4_ENOMSG, |
| 156 | }; |
| 157 | |
| 158 | |
| 159 | static int svr4_fixup(register_t **stack_base, struct image_params *imgp); |
| 160 | |
| 161 | extern struct sysent svr4_sysent[]; |
| 162 | #undef szsigcode |
| 163 | #undef sigcode |
| 164 | |
| 165 | extern int svr4_szsigcode; |
| 166 | extern char svr4_sigcode[]; |
| 167 | |
| 168 | struct sysentvec svr4_sysvec = { |
| 169 | SVR4_SYS_MAXSYSCALL, |
| 170 | svr4_sysent, |
| 171 | 0xff, |
| 172 | SVR4_SIGTBLSZ, |
| 173 | bsd_to_svr4_sig, |
| 174 | ELAST, /* ELAST */ |
| 175 | bsd_to_svr4_errno, |
| 176 | 0, |
| 177 | svr4_fixup, |
| 178 | svr4_sendsig, |
| 179 | svr4_sigcode, |
| 180 | &svr4_szsigcode, |
| 181 | NULL, |
| 182 | "SVR4", |
| 183 | elf_coredump, |
| 184 | NULL, |
| 185 | SVR4_MINSIGSTKSZ |
| 186 | }; |
| 187 | |
| 188 | Elf32_Brandinfo svr4_brand = { |
| 189 | ELFOSABI_SYSV, |
| 190 | "SVR4", |
| 191 | "/compat/svr4", |
| 192 | "/lib/libc.so.1", |
| 193 | &svr4_sysvec |
| 194 | }; |
| 195 | |
| 196 | const char svr4_emul_path[] = "/compat/svr4"; |
| 197 | |
| 198 | static int |
| 199 | svr4_fixup(register_t **stack_base, struct image_params *imgp) |
| 200 | { |
| 201 | Elf32_Auxargs *args = (Elf32_Auxargs *)imgp->auxargs; |
| 202 | register_t *pos; |
| 203 | |
| 204 | pos = *stack_base + (imgp->argc + imgp->envc + 2); |
| 205 | |
| 206 | if (args->trace) { |
| 207 | AUXARGS_ENTRY(pos, AT_DEBUG, 1); |
| 208 | } |
| 209 | if (args->execfd != -1) { |
| 210 | AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); |
| 211 | } |
| 212 | AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); |
| 213 | AUXARGS_ENTRY(pos, AT_PHENT, args->phent); |
| 214 | AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); |
| 215 | AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); |
| 216 | AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); |
| 217 | AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); |
| 218 | AUXARGS_ENTRY(pos, AT_BASE, args->base); |
| 219 | AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); |
| 220 | AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); |
| 221 | AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); |
| 222 | AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); |
| 223 | AUXARGS_ENTRY(pos, AT_NULL, 0); |
| 224 | |
| 225 | free(imgp->auxargs, M_TEMP); |
| 226 | imgp->auxargs = NULL; |
| 227 | |
| 228 | (*stack_base)--; |
| 229 | **stack_base = (int)imgp->argc; |
| 230 | return 0; |
| 231 | } |
| 232 | |
| 233 | /* |
| 234 | * Search an alternate path before passing pathname arguments on |
| 235 | * to system calls. Useful for keeping a seperate 'emulation tree'. |
| 236 | * |
| 237 | * If cflag is set, we check if an attempt can be made to create |
| 238 | * the named file, i.e. we check if the directory it should |
| 239 | * be in exists. |
| 240 | * |
| 241 | * Code shamelessly stolen by Mark Newton from IBCS2 emulation code. |
| 242 | */ |
| 243 | int |
| 244 | svr4_emul_find(sgp, prefix, path, pbuf, cflag) |
| 245 | caddr_t *sgp; /* Pointer to stackgap memory */ |
| 246 | const char *prefix; |
| 247 | char *path; |
| 248 | char **pbuf; |
| 249 | int cflag; |
| 250 | { |
| 251 | struct thread *td = curthread; /* XXX */ |
| 252 | struct nameidata nd; |
| 253 | struct nameidata ndroot; |
| 254 | struct vattr vat; |
| 255 | struct vattr vatroot; |
| 256 | int error; |
| 257 | char *ptr, *buf, *cp; |
| 258 | size_t sz, len; |
| 259 | struct ucred *cred; |
| 260 | |
| 261 | KKASSERT(td->td_proc); |
| 262 | cred = td->td_proc->p_ucred; |
| 263 | |
| 264 | buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK); |
| 265 | *pbuf = path; |
| 266 | |
| 267 | for (ptr = buf; (*ptr = *prefix) != '\0'; ptr++, prefix++) |
| 268 | continue; |
| 269 | |
| 270 | sz = MAXPATHLEN - (ptr - buf); |
| 271 | |
| 272 | /* |
| 273 | * If sgp is not given then the path is already in kernel space |
| 274 | */ |
| 275 | if (sgp == NULL) |
| 276 | error = copystr(path, ptr, sz, &len); |
| 277 | else |
| 278 | error = copyinstr(path, ptr, sz, &len); |
| 279 | |
| 280 | if (error) { |
| 281 | free(buf, M_TEMP); |
| 282 | return error; |
| 283 | } |
| 284 | |
| 285 | if (*ptr != '/') { |
| 286 | free(buf, M_TEMP); |
| 287 | return EINVAL; |
| 288 | } |
| 289 | |
| 290 | /* |
| 291 | * We know that there is a / somewhere in this pathname. |
| 292 | * Search backwards for it, to find the file's parent dir |
| 293 | * to see if it exists in the alternate tree. If it does, |
| 294 | * and we want to create a file (cflag is set). We don't |
| 295 | * need to worry about the root comparison in this case. |
| 296 | */ |
| 297 | |
| 298 | if (cflag) { |
| 299 | for (cp = &ptr[len] - 1; *cp != '/'; cp--); |
| 300 | *cp = '\0'; |
| 301 | |
| 302 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td); |
| 303 | |
| 304 | if ((error = namei(&nd)) != 0) { |
| 305 | free(buf, M_TEMP); |
| 306 | return error; |
| 307 | } |
| 308 | NDFREE(&nd, NDF_ONLY_PNBUF); |
| 309 | |
| 310 | *cp = '/'; |
| 311 | } |
| 312 | else { |
| 313 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td); |
| 314 | |
| 315 | if ((error = namei(&nd)) != 0) { |
| 316 | free(buf, M_TEMP); |
| 317 | return error; |
| 318 | } |
| 319 | NDFREE(&nd, NDF_ONLY_PNBUF); |
| 320 | |
| 321 | /* |
| 322 | * We now compare the vnode of the svr4_root to the one |
| 323 | * vnode asked. If they resolve to be the same, then we |
| 324 | * ignore the match so that the real root gets used. |
| 325 | * This avoids the problem of traversing "../.." to find the |
| 326 | * root directory and never finding it, because "/" resolves |
| 327 | * to the emulation root directory. This is expensive :-( |
| 328 | */ |
| 329 | NDINIT(&ndroot, LOOKUP, FOLLOW, UIO_SYSSPACE, |
| 330 | svr4_emul_path, td); |
| 331 | |
| 332 | if ((error = namei(&ndroot)) != 0) { |
| 333 | /* Cannot happen! */ |
| 334 | free(buf, M_TEMP); |
| 335 | vrele(nd.ni_vp); |
| 336 | return error; |
| 337 | } |
| 338 | NDFREE(&ndroot, NDF_ONLY_PNBUF); |
| 339 | |
| 340 | if ((error = VOP_GETATTR(nd.ni_vp, &vat, cred, td)) != 0) { |
| 341 | goto done; |
| 342 | } |
| 343 | |
| 344 | if ((error = VOP_GETATTR(ndroot.ni_vp, &vatroot, cred, td)) |
| 345 | != 0) { |
| 346 | goto done; |
| 347 | } |
| 348 | |
| 349 | if (vat.va_fsid == vatroot.va_fsid && |
| 350 | vat.va_fileid == vatroot.va_fileid) { |
| 351 | error = ENOENT; |
| 352 | goto done; |
| 353 | } |
| 354 | |
| 355 | } |
| 356 | if (sgp == NULL) |
| 357 | *pbuf = buf; |
| 358 | else { |
| 359 | sz = &ptr[len] - buf; |
| 360 | *pbuf = stackgap_alloc(sgp, sz + 1); |
| 361 | error = copyout(buf, *pbuf, sz); |
| 362 | free(buf, M_TEMP); |
| 363 | } |
| 364 | |
| 365 | |
| 366 | done: |
| 367 | vrele(nd.ni_vp); |
| 368 | if (!cflag) |
| 369 | vrele(ndroot.ni_vp); |
| 370 | return error; |
| 371 | } |
| 372 | |
| 373 | static int |
| 374 | svr4_elf_modevent(module_t mod, int type, void *data) |
| 375 | { |
| 376 | int error; |
| 377 | |
| 378 | error = 0; |
| 379 | |
| 380 | switch(type) { |
| 381 | case MOD_LOAD: |
| 382 | if (elf_insert_brand_entry(&svr4_brand) < 0) |
| 383 | error = EINVAL; |
| 384 | if (error) |
| 385 | printf("cannot insert svr4 elf brand handler\n"); |
| 386 | else if (bootverbose) |
| 387 | printf("svr4 ELF exec handler installed\n"); |
| 388 | break; |
| 389 | case MOD_UNLOAD: |
| 390 | /* Only allow the emulator to be removed if it isn't in use. */ |
| 391 | if (elf_brand_inuse(&svr4_brand) != 0) { |
| 392 | error = EBUSY; |
| 393 | } else if (elf_remove_brand_entry(&svr4_brand) < 0) { |
| 394 | error = EINVAL; |
| 395 | } |
| 396 | |
| 397 | if (error) |
| 398 | printf("Could not deinstall ELF interpreter entry (error %d)\n", |
| 399 | error); |
| 400 | else if (bootverbose) |
| 401 | printf("svr4 ELF exec handler removed\n"); |
| 402 | break; |
| 403 | default: |
| 404 | break; |
| 405 | } |
| 406 | return error; |
| 407 | } |
| 408 | |
| 409 | static moduledata_t svr4_elf_mod = { |
| 410 | "svr4elf", |
| 411 | svr4_elf_modevent, |
| 412 | 0 |
| 413 | }; |
| 414 | DECLARE_MODULE(svr4elf, svr4_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); |