From: Jes Sorensen <jsorensen@xxxxxx> Split the parsing of command line arguments from the actual cmd call, which allows this to be called by other users. Signed-off-by: Jes Sorensen <jsorensen@xxxxxx> --- cmd_enable.c | 131 ++---------------------------------------------- commands.h | 3 +- fsverity.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 131 deletions(-) diff --git a/cmd_enable.c b/cmd_enable.c index 1646299..8c55722 100644 --- a/cmd_enable.c +++ b/cmd_enable.c @@ -18,137 +18,17 @@ #include "fsverity_uapi.h" #include "hash_algs.h" -static bool parse_hash_alg_option(const char *arg, u32 *alg_ptr) -{ - char *end; - unsigned long n = strtoul(arg, &end, 10); - const struct fsverity_hash_alg *alg; - - if (*alg_ptr != 0) { - error_msg("--hash-alg can only be specified once"); - return false; - } - - /* Specified by number? */ - if (n > 0 && n < INT32_MAX && *end == '\0') { - *alg_ptr = n; - return true; - } - - /* Specified by name? */ - alg = find_hash_alg_by_name(arg); - if (alg != NULL) { - *alg_ptr = alg - fsverity_hash_algs; - return true; - } - return false; -} - -static bool read_signature(const char *filename, u8 **sig_ret, - u32 *sig_size_ret) -{ - struct filedes file = { .fd = -1 }; - u64 file_size; - u8 *sig = NULL; - bool ok = false; - - if (!open_file(&file, filename, O_RDONLY, 0)) - goto out; - if (!get_file_size(&file, &file_size)) - goto out; - if (file_size <= 0) { - error_msg("signature file '%s' is empty", filename); - goto out; - } - if (file_size > 1000000) { - error_msg("signature file '%s' is too large", filename); - goto out; - } - sig = xmalloc(file_size); - if (!full_read(&file, sig, file_size)) - goto out; - *sig_ret = sig; - *sig_size_ret = file_size; - sig = NULL; - ok = true; -out: - filedes_close(&file); - free(sig); - return ok; -} - -enum { - OPT_HASH_ALG, - OPT_BLOCK_SIZE, - OPT_SALT, - OPT_SIGNATURE, -}; - -static const struct option longopts[] = { - {"hash-alg", required_argument, NULL, OPT_HASH_ALG}, - {"block-size", required_argument, NULL, OPT_BLOCK_SIZE}, - {"salt", required_argument, NULL, OPT_SALT}, - {"signature", required_argument, NULL, OPT_SIGNATURE}, - {NULL, 0, NULL, 0} -}; - /* Enable fs-verity on a file. */ -int fsverity_cmd_enable(const struct fsverity_command *cmd, - int argc, char *argv[]) +int fsverity_cmd_enable(char *filename, struct fsverity_enable_arg *arg) { - struct fsverity_enable_arg arg = { .version = 1 }; u8 *salt = NULL; u8 *sig = NULL; struct filedes file; int status; - int c; - - while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) { - switch (c) { - case OPT_HASH_ALG: - if (!parse_hash_alg_option(optarg, &arg.hash_algorithm)) - goto out_usage; - break; - case OPT_BLOCK_SIZE: - if (!parse_block_size_option(optarg, &arg.block_size)) - goto out_usage; - break; - case OPT_SALT: - if (!parse_salt_option(optarg, &salt, &arg.salt_size)) - goto out_usage; - arg.salt_ptr = (uintptr_t)salt; - break; - case OPT_SIGNATURE: - if (sig != NULL) { - error_msg("--signature can only be specified once"); - goto out_usage; - } - if (!read_signature(optarg, &sig, &arg.sig_size)) - goto out_err; - arg.sig_ptr = (uintptr_t)sig; - break; - default: - goto out_usage; - } - } - argv += optind; - argc -= optind; - - if (argc != 1) - goto out_usage; - - if (arg.hash_algorithm == 0) - arg.hash_algorithm = FS_VERITY_HASH_ALG_DEFAULT; - - if (arg.block_size == 0) - arg.block_size = get_default_block_size(); - - if (!open_file(&file, argv[0], O_RDONLY, 0)) + if (!open_file(&file, filename, O_RDONLY, 0)) goto out_err; - if (ioctl(file.fd, FS_IOC_ENABLE_VERITY, &arg) != 0) { - error_msg_errno("FS_IOC_ENABLE_VERITY failed on '%s'", - file.name); + if (ioctl(file.fd, FS_IOC_ENABLE_VERITY, arg) != 0) { filedes_close(&file); goto out_err; } @@ -164,9 +44,4 @@ out: out_err: status = 1; goto out; - -out_usage: - usage(cmd, stderr); - status = 2; - goto out; } diff --git a/commands.h b/commands.h index 3e07f3d..e490c25 100644 --- a/commands.h +++ b/commands.h @@ -26,8 +26,7 @@ struct fsverity_signed_digest { void usage(const struct fsverity_command *cmd, FILE *fp); -int fsverity_cmd_enable(const struct fsverity_command *cmd, - int argc, char *argv[]); +int fsverity_cmd_enable(char *filename, struct fsverity_enable_arg *arg); int fsverity_cmd_measure(char *filename, struct fsverity_digest *d); int fsverity_cmd_sign(char *filename, const struct fsverity_hash_alg *hash_alg, u32 block_size, u8 *salt, u32 salt_size, diff --git a/fsverity.c b/fsverity.c index 49eca14..b4e67a2 100644 --- a/fsverity.c +++ b/fsverity.c @@ -24,6 +24,7 @@ enum { OPT_SALT, OPT_KEY, OPT_CERT, + OPT_SIGNATURE, }; static const struct option longopts[] = { @@ -35,6 +36,14 @@ static const struct option longopts[] = { {NULL, 0, NULL, 0} }; +static const struct option enable_longopts[] = { + {"hash-alg", required_argument, NULL, OPT_HASH_ALG}, + {"block-size", required_argument, NULL, OPT_BLOCK_SIZE}, + {"salt", required_argument, NULL, OPT_SALT}, + {"signature", required_argument, NULL, OPT_SIGNATURE}, + {NULL, 0, NULL, 0} +}; + static bool write_signature(const char *filename, const u8 *sig, u32 sig_size) { struct filedes file; @@ -47,6 +56,65 @@ static bool write_signature(const char *filename, const u8 *sig, u32 sig_size) return ok; } +static bool read_signature(const char *filename, u8 **sig_ret, + u32 *sig_size_ret) +{ + struct filedes file = { .fd = -1 }; + u64 file_size; + u8 *sig = NULL; + bool ok = false; + + if (!open_file(&file, filename, O_RDONLY, 0)) + goto out; + if (!get_file_size(&file, &file_size)) + goto out; + if (file_size <= 0) { + error_msg("signature file '%s' is empty", filename); + goto out; + } + if (file_size > 1000000) { + error_msg("signature file '%s' is too large", filename); + goto out; + } + sig = xmalloc(file_size); + if (!full_read(&file, sig, file_size)) + goto out; + *sig_ret = sig; + *sig_size_ret = file_size; + sig = NULL; + ok = true; +out: + filedes_close(&file); + free(sig); + return ok; +} + +static bool parse_hash_alg_option(const char *arg, u32 *alg_ptr) +{ + char *end; + unsigned long n = strtoul(arg, &end, 10); + const struct fsverity_hash_alg *alg; + + if (*alg_ptr != 0) { + error_msg("--hash-alg can only be specified once"); + return false; + } + + /* Specified by number? */ + if (n > 0 && n < INT32_MAX && *end == '\0') { + *alg_ptr = n; + return true; + } + + /* Specified by name? */ + alg = find_hash_alg_by_name(arg); + if (alg != NULL) { + *alg_ptr = alg - fsverity_hash_algs; + return true; + } + return false; +} + int wrap_cmd_sign(const struct fsverity_command *cmd, int argc, char *argv[]) { struct fsverity_signed_digest *digest = NULL; @@ -190,6 +258,73 @@ out_usage: goto out; } +int wrap_cmd_enable(const struct fsverity_command *cmd, + int argc, char *argv[]) +{ + struct fsverity_enable_arg arg = { .version = 1 }; + u8 *salt = NULL; + u8 *sig = NULL; + int status; + int c; + + while ((c = getopt_long(argc, argv, "", enable_longopts, NULL)) != -1) { + switch (c) { + case OPT_HASH_ALG: + if (!parse_hash_alg_option(optarg, &arg.hash_algorithm)) + goto out_usage; + break; + case OPT_BLOCK_SIZE: + if (!parse_block_size_option(optarg, &arg.block_size)) + goto out_usage; + break; + case OPT_SALT: + if (!parse_salt_option(optarg, &salt, &arg.salt_size)) + goto out_usage; + arg.salt_ptr = (uintptr_t)salt; + break; + case OPT_SIGNATURE: + if (sig != NULL) { + error_msg("--signature can only be specified once"); + goto out_usage; + } + if (!read_signature(optarg, &sig, &arg.sig_size)) { + error_msg("unable to read signature file %s", + optarg); + status = 1; + goto out; + } + arg.sig_ptr = (uintptr_t)sig; + break; + default: + goto out_usage; + } + } + + argv += optind; + argc -= optind; + + if (argc != 1) + goto out_usage; + + if (arg.hash_algorithm == 0) + arg.hash_algorithm = FS_VERITY_HASH_ALG_DEFAULT; + + if (arg.block_size == 0) + arg.block_size = get_default_block_size(); + + status = fsverity_cmd_enable(argv[0], &arg); + +out: + free(salt); + free(sig); + return status; + +out_usage: + usage(cmd, stderr); + status = 2; + goto out; +} + static const struct fsverity_command { const char *name; int (*func)(const struct fsverity_command *cmd, int argc, char *argv[]); @@ -198,7 +333,7 @@ static const struct fsverity_command { } fsverity_commands[] = { { .name = "enable", - .func = fsverity_cmd_enable, + .func = wrap_cmd_enable, .short_desc = "Enable fs-verity on a file", .usage_str = " fsverity enable FILE\n" -- 2.24.1