int lx_sendfile64(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) { sysret_t rval; off64_t off = 0; off64_t *offp = (off64_t *)p3; size_t sz = (size_t)p4; int error; struct sendfilevec64 sfv; size_t xferred; if (sz > 0 && uucopy(offp, &off, sizeof (off)) != 0) return (-errno); sfv.sfv_fd = p2; sfv.sfv_flag = 0; sfv.sfv_off = off; sfv.sfv_len = sz; error = __systemcall(&rval, SYS_sendfilev, SENDFILEV64, p1, &sfv, 1, &xferred); if (error == 0 && xferred > 0) { off += xferred; error = uucopy(&off, offp, sizeof (off)); } return (error ? -error : (int)rval.sys_rval1); }
/*ARGSUSED*/ long brand_unimpl(sysret_t *rv, uintptr_t p1) { sysret_t rval; /* * We'd like to print out some kind of error message here like * "unsupported syscall", but we can't because it's not safe to * assume that stderr or STDERR_FILENO actually points to something * that is a terminal, and if we wrote to those files we could * inadvertantly write to some applications open files, which would * be bad. * * Normally, if an application calls an invalid system call * it get a SIGSYS sent to it. So we'll just go ahead and send * ourselves a signal here. Note that this is far from ideal since * if the application has registered a signal handler, that signal * handler may recieve a ucontext_t as the third parameter to * indicate the context of the process when the signal was * generated, and in this case that context will not be what the * application is expecting. Hence, we should probably create a * brandsys() kernel function that can deliver the signal to us * with the correct ucontext_t. */ (void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGSYS); return (ENOSYS); }
/* * ATTENTION: uucopystr() does NOT ensure that string are null terminated! */ int brand_uucopystr(const void *from, void *to, size_t size) { sysret_t rval; if (__systemcall(&rval, SYS_uucopystr + 1024, from, to, size) != 0) return (EFAULT); return (0); }
ssize_t zone_getattr(zoneid_t zoneid, int attr, void *valp, size_t size) { sysret_t rval; int error; error = __systemcall(&rval, SYS_zone, ZONE_GETATTR, zoneid, attr, valp, size); if (error) (void) __set_errno(error); return ((ssize_t)rval.sys_rval1); }
size_t rctllist(char *list_buf, size_t list_bufsz) { sysret_t rval; int error; error = __systemcall(&rval, SYS_rctlsys, 2, NULL, list_buf, NULL, list_bufsz, 0); if (error) (void) __set_errno(error); return ((size_t)rval.sys_rval1); }
/*ARGSUSED*/ void _brand_abort(int err, const char *msg, const char *file, int line) { sysret_t rval; /* Save the error message into convenient globals */ brand_abort_err = err; brand_abort_msg = msg; brand_abort_file = file; brand_abort_line = line; /* kill ourselves */ abort(); /* If abort() didn't work, try something stronger. */ (void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGKILL); }
/*ARGSUSED*/ ulong_t brand_post_init(int version, int argc, char *argv[], char *envp[]) { sysret_t rval; brand_proc_reg_t reg; brand_elf_data_t sed; auxv_t *ap; uintptr_t *p; int err; /* * Register our syscall emulation table with the kernel. * Note that we don't have to do invoke (syscall_number + 1024) * until we've actually establised a syscall emulation callback * handler address, which is what we're doing with this brand * syscall. */ reg.sbr_version = version; #ifdef __x86 reg.sbr_handler = (caddr_t)brand_handler_table; #else /* !__x86 */ reg.sbr_handler = (caddr_t)brand_handler; #endif /* !__x86 */ if ((err = __systemcall(&rval, SYS_brand, B_REGISTER, ®)) != 0) { brand_abort(err, "Failed to brand current process"); /*NOTREACHED*/ } /* Get data about the executable we're running from the kernel. */ if ((err = __systemcall(&rval, SYS_brand + 1024, B_ELFDATA, (void *)&sed)) != 0) { brand_abort(err, "Failed to get required brand ELF data from the kernel"); /*NOTREACHED*/ } /* * Find the aux vector on the stack. */ p = (uintptr_t *)envp; while (*p != NULL) p++; /* * p is now pointing at the 0 word after the environ pointers. * After that is the aux vectors. * * The aux vectors are currently pointing to the brand emulation * library and associated linker. We're going to change them to * point to the brand executable and associated linker (or to no * linker for static binaries). This matches the process data * stored within the kernel and visible from /proc, which was * all setup in sn1_elfexec(). We do this so that when a debugger * attaches to the process it sees the process as a normal solaris * process, this brand emulation library and everything on it's * link map will not be visible, unless our librtld_db plugin * is used. Note that this is very different from how Linux * branded processes are implemented within lx branded zones. * In that situation, the primary linkmap of the process is the * brand emulation libraries linkmap, not the Linux applications * linkmap. * * We also need to clear the AF_SUN_NOPLM flag from the AT_SUN_AUXFLAGS * aux vector. This flag told our linker that we don't have a * primary link map. Now that our linker is done initializing, we * want to clear this flag before we transfer control to the * applications copy of the linker, since we want that linker to have * a primary link map which will be the link map for the application * we're running. */ p++; for (ap = (auxv_t *)p; ap->a_type != AT_NULL; ap++) { switch (ap->a_type) { case AT_BASE: /* Hide AT_BASE if static binary */ if (sed.sed_base == NULL) { ap->a_type = AT_IGNORE; ap->a_un.a_val = NULL; } else { ap->a_un.a_val = sed.sed_base; } break; case AT_ENTRY: ap->a_un.a_val = sed.sed_entry; break; case AT_PHDR: ap->a_un.a_val = sed.sed_phdr; break; case AT_PHENT: ap->a_un.a_val = sed.sed_phent; break; case AT_PHNUM: ap->a_un.a_val = sed.sed_phnum; break; case AT_SUN_AUXFLAGS: ap->a_un.a_val &= ~AF_SUN_NOPLM; break; case AT_SUN_EMULATOR: /* * ld.so.1 inspects AT_SUN_EMULATOR to see if * if it is the linker for the brand emulation * library. Hide AT_SUN_EMULATOR, as the * linker we are about to jump to is the linker * for the binary. */ ap->a_type = AT_IGNORE; ap->a_un.a_val = NULL; break; case AT_SUN_LDDATA: /* Hide AT_SUN_LDDATA if static binary */ if (sed.sed_lddata == NULL) { ap->a_type = AT_IGNORE; ap->a_un.a_val = NULL; } else { ap->a_un.a_val = sed.sed_lddata; } break; default: break; } } return (sed.sed_ldentry); }