Index: lib/libsecureboot/h/libsecureboot.h =================================================================== --- lib/libsecureboot/h/libsecureboot.h +++ lib/libsecureboot/h/libsecureboot.h @@ -69,12 +69,6 @@ int ve_check_hash(br_hash_compat_context *, const br_hash_class *, const char *, const char *, size_t); -struct vectx; -struct vectx* vectx_open(int, const char *, off_t, struct stat *, int *); -ssize_t vectx_read(struct vectx *, void *, size_t); -off_t vectx_lseek(struct vectx *, off_t, int); -int vectx_close(struct vectx *); - char * hexdigest(char *, size_t, unsigned char *, size_t); int verify_fd(int, const char *, off_t, struct stat *); int verify_open(const char *, int); Index: lib/libsecureboot/h/verify_file.h =================================================================== --- lib/libsecureboot/h/verify_file.h +++ lib/libsecureboot/h/verify_file.h @@ -39,13 +39,21 @@ struct stat; -void ve_debug_set(int); -int ve_status_get(int); -void ve_efi_init(void); -int load_manifest(const char *, const char *, const char *, struct stat *); -int pass_manifest(const char *, const char *); -int pass_manifest_export_envs(void); -int verify_file(int, const char *, off_t, int); -void verify_pcr_export(void); +int verify_prep(int, const char *, off_t, struct stat *, const char *); +void ve_debug_set(int); +char *ve_error_get(void); +void ve_efi_init(void); +int ve_status_get(int); +int load_manifest(const char *, const char *, const char *, struct stat *); +int pass_manifest(const char *, const char *); +int pass_manifest_export_envs(void); +int verify_file(int, const char *, off_t, int, const char *); +void verify_pcr_export(void); + +struct vectx; +struct vectx* vectx_open(int, const char *, off_t, struct stat *, int *, const char *); +ssize_t vectx_read(struct vectx *, void *, size_t); +off_t vectx_lseek(struct vectx *, off_t, int); +int vectx_close(struct vectx *, int, const char *); #endif /* _VERIFY_FILE_H_ */ Index: lib/libsecureboot/tests/tvo.c =================================================================== --- lib/libsecureboot/tests/tvo.c +++ lib/libsecureboot/tests/tvo.c @@ -31,6 +31,8 @@ #include #include +size_t DestdirLen; +char *Destdir; char *Skip; int @@ -42,7 +44,10 @@ int Vflag; char *cp; char *prefix; + char *destdir; + Destdir = NULL; + DestdirLen = 0; prefix = NULL; Skip = NULL; @@ -50,8 +55,12 @@ printf("Trust %d\n", n); Vflag = 0; - while ((c = getopt(argc, argv, "dp:s:T:V")) != -1) { + while ((c = getopt(argc, argv, "D:dp:s:T:V")) != -1) { switch (c) { + case 'D': + Destdir = optarg; + DestdirLen = strlen(optarg); + break; case 'd': DebugVe++; break; @@ -92,7 +101,7 @@ */ int x; - x = verify_file(fd, argv[optind], 0, VE_GUESS); + x = verify_file(fd, argv[optind], 0, VE_GUESS, __func__); printf("verify_file(%s) = %d\n", argv[optind], x); close(fd); } @@ -155,7 +164,8 @@ } else { off = vectx_lseek(vp, (st.st_size % 1024), SEEK_SET); - + /* we can seek backwards! */ + off = vectx_lseek(vp, off/2, SEEK_SET); if (off < st.st_size) { n = vectx_read(vp, buf, sizeof(buf)); @@ -165,7 +175,7 @@ off = vectx_lseek(vp, 0, SEEK_END); /* repeating that should be harmless */ off = vectx_lseek(vp, 0, SEEK_END); - error = vectx_close(vp); + error = vectx_close(vp, VE_MUST, __func__); if (error) { printf("vectx_close(%s) == %d %s\n", argv[optind], error, Index: lib/libsecureboot/vectx.c =================================================================== --- lib/libsecureboot/vectx.c +++ lib/libsecureboot/vectx.c @@ -33,6 +33,7 @@ #endif #include "libsecureboot-priv.h" +#include /** * @file vectx.c @@ -50,12 +51,14 @@ const char *vec_path; /* path we are verifying */ const char *vec_want; /* hash value we want */ off_t vec_off; /* current offset */ + off_t vec_hashed; /* where we have hashed to */ size_t vec_size; /* size of path */ size_t vec_hashsz; /* size of hash */ int vec_fd; /* file descriptor */ int vec_status; /* verification status */ }; + /** * @brief * verify an open file as we read it @@ -86,24 +89,31 @@ * NULL is only returned for non-files or out-of-memory. */ struct vectx * -vectx_open(int fd, const char *path, off_t off, struct stat *stp, int *error) +vectx_open(int fd, const char *path, off_t off, struct stat *stp, + int *error, const char *caller) { struct vectx *ctx; struct stat st; size_t hashsz; char *cp; + int rc; - if (!stp) { - if (fstat(fd, &st) == 0) - stp = &st; - } + if (!stp) + stp = &st; - /* we *should* only get called for files */ - if (stp && !S_ISREG(stp->st_mode)) { - *error = 0; + rc = verify_prep(fd, path, off, stp, __func__); + + DEBUG_PRINTF(2, + ("vectx_open: caller=%s,name='%s',prep_rc=%d\n", + caller,path, rc)); + + switch (rc) { + case VE_FINGERPRINT_NONE: + case VE_FINGERPRINT_UNKNOWN: + case VE_FINGERPRINT_WRONG: + *error = rc; return (NULL); } - ctx = malloc(sizeof(struct vectx)); if (!ctx) goto enomem; @@ -111,10 +121,16 @@ ctx->vec_path = path; ctx->vec_size = stp->st_size; ctx->vec_off = 0; + ctx->vec_hashed = 0; ctx->vec_want = NULL; ctx->vec_status = 0; - hashsz = 0; + ctx->vec_hashsz = hashsz = 0; + if (rc == 0) { + /* we are not verifying this */ + *error = 0; + return (ctx); + } cp = fingerprint_info_lookup(fd, path); if (!cp) { ctx->vec_status = VE_FINGERPRINT_NONE; @@ -161,6 +177,10 @@ vectx_lseek(ctx, off, SEEK_SET); } } + DEBUG_PRINTF(2, + ("vectx_open: caller=%s,name='%s',hashsz=%lu,status=%d\n", + caller, path, (unsigned long)ctx->vec_hashsz, + ctx->vec_status)); return (ctx); enomem: /* unlikely */ @@ -175,6 +195,8 @@ * * It is critical that all file I/O comes through here. * We keep track of current offset. + * We also track what offset we have hashed to, + * so we won't replay data if we seek backwards. * * @param[in] pctx * pointer to ctx @@ -190,6 +212,8 @@ { unsigned char *bp = buf; int n; + int delta; + int x; size_t off; if (ctx->vec_hashsz == 0) /* nothing to do */ @@ -201,9 +225,20 @@ if (n < 0) return (n); if (n > 0) { - ctx->vec_md->update(&ctx->vec_ctx.vtable, &bp[off], n); - off += n; - ctx->vec_off += n; + /* we may have seeked backwards! */ + delta = ctx->vec_hashed - ctx->vec_off; + if (delta > 0) { + x = MIN(delta, n); + off += x; + n -= x; + ctx->vec_off += x; + } + if (n > 0) { + ctx->vec_md->update(&ctx->vec_ctx.vtable, &bp[off], n); + off += n; + ctx->vec_off += n; + ctx->vec_hashed += n; + } } } while (n > 0 && off < nbytes); return (off); @@ -213,10 +248,10 @@ * @brief * vectx equivalent of lseek * - * We do not actually, seek, but call vectx_read + * When seeking forwards we actually call vectx_read * to reach the desired offset. * - * We do not support seeking backwards. + * We support seeking backwards. * * @param[in] pctx * pointer to ctx @@ -225,6 +260,8 @@ * desired offset * * @param[in] whence + * We try to convert whence to ``SEEK_SET``. + * We do not support ``SEEK_DATA`` or ``SEEK_HOLE``. * * @return offset or error. */ @@ -239,22 +276,26 @@ return (lseek(ctx->vec_fd, off, whence)); /* - * Try to convert whence to SEEK_SET - * but we cannot support seeking backwards! - * Nor beyond end of file. + * Convert whence to SEEK_SET */ if (whence == SEEK_END && off <= 0) { whence = SEEK_SET; off += ctx->vec_size; - } else if (whence == SEEK_CUR && off >= 0) { + } else if (whence == SEEK_CUR) { whence = SEEK_SET; off += ctx->vec_off; } - if (whence != SEEK_SET || off < ctx->vec_off || + if (whence != SEEK_SET || (size_t)off > ctx->vec_size) { - printf("ERROR: %s: unsupported operation\n", __func__); + printf("ERROR: %s: unsupported operation: whence=%d off=%lld -> %lld\n", + __func__, whence, (long long)ctx->vec_off, (long long)off); return (-1); } + if (off < ctx->vec_hashed) { + /* seeking backwards! just do it */ + ctx->vec_off = lseek(ctx->vec_fd, off, whence); + return (ctx->vec_off); + } n = 0; do { delta = off - ctx->vec_off; @@ -281,7 +322,7 @@ * @return 0 or an error. */ int -vectx_close(struct vectx *ctx) +vectx_close(struct vectx *ctx, int severity, const char *caller) { int rc; @@ -291,6 +332,17 @@ rc = ve_check_hash(&ctx->vec_ctx, ctx->vec_md, ctx->vec_path, ctx->vec_want, ctx->vec_hashsz); } + DEBUG_PRINTF(2, + ("vectx_close: caller=%s,name='%s',rc=%d,severity=%d\n", + caller,ctx->vec_path, rc, severity)); + if (severity > VE_WANT || rc == VE_FINGERPRINT_WRONG) + printf("%serified %s\n", (rc <= 0) ? "Unv" : "V", + ctx->vec_path); +#if !defined(UNIT_TEST) && !defined(DEBUG_VECTX) + /* we are generally called with VE_MUST */ + if (severity > VE_WANT && rc == VE_FINGERPRINT_WRONG) + panic("cannot continue"); +#endif free(ctx); return ((rc < 0) ? rc : 0); } Index: lib/libsecureboot/verify_file.c =================================================================== --- lib/libsecureboot/verify_file.c +++ lib/libsecureboot/verify_file.c @@ -43,6 +43,8 @@ * define MANIFEST_SKIP to Skip - in tests/tvo.c so that * tvo can control the value we use in find_manifest() */ +extern char *Destdir; +extern size_t DestdirLen; extern char *Skip; # undef MANIFEST_SKIP # define MANIFEST_SKIP Skip @@ -167,12 +169,21 @@ ve_utc_set(stp->st_mtime); content = (char *)verify_signed(name, VEF_VERBOSE); if (content) { +#ifdef UNIT_TEST + if (DestdirLen > 0 && + strncmp(name, Destdir, DestdirLen) == 0) { + name += DestdirLen; + if (prefix && + strncmp(prefix, Destdir, DestdirLen) == 0) + prefix += DestdirLen; + } +#endif fingerprint_info_add(name, prefix, skip, content, stp); add_verify_status(stp, VE_VERIFIED); loaded_manifests = 1; /* we are verifying! */ DEBUG_PRINTF(3, ("loaded: %s %s %s\n", name, prefix, skip)); - rc = 0; + rc = VE_VERIFIED; } else { rc = VE_FINGERPRINT_WRONG; add_verify_status(stp, rc); /* remember */ @@ -245,13 +256,15 @@ return (VE_WANT); } +static int Verifying = -1; /* 0 if not verifying */ + static void verify_tweak(int fd, off_t off, struct stat *stp, char *tweak, int *accept_no_fp, - int *verbose, int *verifying) + int *verbose) { if (strcmp(tweak, "off") == 0) { - *verifying = 0; + Verifying = 0; } else if (strcmp(tweak, "strict") == 0) { /* anything caller wants verified must be */ *accept_no_fp = VE_WANT; @@ -314,6 +327,58 @@ return (int)val; } + +/** + * @brief prepare to verify an open file + * + * @param[in] fd + * open descriptor + * + * @param[in] filename + * path we opened and will use to lookup fingerprint + * + * @param[in] stp + * stat pointer so we can check file type + */ +int +verify_prep(int fd, const char *filename, off_t off, struct stat *stp, + const char *caller) +{ + int rc; + + if (Verifying < 0) { + Verifying = ve_trust_init(); +#ifndef UNIT_TEST + ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL)); +#endif + /* initialize ve_status with default result */ + rc = Verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING; + ve_status_set(0, rc); + ve_status_state = VE_STATUS_NONE; + if (Verifying) { + ve_self_tests(); + ve_anchor_verbose_set(1); + } + } + if (!Verifying || fd < 0) + return (0); + if (stp) { + if (fstat(fd, stp) < 0 || !S_ISREG(stp->st_mode)) + return (0); + } + DEBUG_PRINTF(2, + ("caller=%s,fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n", + caller, fd, filename, (long long)off, (long long)stp->st_dev, + (long long)stp->st_ino)); + rc = is_verified(stp); + if (rc == VE_NOT_CHECKED) { + rc = find_manifest(filename); + } else { + ve_status_set(fd, rc); + } + return (rc); +} + /** * @brief verify an open file * @@ -342,45 +407,26 @@ * @return >= 0 on success < 0 on failure */ int -verify_file(int fd, const char *filename, off_t off, int severity) +verify_file(int fd, const char *filename, off_t off, int severity, + const char *caller) { - static int verifying = -1; + static int once; static int accept_no_fp = ACCEPT_NO_FP_DEFAULT; static int verbose = VE_VERBOSE_DEFAULT; struct stat st; char *cp; int rc; - if (verifying < 0) { - verifying = ve_trust_init(); - verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT); - ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL)); - /* initialize ve_status with default result */ - rc = verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING; - ve_status_set(0, rc); - ve_status_state = VE_STATUS_NONE; - if (verifying) { - ve_self_tests(); - ve_anchor_verbose_set(1); - } - } - if (!verifying) - return (0); + rc = verify_prep(fd, filename, off, &st, caller); - if (fd < 0 || fstat(fd, &st) < 0 || !S_ISREG(st.st_mode)) + if (!rc) return (0); - DEBUG_PRINTF(3, ("fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n", - fd, filename, (long long)off, (long long)st.st_dev, - (long long)st.st_ino)); - - - rc = is_verified(&st); - if (rc != VE_NOT_CHECKED) { - ve_status_set(fd, rc); - return (rc); + if (!once) { + once++; + verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT); } - rc = find_manifest(filename); + if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) { if (severity <= VE_GUESS) severity = severity_guess(filename); @@ -392,6 +438,12 @@ */ ve_pcr_updating_set((severity == VE_MUST)); #endif +#ifdef UNIT_TEST + if (DestdirLen > 0 && + strncmp(filename, Destdir, DestdirLen) == 0) { + filename += DestdirLen; + } +#endif if ((rc = verify_fd(fd, filename, off, &st)) >= 0) { if (verbose || severity > VE_WANT) { #if defined(VE_DEBUG_LEVEL) && VE_DEBUG_LEVEL > 0 @@ -412,8 +464,7 @@ if (strncmp(cp, "loader.ve.", 10) == 0) { cp += 10; verify_tweak(fd, off, &st, cp, - &accept_no_fp, &verbose, - &verifying); + &accept_no_fp, &verbose); } } } Index: share/mk/src.opts.mk =================================================================== --- share/mk/src.opts.mk +++ share/mk/src.opts.mk @@ -225,6 +225,7 @@ CLANG_FULL/CLANG \ LOADER_VERIEXEC/BEARSSL \ LOADER_EFI_SECUREBOOT/LOADER_VERIEXEC \ + LOADER_VERIEXEC_VECTX/LOADER_VERIEXEC \ VERIEXEC/BEARSSL \ # MK_*_SUPPORT options which default to "yes" unless their corresponding Index: stand/common/bootstrap.h =================================================================== --- stand/common/bootstrap.h +++ stand/common/bootstrap.h @@ -44,6 +44,19 @@ #define CMD_CRIT 3 #define CMD_FATAL 4 +#ifdef LOADER_VERIEXEC +#include +#endif +#ifdef LOADER_VERIEXEC_VECTX +#define READIN_HANDLE_T struct vectx * +#define VECTX_READ vectx_read +#define VECTX_LSEEK vectx_lseek +#else +#define READIN_HANDLE_T int +#define VECTX_READ read +#define VECTX_LSEEK lseek +#endif + /* interp.c */ void interact(void); void interp_emit_prompt(void); @@ -70,8 +83,8 @@ size_t strlenout(vm_offset_t str); char *strdupout(vm_offset_t str); void kern_bzero(vm_offset_t dest, size_t len); -int kern_pread(int fd, vm_offset_t dest, size_t len, off_t off); -void *alloc_pread(int fd, off_t off, size_t len); +int kern_pread(READIN_HANDLE_T fd, vm_offset_t dest, size_t len, off_t off); +void *alloc_pread(READIN_HANDLE_T fd, off_t off, size_t len); /* bcache.c */ void bcache_init(size_t nblks, size_t bsize); @@ -303,7 +316,7 @@ ssize_t (*arch_copyout)(const vm_offset_t src, void *dest, const size_t len); /* Read from file to module address space, same semantics as read() */ - ssize_t (*arch_readin)(const int fd, vm_offset_t dest, + ssize_t (*arch_readin)(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len); /* Perform ISA byte port I/O (only for systems with ISA) */ int (*arch_isainb)(int port); @@ -349,8 +362,4 @@ #define CTASSERT(x) _Static_assert(x, "compile-time assertion failed") #endif -#ifdef LOADER_VERIEXEC -#include -#endif - #endif /* !_BOOTSTRAP_H_ */ Index: stand/common/interp_forth.c =================================================================== --- stand/common/interp_forth.c +++ stand/common/interp_forth.c @@ -284,7 +284,7 @@ /* try to load and run init file if present */ if ((fd = open("/boot/boot.4th", O_RDONLY)) != -1) { #ifdef LOADER_VERIEXEC - if (verify_file(fd, "/boot/boot.4th", 0, VE_GUESS) < 0) { + if (verify_file(fd, "/boot/boot.4th", 0, VE_GUESS, __func__) < 0) { close(fd); return; } @@ -386,7 +386,7 @@ } #ifdef LOADER_VERIEXEC - if (verify_file(fd, filename, 0, VE_GUESS) < 0) { + if (verify_file(fd, filename, 0, VE_GUESS, __func__) < 0) { close(fd); sprintf(command_errbuf,"can't verify '%s'", filename); return(CMD_ERROR); Index: stand/common/interp_simple.c =================================================================== --- stand/common/interp_simple.c +++ stand/common/interp_simple.c @@ -97,7 +97,7 @@ } #ifdef LOADER_VERIEXEC - if (verify_file(fd, filename, 0, VE_GUESS) < 0) { + if (verify_file(fd, filename, 0, VE_GUESS, __func__) < 0) { close(fd); sprintf(command_errbuf,"can't verify '%s'", filename); return(CMD_ERROR); Index: stand/common/load_elf.c =================================================================== --- stand/common/load_elf.c +++ stand/common/load_elf.c @@ -71,8 +71,17 @@ size_t firstlen; int kernel; uint64_t off; +#ifdef LOADER_VERIEXEC_VECTX + struct vectx *vctx; +#endif } *elf_file_t; +#ifdef LOADER_VERIEXEC_VECTX +#define VECTX_HANDLE(ef) (ef)->vctx +#else +#define VECTX_HANDLE(ef) (ef)->fd +#endif + static int __elfN(loadimage)(struct preloaded_file *mp, elf_file_t ef, uint64_t loadaddr); static int __elfN(lookup_symbol)(struct preloaded_file *mp, elf_file_t ef, @@ -214,7 +223,20 @@ close(ef->fd); return (ENOMEM); } - bytes_read = read(ef->fd, ef->firstpage, PAGE_SIZE); +#ifdef LOADER_VERIEXEC_VECTX + { + int verror; + + ef->vctx = vectx_open(ef->fd, filename, 0L, NULL, &verror, __func__); + if (verror) { + printf("Unverified %s: %s\n", filename, ve_error_get()); + close(ef->fd); + free(ef->vctx); + return (EAUTH); + } + } +#endif + bytes_read = VECTX_READ(VECTX_HANDLE(ef), ef->firstpage, PAGE_SIZE); ef->firstlen = (size_t)bytes_read; if (bytes_read < 0 || ef->firstlen <= sizeof(Elf_Ehdr)) { err = EFTYPE; /* could be EIO, but may be small file */ @@ -245,10 +267,10 @@ goto error; } -#ifdef LOADER_VERIEXEC - if (verify_file(ef->fd, filename, bytes_read, VE_MUST) < 0) { - err = EAUTH; - goto error; +#if defined(LOADER_VERIEXEC) && !defined(LOADER_VERIEXEC_VECTX) + if (verify_file(ef->fd, filename, bytes_read, VE_MUST, __func__) < 0) { + err = EAUTH; + goto error; } #endif return (0); @@ -259,6 +281,9 @@ ef->firstpage = NULL; } if (ef->fd != -1) { +#ifdef LOADER_VERIEXEC_VECTX + free(ef->vctx); +#endif close(ef->fd); ef->fd = -1; } @@ -415,8 +440,20 @@ out: if (ef.firstpage) free(ef.firstpage); - if (ef.fd != -1) + if (ef.fd != -1) { +#ifdef LOADER_VERIEXEC_VECTX + if (!err && ef.vctx) { + int verror; + + verror = vectx_close(ef.vctx, VE_MUST, __func__); + if (verror) { + err = EAUTH; + file_discard(fp); + } + } +#endif close(ef.fd); + } return (err); } @@ -562,7 +599,8 @@ phdr[i].p_vaddr + off, fpcopy); } if (phdr[i].p_filesz > fpcopy) { - if (kern_pread(ef->fd, phdr[i].p_vaddr + off + fpcopy, + if (kern_pread(VECTX_HANDLE(ef), + phdr[i].p_vaddr + off + fpcopy, phdr[i].p_filesz - fpcopy, phdr[i].p_offset + fpcopy) != 0) { printf("\nelf" __XSTRING(__ELF_WORD_SIZE) @@ -606,7 +644,7 @@ chunk = (size_t)ehdr->e_shnum * (size_t)ehdr->e_shentsize; if (chunk == 0 || ehdr->e_shoff == 0) goto nosyms; - shdr = alloc_pread(ef->fd, ehdr->e_shoff, chunk); + shdr = alloc_pread(VECTX_HANDLE(ef), ehdr->e_shoff, chunk); if (shdr == NULL) { printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: failed to read section headers"); @@ -625,8 +663,8 @@ */ chunk = shdr[ehdr->e_shstrndx].sh_size; if (chunk) { - shstr = alloc_pread(ef->fd, shdr[ehdr->e_shstrndx].sh_offset, - chunk); + shstr = alloc_pread(VECTX_HANDLE(ef), + shdr[ehdr->e_shstrndx].sh_offset, chunk); if (shstr) { for (i = 0; i < ehdr->e_shnum; i++) { if (strcmp(shstr + shdr[i].sh_name, @@ -716,14 +754,14 @@ printf("0x%lx+0x%lx", (long)sizeof(size), (long)size); #endif - if (lseek(ef->fd, (off_t)shdr[i].sh_offset, SEEK_SET) == -1) { + if (VECTX_LSEEK(VECTX_HANDLE(ef), (off_t)shdr[i].sh_offset, SEEK_SET) == -1) { printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not seek for symbols - skipped!"); lastaddr = ssym; ssym = 0; goto nosyms; } - result = archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size); + result = archsw.arch_readin(VECTX_HANDLE(ef), lastaddr, shdr[i].sh_size); if (result < 0 || (size_t)result != shdr[i].sh_size) { printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_loadimage: could not read symbols - skipped! " @@ -933,14 +971,14 @@ } size = (size_t)ef.ehdr->e_shnum * (size_t)ef.ehdr->e_shentsize; - shdr = alloc_pread(ef.fd, ef.ehdr->e_shoff, size); + shdr = alloc_pread(VECTX_HANDLE(&ef), ef.ehdr->e_shoff, size); if (shdr == NULL) { err = ENOMEM; goto out; } /* Load shstrtab. */ - shstrtab = alloc_pread(ef.fd, shdr[ef.ehdr->e_shstrndx].sh_offset, + shstrtab = alloc_pread(VECTX_HANDLE(&ef), shdr[ef.ehdr->e_shstrndx].sh_offset, shdr[ef.ehdr->e_shstrndx].sh_size); if (shstrtab == NULL) { printf("\nelf" __XSTRING(__ELF_WORD_SIZE) @@ -969,7 +1007,7 @@ } /* Load set_modmetadata_set into memory */ - err = kern_pread(ef.fd, dest, sh_meta->sh_size, sh_meta->sh_offset); + err = kern_pread(VECTX_HANDLE(&ef), dest, sh_meta->sh_size, sh_meta->sh_offset); if (err != 0) { printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "load_modmetadata: unable to load set_modmetadata_set: %d\n", err); @@ -980,7 +1018,7 @@ dest += sh_meta->sh_size; /* Load data sections into memory. */ - err = kern_pread(ef.fd, dest, sh_data[0]->sh_size, + err = kern_pread(VECTX_HANDLE(&ef), dest, sh_data[0]->sh_size, sh_data[0]->sh_offset); if (err != 0) { printf("\nelf" __XSTRING(__ELF_WORD_SIZE) @@ -995,7 +1033,7 @@ ef.off = -(sh_data[0]->sh_addr - dest); dest += (sh_data[1]->sh_addr - sh_data[0]->sh_addr); - err = kern_pread(ef.fd, dest, sh_data[1]->sh_size, + err = kern_pread(VECTX_HANDLE(&ef), dest, sh_data[1]->sh_size, sh_data[1]->sh_offset); if (err != 0) { printf("\nelf" __XSTRING(__ELF_WORD_SIZE) @@ -1017,8 +1055,20 @@ free(shdr); if (ef.firstpage != NULL) free(ef.firstpage); - if (ef.fd != -1) + if (ef.fd != -1) { +#ifdef LOADER_VERIEXEC_VECTX + if (!err && ef.vctx) { + int verror; + + verror = vectx_close(ef.vctx, VE_MUST, __func__); + if (verror) { + err = EAUTH; + file_discard(fp); + } + } +#endif close(ef.fd); + } return (err); } Index: stand/common/load_elf_obj.c =================================================================== --- stand/common/load_elf_obj.c +++ stand/common/load_elf_obj.c @@ -60,8 +60,17 @@ int fd; vm_offset_t off; +#ifdef LOADER_VERIEXEC_VECTX + struct vectx *vctx; +#endif } *elf_file_t; +#ifdef LOADER_VERIEXEC_VECTX +#define VECTX_HANDLE(ef) (ef)->vctx +#else +#define VECTX_HANDLE(ef) (ef)->fd +#endif + static int __elfN(obj_loadimage)(struct preloaded_file *mp, elf_file_t ef, uint64_t loadaddr); static int __elfN(obj_lookup_set)(struct preloaded_file *mp, elf_file_t ef, @@ -100,9 +109,22 @@ return(EFTYPE); if ((ef.fd = open(filename, O_RDONLY)) == -1) return(errno); +#ifdef LOADER_VERIEXEC_VECTX + { + int verror; + + ef.vctx = vectx_open(ef.fd, filename, 0L, NULL, &verror, __func__); + if (verror) { + printf("Unverified %s: %s\n", filename, ve_error_get()); + close(ef.fd); + free(ef.vctx); + return (EAUTH); + } + } +#endif hdr = &ef.hdr; - bytes_read = read(ef.fd, hdr, sizeof(*hdr)); + bytes_read = VECTX_READ(VECTX_HANDLE(&ef), hdr, sizeof(*hdr)); if (bytes_read != sizeof(*hdr)) { err = EFTYPE; /* could be EIO, but may be small file */ goto oerr; @@ -129,10 +151,10 @@ goto oerr; } -#ifdef LOADER_VERIEXEC - if (verify_file(ef.fd, filename, bytes_read, VE_MUST) < 0) { - err = EAUTH; - goto oerr; +#if defined(LOADER_VERIEXEC) && !defined(LOADER_VERIEXEC_VECTX) + if (verify_file(ef.fd, filename, bytes_read, VE_MUST, __func__) < 0) { + err = EAUTH; + goto oerr; } #endif @@ -181,6 +203,17 @@ oerr: file_discard(fp); out: +#ifdef LOADER_VERIEXEC_VECTX + if (!err && ef.vctx) { + int verror; + + verror = vectx_close(ef.vctx, VE_MUST, __func__); + if (verror) { + err = EAUTH; + file_discard(fp); + } + } +#endif close(ef.fd); if (ef.e_shdr != NULL) free(ef.e_shdr); @@ -207,7 +240,7 @@ /* Read in the section headers. */ shdrbytes = hdr->e_shnum * hdr->e_shentsize; - shdr = alloc_pread(ef->fd, (off_t)hdr->e_shoff, shdrbytes); + shdr = alloc_pread(VECTX_HANDLE(ef), (off_t)hdr->e_shoff, shdrbytes); if (shdr == NULL) { printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_obj_loadimage: read section headers failed\n"); @@ -328,7 +361,7 @@ if (cshdr == lshdr) break; - if (kern_pread(ef->fd, (vm_offset_t)cshdr->sh_addr, + if (kern_pread(VECTX_HANDLE(ef), (vm_offset_t)cshdr->sh_addr, cshdr->sh_size, (off_t)cshdr->sh_offset) != 0) { printf("\nelf" __XSTRING(__ELF_WORD_SIZE) "_obj_loadimage: read failed\n"); Index: stand/common/misc.c =================================================================== --- stand/common/misc.c +++ stand/common/misc.c @@ -116,10 +116,10 @@ * and it just returns 0 if successful. */ int -kern_pread(int fd, vm_offset_t dest, size_t len, off_t off) +kern_pread(READIN_HANDLE_T fd, vm_offset_t dest, size_t len, off_t off) { - if (lseek(fd, off, SEEK_SET) == -1) { + if (VECTX_LSEEK(fd, off, SEEK_SET) == -1) { #ifdef DEBUG printf("\nlseek failed\n"); #endif @@ -140,7 +140,7 @@ */ /* coverity[ -tainted_data_return ] */ void * -alloc_pread(int fd, off_t off, size_t len) +alloc_pread(READIN_HANDLE_T fd, off_t off, size_t len) { void *buf; @@ -152,14 +152,14 @@ errno = ENOMEM; return (NULL); } - if (lseek(fd, off, SEEK_SET) == -1) { + if (VECTX_LSEEK(fd, off, SEEK_SET) == -1) { #ifdef DEBUG printf("\nlseek failed\n"); #endif free(buf); return (NULL); } - if ((size_t)read(fd, buf, len) != len) { + if ((size_t)VECTX_READ(fd, buf, len) != len) { #ifdef DEBUG printf("\nread failed\n"); #endif Index: stand/common/module.c =================================================================== --- stand/common/module.c +++ stand/common/module.c @@ -616,6 +616,14 @@ return (error); } + +#ifdef LOADER_VERIEXEC_VECTX +#define VECTX_HANDLE(fd) vctx +#else +#define VECTX_HANDLE(fd) fd +#endif + + /* * We've been asked to load (fname) as (type), so just suck it in, * no arguments or anything. @@ -627,6 +635,10 @@ char *name; int fd, got; vm_offset_t laddr; +#ifdef LOADER_VERIEXEC_VECTX + struct vectx *vctx; + int verror; +#endif /* We can't load first */ if ((file_findfile(NULL, NULL)) == NULL) { @@ -649,14 +661,27 @@ return(NULL); } +#ifdef LOADER_VERIEXEC_VECTX + vctx = vectx_open(fd, name, 0L, NULL, &verror, __func__); + if (verror) { + sprintf(command_errbuf, "can't verify '%s': %s", + name, ve_error_get()); + free(name); + free(vctx); + close(fd); + return(NULL); + } +#else #ifdef LOADER_VERIEXEC - if (verify_file(fd, name, 0, VE_MUST) < 0) { - sprintf(command_errbuf, "can't verify '%s'", name); + if (verify_file(fd, name, 0, VE_MUST, __func__) < 0) { + sprintf(command_errbuf, "can't verify '%s': %s", + name, ve_error_get()); free(name); close(fd); return(NULL); } #endif +#endif if (archsw.arch_loadaddr != NULL) loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr); @@ -666,7 +691,7 @@ laddr = loadaddr; for (;;) { /* read in 4k chunks; size is not really important */ - got = archsw.arch_readin(fd, laddr, 4096); + got = archsw.arch_readin(VECTX_HANDLE(fd), laddr, 4096); if (got == 0) /* end of file */ break; if (got < 0) { /* error */ @@ -674,12 +699,24 @@ "error reading '%s': %s", name, strerror(errno)); free(name); close(fd); +#ifdef LOADER_VERIEXEC_VECTX + free(vctx); +#endif return(NULL); } laddr += got; } printf("size=%#jx\n", (uintmax_t)(laddr - loadaddr)); +#ifdef LOADER_VERIEXEC_VECTX + verror = vectx_close(vctx, VE_MUST, __func__); + if (verror) { + free(name); + close(fd); + free(vctx); + return(NULL); + } +#endif /* Looks OK so far; create & populate control structure */ fp = file_alloc(); Index: stand/efi/loader/arch/i386/i386_copy.c =================================================================== --- stand/efi/loader/arch/i386/i386_copy.c +++ stand/efi/loader/arch/i386/i386_copy.c @@ -51,9 +51,8 @@ return(len); } - ssize_t -i386_readin(const int fd, vm_offset_t dest, const size_t len) +i386_readin(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len) { - return (read(fd, PTOV(dest), len)); + return (VECTX_READ(fd, PTOV(dest), len)); } Index: stand/efi/loader/copy.c =================================================================== --- stand/efi/loader/copy.c +++ stand/efi/loader/copy.c @@ -341,14 +341,14 @@ ssize_t -efi_readin(const int fd, vm_offset_t dest, const size_t len) +efi_readin(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len) { if (!efi_check_space(dest + stage_offset + len)) { errno = ENOMEM; return (-1); } - return (read(fd, (void *)(dest + stage_offset), len)); + return (VECTX_READ(fd, (void *)(dest + stage_offset), len)); } void Index: stand/efi/loader/loader_efi.h =================================================================== --- stand/efi/loader/loader_efi.h +++ stand/efi/loader/loader_efi.h @@ -33,13 +33,24 @@ #include +#ifndef READIN_HANDLE_T +#ifdef LOADER_VERIEXEC_VECTX +#include +#define READIN_HANDLE_T struct vectx * +#define VECTX_READ vectx_read +#else +#define READIN_HANDLE_T int +#define VECTX_READ read +#endif +#endif + int efi_autoload(void); int efi_copy_init(void); ssize_t efi_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t efi_copyout(const vm_offset_t src, void *dest, const size_t len); -ssize_t efi_readin(const int fd, vm_offset_t dest, const size_t len); +ssize_t efi_readin(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len); void * efi_translate(vm_offset_t ptr); void efi_copy_finish(void); Index: stand/efi/loader/main.c =================================================================== --- stand/efi/loader/main.c +++ stand/efi/loader/main.c @@ -1460,7 +1460,7 @@ } #ifdef LOADER_VERIEXEC - if (verify_file(fd, name, 0, VE_MUST) < 0) { + if (verify_file(fd, name, 0, VE_MUST, __func__) < 0) { sprintf(command_errbuf, "can't verify: %s", name); close(fd); return (CMD_ERROR); Index: stand/ficl/loader.c =================================================================== --- stand/ficl/loader.c +++ stand/ficl/loader.c @@ -530,7 +530,7 @@ fd = open(name, mode); #ifdef LOADER_VERIEXEC if (fd >= 0) { - if (verify_file(fd, name, 0, VE_GUESS) < 0) { + if (verify_file(fd, name, 0, VE_GUESS, __func__) < 0) { /* not verified writing ok but reading is not */ if ((mode & O_ACCMODE) != O_WRONLY) { close(fd); Index: stand/i386/libi386/i386_copy.c =================================================================== --- stand/i386/libi386/i386_copy.c +++ stand/i386/libi386/i386_copy.c @@ -63,7 +63,7 @@ ssize_t -i386_readin(const int fd, vm_offset_t dest, const size_t len) +i386_readin(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len) { if (dest + len >= memtop_copyin) { @@ -71,5 +71,5 @@ return (-1); } - return (read(fd, PTOV(dest), len)); + return (VECTX_READ(fd, PTOV(dest), len)); } Index: stand/i386/libi386/libi386.h =================================================================== --- stand/i386/libi386/libi386.h +++ stand/i386/libi386/libi386.h @@ -89,6 +89,17 @@ #define MAXDEV 31 /* maximum number of distinct devices */ #define MAXBDDEV MAXDEV +#ifndef READIN_HANDLE_T +#ifdef LOADER_VERIEXEC_VECTX +#include +#define READIN_HANDLE_T struct vectx * +#define VECTX_READ vectx_read +#else +#define READIN_HANDLE_T int +#define VECTX_READ read +#endif +#endif + /* exported devices XXX rename? */ extern struct devsw bioscd; extern struct devsw biosfd; @@ -104,7 +115,7 @@ ssize_t i386_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t i386_copyout(const vm_offset_t src, void *dest, const size_t len); -ssize_t i386_readin(const int fd, vm_offset_t dest, const size_t len); +ssize_t i386_readin(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len); struct preloaded_file; void bios_addsmapdata(struct preloaded_file *); Index: stand/i386/loader/chain.c =================================================================== --- stand/i386/loader/chain.c +++ stand/i386/loader/chain.c @@ -43,6 +43,12 @@ #include "libi386/libi386.h" #include "btxv86.h" +#ifdef LOADER_VERIEXEC_VECTX +#define VECTX_HANDLE(x) vctx +#else +#define VECTX_HANDLE(x) x +#endif + /* * The MBR/VBR is located in first sector of disk/partition. * Read 512B to temporary location and set up relocation. Then @@ -59,6 +65,10 @@ struct stat st; vm_offset_t mem = 0x100000; struct i386_devdesc *rootdev; +#ifdef LOADER_VERIEXEC_VECTX + struct vectx *vctx; + int verror; +#endif if (argc == 1) { command_errmsg = "no device or file name specified"; @@ -75,6 +85,15 @@ return (CMD_ERROR); } +#ifdef LOADER_VERIEXEC_VECTX + vctx = vectx_open(fd, argv[1], 0L, NULL, &verror, __func__); + if (verror) { + sprintf(command_errbuf, "can't verify: %s", argv[1]); + close(fd); + free(vctx); + return (CMD_ERROR); + } +#else #ifdef LOADER_VERIEXEC if (verify_file(fd, argv[1], 0, VE_MUST) < 0) { sprintf(command_errbuf, "can't verify: %s", argv[1]); @@ -82,7 +101,7 @@ return (CMD_ERROR); } #endif - +#endif len = strlen(argv[1]); if (argv[1][len-1] != ':') { if (fstat(fd, &st) == -1) { @@ -104,13 +123,19 @@ return (CMD_ERROR); } - if (archsw.arch_readin(fd, mem, size) != size) { + if (archsw.arch_readin(VECTX_HANDLE(fd), mem, size) != size) { command_errmsg = "failed to read disk"; close(fd); return (CMD_ERROR); } close(fd); - +#ifdef LOADER_VERIEXEC_VECTX + verror = vectx_close(vctx, VE_MUST, __func__); + if (verror) { + free(vctx); + return (CMD_ERROR); + } +#endif if (argv[1][len-1] == ':' && *((uint16_t *)PTOV(mem + DOSMAGICOFFSET)) != DOSMAGIC) { command_errmsg = "wrong magic"; Index: stand/libofw/libofw.h =================================================================== --- stand/libofw/libofw.h +++ stand/libofw/libofw.h @@ -49,9 +49,20 @@ int ofwn_getunit(const char *); +#ifndef READIN_HANDLE_T +#ifdef LOADER_VERIEXEC_VECTX +#include +#define READIN_HANDLE_T struct vectx * +#define VECTX_READ vectx_read +#else +#define READIN_HANDLE_T int +#define VECTX_READ read +#endif +#endif + ssize_t ofw_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t ofw_copyout(const vm_offset_t src, void *dest, const size_t len); -ssize_t ofw_readin(const int fd, vm_offset_t dest, const size_t len); +ssize_t ofw_readin(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len); extern int ofw_boot(void); extern int ofw_autoload(void); Index: stand/libofw/ofw_copy.c =================================================================== --- stand/libofw/ofw_copy.c +++ stand/libofw/ofw_copy.c @@ -133,7 +133,7 @@ } ssize_t -ofw_readin(const int fd, vm_offset_t dest, const size_t len) +ofw_readin(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len) { void *buf; size_t resid, chunk, get; @@ -157,7 +157,7 @@ for (resid = len; resid > 0; resid -= got, p += got) { get = min(chunk, resid); - got = read(fd, buf, get); + got = VECTX_READ(fd, buf, get); if (got <= 0) { if (got < 0) Index: stand/loader.mk =================================================================== --- stand/loader.mk +++ stand/loader.mk @@ -74,6 +74,9 @@ .if ${MK_LOADER_VERIEXEC} != "no" CFLAGS+= -DLOADER_VERIEXEC -I${SRCTOP}/lib/libsecureboot/h .endif +.if ${MK_LOADER_VERIEXEC_VECTX} != "no" +CFLAGS+= -DLOADER_VERIEXEC_VECTX +.endif .if ${MK_LOADER_VERIEXEC_PASS_MANIFEST} != "no" CFLAGS+= -DLOADER_VERIEXEC_PASS_MANIFEST -I${SRCTOP}/lib/libsecureboot/h Index: stand/mips/beri/loader/arch.c =================================================================== --- stand/mips/beri/loader/arch.c +++ stand/mips/beri/loader/arch.c @@ -40,11 +40,21 @@ #include #include +#undef VECTX_READ +#ifdef LOADER_VERIEXEC_VECTX +#include +#define READIN_HANDLE_T struct vectx * +#define VECTX_READ vectx_read +#else +#define READIN_HANDLE_T int +#define VECTX_READ read +#endif + static int beri_arch_autoload(void); static ssize_t beri_arch_copyin(const void *src, vm_offset_t va, size_t len); static ssize_t beri_arch_copyout(vm_offset_t va, void *dst, size_t len); static uint64_t beri_arch_loadaddr(u_int type, void *data, uint64_t addr); -static ssize_t beri_arch_readin(int fd, vm_offset_t va, size_t len); +static ssize_t beri_arch_readin(READIN_HANDLE_T fd, vm_offset_t va, size_t len); struct arch_switch archsw = { .arch_autoload = beri_arch_autoload, @@ -90,8 +100,8 @@ } static ssize_t -beri_arch_readin(int fd, vm_offset_t va, size_t len) +beri_arch_readin(READIN_HANDLE_T fd, vm_offset_t va, size_t len) { - return (read(fd, (void *)va, len)); + return (VECTX_READ(fd, (void *)va, len)); } Index: stand/powerpc/kboot/main.c =================================================================== --- stand/powerpc/kboot/main.c +++ stand/powerpc/kboot/main.c @@ -35,6 +35,15 @@ #include "bootstrap.h" #include "host_syscall.h" +#undef VECTX_READ +#ifdef LOADER_VERIEXEC_VECTX +#include +#define READIN_HANDLE_T struct vectx * +#define VECTX_READ vectx_read +#else +#define READIN_HANDLE_T int +#define VECTX_READ read +#endif struct arch_switch archsw; extern void *_end; @@ -42,7 +51,7 @@ int kboot_getdev(void **vdev, const char *devspec, const char **path); ssize_t kboot_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t kboot_copyout(vm_offset_t src, void *dest, const size_t len); -ssize_t kboot_readin(const int fd, vm_offset_t dest, const size_t len); +ssize_t kboot_readin(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len); int kboot_autoload(void); uint64_t kboot_loadaddr(u_int type, void *data, uint64_t addr); int kboot_setcurrdev(struct env_var *ev, int flags, const void *value); @@ -410,7 +419,7 @@ } ssize_t -kboot_readin(const int fd, vm_offset_t dest, const size_t len) +kboot_readin(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len) { void *buf; size_t resid, chunk, get; @@ -428,7 +437,7 @@ for (resid = len; resid > 0; resid -= got, p += got) { get = min(chunk, resid); - got = read(fd, buf, get); + got = VECTX_READ(fd, buf, get); if (got <= 0) { if (got < 0) printf("kboot_readin: read failed\n"); Index: stand/uboot/lib/copy.c =================================================================== --- stand/uboot/lib/copy.c +++ stand/uboot/lib/copy.c @@ -160,7 +160,7 @@ } ssize_t -uboot_readin(const int fd, vm_offset_t dest, const size_t len) +uboot_readin(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len) { - return (read(fd, (void *)dest, len)); + return (VECTX_READ(fd, (void *)dest, len)); } Index: stand/uboot/lib/libuboot.h =================================================================== --- stand/uboot/lib/libuboot.h +++ stand/uboot/lib/libuboot.h @@ -48,6 +48,17 @@ #define PKTALIGN 32 #endif +#ifndef READIN_HANDLE_T +#ifdef LOADER_VERIEXEC_VECTX +#include +#define READIN_HANDLE_T struct vectx * +#define VECTX_READ vectx_read +#else +#define READIN_HANDLE_T int +#define VECTX_READ read +#endif +#endif + int uboot_getdev(void **vdev, const char *devspec, const char **path); char *uboot_fmtdev(void *vdev); int uboot_setcurrdev(struct env_var *ev, int flags, const void *value); @@ -62,7 +73,7 @@ uint64_t uboot_loadaddr(u_int type, void *data, uint64_t addr); ssize_t uboot_copyin(const void *src, vm_offset_t dest, const size_t len); ssize_t uboot_copyout(const vm_offset_t src, void *dest, const size_t len); -ssize_t uboot_readin(const int fd, vm_offset_t dest, const size_t len); +ssize_t uboot_readin(READIN_HANDLE_T fd, vm_offset_t dest, const size_t len); extern int uboot_autoload(void); struct preloaded_file; Index: stand/userboot/userboot/copy.c =================================================================== --- stand/userboot/userboot/copy.c +++ stand/userboot/userboot/copy.c @@ -48,7 +48,7 @@ } ssize_t -userboot_readin(int fd, vm_offset_t va, size_t len) +userboot_readin(READIN_HANDLE_T fd, vm_offset_t va, size_t len) { ssize_t res, s; size_t sz; @@ -59,7 +59,7 @@ sz = len; if (sz > sizeof(buf)) sz = sizeof(buf); - s = read(fd, buf, sz); + s = VECTX_READ(fd, buf, sz); if (s == 0) break; if (s < 0) Index: stand/userboot/userboot/libuserboot.h =================================================================== --- stand/userboot/userboot/libuserboot.h +++ stand/userboot/userboot/libuserboot.h @@ -51,10 +51,21 @@ extern void delay(int); +#ifndef READIN_HANDLE_T +#ifdef LOADER_VERIEXEC_VECTX +#include +#define READIN_HANDLE_T struct vectx * +#define VECTX_READ vectx_read +#else +#define READIN_HANDLE_T int +#define VECTX_READ read +#endif +#endif + extern int userboot_autoload(void); extern ssize_t userboot_copyin(const void *, vm_offset_t, size_t); extern ssize_t userboot_copyout(vm_offset_t, void *, size_t); -extern ssize_t userboot_readin(int, vm_offset_t, size_t); +extern ssize_t userboot_readin(READIN_HANDLE_T, vm_offset_t, size_t); extern int userboot_getdev(void **, const char *, const char **); char *userboot_fmtdev(void *vdev); int userboot_setcurrdev(struct env_var *ev, int flags, const void *value);