futility: Rework file opening and mapping

Adding calls to cbfstool truncate command requires file to be closed and
not mapped to work correctly. This patch reworks file opening and
mapping to make it simpler. It also moves responsibility from main
command runner to command functions to correctly operate on their
input/output files.

BUG=b:197114807
TEST=sudo FEATURES=test emerge vboot_reference
TEST=build and boot while chromeos-bootimage and boot on volteer/voxel
     platform
BRANCH=none

Signed-off-by: Jakub Czapiga <jacz@semihalf.com>
Change-Id: Iee24fdc43f2a57f54c65f6e55cdd26adf44a0b29
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/3575324
Tested-by: Jakub Czapiga <czapiga@google.com>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Commit-Queue: Julius Werner <jwerner@chromium.org>
Auto-Submit: Jakub Czapiga <czapiga@google.com>
diff --git a/futility/cmd_gscvd.c b/futility/cmd_gscvd.c
index e8b2fae..d6187c9 100644
--- a/futility/cmd_gscvd.c
+++ b/futility/cmd_gscvd.c
@@ -143,35 +143,22 @@
 static int load_ap_firmware(const char *file_name, struct file_buf *file,
 			int mode)
 {
-	int fd;
-	int rv;
+	if (futil_open_and_map_file(file_name, &file->fd, mode, &file->data,
+				    &file->len))
+		return 1;
 
-	fd = open(file_name, mode);
-	if (fd < 0) {
-		ERROR("Can't open %s: %s\n", file_name,
-		      strerror(errno));
+	if (!fmap_find_by_name(file->data, file->len, NULL, "RO_GSCVD",
+			       &file->ro_gscvd)) {
+		ERROR("Could not find RO_GSCVD in the FMAP\n");
+		futil_unmap_and_close_file(file->fd, mode, file->data,
+					   file->len);
+		file->fd = -1;
+		file->data = NULL;
+		file->len = 0;
 		return 1;
 	}
 
-	file->fd = fd;
-	do {
-		rv = 1;
-
-		if (futil_map_file(fd, mode == O_RDWR ? MAP_RW : MAP_RO,
-				   &file->data, &file->len)) {
-			file->data = NULL;
-			break;
-		}
-
-		if (!fmap_find_by_name(file->data, file->len, NULL, "RO_GSCVD",
-				       &file->ro_gscvd)) {
-			ERROR("Could not find RO_GSCVD in the FMAP\n");
-			break;
-		}
-		rv = 0;
-	} while (false);
-
-	return rv;
+	return 0;
 }
 
 /**
@@ -809,7 +796,7 @@
 
 		rv = -1; /* Speculative, will be cleared on success. */
 
-		if (load_ap_firmware(file_name, &ap_firmware_file, O_RDONLY))
+		if (load_ap_firmware(file_name, &ap_firmware_file, FILE_RO))
 			break;
 
 		/* Copy ranges from gscvd to local structure. */
@@ -857,6 +844,11 @@
 		rv = 0;
 	} while (false);
 
+	if (ap_firmware_file.fd != -1)
+		futil_unmap_and_close_file(ap_firmware_file.fd, FILE_RO,
+					   ap_firmware_file.data,
+					   ap_firmware_file.len);
+
 	return rv;
 }
 
@@ -1014,7 +1006,7 @@
 		if (validate_privk(kblock, plat_privk))
 			break;
 
-		if (load_ap_firmware(work_file, &ap_firmware_file, O_RDWR))
+		if (load_ap_firmware(work_file, &ap_firmware_file, FILE_RW))
 			break;
 
 		if (verify_ranges(&ranges, &ap_firmware_file))
@@ -1038,15 +1030,10 @@
 	free(kblock);
 	vb2_private_key_free(plat_privk);
 
-	/* Now flush the file. */
-	if (ap_firmware_file.data) {
-		rv |= futil_unmap_file(ap_firmware_file.fd, true,
-				       ap_firmware_file.data,
-				       ap_firmware_file.len);
-	}
-
 	if (ap_firmware_file.fd != -1)
-		close(ap_firmware_file.fd);
+		futil_unmap_and_close_file(ap_firmware_file.fd, FILE_RW,
+					   ap_firmware_file.data,
+					   ap_firmware_file.len);
 
 	return rv;
 }
diff --git a/futility/cmd_load_fmap.c b/futility/cmd_load_fmap.c
index 818fda8..4ab194e 100644
--- a/futility/cmd_load_fmap.c
+++ b/futility/cmd_load_fmap.c
@@ -149,22 +149,16 @@
 	else
 		outfile = infile;
 
-	fd = open(outfile, O_RDWR);
-	if (fd < 0) {
-		fprintf(stderr, "Can't open %s: %s\n",
-			outfile, strerror(errno));
-		return 1;
-	}
+	errorcnt |= futil_open_and_map_file(outfile, &fd, FILE_RW, &buf, &len);
 
-	errorcnt |= futil_map_file(fd, MAP_RW, &buf, &len);
 	if (errorcnt)
-		goto done_file;
+		goto done;
 
 	fmap = fmap_find(buf, len);
 	if (!fmap) {
 		fprintf(stderr, "Can't find an FMAP in %s\n", infile);
 		errorcnt++;
-		goto done_map;
+		goto done;
 	}
 
 	for (i = optind; i < argc; i++) {
@@ -190,20 +184,10 @@
 		}
 	}
 
-done_map:
-	errorcnt |= futil_unmap_file(fd, 1, buf, len);
-
-done_file:
-
-	if (0 != close(fd)) {
-		fprintf(stderr, "Error closing %s: %s\n",
-			outfile, strerror(errno));
-		errorcnt++;
-	}
-
+done:
+	errorcnt |= futil_unmap_and_close_file(fd, FILE_RW, buf, len);
 	return !!errorcnt;
 }
 
 DECLARE_FUTIL_COMMAND(load_fmap, do_load_fmap, VBOOT_VERSION_ALL,
 		      "Replace the contents of specified FMAP areas");
-
diff --git a/futility/cmd_show.c b/futility/cmd_show.c
index 08974e4..9816106 100644
--- a/futility/cmd_show.c
+++ b/futility/cmd_show.c
@@ -86,31 +86,49 @@
 	       packed_key_sha1_string(data_key));
 }
 
-int ft_show_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
+int ft_show_pubkey(const char *name, void *data)
 {
-	struct vb2_packed_key *pubkey = (struct vb2_packed_key *)buf;
+	int fd = -1;
+	struct vb2_packed_key *pubkey;
+	uint32_t len;
+	int rv = 0;
+
+	if (futil_open_and_map_file(name, &fd, FILE_RO, (uint8_t **)&pubkey,
+				     &len))
+		return 1;
 
 	if (vb2_packed_key_looks_ok(pubkey, len)) {
 		printf("%s looks bogus\n", name);
-		return 1;
+		rv = 1;
+		goto done;
 	}
 
 	printf("Public Key file:       %s\n", name);
 	show_pubkey(pubkey, "  ");
 
-	return 0;
+done:
+	futil_unmap_and_close_file(fd, FILE_RO, (uint8_t *)pubkey, len);
+	return rv;
 }
 
-int ft_show_privkey(const char *name, uint8_t *buf, uint32_t len, void *data)
+int ft_show_privkey(const char *name, void *data)
 {
-	struct vb2_packed_private_key *pkey =
-		(struct vb2_packed_private_key *)buf;
+	int fd = -1;
+	int rv = 0;
+	struct vb2_packed_private_key *pkey = NULL;
+	uint32_t len;
 	struct vb2_private_key key;
-	const unsigned char *start = pkey->key_data;
+	const unsigned char *start;
 
+	if (futil_open_and_map_file(name, &fd, FILE_RO, (uint8_t **)&pkey,
+				     &len))
+		return 1;
+
+	start = pkey->key_data;
 	if (len <= sizeof(*pkey)) {
 		printf("%s looks bogus\n", name);
-		return 1;
+		rv = 1;
+		goto done;
 	}
 	len -= sizeof(*pkey);
 	key.rsa_private_key = d2i_RSAPrivateKey(NULL, &start, len);
@@ -122,20 +140,30 @@
 	printf("  Key sha1sum:         %s\n",
 	       private_key_sha1_string(&key));
 
-	return 0;
+done:
+	futil_unmap_and_close_file(fd, FILE_RO, (uint8_t *)pkey, len);
+	return rv;
 }
 
-int ft_show_keyblock(const char *name, uint8_t *buf, uint32_t len, void *data)
+int ft_show_keyblock(const char *name, void *data)
 {
-	struct vb2_keyblock *block = (struct vb2_keyblock *)buf;
+	struct vb2_keyblock *block;
 	struct vb2_public_key *sign_key = show_option.k;
 	int good_sig = 0;
 	int retval = 0;
+	int fd = -1;
+	uint32_t len;
+
+	retval = futil_open_and_map_file(name, &fd, FILE_RO, (uint8_t **)&block,
+					 &len);
+	if (retval)
+		return 1;
 
 	/* Check the hash only first */
 	if (0 != vb2_verify_keyblock_hash(block, len, &wb)) {
 		printf("%s is invalid\n", name);
-		return 1;
+		retval = 1;
+		goto done;
 	}
 
 	/* Check the signature if we have one */
@@ -148,11 +176,13 @@
 
 	show_keyblock(block, name, !!sign_key, good_sig);
 
+done:
+	futil_unmap_and_close_file(fd, FILE_RO, (uint8_t *)block, len);
 	return retval;
 }
 
-int ft_show_fw_preamble(const char *name, uint8_t *buf, uint32_t len,
-			void *data)
+int show_fw_preamble_buf(const char *name, uint8_t *buf, uint32_t len,
+			 void *data)
 {
 	struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf;
 	struct bios_state_s *state = (struct bios_state_s *)data;
@@ -282,17 +312,40 @@
 	return retval;
 }
 
-int ft_show_kernel_preamble(const char *name, uint8_t *buf, uint32_t len,
-			    void *data)
+int ft_show_fw_preamble(const char *name, void *data)
 {
-	struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf;
+	int rv = 0;
+	int fd = -1;
+	uint8_t *buf;
+	uint32_t len;
+
+	if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len))
+		return 1;
+
+	rv = show_fw_preamble_buf(name, buf, len, data);
+
+	futil_unmap_and_close_file(fd, FILE_RO, buf, len);
+	return rv;
+}
+
+int ft_show_kernel_preamble(const char *name, void *data)
+{
+	struct vb2_keyblock *keyblock;
 	struct vb2_public_key *sign_key = show_option.k;
-	int retval = 0;
+	int retval = 1;
+	int fd = -1;
+	uint8_t *buf;
+	uint32_t len;
+
+	if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len))
+		return 1;
+
+	keyblock = (struct vb2_keyblock *)buf;
 
 	/* Check the hash... */
 	if (VB2_SUCCESS != vb2_verify_keyblock_hash(keyblock, len, &wb)) {
 		printf("%s keyblock component is invalid\n", name);
-		return 1;
+		goto done;
 	}
 
 	/* If we have a key, check the signature too */
@@ -304,13 +357,10 @@
 	printf("Kernel partition:        %s\n", name);
 	show_keyblock(keyblock, NULL, !!sign_key, good_sig);
 
-	if (show_option.strict && (!sign_key || !good_sig))
-		retval = 1;
-
 	struct vb2_public_key data_key;
 	if (VB2_SUCCESS != vb2_unpack_key(&data_key, &keyblock->data_key)) {
 		fprintf(stderr, "Error parsing data key in %s\n", name);
-		return 1;
+		goto done;
 	}
 
 	uint32_t more = keyblock->keyblock_size;
@@ -320,7 +370,7 @@
 	if (VB2_SUCCESS != vb2_verify_kernel_preamble(pre2, len - more,
 						      &data_key, &wb)) {
 		printf("%s is invalid\n", name);
-		return 1;
+		goto done;
 	}
 
 	printf("Kernel Preamble:\n");
@@ -367,20 +417,24 @@
 	if (!kernel_blob) {
 		/* TODO: Is this always a failure? The preamble is okay. */
 		fprintf(stderr, "No kernel blob available to verify.\n");
-		return 1;
+		goto done;
 	}
 
 	if (VB2_SUCCESS !=
 	    vb2_verify_data(kernel_blob, kernel_size, &pre2->body_signature,
 			    &data_key, &wb)) {
 		fprintf(stderr, "Error verifying kernel body.\n");
-		return 1;
+		goto done;
 	}
 
 	printf("Body verification succeeded.\n");
 
 	printf("Config:\n%s\n", kernel_blob + kernel_cmd_line_offset(pre2));
 
+	if (!show_option.strict || (sign_key && good_sig))
+		retval = 0;
+done:
+	futil_unmap_and_close_file(fd, FILE_RO, buf, len);
 	return retval;
 }
 
@@ -476,9 +530,8 @@
 	uint8_t *pubkbuf = NULL;
 	struct vb2_public_key pubk2;
 	char *infile = 0;
-	int ifd, i;
+	int i;
 	int errorcnt = 0;
-	uint8_t *buf;
 	uint32_t len;
 	char *e = 0;
 	int type_override = 0;
@@ -585,34 +638,14 @@
 
 	for (i = optind; i < argc; i++) {
 		infile = argv[i];
-		ifd = open(infile, O_RDONLY);
-		if (ifd < 0) {
-			errorcnt++;
-			fprintf(stderr, "Can't open %s: %s\n",
-				infile, strerror(errno));
-			continue;
-		}
-
-		if (0 != futil_map_file(ifd, MAP_RO, &buf, &len)) {
-			errorcnt++;
-			goto boo;
-		}
 
 		/* Allow the user to override the type */
 		if (type_override)
 			type = show_option.type;
 		else
-			type = futil_file_type_buf(buf, len);
+			futil_file_type(infile, &type);
 
-		errorcnt += futil_file_type_show(type, infile, buf, len);
-
-		errorcnt += futil_unmap_file(ifd, MAP_RO, buf, len);
-boo:
-		if (close(ifd)) {
-			errorcnt++;
-			fprintf(stderr, "Error when closing %s: %s\n",
-				infile, strerror(errno));
-		}
+		errorcnt += futil_file_type_show(type, infile);
 	}
 
 done:
diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c
index a08238e..5999997 100644
--- a/futility/cmd_sign.c
+++ b/futility/cmd_sign.c
@@ -55,14 +55,21 @@
 }
 
 /* This wraps/signs a public key, producing a keyblock. */
-int ft_sign_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
+int ft_sign_pubkey(const char *name, void *data)
 {
-	struct vb2_packed_key *data_key = (struct vb2_packed_key *)buf;
+	struct vb2_packed_key *data_key;
+	uint32_t data_len;
 	struct vb2_keyblock *block;
+	int rv = 1;
+	int fd = -1;
 
-	if (vb2_packed_key_looks_ok(data_key, len)) {
-		fprintf(stderr, "Public key looks bad.\n");
+	if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option),
+				    (uint8_t **)&data_key, &data_len))
 		return 1;
+
+	if (vb2_packed_key_looks_ok(data_key, data_len)) {
+		fprintf(stderr, "Public key looks bad.\n");
+		goto done;
 	}
 
 	if (sign_option.pem_signpriv) {
@@ -82,7 +89,7 @@
 				fprintf(stderr,
 					"Unable to read PEM signing key: %s\n",
 					strerror(errno));
-				return 1;
+				goto done;
 			}
 			block = vb2_create_keyblock(data_key,
 						    sign_option.signprivate,
@@ -95,20 +102,24 @@
 	}
 
 	/* Write it out */
-	return WriteSomeParts(sign_option.outfile,
-			      block, block->keyblock_size,
-			      NULL, 0);
+	rv = WriteSomeParts(sign_option.outfile, block, block->keyblock_size,
+			    NULL, 0);
+done:
+	futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option),
+				   (uint8_t *)data_key, data_len);
+	return rv;
 }
 
-int ft_sign_raw_kernel(const char *name, uint8_t *buf, uint32_t len,
-		       void *data)
+int ft_sign_raw_kernel(const char *name, void *data)
 {
-	uint8_t *vmlinuz_data, *kblob_data, *vblock_data;
+	uint8_t *vmlinuz_data = NULL, *kblob_data = NULL, *vblock_data = NULL;
 	uint32_t vmlinuz_size, kblob_size, vblock_size;
-	int rv;
+	int rv = 1;
+	int fd = -1;
 
-	vmlinuz_data = buf;
-	vmlinuz_size = len;
+	if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option),
+				    &vmlinuz_data, &vmlinuz_size))
+		return 1;
 
 	kblob_data = CreateKernelBlob(
 		vmlinuz_data, vmlinuz_size,
@@ -118,7 +129,7 @@
 		&kblob_size);
 	if (!kblob_data) {
 		fprintf(stderr, "Unable to create kernel blob\n");
-		return 1;
+		goto done;
 	}
 	VB2_DEBUG("kblob_size = %#x\n", kblob_size);
 
@@ -131,8 +142,7 @@
 				     sign_option.flags, &vblock_size);
 	if (!vblock_data) {
 		fprintf(stderr, "Unable to sign kernel blob\n");
-		free(kblob_data);
-		return 1;
+		goto done;
 	}
 	VB2_DEBUG("vblock_size = %#x\n", vblock_size);
 
@@ -150,22 +160,26 @@
 				    vblock_data, vblock_size,
 				    kblob_data, kblob_size);
 
+done:
+	futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option),
+				   vmlinuz_data, vmlinuz_size);
 	free(vblock_data);
 	free(kblob_data);
 	return rv;
 }
 
-int ft_sign_kern_preamble(const char *name, uint8_t *buf, uint32_t len,
-			  void *data)
+int ft_sign_kern_preamble(const char *name, void *data)
 {
-	uint8_t *kpart_data, *kblob_data, *vblock_data;
+	uint8_t *kpart_data = NULL, *kblob_data = NULL, *vblock_data = NULL;
 	uint32_t kpart_size, kblob_size, vblock_size;
 	struct vb2_keyblock *keyblock = NULL;
 	struct vb2_kernel_preamble *preamble = NULL;
-	int rv = 0;
+	int rv = 1;
+	int fd = -1;
 
-	kpart_data = buf;
-	kpart_size = len;
+	if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option),
+				    &kpart_data, &kpart_size))
+		return 1;
 
 	/* Note: This just sets some static pointers. It doesn't malloc. */
 	kblob_data = unpack_kernel_partition(kpart_data, kpart_size,
@@ -174,7 +188,7 @@
 
 	if (!kblob_data) {
 		fprintf(stderr, "Unable to unpack kernel partition\n");
-		return 1;
+		goto done;
 	}
 
 	/*
@@ -192,7 +206,7 @@
 					sign_option.config_data,
 					sign_option.config_size)) {
 		fprintf(stderr, "Unable to update config\n");
-		return 1;
+		goto done;
 	}
 
 	/* Preserve the version unless a new one is given */
@@ -219,7 +233,7 @@
 				     &vblock_size);
 	if (!vblock_data) {
 		fprintf(stderr, "Unable to sign kernel blob\n");
-		return 1;
+		goto done;
 	}
 	VB2_DEBUG("vblock_size = %#x\n", vblock_size);
 
@@ -238,24 +252,33 @@
 		 * all our modifications to the buffer will get flushed to
 		 * disk when we close it. */
 		memcpy(kpart_data, vblock_data, vblock_size);
+		rv = 0;
 	}
-
+done:
+	futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), kpart_data,
+				   kpart_size);
 	free(vblock_data);
 	return rv;
 }
 
 
-int ft_sign_raw_firmware(const char *name, uint8_t *buf, uint32_t len,
-			 void *data)
+int ft_sign_raw_firmware(const char *name, void *data)
 {
-	struct vb2_signature *body_sig;
-	struct vb2_fw_preamble *preamble;
-	int rv;
+	struct vb2_signature *body_sig = NULL;
+	struct vb2_fw_preamble *preamble = NULL;
+	uint8_t *buf;
+	uint32_t len;
+	int rv = 1;
+	int fd = -1;
+
+	if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option),
+				    &buf, &len))
+		return 1;
 
 	body_sig = vb2_calculate_signature(buf, len, sign_option.signprivate);
 	if (!body_sig) {
 		fprintf(stderr, "Error calculating body signature\n");
-		return 1;
+		goto done;
 	}
 
 	preamble = vb2_create_fw_preamble(
@@ -267,7 +290,7 @@
 	if (!preamble) {
 		fprintf(stderr, "Error creating firmware preamble.\n");
 		free(body_sig);
-		return 1;
+		goto done;
 	}
 
 	rv = WriteSomeParts(sign_option.outfile,
@@ -275,6 +298,8 @@
 			    sign_option.keyblock->keyblock_size,
 			    preamble, preamble->preamble_size);
 
+done:
+	futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), buf, len);
 	free(preamble);
 	free(body_sig);
 
@@ -648,12 +673,8 @@
 {
 	char *infile = 0;
 	int i;
-	int ifd = -1;
 	int errorcnt = 0;
-	uint8_t *buf;
-	uint32_t buf_len;
 	char *e = 0;
-	int mapping;
 	int helpind = 0;
 	int longindex;
 
@@ -1009,56 +1030,18 @@
 	if (errorcnt)
 		goto done;
 
-	if (sign_option.create_new_outfile) {
-		/* The input is read-only, the output is write-only. */
-		mapping = MAP_RO;
-		VB2_DEBUG("open RO %s\n", infile);
-		ifd = open(infile, O_RDONLY);
-		if (ifd < 0) {
-			errorcnt++;
-			fprintf(stderr, "Can't open %s for reading: %s\n",
-				infile, strerror(errno));
-			goto done;
-		}
-	} else {
+	if (!sign_option.create_new_outfile) {
 		/* We'll read-modify-write the output file */
-		mapping = MAP_RW;
 		if (sign_option.inout_file_count > 1)
 			futil_copy_file_or_die(infile, sign_option.outfile);
-		VB2_DEBUG("open RW %s\n", sign_option.outfile);
 		infile = sign_option.outfile;
-		ifd = open(sign_option.outfile, O_RDWR);
-		if (ifd < 0) {
-			errorcnt++;
-			fprintf(stderr, "Can't open %s for writing: %s\n",
-				sign_option.outfile, strerror(errno));
-			goto done;
-		}
 	}
 
-	if (0 != futil_map_file(ifd, mapping, &buf, &buf_len)) {
-		errorcnt++;
-		goto done;
-	}
-
-	errorcnt += futil_file_type_sign(sign_option.type, infile,
-					 buf, buf_len);
-
-	errorcnt += futil_unmap_file(ifd, mapping, buf, buf_len);
-
+	errorcnt += futil_file_type_sign(sign_option.type, infile);
 done:
-	if (ifd >= 0 && close(ifd)) {
-		errorcnt++;
-		fprintf(stderr, "Error when closing ifd: %s\n",
-			strerror(errno));
-	}
-
-	if (sign_option.signprivate)
-		free(sign_option.signprivate);
-	if (sign_option.keyblock)
-		free(sign_option.keyblock);
-	if (sign_option.kernel_subkey)
-		free(sign_option.kernel_subkey);
+	free(sign_option.signprivate);
+	free(sign_option.keyblock);
+	free(sign_option.kernel_subkey);
 	if (sign_option.prikey)
 		vb2_private_key_free(sign_option.prikey);
 
diff --git a/futility/cmd_validate_rec_mrc.c b/futility/cmd_validate_rec_mrc.c
index 1d35bed..7ba5931 100644
--- a/futility/cmd_validate_rec_mrc.c
+++ b/futility/cmd_validate_rec_mrc.c
@@ -222,31 +222,21 @@
 
 	infile = argv[optind++];
 
-	fd = open(infile, O_RDONLY);
-	if (fd < 0) {
-		fprintf(stderr, "Cannot open %s:%s\n", infile, strerror(errno));
+	if (futil_open_and_map_file(infile, &fd, FILE_RO, &buff, &file_size) !=
+	    FILE_ERR_NONE)
 		return 1;
-	}
-
-	if (futil_map_file(fd, MAP_RO, &buff, &file_size) != FILE_ERR_NONE) {
-		fprintf(stderr, "Cannot map file %s\n", infile);
-		close(fd);
-		return 1;
-	}
 
 	if (offset > file_size) {
 		fprintf(stderr, "File size(%#x) smaller than offset(%#x)\n",
 			file_size, offset);
-		futil_unmap_file(fd, MAP_RO, buff, file_size);
-		close(fd);
+		futil_unmap_and_close_file(fd, FILE_RO, buff, file_size);
 		return 1;
 	}
 
 	if (get_mrc_data_slot((uint16_t *)(buff + offset), &data_offset,
 			      &data_size)) {
 		fprintf(stderr, "Metadata block error\n");
-		futil_unmap_file(fd, MAP_RO, buff, file_size);
-		close(fd);
+		futil_unmap_and_close_file(fd, FILE_RO, buff, file_size);
 		return 1;
 	}
 	offset += data_offset;
@@ -259,12 +249,10 @@
 			"offset=%#x, file size=%#x, data_size=%#x\n",
 			offset, file_size, data_size);
 
-	if (futil_unmap_file(fd, MAP_RO, buff, file_size) != FILE_ERR_NONE) {
-		fprintf(stderr, "Failed to unmap file %s\n", infile);
-		ret = 1;
-	}
+	if (futil_unmap_and_close_file(fd, FILE_RO, buff, file_size) !=
+	    FILE_ERR_NONE)
+		return 1;
 
-	close(fd);
 	return ret;
 }
 
diff --git a/futility/file_type.c b/futility/file_type.c
index b55d13f..29c4667 100644
--- a/futility/file_type.c
+++ b/futility/file_type.c
@@ -24,8 +24,8 @@
 	const char *desc;
 	/* Functions to identify, display, and sign this type of file. */
 	enum futil_file_type (*recognize)(uint8_t *buf, uint32_t len);
-	int (*show)(const char *name, uint8_t *buf, uint32_t len, void *data);
-	int (*sign)(const char *name, uint8_t *buf, uint32_t len, void *data);
+	int (*show)(const char *name, void *data);
+	int (*sign)(const char *name, void *data);
 };
 
 /* Populate a list of file types and operator functions. */
@@ -99,42 +99,29 @@
 enum futil_file_err futil_file_type(const char *filename,
 				    enum futil_file_type *type)
 {
-	int ifd;
-	uint8_t *buf;
-	uint32_t buf_len;
+	int ifd = -1;
+	uint8_t *buf = NULL;
+	uint32_t buf_len = 0;
 	struct stat sb;
 	enum futil_file_err err = FILE_ERR_NONE;
 
 	*type = FILE_TYPE_UNKNOWN;
 
-	ifd = open(filename, O_RDONLY);
-	if (ifd < 0) {
-		fprintf(stderr, "Can't open %s: %s\n",
-			filename, strerror(errno));
-		return FILE_ERR_OPEN;
-	}
+	err = futil_open_file(filename, &ifd, FILE_RO);
+	if (err != FILE_ERR_NONE)
+		goto done;
 
 	if (0 != fstat(ifd, &sb)) {
-		fprintf(stderr, "Can't stat input file: %s\n",
-			strerror(errno));
-		close(ifd);
-		return FILE_ERR_STAT;
+		fprintf(stderr, "Can't stat input file: %s\n", strerror(errno));
+		err = FILE_ERR_STAT;
+		goto done;
 	}
 
 	if (S_ISREG(sb.st_mode) || S_ISBLK(sb.st_mode)) {
-		err = futil_map_file(ifd, MAP_RO, &buf, &buf_len);
-		if (err) {
-			close(ifd);
-			return err;
-		}
-
+		err = futil_map_file(ifd, FILE_RO, &buf, &buf_len);
+		if (err)
+			goto done;
 		*type = futil_file_type_buf(buf, buf_len);
-
-		err = futil_unmap_file(ifd, MAP_RO, buf, buf_len);
-		if (err) {
-			close(ifd);
-			return err;
-		}
 	} else if (S_ISDIR(sb.st_mode)) {
 		err = FILE_ERR_DIR;
 	} else if (S_ISCHR(sb.st_mode)) {
@@ -144,37 +131,27 @@
 	} else if (S_ISSOCK(sb.st_mode)) {
 		err = FILE_ERR_SOCK;
 	}
-
-	if (close(ifd)) {
-		fprintf(stderr, "Error when closing %s: %s\n",
-			filename, strerror(errno));
-		return FILE_ERR_CLOSE;
-	}
-
+done:
+	futil_unmap_and_close_file(ifd, FILE_RO, buf, buf_len);
 	return err;
 }
 
-int futil_file_type_show(enum futil_file_type type,
-			 const char *filename,
-			 uint8_t *buf, uint32_t len)
+int futil_file_type_show(enum futil_file_type type, const char *filename)
 {
 	if (futil_file_types[type].show)
-		return futil_file_types[type].show(filename, buf, len, 0);
+		return futil_file_types[type].show(filename, 0);
 
 	fprintf(stderr, "Don't know how to show %s (type %s)\n",
 		filename, futil_file_type_name(type));
 	return 1;
 }
 
-int futil_file_type_sign(enum futil_file_type type,
-			 const char *filename,
-			 uint8_t *buf, uint32_t len)
+int futil_file_type_sign(enum futil_file_type type, const char *filename)
 {
 	if (futil_file_types[type].sign)
-		return futil_file_types[type].sign(filename, buf, len, 0);
+		return futil_file_types[type].sign(filename, 0);
 
 	fprintf(stderr, "Don't know how to sign %s (type %s)\n",
 		filename, futil_file_type_name(type));
 	return 1;
 }
-
diff --git a/futility/file_type.h b/futility/file_type.h
index e1efe76..5a074b3 100644
--- a/futility/file_type.h
+++ b/futility/file_type.h
@@ -40,22 +40,18 @@
 				    enum futil_file_type *type);
 
 /*
- * Call the show() method on a buffer containing a specific file type.
+ * Call the show() method on a file containing a specific file type.
  * Returns zero on success. It's up to the caller to ensure that only valid
  * file types are invoked.
  */
-int futil_file_type_show(enum futil_file_type type,
-			 const char *filename,
-			 uint8_t *buf, uint32_t len);
+int futil_file_type_show(enum futil_file_type type, const char *filename);
 
 /*
- * Call the sign() method on a buffer containing a specific file type.
+ * Call the sign() method on a file with specific file type.
  * Returns zero on success. It's up to the caller to ensure that only valid
  * file types are invoked.
  */
-int futil_file_type_sign(enum futil_file_type type,
-			 const char *filename,
-			 uint8_t *buf, uint32_t len);
+int futil_file_type_sign(enum futil_file_type type, const char *filename);
 
 /*
  * Declare the file_type functions. Certain functions are reused for more than
@@ -66,14 +62,21 @@
 #define R_(FOO) \
 	enum futil_file_type FOO(uint8_t *buf, uint32_t len);
 #define S_(FOO) \
-	int FOO(const char *name, uint8_t *buf, uint32_t len, void *data);
+	int FOO(const char *name, void *data);
 #define NONE
 #define FILE_TYPE(A, B, C, D, E, F) D E F
 #include "file_type.inc"
 #undef FILE_TYPE
 #undef NONE
+#undef SG_
 #undef S_
 #undef R_
 #pragma GCC diagnostic pop
 
+/* Declared for use inside other show functions. */
+int show_fw_preamble_buf(const char *name, uint8_t *buf, uint32_t len,
+			 void *data);
+int show_vb21_pubkey_buf(const char *name, uint8_t *buf, uint32_t len,
+			 void *data);
+
 #endif  /* VBOOT_REFERENCE_FILE_TYPE_H_ */
diff --git a/futility/file_type_bios.c b/futility/file_type_bios.c
index 6427201..17efdde 100644
--- a/futility/file_type_bios.c
+++ b/futility/file_type_bios.c
@@ -40,7 +40,8 @@
 
 /** Show functions **/
 
-int ft_show_gbb(const char *name, uint8_t *buf, uint32_t len, void *data)
+static int show_gbb_buf(const char *name, uint8_t *buf, uint32_t len,
+			void *data)
 {
 	struct vb2_gbb_header *gbb = (struct vb2_gbb_header *)buf;
 	struct bios_state_s *state = (struct bios_state_s *)data;
@@ -75,7 +76,7 @@
 
 	if (retval) {
 		printf("GBB header is invalid, ignoring content\n");
-		return 1;
+		return retval;
 	}
 
 	printf("GBB content:\n");
@@ -125,6 +126,23 @@
 	return retval;
 }
 
+int ft_show_gbb(const char *name, void *data)
+{
+	int retval = 0;
+	int fd = -1;
+	uint8_t *buf;
+	uint32_t len;
+
+	retval = futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len);
+	if (retval)
+		return 1;
+
+	retval = show_gbb_buf(name, buf, len, data);
+
+	futil_unmap_and_close_file(fd, FILE_RO, buf, len);
+	return retval;
+}
+
 /*
  * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image.
  *
@@ -155,16 +173,16 @@
 /* Functions to call to show the bios components */
 static int (*fmap_show_fn[])(const char *name, uint8_t *buf, uint32_t len,
 			       void *data) = {
-	ft_show_gbb,
+	show_gbb_buf,
 	fmap_show_fw_main,
 	fmap_show_fw_main,
-	ft_show_fw_preamble,
-	ft_show_fw_preamble,
+	show_fw_preamble_buf,
+	show_fw_preamble_buf,
 };
 _Static_assert(ARRAY_SIZE(fmap_show_fn) == NUM_BIOS_COMPONENTS,
 	       "Size of fmap_show_fn[] should match NUM_BIOS_COMPONENTS");
 
-int ft_show_bios(const char *name, uint8_t *buf, uint32_t len, void *data)
+int ft_show_bios(const char *name, void *data)
 {
 	FmapHeader *fmap;
 	FmapAreaHeader *ah = 0;
@@ -172,6 +190,13 @@
 	enum bios_component c;
 	int retval = 0;
 	struct bios_state_s state;
+	int fd = -1;
+	uint8_t *buf;
+	uint32_t len;
+
+	retval = futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len);
+	if (retval)
+		return 1;
 
 	memset(&state, 0, sizeof(state));
 
@@ -206,6 +231,7 @@
 		}
 	}
 
+	futil_unmap_and_close_file(fd, FILE_RO, buf, len);
 	return retval;
 }
 
@@ -428,7 +454,7 @@
 _Static_assert(ARRAY_SIZE(fmap_sign_fn) == NUM_BIOS_COMPONENTS,
 	       "Size of fmap_sign_fn[] should match NUM_BIOS_COMPONENTS");
 
-int ft_sign_bios(const char *name, uint8_t *buf, uint32_t len, void *data)
+int ft_sign_bios(const char *name, void *data)
 {
 	FmapHeader *fmap;
 	FmapAreaHeader *ah = 0;
@@ -436,6 +462,14 @@
 	enum bios_component c;
 	int retval = 0;
 	struct bios_state_s state;
+	int fd = -1;
+	uint8_t *buf = NULL;
+	uint32_t len = 0;
+
+	retval = futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option),
+					 &buf, &len);
+	if (retval)
+		return 1;
 
 	memset(&state, 0, sizeof(state));
 
@@ -469,6 +503,7 @@
 
 	retval += sign_bios_at_end(&state);
 
+	futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), buf, len);
 	return retval;
 }
 
diff --git a/futility/file_type_rwsig.c b/futility/file_type_rwsig.c
index a09782c..b595e25 100644
--- a/futility/file_type_rwsig.c
+++ b/futility/file_type_rwsig.c
@@ -58,7 +58,7 @@
 	       sig->data_size);
 }
 
-int ft_show_rwsig(const char *name, uint8_t *buf, uint32_t len, void *nuthin)
+int ft_show_rwsig(const char *name, void *nuthin)
 {
 	const struct vb21_signature *sig = 0;
 	const struct vb21_packed_key *pkey = show_option.pkey;
@@ -71,6 +71,15 @@
 	uint8_t *data;
 	FmapHeader *fmap;
 	int i;
+	int fd = -1;
+	uint8_t *buf;
+	uint32_t len;
+	int rv;
+
+	if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len))
+		return 1;
+
+	rv = 1;
 
 	VB2_DEBUG("name %s len 0x%08x (%d)\n", name, len, len);
 
@@ -81,7 +90,8 @@
 		show_sig(name, sig);
 		if (!show_option.fv) {
 			printf("No data available to verify\n");
-			return show_option.strict;
+			rv = show_option.strict;
+			goto done;
 		}
 		data = show_option.fv;
 		data_size = show_option.fv_size;
@@ -99,15 +109,15 @@
 				fmap_find_by_name(buf, len, fmap, "KEY_RO", 0);
 
 			if (pkey)
-				ft_show_vb21_pubkey(name, (uint8_t *)pkey,
-						pkey->c.total_size, NULL);
+				show_vb21_pubkey_buf(name, (uint8_t *)pkey,
+						     pkey->c.total_size, NULL);
 		}
 
 		sig = (const struct vb21_signature *)
 			fmap_find_by_name(buf, len, fmap, "SIG_RW", &fmaparea);
 		if (!sig) {
 			VB2_DEBUG("No SIG_RW in FMAP.\n");
-			return 1;
+			goto done;
 		}
 
 		sig_size = fmaparea->area_size;
@@ -116,7 +126,7 @@
 			  (uint8_t*)sig - buf, sig_size);
 
 		if (VB2_SUCCESS != vb21_verify_signature(sig, sig_size))
-			return 1;
+			goto done;
 
 		show_sig(name, sig);
 		data = fmap_find_by_name(buf, len, fmap, "EC_RW", &fmaparea);
@@ -129,7 +139,7 @@
 
 		if (!data) {
 			VB2_DEBUG("No EC_RW in FMAP.\n");
-			return 1;
+			goto done;
 		}
 	} else {
 		/* Or maybe this is just the RW portion, that does not
@@ -141,7 +151,7 @@
 
 		if (len < sig_size) {
 			VB2_DEBUG("File is too small\n");
-			return 1;
+			goto done;
 		}
 
 		sig = (const struct vb21_signature *)(buf + len - sig_size);
@@ -151,13 +161,14 @@
 			data_size = sig->data_size;
 			total_data_size = len - sig_size;
 		} else {
-			return 1;
+			goto done;
 		}
 	}
 
 	if (!pkey) {
 		printf("No public key available to verify with\n");
-		return show_option.strict;
+		rv = show_option.strict;
+		goto done;
 	}
 
 	/* We already did this once, so it should work again */
@@ -165,12 +176,12 @@
 			    (const uint8_t *)pkey,
 			    pkey->c.total_size)) {
 		VB2_DEBUG("Can't unpack pubkey\n");
-		return 1;
+		goto done;
 	}
 
 	if (data_size > total_data_size) {
 		VB2_DEBUG("Invalid signature data_size: bigger than total area size.\n");
-		return 1;
+		goto done;
 	}
 
 	/* The sig is destroyed by the verify operation, so make a copy */
@@ -185,7 +196,7 @@
 				     (const struct vb2_public_key *)&key,
 				     &wb)) {
 			fprintf(stderr, "Signature verification failed\n");
-			return 1;
+			goto done;
 		}
 	}
 
@@ -193,33 +204,46 @@
 	for (i = data_size; i < total_data_size; i++) {
 		if (data[i] != 0xff) {
 			fprintf(stderr, "Padding verification failed\n");
-			return 1;
+			goto done;
 		}
 	}
 
 	printf("Signature verification succeeded.\n");
-	return 0;
+	rv = 0;
+done:
+	futil_unmap_and_close_file(fd, FILE_RO, buf, len);
+	return rv;
 }
 
-int ft_sign_rwsig(const char *name, uint8_t *buf, uint32_t len, void *nuthin)
+int ft_sign_rwsig(const char *name, void *nuthin)
 {
 	struct vb21_signature *tmp_sig = 0;
 	struct vb2_public_key *pubkey = 0;
 	struct vb21_packed_key *packedkey = 0;
 	uint8_t *keyb_data = 0;
 	uint32_t keyb_size;
-	uint8_t* data = buf; /* data to be signed */
-	uint32_t r, data_size = len, sig_size = SIGNATURE_RSVD_SIZE;
+	uint8_t *data; /* data to be signed */
+	uint32_t r, data_size, sig_size = SIGNATURE_RSVD_SIZE;
 	int retval = 1;
 	FmapHeader *fmap = NULL;
 	FmapAreaHeader *fmaparea;
 	struct vb21_signature *old_sig = 0;
+	uint8_t *buf = NULL;
+	uint32_t len;
+	int fd = -1;
+
+	if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option),
+				    &buf, &len))
+		return 1;
+
+	data = buf;
+	data_size = len;
 
 	VB2_DEBUG("name %s len  0x%08x (%d)\n", name, len, len);
 
 	/* If we don't have a distinct OUTFILE, look for an existing sig */
 	if (sign_option.inout_file_count < 2) {
-		fmap = fmap_find(buf, len);
+		fmap = fmap_find(data, len);
 
 		if (fmap) {
 			/* This looks like a full image. */
@@ -395,14 +419,12 @@
 	/* Finally */
 	retval = 0;
 done:
-	if (tmp_sig)
-		free(tmp_sig);
+	futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), buf, len);
+	free(tmp_sig);
 	if (pubkey)
 		vb2_public_key_free(pubkey);
-	if (packedkey)
-		free(packedkey);
-	if (keyb_data)
-		free(keyb_data);
+	free(packedkey);
+	free(keyb_data);
 
 	return retval;
 }
diff --git a/futility/file_type_usbpd1.c b/futility/file_type_usbpd1.c
index 9379188..a128a99 100644
--- a/futility/file_type_usbpd1.c
+++ b/futility/file_type_usbpd1.c
@@ -78,7 +78,7 @@
 	return 1;
 }
 
-int ft_sign_usbpd1(const char *name, uint8_t *buf, uint32_t len, void *data)
+int ft_sign_usbpd1(const char *name, void *data)
 {
 	struct vb2_private_key *key_ptr = 0;
 	struct vb21_signature *sig_ptr = 0;
@@ -94,6 +94,13 @@
 	uint32_t ro_offset;
 	uint32_t rw_offset;
 	uint32_t r;
+	uint8_t *buf = NULL;
+	uint32_t len;
+	int fd = -1;
+
+	if (futil_open_and_map_file(name, &fd, FILE_MODE_SIGN(sign_option),
+					 &buf, &len))
+		return 1;
 
 	VB2_DEBUG("name %s len  %#.8x (%d)\n", name, len, len);
 
@@ -237,6 +244,7 @@
 	/* Finally */
 	retval = 0;
 done:
+	futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), buf, len);
 	if (key_ptr)
 		vb2_private_key_free(key_ptr);
 	if (keyb_data)
@@ -425,35 +433,47 @@
 }
 
 
-int ft_show_usbpd1(const char *name, uint8_t *buf, uint32_t len, void *data)
+int ft_show_usbpd1(const char *name, void *data)
 {
 	uint32_t ro_size, rw_size, ro_offset, rw_offset;
 	int s, h;
+	int fd = -1;
+	uint8_t *buf;
+	uint32_t len;
+	int rv = 1;
+
+	if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len))
+		return 1;
 
 	VB2_DEBUG("name %s len  0x%08x (%d)\n", name, len, len);
 
 	/* Get image locations */
 	if (!parse_size_opts(len, &ro_size, &rw_size, &ro_offset, &rw_offset))
-		return 1;
+		goto done;
 
 	/* TODO: If we don't have a RO image, ask for a public key
 	 * TODO: If we're given an external public key, use it (and its alg) */
 	if (!ro_size) {
 		printf("Can't find the public key\n");
-		return 1;
+		goto done;
 	}
 
 	/* TODO: Only loop through the numbers we haven't been given */
-	for (s = 0; s < ARRAY_SIZE(sigs); s++)
-		for (h = 0; h < ARRAY_SIZE(hashes); h++)
-			if (!check_self_consistency(buf, name,
-						    ro_size, rw_size,
+	for (s = 0; s < ARRAY_SIZE(sigs); s++) {
+		for (h = 0; h < ARRAY_SIZE(hashes); h++) {
+			if (!check_self_consistency(buf, name, ro_size, rw_size,
 						    ro_offset, rw_offset,
-						    sigs[s], hashes[h]))
-				return 0;
+						    sigs[s], hashes[h])) {
+				rv = 0;
+				goto done;
+			}
+		}
+	}
 
 	printf("This doesn't appear to be a complete usbpd1 image\n");
-	return 1;
+done:
+	futil_unmap_and_close_file(fd, FILE_RO, buf, len);
+	return rv;
 }
 
 enum futil_file_type ft_recognize_usbpd1(uint8_t *buf, uint32_t len)
diff --git a/futility/futility.h b/futility/futility.h
index 9d40ba7..fa4d3de 100644
--- a/futility/futility.h
+++ b/futility/futility.h
@@ -132,13 +132,26 @@
 	FILE_ERR_SOCK,
 };
 
+enum file_mode {
+	FILE_RO,
+	FILE_RW,
+};
+
+enum futil_file_err futil_open_file(const char *infile, int *fd,
+				    enum file_mode mode);
+enum futil_file_err futil_close_file(int fd);
+
 /* Wrapper for mmap/munmap. Skips stupidly large files. */
-#define MAP_RO 0
-#define MAP_RW 1
-enum futil_file_err futil_map_file(int fd, int writeable,
-				   uint8_t **buf, uint32_t *len);
-enum futil_file_err futil_unmap_file(int fd, int writeable,
-				     uint8_t *buf, uint32_t len);
+enum futil_file_err futil_map_file(int fd, enum file_mode mode, uint8_t **buf,
+				   uint32_t *len);
+enum futil_file_err futil_unmap_file(int fd, enum file_mode mode, uint8_t *buf,
+				     uint32_t len);
+
+enum futil_file_err futil_open_and_map_file(const char *infile, int *fd,
+					    enum file_mode mode, uint8_t **buf,
+					    uint32_t *len);
+enum futil_file_err futil_unmap_and_close_file(int fd, enum file_mode mode,
+					       uint8_t *buf, uint32_t len);
 
 /*
  * Parse input string as a hex representation of size len, exit with error if
diff --git a/futility/futility_options.h b/futility/futility_options.h
index a79505c..9c99bba 100644
--- a/futility/futility_options.h
+++ b/futility/futility_options.h
@@ -67,4 +67,7 @@
 };
 extern struct sign_option_s sign_option;
 
+#define FILE_MODE_SIGN(sign_options)                                           \
+	(sign_options.create_new_outfile ? FILE_RO : FILE_RW)
+
 #endif  /* VBOOT_REFERENCE_FUTILITY_OPTIONS_H_ */
diff --git a/futility/misc.c b/futility/misc.c
index 76b8ad1..4aec13a 100644
--- a/futility/misc.c
+++ b/futility/misc.c
@@ -5,6 +5,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <fcntl.h>
 #if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
 #include <linux/fs.h>		/* For BLKGETSIZE64 */
 #endif
@@ -258,8 +259,40 @@
 	exit(1);
 }
 
+enum futil_file_err futil_open_file(const char *infile, int *fd,
+				    enum file_mode mode)
+{
+	if (mode == FILE_RW) {
+		VB2_DEBUG("open RW %s\n", infile);
+		*fd = open(infile, O_RDWR);
+		if (*fd < 0) {
+			fprintf(stderr, "Can't open %s for writing: %s\n",
+				infile, strerror(errno));
+			return FILE_ERR_OPEN;
+		}
+	} else {
+		VB2_DEBUG("open RO %s\n", infile);
+		*fd = open(infile, O_RDONLY);
+		if (*fd < 0) {
+			fprintf(stderr, "Can't open %s for reading: %s\n",
+				infile, strerror(errno));
+			return FILE_ERR_OPEN;
+		}
+	}
+	return FILE_ERR_NONE;
+}
 
-enum futil_file_err futil_map_file(int fd, int writeable,
+enum futil_file_err futil_close_file(int fd)
+{
+	if (fd >= 0 && close(fd)) {
+		fprintf(stderr, "Error when closing ifd: %s\n",
+			strerror(errno));
+		return FILE_ERR_CLOSE;
+	}
+	return FILE_ERR_NONE;
+}
+
+enum futil_file_err futil_map_file(int fd, enum file_mode mode,
 				   uint8_t **buf, uint32_t *len)
 {
 	struct stat sb;
@@ -284,7 +317,7 @@
 	}
 	reasonable_len = (uint32_t)sb.st_size;
 
-	if (writeable)
+	if (mode == FILE_RW)
 		mmap_ptr = mmap(0, sb.st_size,
 				PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
 	else
@@ -293,7 +326,7 @@
 
 	if (mmap_ptr == (void *)-1) {
 		fprintf(stderr, "Can't mmap %s file: %s\n",
-			writeable ? "output" : "input",
+			mode == FILE_RW ? "output" : "input",
 			strerror(errno));
 		return FILE_ERR_MMAP;
 	}
@@ -303,14 +336,14 @@
 	return FILE_ERR_NONE;
 }
 
-enum futil_file_err futil_unmap_file(int fd, int writeable,
+enum futil_file_err futil_unmap_file(int fd, enum file_mode mode,
 				     uint8_t *buf, uint32_t len)
 {
 	void *mmap_ptr = buf;
 	enum futil_file_err err = FILE_ERR_NONE;
 
-	if (writeable &&
-	    (0 != msync(mmap_ptr, len, MS_SYNC|MS_INVALIDATE))) {
+	if (mode == FILE_RW &&
+	    (0 != msync(mmap_ptr, len, MS_SYNC | MS_INVALIDATE))) {
 		fprintf(stderr, "msync failed: %s\n", strerror(errno));
 		err = FILE_ERR_MSYNC;
 	}
@@ -325,6 +358,36 @@
 	return err;
 }
 
+enum futil_file_err futil_open_and_map_file(const char *infile, int *fd,
+					    enum file_mode mode, uint8_t **buf,
+					    uint32_t *len)
+{
+	enum futil_file_err rv = futil_open_file(infile, fd, mode);
+	if (rv != FILE_ERR_NONE)
+		return rv;
+
+	rv = futil_map_file(*fd, mode,  buf, len);
+	if (rv != FILE_ERR_NONE)
+		futil_close_file(*fd);
+
+	return rv;
+}
+
+enum futil_file_err futil_unmap_and_close_file(int fd, enum file_mode mode,
+					       uint8_t *buf, uint32_t len)
+{
+	enum futil_file_err rv = FILE_ERR_NONE;
+
+	if (buf)
+		rv = futil_unmap_file(fd, mode, buf, len);
+	if (rv != FILE_ERR_NONE)
+		return rv;
+
+	if (fd != -1)
+		return futil_close_file(fd);
+	else
+		return FILE_ERR_NONE;
+}
 
 #define DISK_SECTOR_SIZE 512
 enum futil_file_type ft_recognize_gpt(uint8_t *buf, uint32_t len)
diff --git a/futility/vb2_helper.c b/futility/vb2_helper.c
index 4d676a6..a8452db 100644
--- a/futility/vb2_helper.c
+++ b/futility/vb2_helper.c
@@ -60,7 +60,7 @@
 	return 1;
 }
 
-int ft_show_vb21_pubkey(const char *name, uint8_t *buf, uint32_t len,
+int show_vb21_pubkey_buf(const char *name, uint8_t *buf, uint32_t len,
 			void *data)
 {
 	struct vb2_public_key key;
@@ -91,6 +91,22 @@
 	return 0;
 }
 
+int ft_show_vb21_pubkey(const char *name, void *data)
+{
+	int fd = -1;
+	uint8_t *buf;
+	uint32_t len;
+	int rv;
+
+	if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len))
+		return 1;
+
+	rv = show_vb21_pubkey_buf(name, buf, len, data);
+
+	futil_unmap_and_close_file(fd, FILE_RO, buf, len);
+	return rv;
+}
+
 static int vb2_private_key_sha1sum(struct vb2_private_key *key, uint8_t *digest)
 {
 	uint8_t *buf;
@@ -106,15 +122,23 @@
 	return 1;
 }
 
-int ft_show_vb21_privkey(const char *name, uint8_t *buf, uint32_t len,
-			 void *data)
+int ft_show_vb21_privkey(const char *name, void *data)
 {
 	struct vb2_private_key *key = 0;
 	uint8_t sha1sum[VB2_SHA1_DIGEST_SIZE];
+	int fd = -1;
+	uint8_t *buf;
+	uint32_t len;
+	int rv = 0;
 
-	if (VB2_SUCCESS != vb21_private_key_unpack(&key, buf, len))
+	if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len))
 		return 1;
 
+	if (VB2_SUCCESS != vb21_private_key_unpack(&key, buf, len)) {
+		rv = 1;
+		goto done;
+	}
+
 	printf("Private key file:      %s\n", name);
 	printf("  Vboot API:           2.1\n");
 	printf("  Desc:                \"%s\"\n", key->desc ? key->desc : "");
@@ -132,7 +156,9 @@
 		printf("\n");
 	}
 	vb2_private_key_free(key);
-	return 0;
+done:
+	futil_unmap_and_close_file(fd, FILE_RO, buf, len);
+	return rv;
 }
 
 static RSA *rsa_from_buffer(uint8_t *buf, uint32_t len)
@@ -172,7 +198,7 @@
 	return FILE_TYPE_UNKNOWN;
 }
 
-int ft_show_pem(const char *name, uint8_t *buf, uint32_t len, void *data)
+int ft_show_pem(const char *name, void *data)
 {
 	RSA *rsa_key;
 	uint8_t *keyb;
@@ -180,6 +206,13 @@
 	uint32_t keyb_len;
 	int i, bits;
 	const BIGNUM *rsa_key_n, *rsa_key_d;
+	int fd = -1;
+	uint8_t *buf;
+	uint32_t len;
+	int rv = 0;
+
+	if (futil_open_and_map_file(name, &fd, FILE_RO, &buf, &len))
+		return 1;
 
 	/* We're called only after ft_recognize_pem, so this should work. */
 	rsa_key = rsa_from_buffer(buf, len);
@@ -197,7 +230,8 @@
 	if (vb_keyb_from_rsa(rsa_key, &keyb, &keyb_len)) {
 		printf("  Key sha1sum:         <error>");
 		RSA_free(rsa_key);
-		return 1;
+		rv = 1;
+		goto done;
 	}
 
 	printf("  Key sha1sum:         ");
@@ -209,5 +243,7 @@
 
 	free(keyb);
 	RSA_free(rsa_key);
-	return 0;
+done:
+	futil_unmap_and_close_file(fd, FILE_RO, buf, len);
+	return rv;
 }