• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * fs-verity userspace tool
4  *
5  * Copyright (C) 2018 Google LLC
6  *
7  * Written by Eric Biggers.
8  */
9 
10 #include <limits.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 
15 #include "commands.h"
16 #include "hash_algs.h"
17 
18 static const struct fsverity_command {
19 	const char *name;
20 	int (*func)(const struct fsverity_command *cmd, int argc, char *argv[]);
21 	const char *short_desc;
22 	const char *usage_str;
23 } fsverity_commands[] = {
24 	{
25 		.name = "enable",
26 		.func = fsverity_cmd_enable,
27 		.short_desc = "Enable fs-verity on a file",
28 		.usage_str =
29 "    fsverity enable FILE\n"
30 "               [--hash-alg=HASH_ALG] [--block-size=BLOCK_SIZE] [--salt=SALT]\n"
31 "               [--signature=SIGFILE]\n"
32 	}, {
33 		.name = "measure",
34 		.func = fsverity_cmd_measure,
35 		.short_desc =
36 "Display the measurement of the given verity file(s)",
37 		.usage_str =
38 "    fsverity measure FILE...\n"
39 	}, {
40 		.name = "sign",
41 		.func = fsverity_cmd_sign,
42 		.short_desc = "Sign a file for fs-verity",
43 		.usage_str =
44 "    fsverity sign FILE OUT_SIGFILE --key=KEYFILE\n"
45 "               [--hash-alg=HASH_ALG] [--block-size=BLOCK_SIZE] [--salt=SALT]\n"
46 "               [--cert=CERTFILE]\n"
47 	}
48 };
49 
usage_all(FILE * fp)50 static void usage_all(FILE *fp)
51 {
52 	int i;
53 
54 	fputs("Usage:\n", fp);
55 	for (i = 0; i < ARRAY_SIZE(fsverity_commands); i++)
56 		fprintf(fp, "  %s:\n%s\n", fsverity_commands[i].short_desc,
57 			fsverity_commands[i].usage_str);
58 	fputs(
59 "  Standard options:\n"
60 "    fsverity --help\n"
61 "    fsverity --version\n"
62 "\n"
63 "Available hash algorithms: ", fp);
64 	show_all_hash_algs(fp);
65 	fputs("\nSee `man fsverity` for more details.\n", fp);
66 }
67 
usage_cmd(const struct fsverity_command * cmd,FILE * fp)68 static void usage_cmd(const struct fsverity_command *cmd, FILE *fp)
69 {
70 	fprintf(fp, "Usage:\n%s", cmd->usage_str);
71 }
72 
usage(const struct fsverity_command * cmd,FILE * fp)73 void usage(const struct fsverity_command *cmd, FILE *fp)
74 {
75 	if (cmd)
76 		usage_cmd(cmd, fp);
77 	else
78 		usage_all(fp);
79 }
80 
81 #define PACKAGE_VERSION    "v0.0-alpha"
82 #define PACKAGE_BUGREPORT  "linux-fscrypt@vger.kernel.org"
83 
show_version(void)84 static void show_version(void)
85 {
86 	static const char * const str =
87 "fsverity " PACKAGE_VERSION "\n"
88 "Copyright (C) 2018 Google LLC\n"
89 "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n"
90 "This is free software: you are free to change and redistribute it.\n"
91 "There is NO WARRANTY, to the extent permitted by law.\n"
92 "\n"
93 "Report bugs to " PACKAGE_BUGREPORT ".\n";
94 	fputs(str, stdout);
95 }
96 
handle_common_options(int argc,char * argv[],const struct fsverity_command * cmd)97 static void handle_common_options(int argc, char *argv[],
98 				  const struct fsverity_command *cmd)
99 {
100 	int i;
101 
102 	for (i = 1; i < argc; i++) {
103 		const char *arg = argv[i];
104 
105 		if (*arg++ != '-')
106 			continue;
107 		if (*arg++ != '-')
108 			continue;
109 		if (!strcmp(arg, "help")) {
110 			usage(cmd, stdout);
111 			exit(0);
112 		} else if (!strcmp(arg, "version")) {
113 			show_version();
114 			exit(0);
115 		} else if (!*arg) /* reached "--", no more options */
116 			return;
117 	}
118 }
119 
find_command(const char * name)120 static const struct fsverity_command *find_command(const char *name)
121 {
122 	int i;
123 
124 	for (i = 0; i < ARRAY_SIZE(fsverity_commands); i++)
125 		if (!strcmp(name, fsverity_commands[i].name))
126 			return &fsverity_commands[i];
127 	return NULL;
128 }
129 
parse_block_size_option(const char * arg,u32 * size_ptr)130 bool parse_block_size_option(const char *arg, u32 *size_ptr)
131 {
132 	char *end;
133 	unsigned long n = strtoul(arg, &end, 10);
134 
135 	if (*size_ptr != 0) {
136 		error_msg("--block-size can only be specified once");
137 		return false;
138 	}
139 
140 	if (n <= 0 || n >= INT_MAX || !is_power_of_2(n) || *end != '\0') {
141 		error_msg("Invalid block size: %s.  Must be power of 2", arg);
142 		return false;
143 	}
144 	*size_ptr = n;
145 	return true;
146 }
147 
parse_salt_option(const char * arg,u8 ** salt_ptr,u32 * salt_size_ptr)148 bool parse_salt_option(const char *arg, u8 **salt_ptr, u32 *salt_size_ptr)
149 {
150 	if (*salt_ptr != NULL) {
151 		error_msg("--salt can only be specified once");
152 		return false;
153 	}
154 	*salt_size_ptr = strlen(arg) / 2;
155 	*salt_ptr = xmalloc(*salt_size_ptr);
156 	if (!hex2bin(arg, *salt_ptr, *salt_size_ptr)) {
157 		error_msg("salt is not a valid hex string");
158 		return false;
159 	}
160 	return true;
161 }
162 
get_default_block_size(void)163 u32 get_default_block_size(void)
164 {
165 	long n = sysconf(_SC_PAGESIZE);
166 
167 	if (n <= 0 || n >= INT_MAX || !is_power_of_2(n)) {
168 		fprintf(stderr,
169 			"Warning: invalid _SC_PAGESIZE (%ld).  Assuming 4K blocks.\n",
170 			n);
171 		return 4096;
172 	}
173 	return n;
174 }
175 
main(int argc,char * argv[])176 int main(int argc, char *argv[])
177 {
178 	const struct fsverity_command *cmd;
179 
180 	if (argc < 2) {
181 		error_msg("no command specified");
182 		usage_all(stderr);
183 		return 2;
184 	}
185 
186 	cmd = find_command(argv[1]);
187 
188 	handle_common_options(argc, argv, cmd);
189 
190 	if (!cmd) {
191 		error_msg("unrecognized command: '%s'", argv[1]);
192 		usage_all(stderr);
193 		return 2;
194 	}
195 	return cmd->func(cmd, argc - 1, argv + 1);
196 }
197