xref: /aosp_15_r20/external/fsverity-utils/programs/cmd_dump_metadata.c (revision b13c0e4024008a1f948ee8189745cb3371f4ac04)
1*b13c0e40SEric Biggers // SPDX-License-Identifier: MIT
2*b13c0e40SEric Biggers /*
3*b13c0e40SEric Biggers  * The 'fsverity dump_metadata' command
4*b13c0e40SEric Biggers  *
5*b13c0e40SEric Biggers  * Copyright 2021 Google LLC
6*b13c0e40SEric Biggers  *
7*b13c0e40SEric Biggers  * Use of this source code is governed by an MIT-style
8*b13c0e40SEric Biggers  * license that can be found in the LICENSE file or at
9*b13c0e40SEric Biggers  * https://opensource.org/licenses/MIT.
10*b13c0e40SEric Biggers  */
11*b13c0e40SEric Biggers 
12*b13c0e40SEric Biggers #include "fsverity.h"
13*b13c0e40SEric Biggers 
14*b13c0e40SEric Biggers #include <fcntl.h>
15*b13c0e40SEric Biggers #include <getopt.h>
16*b13c0e40SEric Biggers #include <sys/ioctl.h>
17*b13c0e40SEric Biggers #include <unistd.h>
18*b13c0e40SEric Biggers 
19*b13c0e40SEric Biggers static const struct option longopts[] = {
20*b13c0e40SEric Biggers 	{"offset",	required_argument, NULL, OPT_OFFSET},
21*b13c0e40SEric Biggers 	{"length",	required_argument, NULL, OPT_LENGTH},
22*b13c0e40SEric Biggers 	{NULL, 0, NULL, 0}
23*b13c0e40SEric Biggers };
24*b13c0e40SEric Biggers 
25*b13c0e40SEric Biggers static const struct {
26*b13c0e40SEric Biggers 	const char *name;
27*b13c0e40SEric Biggers 	int val;
28*b13c0e40SEric Biggers } metadata_types[] = {
29*b13c0e40SEric Biggers 	{"merkle_tree", FS_VERITY_METADATA_TYPE_MERKLE_TREE},
30*b13c0e40SEric Biggers 	{"descriptor", FS_VERITY_METADATA_TYPE_DESCRIPTOR},
31*b13c0e40SEric Biggers 	{"signature", FS_VERITY_METADATA_TYPE_SIGNATURE},
32*b13c0e40SEric Biggers };
33*b13c0e40SEric Biggers 
parse_metadata_type(const char * name,__u64 * val_ret)34*b13c0e40SEric Biggers static bool parse_metadata_type(const char *name, __u64 *val_ret)
35*b13c0e40SEric Biggers {
36*b13c0e40SEric Biggers 	size_t i;
37*b13c0e40SEric Biggers 
38*b13c0e40SEric Biggers 	for (i = 0; i < ARRAY_SIZE(metadata_types); i++) {
39*b13c0e40SEric Biggers 		if (strcmp(name, metadata_types[i].name) == 0) {
40*b13c0e40SEric Biggers 			*val_ret = metadata_types[i].val;
41*b13c0e40SEric Biggers 			return true;
42*b13c0e40SEric Biggers 		}
43*b13c0e40SEric Biggers 	}
44*b13c0e40SEric Biggers 	error_msg("unknown metadata type: %s", name);
45*b13c0e40SEric Biggers 	fputs("       Expected", stderr);
46*b13c0e40SEric Biggers 	for (i = 0; i < ARRAY_SIZE(metadata_types); i++) {
47*b13c0e40SEric Biggers 		if (i != 0 && ARRAY_SIZE(metadata_types) > 2)
48*b13c0e40SEric Biggers 			putc(',', stderr);
49*b13c0e40SEric Biggers 		putc(' ', stderr);
50*b13c0e40SEric Biggers 		if (i != 0 && i == ARRAY_SIZE(metadata_types) - 1)
51*b13c0e40SEric Biggers 			fputs("or ", stderr);
52*b13c0e40SEric Biggers 		fprintf(stderr, "\"%s\"", metadata_types[i].name);
53*b13c0e40SEric Biggers 	}
54*b13c0e40SEric Biggers 	fprintf(stderr, "\n");
55*b13c0e40SEric Biggers 	return false;
56*b13c0e40SEric Biggers }
57*b13c0e40SEric Biggers 
58*b13c0e40SEric Biggers /* Dump the fs-verity metadata of the given file. */
fsverity_cmd_dump_metadata(const struct fsverity_command * cmd,int argc,char * argv[])59*b13c0e40SEric Biggers int fsverity_cmd_dump_metadata(const struct fsverity_command *cmd,
60*b13c0e40SEric Biggers 			       int argc, char *argv[])
61*b13c0e40SEric Biggers {
62*b13c0e40SEric Biggers 	bool offset_specified = false;
63*b13c0e40SEric Biggers 	bool length_specified = false;
64*b13c0e40SEric Biggers 	struct filedes file = { .fd = -1 };
65*b13c0e40SEric Biggers 	struct filedes stdout_filedes = { .fd = STDOUT_FILENO,
66*b13c0e40SEric Biggers 					  .name = "stdout" };
67*b13c0e40SEric Biggers 	struct fsverity_read_metadata_arg arg = { .length = 32768 };
68*b13c0e40SEric Biggers 	void *buf = NULL;
69*b13c0e40SEric Biggers 	char *tmp;
70*b13c0e40SEric Biggers 	int c;
71*b13c0e40SEric Biggers 	int status;
72*b13c0e40SEric Biggers 	int bytes_read;
73*b13c0e40SEric Biggers 
74*b13c0e40SEric Biggers 	while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
75*b13c0e40SEric Biggers 		switch (c) {
76*b13c0e40SEric Biggers 		case OPT_OFFSET:
77*b13c0e40SEric Biggers 			if (offset_specified) {
78*b13c0e40SEric Biggers 				error_msg("--offset can only be specified once");
79*b13c0e40SEric Biggers 				goto out_usage;
80*b13c0e40SEric Biggers 			}
81*b13c0e40SEric Biggers 			errno = 0;
82*b13c0e40SEric Biggers 			arg.offset = strtoull(optarg, &tmp, 10);
83*b13c0e40SEric Biggers 			if (errno || *tmp) {
84*b13c0e40SEric Biggers 				error_msg("invalid value for --offset");
85*b13c0e40SEric Biggers 				goto out_usage;
86*b13c0e40SEric Biggers 			}
87*b13c0e40SEric Biggers 			offset_specified = true;
88*b13c0e40SEric Biggers 			break;
89*b13c0e40SEric Biggers 		case OPT_LENGTH:
90*b13c0e40SEric Biggers 			if (length_specified) {
91*b13c0e40SEric Biggers 				error_msg("--length can only be specified once");
92*b13c0e40SEric Biggers 				goto out_usage;
93*b13c0e40SEric Biggers 			}
94*b13c0e40SEric Biggers 			errno = 0;
95*b13c0e40SEric Biggers 			arg.length = strtoull(optarg, &tmp, 10);
96*b13c0e40SEric Biggers 			if (errno || *tmp || arg.length > SIZE_MAX) {
97*b13c0e40SEric Biggers 				error_msg("invalid value for --length");
98*b13c0e40SEric Biggers 				goto out_usage;
99*b13c0e40SEric Biggers 			}
100*b13c0e40SEric Biggers 			length_specified = true;
101*b13c0e40SEric Biggers 			break;
102*b13c0e40SEric Biggers 		default:
103*b13c0e40SEric Biggers 			goto out_usage;
104*b13c0e40SEric Biggers 		}
105*b13c0e40SEric Biggers 	}
106*b13c0e40SEric Biggers 
107*b13c0e40SEric Biggers 	argv += optind;
108*b13c0e40SEric Biggers 	argc -= optind;
109*b13c0e40SEric Biggers 
110*b13c0e40SEric Biggers 	if (argc != 2)
111*b13c0e40SEric Biggers 		goto out_usage;
112*b13c0e40SEric Biggers 
113*b13c0e40SEric Biggers 	if (!parse_metadata_type(argv[0], &arg.metadata_type))
114*b13c0e40SEric Biggers 		goto out_usage;
115*b13c0e40SEric Biggers 
116*b13c0e40SEric Biggers 	if (length_specified && !offset_specified) {
117*b13c0e40SEric Biggers 		error_msg("--length specified without --offset");
118*b13c0e40SEric Biggers 		goto out_usage;
119*b13c0e40SEric Biggers 	}
120*b13c0e40SEric Biggers 	if (offset_specified && !length_specified) {
121*b13c0e40SEric Biggers 		error_msg("--offset specified without --length");
122*b13c0e40SEric Biggers 		goto out_usage;
123*b13c0e40SEric Biggers 	}
124*b13c0e40SEric Biggers 
125*b13c0e40SEric Biggers 	buf = xzalloc(arg.length);
126*b13c0e40SEric Biggers 	arg.buf_ptr = (uintptr_t)buf;
127*b13c0e40SEric Biggers 
128*b13c0e40SEric Biggers 	if (!open_file(&file, argv[1], O_RDONLY, 0))
129*b13c0e40SEric Biggers 		goto out_err;
130*b13c0e40SEric Biggers 
131*b13c0e40SEric Biggers 	/*
132*b13c0e40SEric Biggers 	 * If --offset and --length were specified, then do only the single read
133*b13c0e40SEric Biggers 	 * requested.  Otherwise read until EOF.
134*b13c0e40SEric Biggers 	 */
135*b13c0e40SEric Biggers 	do {
136*b13c0e40SEric Biggers 		bytes_read = ioctl(file.fd, FS_IOC_READ_VERITY_METADATA, &arg);
137*b13c0e40SEric Biggers 		if (bytes_read < 0) {
138*b13c0e40SEric Biggers 			error_msg_errno("FS_IOC_READ_VERITY_METADATA failed on '%s'",
139*b13c0e40SEric Biggers 					file.name);
140*b13c0e40SEric Biggers 			goto out_err;
141*b13c0e40SEric Biggers 		}
142*b13c0e40SEric Biggers 		if (bytes_read == 0)
143*b13c0e40SEric Biggers 			break;
144*b13c0e40SEric Biggers 		if (!full_write(&stdout_filedes, buf, bytes_read))
145*b13c0e40SEric Biggers 			goto out_err;
146*b13c0e40SEric Biggers 		arg.offset += bytes_read;
147*b13c0e40SEric Biggers 	} while (!length_specified);
148*b13c0e40SEric Biggers 
149*b13c0e40SEric Biggers 	status = 0;
150*b13c0e40SEric Biggers out:
151*b13c0e40SEric Biggers 	free(buf);
152*b13c0e40SEric Biggers 	filedes_close(&file);
153*b13c0e40SEric Biggers 	return status;
154*b13c0e40SEric Biggers 
155*b13c0e40SEric Biggers out_err:
156*b13c0e40SEric Biggers 	status = 1;
157*b13c0e40SEric Biggers 	goto out;
158*b13c0e40SEric Biggers 
159*b13c0e40SEric Biggers out_usage:
160*b13c0e40SEric Biggers 	usage(cmd, stderr);
161*b13c0e40SEric Biggers 	status = 2;
162*b13c0e40SEric Biggers 	goto out;
163*b13c0e40SEric Biggers }
164