xref: /freebsd/lib/libsecureboot/vectx.c (revision f616d61ab6b071e5fbfdbae7033a9ef04c1444ad)
15fff9558SSimon J. Gerraty /*-
25fff9558SSimon J. Gerraty  * Copyright (c) 2018, Juniper Networks, Inc.
35fff9558SSimon J. Gerraty  *
45fff9558SSimon J. Gerraty  * Redistribution and use in source and binary forms, with or without
55fff9558SSimon J. Gerraty  * modification, are permitted provided that the following conditions
65fff9558SSimon J. Gerraty  * are met:
75fff9558SSimon J. Gerraty  * 1. Redistributions of source code must retain the above copyright
85fff9558SSimon J. Gerraty  *    notice, this list of conditions and the following disclaimer.
95fff9558SSimon J. Gerraty  * 2. Redistributions in binary form must reproduce the above copyright
105fff9558SSimon J. Gerraty  *    notice, this list of conditions and the following disclaimer in the
115fff9558SSimon J. Gerraty  *    documentation and/or other materials provided with the distribution.
125fff9558SSimon J. Gerraty  *
135fff9558SSimon J. Gerraty  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
145fff9558SSimon J. Gerraty  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
155fff9558SSimon J. Gerraty  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
165fff9558SSimon J. Gerraty  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
175fff9558SSimon J. Gerraty  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
185fff9558SSimon J. Gerraty  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
195fff9558SSimon J. Gerraty  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
205fff9558SSimon J. Gerraty  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
215fff9558SSimon J. Gerraty  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
225fff9558SSimon J. Gerraty  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
235fff9558SSimon J. Gerraty  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
245fff9558SSimon J. Gerraty  */
255fff9558SSimon J. Gerraty #include <sys/cdefs.h>
265fff9558SSimon J. Gerraty #ifndef _STANDALONE
275fff9558SSimon J. Gerraty /* Avoid unwanted userlandish components */
285fff9558SSimon J. Gerraty #define _KERNEL
295fff9558SSimon J. Gerraty #include <sys/errno.h>
305fff9558SSimon J. Gerraty #undef _KERNEL
315fff9558SSimon J. Gerraty #endif
325fff9558SSimon J. Gerraty 
3366655411SSimon J. Gerraty #ifdef VECTX_DEBUG
3466655411SSimon J. Gerraty static int vectx_debug = VECTX_DEBUG;
3566655411SSimon J. Gerraty # define DEBUG_PRINTF(n, x) if (vectx_debug >= n) printf x
3666655411SSimon J. Gerraty #endif
3766655411SSimon J. Gerraty 
385fff9558SSimon J. Gerraty #include "libsecureboot-priv.h"
39afc571b1SSimon J. Gerraty #include <verify_file.h>
405fff9558SSimon J. Gerraty 
415fff9558SSimon J. Gerraty /**
425fff9558SSimon J. Gerraty  * @file vectx.c
435fff9558SSimon J. Gerraty  * @brief api to verify file while reading
445fff9558SSimon J. Gerraty  *
455fff9558SSimon J. Gerraty  * This API allows the hash of a file to be computed as it is read.
465fff9558SSimon J. Gerraty  * Key to this is seeking by reading.
475fff9558SSimon J. Gerraty  *
485fff9558SSimon J. Gerraty  * On close an indication of the verification result is returned.
495fff9558SSimon J. Gerraty  */
505fff9558SSimon J. Gerraty 
515fff9558SSimon J. Gerraty struct vectx {
525fff9558SSimon J. Gerraty 	br_hash_compat_context vec_ctx;	/* hash ctx */
535fff9558SSimon J. Gerraty 	const br_hash_class *vec_md;	/* hash method */
545fff9558SSimon J. Gerraty 	const char	*vec_path;	/* path we are verifying */
555fff9558SSimon J. Gerraty 	const char	*vec_want;	/* hash value we want */
565fff9558SSimon J. Gerraty 	off_t		vec_off;	/* current offset */
57afc571b1SSimon J. Gerraty 	off_t		vec_hashed;	/* where we have hashed to */
5866655411SSimon J. Gerraty 	off_t		vec_size;	/* size of path */
595fff9558SSimon J. Gerraty 	size_t		vec_hashsz;	/* size of hash */
605fff9558SSimon J. Gerraty 	int		vec_fd;		/* file descriptor */
615fff9558SSimon J. Gerraty 	int		vec_status;	/* verification status */
6266655411SSimon J. Gerraty 	int		vec_closing;	/* we are closing */
635fff9558SSimon J. Gerraty };
645fff9558SSimon J. Gerraty 
65afc571b1SSimon J. Gerraty 
665fff9558SSimon J. Gerraty /**
675fff9558SSimon J. Gerraty  * @brief
685fff9558SSimon J. Gerraty  * verify an open file as we read it
695fff9558SSimon J. Gerraty  *
705fff9558SSimon J. Gerraty  * If the file has no fingerprint to match, we will still return a
715fff9558SSimon J. Gerraty  * verification context containing little more than the file
725fff9558SSimon J. Gerraty  * descriptor, and an error code in @c error.
735fff9558SSimon J. Gerraty  *
745fff9558SSimon J. Gerraty  * @param[in] fd
755fff9558SSimon J. Gerraty  *	open descriptor
765fff9558SSimon J. Gerraty  *
775fff9558SSimon J. Gerraty  * @param[in] path
785fff9558SSimon J. Gerraty  *	pathname to open
795fff9558SSimon J. Gerraty  *
805fff9558SSimon J. Gerraty  * @param[in] off
815fff9558SSimon J. Gerraty  *	current offset
825fff9558SSimon J. Gerraty  *
835fff9558SSimon J. Gerraty  * @param[in] stp
845fff9558SSimon J. Gerraty  *	pointer to struct stat
855fff9558SSimon J. Gerraty  *
865fff9558SSimon J. Gerraty  * @param[out] error
875fff9558SSimon J. Gerraty  *	@li 0 all is good
885fff9558SSimon J. Gerraty  *	@li ENOMEM out of memory
895fff9558SSimon J. Gerraty  *	@li VE_FINGERPRINT_NONE	no entry found
905fff9558SSimon J. Gerraty  *	@li VE_FINGERPRINT_UNKNOWN no fingerprint in entry
915fff9558SSimon J. Gerraty  *
925fff9558SSimon J. Gerraty  * @return ctx or NULL on error.
935fff9558SSimon J. Gerraty  *	NULL is only returned for non-files or out-of-memory.
945fff9558SSimon J. Gerraty  */
955fff9558SSimon J. Gerraty struct vectx *
vectx_open(int fd,const char * path,off_t off,struct stat * stp,int * error,const char * caller)96afc571b1SSimon J. Gerraty vectx_open(int fd, const char *path, off_t off, struct stat *stp,
97afc571b1SSimon J. Gerraty     int *error, const char *caller)
985fff9558SSimon J. Gerraty {
995fff9558SSimon J. Gerraty 	struct vectx *ctx;
1005fff9558SSimon J. Gerraty 	struct stat st;
1015fff9558SSimon J. Gerraty 	size_t hashsz;
1025fff9558SSimon J. Gerraty 	char *cp;
103afc571b1SSimon J. Gerraty 	int rc;
1045fff9558SSimon J. Gerraty 
105afc571b1SSimon J. Gerraty 	if (!stp)
1065fff9558SSimon J. Gerraty 	    stp = &st;
1075fff9558SSimon J. Gerraty 
108afc571b1SSimon J. Gerraty 	rc = verify_prep(fd, path, off, stp, __func__);
109afc571b1SSimon J. Gerraty 
110afc571b1SSimon J. Gerraty 	DEBUG_PRINTF(2,
11153f151f9SSimon J. Gerraty 	    ("vectx_open: caller=%s,fd=%d,name='%s',prep_rc=%d\n",
11253f151f9SSimon J. Gerraty 		caller, fd, path, rc));
113afc571b1SSimon J. Gerraty 
114afc571b1SSimon J. Gerraty 	switch (rc) {
115afc571b1SSimon J. Gerraty 	case VE_FINGERPRINT_NONE:
116afc571b1SSimon J. Gerraty 	case VE_FINGERPRINT_UNKNOWN:
117afc571b1SSimon J. Gerraty 	case VE_FINGERPRINT_WRONG:
118afc571b1SSimon J. Gerraty 		*error = rc;
1195fff9558SSimon J. Gerraty 		return (NULL);
1205fff9558SSimon J. Gerraty 	}
1215fff9558SSimon J. Gerraty 	ctx = malloc(sizeof(struct vectx));
1225fff9558SSimon J. Gerraty 	if (!ctx)
1235fff9558SSimon J. Gerraty 		goto enomem;
1245fff9558SSimon J. Gerraty 	ctx->vec_fd = fd;
1255fff9558SSimon J. Gerraty 	ctx->vec_path = path;
1265fff9558SSimon J. Gerraty 	ctx->vec_size = stp->st_size;
1275fff9558SSimon J. Gerraty 	ctx->vec_off = 0;
128afc571b1SSimon J. Gerraty 	ctx->vec_hashed = 0;
1295fff9558SSimon J. Gerraty 	ctx->vec_want = NULL;
1305fff9558SSimon J. Gerraty 	ctx->vec_status = 0;
131afc571b1SSimon J. Gerraty 	ctx->vec_hashsz = hashsz = 0;
13266655411SSimon J. Gerraty 	ctx->vec_closing = 0;
1335fff9558SSimon J. Gerraty 
134afc571b1SSimon J. Gerraty 	if (rc == 0) {
135afc571b1SSimon J. Gerraty 		/* we are not verifying this */
136afc571b1SSimon J. Gerraty 		*error = 0;
137afc571b1SSimon J. Gerraty 		return (ctx);
138afc571b1SSimon J. Gerraty 	}
1395fff9558SSimon J. Gerraty 	cp = fingerprint_info_lookup(fd, path);
1405fff9558SSimon J. Gerraty 	if (!cp) {
1415fff9558SSimon J. Gerraty 		ctx->vec_status = VE_FINGERPRINT_NONE;
1425fff9558SSimon J. Gerraty 		ve_error_set("%s: no entry", path);
1435fff9558SSimon J. Gerraty 	} else {
14464ca9a7fSSimon J. Gerraty 		if (strncmp(cp, "no_hash", 7) == 0) {
14564ca9a7fSSimon J. Gerraty 			ctx->vec_status = VE_FINGERPRINT_IGNORE;
14664ca9a7fSSimon J. Gerraty 			hashsz = 0;
14764ca9a7fSSimon J. Gerraty 		} else if (strncmp(cp, "sha256=", 7) == 0) {
1485fff9558SSimon J. Gerraty 			ctx->vec_md = &br_sha256_vtable;
1495fff9558SSimon J. Gerraty 			hashsz = br_sha256_SIZE;
1505fff9558SSimon J. Gerraty 			cp += 7;
1515fff9558SSimon J. Gerraty #ifdef VE_SHA1_SUPPORT
1525fff9558SSimon J. Gerraty 		} else if (strncmp(cp, "sha1=", 5) == 0) {
1535fff9558SSimon J. Gerraty 			ctx->vec_md = &br_sha1_vtable;
1545fff9558SSimon J. Gerraty 			hashsz = br_sha1_SIZE;
1555fff9558SSimon J. Gerraty 			cp += 5;
1565fff9558SSimon J. Gerraty #endif
1575fff9558SSimon J. Gerraty #ifdef VE_SHA384_SUPPORT
1585fff9558SSimon J. Gerraty 		} else if (strncmp(cp, "sha384=", 7) == 0) {
1595fff9558SSimon J. Gerraty 		    ctx->vec_md = &br_sha384_vtable;
1605fff9558SSimon J. Gerraty 		    hashsz = br_sha384_SIZE;
1615fff9558SSimon J. Gerraty 		    cp += 7;
1625fff9558SSimon J. Gerraty #endif
1635fff9558SSimon J. Gerraty #ifdef VE_SHA512_SUPPORT
1645fff9558SSimon J. Gerraty 		} else if (strncmp(cp, "sha512=", 7) == 0) {
1655fff9558SSimon J. Gerraty 		    ctx->vec_md = &br_sha512_vtable;
1665fff9558SSimon J. Gerraty 		    hashsz = br_sha512_SIZE;
1675fff9558SSimon J. Gerraty 		    cp += 7;
1685fff9558SSimon J. Gerraty #endif
1695fff9558SSimon J. Gerraty 		} else {
1705fff9558SSimon J. Gerraty 			ctx->vec_status = VE_FINGERPRINT_UNKNOWN;
1715fff9558SSimon J. Gerraty 			ve_error_set("%s: no supported fingerprint", path);
1725fff9558SSimon J. Gerraty 		}
1735fff9558SSimon J. Gerraty 	}
1745fff9558SSimon J. Gerraty 	*error = ctx->vec_status;
1755fff9558SSimon J. Gerraty 	ctx->vec_hashsz = hashsz;
1765fff9558SSimon J. Gerraty 	ctx->vec_want = cp;
17764ca9a7fSSimon J. Gerraty 	if (hashsz > 0) {
1785fff9558SSimon J. Gerraty 		ctx->vec_md->init(&ctx->vec_ctx.vtable);
1795fff9558SSimon J. Gerraty 
18064ca9a7fSSimon J. Gerraty 		if (off > 0) {
1815fff9558SSimon J. Gerraty 			lseek(fd, 0, SEEK_SET);
1825fff9558SSimon J. Gerraty 			vectx_lseek(ctx, off, SEEK_SET);
1835fff9558SSimon J. Gerraty 		}
18464ca9a7fSSimon J. Gerraty 	}
185afc571b1SSimon J. Gerraty 	DEBUG_PRINTF(2,
186afc571b1SSimon J. Gerraty 	    ("vectx_open: caller=%s,name='%s',hashsz=%lu,status=%d\n",
187afc571b1SSimon J. Gerraty 		caller, path, (unsigned long)ctx->vec_hashsz,
188afc571b1SSimon J. Gerraty 		ctx->vec_status));
1895fff9558SSimon J. Gerraty 	return (ctx);
1905fff9558SSimon J. Gerraty 
1915fff9558SSimon J. Gerraty enomem:					/* unlikely */
1925fff9558SSimon J. Gerraty 	*error = ENOMEM;
1935fff9558SSimon J. Gerraty 	free(ctx);
1945fff9558SSimon J. Gerraty 	return (NULL);
1955fff9558SSimon J. Gerraty }
1965fff9558SSimon J. Gerraty 
1975fff9558SSimon J. Gerraty /**
1985fff9558SSimon J. Gerraty  * @brief
1995fff9558SSimon J. Gerraty  * read bytes from file and update hash
2005fff9558SSimon J. Gerraty  *
2015fff9558SSimon J. Gerraty  * It is critical that all file I/O comes through here.
2025fff9558SSimon J. Gerraty  * We keep track of current offset.
203afc571b1SSimon J. Gerraty  * We also track what offset we have hashed to,
204afc571b1SSimon J. Gerraty  * so we won't replay data if we seek backwards.
2055fff9558SSimon J. Gerraty  *
2065fff9558SSimon J. Gerraty  * @param[in] pctx
2075fff9558SSimon J. Gerraty  *	pointer to ctx
2085fff9558SSimon J. Gerraty  *
2095fff9558SSimon J. Gerraty  * @param[in] buf
2105fff9558SSimon J. Gerraty  *
2115fff9558SSimon J. Gerraty  * @param[in] nbytes
2125fff9558SSimon J. Gerraty  *
2135fff9558SSimon J. Gerraty  * @return bytes read or error.
2145fff9558SSimon J. Gerraty  */
2155fff9558SSimon J. Gerraty ssize_t
vectx_read(struct vectx * ctx,void * buf,size_t nbytes)2165fff9558SSimon J. Gerraty vectx_read(struct vectx *ctx, void *buf, size_t nbytes)
2175fff9558SSimon J. Gerraty {
2185fff9558SSimon J. Gerraty 	unsigned char *bp = buf;
219723f9041SSimon J. Gerraty 	int d;
2205fff9558SSimon J. Gerraty 	int n;
221afc571b1SSimon J. Gerraty 	int delta;
222afc571b1SSimon J. Gerraty 	int x;
2235fff9558SSimon J. Gerraty 	size_t off;
2245fff9558SSimon J. Gerraty 
2255fff9558SSimon J. Gerraty 	if (ctx->vec_hashsz == 0)	/* nothing to do */
2265fff9558SSimon J. Gerraty 		return (read(ctx->vec_fd, buf, nbytes));
2275fff9558SSimon J. Gerraty 
2285fff9558SSimon J. Gerraty 	off = 0;
2295fff9558SSimon J. Gerraty 	do {
230723f9041SSimon J. Gerraty 		/*
231723f9041SSimon J. Gerraty 		 * Do this in reasonable chunks so
232723f9041SSimon J. Gerraty 		 * we don't timeout if doing tftp
233723f9041SSimon J. Gerraty 		 */
234723f9041SSimon J. Gerraty 		x = nbytes - off;
235723f9041SSimon J. Gerraty 		x = MIN(PAGE_SIZE, x);
236723f9041SSimon J. Gerraty 		d = n = read(ctx->vec_fd, &bp[off], x);
23766655411SSimon J. Gerraty 		if (ctx->vec_closing && n < x) {
23866655411SSimon J. Gerraty 			DEBUG_PRINTF(3,
23966655411SSimon J. Gerraty 			    ("%s: read %d off=%ld hashed=%ld size=%ld\n",
24066655411SSimon J. Gerraty 			     __func__, n, (long)ctx->vec_off,
24166655411SSimon J. Gerraty 			     (long)ctx->vec_hashed, (long)ctx->vec_size));
24266655411SSimon J. Gerraty 		}
243723f9041SSimon J. Gerraty 		if (n < 0) {
2445fff9558SSimon J. Gerraty 			return (n);
245723f9041SSimon J. Gerraty 		}
246723f9041SSimon J. Gerraty 		if (d > 0) {
247afc571b1SSimon J. Gerraty 			/* we may have seeked backwards! */
248afc571b1SSimon J. Gerraty 			delta = ctx->vec_hashed - ctx->vec_off;
249afc571b1SSimon J. Gerraty 			if (delta > 0) {
250723f9041SSimon J. Gerraty 				x = MIN(delta, d);
251afc571b1SSimon J. Gerraty 				off += x;
252723f9041SSimon J. Gerraty 				d -= x;
253afc571b1SSimon J. Gerraty 				ctx->vec_off += x;
254afc571b1SSimon J. Gerraty 			}
255723f9041SSimon J. Gerraty 			if (d > 0) {
25666655411SSimon J. Gerraty 				if (ctx->vec_closing && d < PAGE_SIZE) {
25766655411SSimon J. Gerraty 					DEBUG_PRINTF(3,
25866655411SSimon J. Gerraty 					    ("%s: update %ld + %d\n",
25966655411SSimon J. Gerraty 						__func__,
26066655411SSimon J. Gerraty 						(long)ctx->vec_hashed, d));
26166655411SSimon J. Gerraty 				}
262723f9041SSimon J. Gerraty 				ctx->vec_md->update(&ctx->vec_ctx.vtable, &bp[off], d);
263723f9041SSimon J. Gerraty 				off += d;
264723f9041SSimon J. Gerraty 				ctx->vec_off += d;
265723f9041SSimon J. Gerraty 				ctx->vec_hashed += d;
266afc571b1SSimon J. Gerraty 			}
2675fff9558SSimon J. Gerraty 		}
2685fff9558SSimon J. Gerraty 	} while (n > 0 && off < nbytes);
2695fff9558SSimon J. Gerraty 	return (off);
2705fff9558SSimon J. Gerraty }
2715fff9558SSimon J. Gerraty 
2725fff9558SSimon J. Gerraty /**
2735fff9558SSimon J. Gerraty  * @brief
2745fff9558SSimon J. Gerraty  * vectx equivalent of lseek
2755fff9558SSimon J. Gerraty  *
276afc571b1SSimon J. Gerraty  * When seeking forwards we actually call vectx_read
2775fff9558SSimon J. Gerraty  * to reach the desired offset.
2785fff9558SSimon J. Gerraty  *
279afc571b1SSimon J. Gerraty  * We support seeking backwards.
2805fff9558SSimon J. Gerraty  *
2815fff9558SSimon J. Gerraty  * @param[in] pctx
2825fff9558SSimon J. Gerraty  *	pointer to ctx
2835fff9558SSimon J. Gerraty  *
2845fff9558SSimon J. Gerraty  * @param[in] off
2855fff9558SSimon J. Gerraty  *	desired offset
2865fff9558SSimon J. Gerraty  *
2875fff9558SSimon J. Gerraty  * @param[in] whence
288afc571b1SSimon J. Gerraty  * 	We try to convert whence to ``SEEK_SET``.
289afc571b1SSimon J. Gerraty  *	We do not support ``SEEK_DATA`` or ``SEEK_HOLE``.
2905fff9558SSimon J. Gerraty  *
2915fff9558SSimon J. Gerraty  * @return offset or error.
2925fff9558SSimon J. Gerraty  */
2935fff9558SSimon J. Gerraty off_t
vectx_lseek(struct vectx * ctx,off_t off,int whence)2945fff9558SSimon J. Gerraty vectx_lseek(struct vectx *ctx, off_t off, int whence)
2955fff9558SSimon J. Gerraty {
2965fff9558SSimon J. Gerraty 	unsigned char buf[PAGE_SIZE];
2975fff9558SSimon J. Gerraty 	size_t delta;
2985fff9558SSimon J. Gerraty 	ssize_t n;
2995fff9558SSimon J. Gerraty 
3005fff9558SSimon J. Gerraty 	if (ctx->vec_hashsz == 0)	/* nothing to do */
3015fff9558SSimon J. Gerraty 		return (lseek(ctx->vec_fd, off, whence));
3025fff9558SSimon J. Gerraty 
3035fff9558SSimon J. Gerraty 	/*
304afc571b1SSimon J. Gerraty 	 * Convert whence to SEEK_SET
3055fff9558SSimon J. Gerraty 	 */
30666655411SSimon J. Gerraty 	DEBUG_PRINTF(3,
30766655411SSimon J. Gerraty 	    ("%s(%s, %ld, %d)\n", __func__, ctx->vec_path, (long)off, whence));
3085fff9558SSimon J. Gerraty 	if (whence == SEEK_END && off <= 0) {
309*f616d61aSSimon J. Gerraty 		if (ctx->vec_size < 0) {
310*f616d61aSSimon J. Gerraty 			if (ctx->vec_closing) {
311*f616d61aSSimon J. Gerraty 				/* size unknown - read until EOF */
312*f616d61aSSimon J. Gerraty 				do {
313*f616d61aSSimon J. Gerraty 					n = vectx_read(ctx, buf, PAGE_SIZE);
314*f616d61aSSimon J. Gerraty 					if (n < 0)
315*f616d61aSSimon J. Gerraty 						return (n);
316*f616d61aSSimon J. Gerraty 				} while (n > 0);
317*f616d61aSSimon J. Gerraty 				return (ctx->vec_off);
318*f616d61aSSimon J. Gerraty 			}
319*f616d61aSSimon J. Gerraty 		} else {
32066655411SSimon J. Gerraty 			if (ctx->vec_closing && ctx->vec_hashed < ctx->vec_size) {
32166655411SSimon J. Gerraty 				DEBUG_PRINTF(3, ("%s: SEEK_END %ld\n",
32266655411SSimon J. Gerraty 					__func__,
32366655411SSimon J. Gerraty 					(long)(ctx->vec_size - ctx->vec_hashed)));
32466655411SSimon J. Gerraty 			}
3255fff9558SSimon J. Gerraty 			whence = SEEK_SET;
3265fff9558SSimon J. Gerraty 			off += ctx->vec_size;
327*f616d61aSSimon J. Gerraty 		}
328afc571b1SSimon J. Gerraty 	} else if (whence == SEEK_CUR) {
3295fff9558SSimon J. Gerraty 		whence = SEEK_SET;
3305fff9558SSimon J. Gerraty 		off += ctx->vec_off;
3315fff9558SSimon J. Gerraty 	}
332afc571b1SSimon J. Gerraty 	if (whence != SEEK_SET ||
333*f616d61aSSimon J. Gerraty 	    (off > ctx->vec_size && ctx->vec_size > 0)) {
33466655411SSimon J. Gerraty 		printf("ERROR: %s: unsupported operation: whence=%d off=%ld -> %ld\n",
33566655411SSimon J. Gerraty 		    __func__, whence, (long)ctx->vec_off, (long)off);
3365fff9558SSimon J. Gerraty 		return (-1);
3375fff9558SSimon J. Gerraty 	}
338afc571b1SSimon J. Gerraty 	if (off < ctx->vec_hashed) {
33966655411SSimon J. Gerraty #ifdef _STANDALONE
34066655411SSimon J. Gerraty 		struct open_file *f = fd2open_file(ctx->vec_fd);
34166655411SSimon J. Gerraty 
34266655411SSimon J. Gerraty 		if (f != NULL &&
34366655411SSimon J. Gerraty 		    strncmp(f->f_ops->fs_name, "tftp", 4) == 0) {
34466655411SSimon J. Gerraty 			/* we cannot rewind if we've hashed much of the file */
34566655411SSimon J. Gerraty 			if (ctx->vec_hashed > ctx->vec_size / 5)
34666655411SSimon J. Gerraty 				return (-1);	/* refuse! */
34766655411SSimon J. Gerraty 		}
34866655411SSimon J. Gerraty #endif
349afc571b1SSimon J. Gerraty 		/* seeking backwards! just do it */
350afc571b1SSimon J. Gerraty 		ctx->vec_off = lseek(ctx->vec_fd, off, whence);
351afc571b1SSimon J. Gerraty 		return (ctx->vec_off);
352afc571b1SSimon J. Gerraty 	}
3535fff9558SSimon J. Gerraty 	n = 0;
3545fff9558SSimon J. Gerraty 	do {
3555fff9558SSimon J. Gerraty 		delta = off - ctx->vec_off;
3565fff9558SSimon J. Gerraty 		if (delta > 0) {
3575fff9558SSimon J. Gerraty 			delta = MIN(PAGE_SIZE, delta);
3585fff9558SSimon J. Gerraty 			n = vectx_read(ctx, buf, delta);
3595fff9558SSimon J. Gerraty 			if (n < 0)
3605fff9558SSimon J. Gerraty 				return (n);
3615fff9558SSimon J. Gerraty 		}
3625fff9558SSimon J. Gerraty 	} while (ctx->vec_off < off && n > 0);
3635fff9558SSimon J. Gerraty 	return (ctx->vec_off);
3645fff9558SSimon J. Gerraty }
3655fff9558SSimon J. Gerraty 
3665fff9558SSimon J. Gerraty /**
3675fff9558SSimon J. Gerraty  * @brief
3685fff9558SSimon J. Gerraty  * check that hashes match and cleanup
3695fff9558SSimon J. Gerraty  *
3705fff9558SSimon J. Gerraty  * We have finished reading file, compare the hash with what
3715fff9558SSimon J. Gerraty  * we wanted.
3725fff9558SSimon J. Gerraty  *
37353f151f9SSimon J. Gerraty  * Be sure to call this before closing the file, since we may
37453f151f9SSimon J. Gerraty  * need to seek to the end to ensure hashing is complete.
37553f151f9SSimon J. Gerraty  *
3765fff9558SSimon J. Gerraty  * @param[in] pctx
3775fff9558SSimon J. Gerraty  *	pointer to ctx
3785fff9558SSimon J. Gerraty  *
3795fff9558SSimon J. Gerraty  * @return 0 or an error.
3805fff9558SSimon J. Gerraty  */
3815fff9558SSimon J. Gerraty int
vectx_close(struct vectx * ctx,int severity,const char * caller)382afc571b1SSimon J. Gerraty vectx_close(struct vectx *ctx, int severity, const char *caller)
3835fff9558SSimon J. Gerraty {
3845fff9558SSimon J. Gerraty 	int rc;
3855fff9558SSimon J. Gerraty 
38666655411SSimon J. Gerraty 	ctx->vec_closing = 1;
3875fff9558SSimon J. Gerraty 	if (ctx->vec_hashsz == 0) {
3885fff9558SSimon J. Gerraty 		rc = ctx->vec_status;
3895fff9558SSimon J. Gerraty 	} else {
390afc571b1SSimon J. Gerraty #ifdef VE_PCR_SUPPORT
391afc571b1SSimon J. Gerraty 		/*
392afc571b1SSimon J. Gerraty 		 * Only update pcr with things that must verify
393afc571b1SSimon J. Gerraty 		 * these tend to be processed in a more deterministic
394afc571b1SSimon J. Gerraty 		 * order, which makes our pseudo pcr more useful.
395afc571b1SSimon J. Gerraty 		 */
396afc571b1SSimon J. Gerraty 		ve_pcr_updating_set((severity == VE_MUST));
397afc571b1SSimon J. Gerraty #endif
39853f151f9SSimon J. Gerraty 		/* make sure we have hashed it all */
39953f151f9SSimon J. Gerraty 		vectx_lseek(ctx, 0, SEEK_END);
4005fff9558SSimon J. Gerraty 		rc = ve_check_hash(&ctx->vec_ctx, ctx->vec_md,
4015fff9558SSimon J. Gerraty 		    ctx->vec_path, ctx->vec_want, ctx->vec_hashsz);
4025fff9558SSimon J. Gerraty 	}
403afc571b1SSimon J. Gerraty 	DEBUG_PRINTF(2,
404afc571b1SSimon J. Gerraty 	    ("vectx_close: caller=%s,name='%s',rc=%d,severity=%d\n",
405afc571b1SSimon J. Gerraty 		caller,ctx->vec_path, rc, severity));
40666655411SSimon J. Gerraty 	verify_report(ctx->vec_path, severity, rc, NULL);
40753f151f9SSimon J. Gerraty 	if (rc == VE_FINGERPRINT_WRONG) {
408afc571b1SSimon J. Gerraty #if !defined(UNIT_TEST) && !defined(DEBUG_VECTX)
409afc571b1SSimon J. Gerraty 		/* we are generally called with VE_MUST */
41053f151f9SSimon J. Gerraty 		if (severity > VE_WANT)
411afc571b1SSimon J. Gerraty 			panic("cannot continue");
412afc571b1SSimon J. Gerraty #endif
41353f151f9SSimon J. Gerraty 	}
4145fff9558SSimon J. Gerraty 	free(ctx);
4155fff9558SSimon J. Gerraty 	return ((rc < 0) ? rc : 0);
4165fff9558SSimon J. Gerraty }
417