Update for API changes
Signed-off-by: Eric Biggers <ebiggers@google.com>
diff --git a/fsverity.c b/fsverity.c
new file mode 100644
index 0000000..931cb07
--- /dev/null
+++ b/fsverity.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * fs-verity userspace tool
+ *
+ * Copyright (C) 2018, Google, Inc.
+ */
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "fsverity_api.h"
+
+#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
+
+static const struct fsverity_hash_alg {
+ const char *name;
+ int digest_size;
+} fsverity_hash_algs[] = {
+ [FS_VERITY_ALG_SHA256] = {
+ .name = "sha256",
+ .digest_size = 32,
+ },
+ [FS_VERITY_ALG_CRC32] = {
+ .name = "crc32",
+ .digest_size = 4,
+ },
+};
+
+static void show_hash_algs(void)
+{
+ size_t i;
+
+ fprintf(stderr, "Available hash algorithms:");
+ for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) {
+ if (fsverity_hash_algs[i].name)
+ fprintf(stderr, " %s", fsverity_hash_algs[i].name);
+ }
+ fprintf(stderr, "\n");
+}
+
+static const struct fsverity_hash_alg *find_hash_alg(const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) {
+ if (fsverity_hash_algs[i].name &&
+ !strcmp(name, fsverity_hash_algs[i].name))
+ return &fsverity_hash_algs[i];
+ }
+ return NULL;
+}
+
+static int hex2bin_char(char c)
+{
+ if (c >= 'a' && c <= 'f')
+ return 10 + c - 'a';
+ if (c >= 'A' && c <= 'F')
+ return 10 + c - 'A';
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ return -1;
+}
+
+static bool parse_hex_digest(const char *hex, __u8 *bin, size_t bin_len)
+{
+ size_t i;
+
+ if (strlen(hex) != 2 * bin_len)
+ return false;
+
+ for (i = 0; i < bin_len; i++) {
+ int hi = hex2bin_char(hex[i * 2]);
+ int lo = hex2bin_char(hex[i * 2 + 1]);
+
+ if (hi < 0 || lo < 0)
+ return false;
+ bin[i] = (hi << 4) | lo;
+ }
+ return true;
+}
+
+enum {
+ OPT_HASH,
+};
+
+static void usage(void)
+{
+ const char * const usage_str =
+"Usage: fsverity enable FILE\n"
+" fsverity set_measurement [--hash=HASH] FILE EXPECTED_MEASUREMENT\n"
+"\n"
+"EXPECTED_MEASUREMENT must be given as a hex string.\n"
+"The default HASH algorithm is sha256.\n"
+ ;
+ fputs(usage_str, stderr);
+ show_hash_algs();
+ exit(2);
+}
+
+static int fsverity_enable(int argc, char *argv[])
+{
+ int fd;
+
+ if (argc != 2)
+ usage();
+
+ fd = open(argv[1], O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Can't open %s: %m\n", argv[1]);
+ return 1;
+ }
+ if (ioctl(fd, FS_IOC_ENABLE_VERITY, NULL)) {
+ fprintf(stderr, "FS_IOC_ENABLE_VERITY: %m\n");
+ return 1;
+ }
+ close(fd);
+ return 0;
+}
+
+static int fsverity_set_measurement(int argc, char *argv[])
+{
+ static const struct option longopts[] = {
+ {"hash", required_argument, NULL, OPT_HASH},
+ {NULL, 0, NULL, 0},
+ };
+ const struct fsverity_hash_alg *alg =
+ &fsverity_hash_algs[FS_VERITY_ALG_SHA256];
+ int c;
+ int fd;
+ struct fsverity_measurement *measurement;
+
+ while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
+ switch (c) {
+ case OPT_HASH:
+ alg = find_hash_alg(optarg);
+ if (!alg) {
+ fprintf(stderr,
+ "Unknown hash algorithm: '%s'\n",
+ optarg);
+ show_hash_algs();
+ return 2;
+ }
+ break;
+ default:
+ usage();
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (argc != 2)
+ usage();
+
+ fd = open(argv[0], O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Can't open %s: %m\n", argv[0]);
+ return 1;
+ }
+
+ measurement = calloc(1, sizeof(*measurement) + alg->digest_size);
+ measurement->digest_algorithm = alg - &fsverity_hash_algs[0];
+ measurement->digest_size = alg->digest_size;
+ if (!parse_hex_digest(argv[1], measurement->digest, alg->digest_size)) {
+ fprintf(stderr,
+ "Invalid EXPECTED_MEASUREMENT hex string. Expected %u-character hex string for hash algorithm '%s'\n",
+ alg->digest_size * 2, alg->name);
+ return 2;
+ }
+
+ if (ioctl(fd, FS_IOC_SET_VERITY_MEASUREMENT, measurement)) {
+ fprintf(stderr, "FS_IOC_SET_VERITY_MEASUREMENT: %m\n");
+ return 1;
+ }
+ close(fd);
+ return 0;
+}
+
+static const struct {
+ const char *name;
+ int (*func)(int argc, char *argv[]);
+} commands[] = {
+ { "enable", fsverity_enable },
+ { "set_measurement", fsverity_set_measurement },
+};
+
+int main(int argc, char *argv[])
+{
+ size_t i;
+
+ if (argc < 2)
+ usage();
+
+ for (i = 0; i < ARRAY_SIZE(commands); i++) {
+ if (!strcmp(argv[1], commands[i].name))
+ return commands[i].func(argc - 1, argv + 1);
+ }
+ usage();
+}