diff options
author | Eric Biggers <ebiggers@google.com> | 2018-03-21 17:53:20 -0700 |
---|---|---|
committer | Eric Biggers <ebiggers@google.com> | 2018-03-21 17:53:20 -0700 |
commit | 1e64b3d34ef07017c00772aad35cd0970d84c581 (patch) | |
tree | ce3be1d87c27018b7aba287bb38a57701af85cf5 | |
parent | 6d8d3d205f8a59bbe2caa95f022cfa4a202c7039 (diff) | |
download | fsverity-utils-1e64b3d34ef07017c00772aad35cd0970d84c581.tar.gz |
Update for API changes
Signed-off-by: Eric Biggers <ebiggers@google.com>
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | fsverity.c | 204 | ||||
-rw-r--r-- | fsverity_api.h | 46 | ||||
-rw-r--r-- | fsveritymeasure.c | 44 | ||||
-rw-r--r-- | fsverityset.c | 34 | ||||
-rwxr-xr-x | fsveritysetup.py | 4 | ||||
-rwxr-xr-x | full-run-fsverity.sh | 4 |
8 files changed, 223 insertions, 118 deletions
@@ -1,5 +1,4 @@ -fsveritymeasure -fsverityset +fsverity fsveritysetup.pyc tags cscope.* @@ -1,5 +1,5 @@ CFLAGS := -O2 -Wall -EXE := fsverityset fsveritymeasure +EXE := fsverity all:$(EXE) 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(); +} diff --git a/fsverity_api.h b/fsverity_api.h index db0483f..e4cc960 100644 --- a/fsverity_api.h +++ b/fsverity_api.h @@ -1,5 +1,5 @@ -#ifndef _FSVERITY_KERNEL_DEFS_H -#define _FSVERITY_KERNEL_DEFS_H +#ifndef _FSVERITY_API_H +#define _FSVERITY_API_H #include <linux/limits.h> #include <linux/ioctl.h> @@ -7,38 +7,18 @@ /* file-based verity support */ -/* - * TODO(ebiggers): What is the purpose of this structure? It's not actually - * used for anything. - */ -struct fsverity_set { - __u64 offset; - __u64 flags; -}; - -/* - * TODO(ebiggers): why isn't this using the same type code as used in the - * fsverity_header? - */ -#define FS_VERITY_ROOT_HASH_ALGO_SHA256 0x0000 +#define FS_VERITY_ALG_SHA256 1 +#define FS_VERITY_ALG_CRC32 2 -/* - * TODO(ebiggers): rename this to 'struct fsverity_measurement' to avoid - * confusion with the Merkle tree root hash? - */ -struct fsverity_root_hash { - __u32 root_hash_algorithm; - __u32 flags; - __u8 reserved[4]; - __u8 root_hash[64]; +struct fsverity_measurement { + __u16 digest_algorithm; + __u16 digest_size; + __u32 reserved1; + __u64 reserved2[3]; + __u8 digest[]; }; -/* - * TODO(ebiggers): is there a less confusing name for this? "measure" makes it - * sound like it's returning something... - */ -#define FS_IOC_MEASURE_FSVERITY _IOW('f', 133, \ - struct fsverity_root_hash) -#define FS_IOC_SET_FSVERITY _IOW('f', 134, struct fsverity_set) +#define FS_IOC_ENABLE_VERITY _IO('f', 133) +#define FS_IOC_SET_VERITY_MEASUREMENT _IOW('f', 134, struct fsverity_measurement) -#endif /* _FSVERITY_KERNEL_DEFS_H */ +#endif /* _FSVERITY_API_H */ diff --git a/fsveritymeasure.c b/fsveritymeasure.c deleted file mode 100644 index 0be1c25..0000000 --- a/fsveritymeasure.c +++ /dev/null @@ -1,44 +0,0 @@ -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <unistd.h> - -#include "fsverity_api.h" - -static void usage(void) -{ - fprintf(stderr, -"Usage: fsveritymeasure FILE EXPECTED_MEASUREMENT\n" -"\n" -"EXPECTED_MEASUREMENT must be a 64-character hex string.\n"); - exit(2); -} - -int main(int args, char *argv[]) -{ - int fd, i; - unsigned int byte; - struct fsverity_root_hash measurement = { 0 }; - - if (args != 3 || strlen(argv[2]) != 64) - usage(); - - for (i = 0; i < 32; i++) { - if (sscanf(&argv[2][i*2], "%02x", &byte) != 1) - usage(); - measurement.root_hash[i] = byte; - } - 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_MEASURE_FSVERITY, &measurement)) { - fprintf(stderr, "FS_IOC_MEASURE_FSVERITY: %m\n"); - return 1; - } - close(fd); - return 0; -} diff --git a/fsverityset.c b/fsverityset.c deleted file mode 100644 index 6075071..0000000 --- a/fsverityset.c +++ /dev/null @@ -1,34 +0,0 @@ -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/ioctl.h> -#include <unistd.h> - -#include "fsverity_api.h" - -static void usage(void) -{ - fprintf(stderr, "Usage: fsverityset FILE\n"); - exit(2); -} - -int main(int args, char *argv[]) -{ - int fd; - struct fsverity_set set = { 0 }; - - if (args != 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_SET_FSVERITY, &set)) { - fprintf(stderr, "FS_IOC_SET_FSVERITY: %m\n"); - return 1; - } - close(fd); - return 0; -} diff --git a/fsveritysetup.py b/fsveritysetup.py index 692304c..282bff7 100755 --- a/fsveritysetup.py +++ b/fsveritysetup.py @@ -21,8 +21,8 @@ FS_VERITY_MAGIC = b'TrueBrew' FS_VERITY_SALT_SIZE = 8 FS_VERITY_EXT_ELIDE = 0 FS_VERITY_EXT_PATCH = 1 -FS_VERITY_ALG_CRC32 = 0 FS_VERITY_ALG_SHA256 = 1 +FS_VERITY_ALG_CRC32 = 2 class CRC32Hash(object): @@ -68,8 +68,8 @@ class HashAlgorithm(object): HASH_ALGORITHMS = [ - HashAlgorithm(FS_VERITY_ALG_CRC32, 'crc32', 4), HashAlgorithm(FS_VERITY_ALG_SHA256, 'sha256', 32), + HashAlgorithm(FS_VERITY_ALG_CRC32, 'crc32', 4), ] diff --git a/full-run-fsverity.sh b/full-run-fsverity.sh index 14bb3dc..2507f57 100755 --- a/full-run-fsverity.sh +++ b/full-run-fsverity.sh @@ -7,8 +7,8 @@ dd if=/dev/zero of=/root/f2fs.img seek=$(($1<16384000?128000:$1/128)) bs=512 cou mount -o loop /root/f2fs.img /mnt/f2fs cp /root/output-$1.apk /mnt/f2fs/output-$1.apk make -./fsverityset /mnt/f2fs/output-$1.apk -./fsveritymeasure /mnt/f2fs/output-$1.apk $2 +./fsverity enable /mnt/f2fs/output-$1.apk +./fsverity set_measurement /mnt/f2fs/output-$1.apk $2 sync echo 3 > /proc/sys/vm/drop_caches dd if=/mnt/f2fs/output-$1.apk of=byte0-$1 count=1 bs=1 |