From e060ed32e46bdd7583dcad87ff462ff4c006115f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 18:15:42 +0100 Subject: [PATCH] cryptsetup: modify keyfile search logic to use read_file_full() too Let's move the 3rd way how cryptsetup acquires key files to read_file_full() too. Since load_key_file()'s raison d'etre now is just the search path logic, let's rename the function to find_key_file(). --- src/cryptsetup/cryptsetup-keyfile.c | 113 ++++++++-------------------- src/cryptsetup/cryptsetup-keyfile.h | 5 +- src/cryptsetup/cryptsetup.c | 14 +++- 3 files changed, 42 insertions(+), 90 deletions(-) diff --git a/src/cryptsetup/cryptsetup-keyfile.c b/src/cryptsetup/cryptsetup-keyfile.c index f849123563..a6281fbdee 100644 --- a/src/cryptsetup/cryptsetup-keyfile.c +++ b/src/cryptsetup/cryptsetup-keyfile.c @@ -1,29 +1,18 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include - #include "cryptsetup-keyfile.h" -#include "fd-util.h" -#include "format-util.h" -#include "memory-util.h" +#include "fileio.h" #include "path-util.h" -#include "stat-util.h" #include "strv.h" -#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */ - -int load_key_file( +int find_key_file( const char *key_file, char **search_path, - size_t key_file_size, - uint64_t key_file_offset, + const char *bindname, void **ret_key, size_t *ret_key_size) { - _cleanup_(erase_and_freep) char *buffer = NULL; - _cleanup_free_ char *discovered_path = NULL; - _cleanup_close_ int fd = -1; - ssize_t n; + char **i; int r; assert(key_file); @@ -31,80 +20,38 @@ int load_key_file( assert(ret_key_size); if (strv_isempty(search_path) || path_is_absolute(key_file)) { - fd = open(key_file, O_RDONLY|O_CLOEXEC); - if (fd < 0) - return log_error_errno(errno, "Failed to load key file '%s': %m", key_file); - } else { - char **i; - STRV_FOREACH(i, search_path) { - _cleanup_free_ char *joined; - - joined = path_join(*i, key_file); - if (!joined) - return log_oom(); - - fd = open(joined, O_RDONLY|O_CLOEXEC); - if (fd >= 0) { - discovered_path = TAKE_PTR(joined); - break; - } - if (errno != ENOENT) - return log_error_errno(errno, "Failed to load key file '%s': %m", joined); - } - - if (!discovered_path) { - /* Search path supplied, but file not found, report by returning NULL, but not failing */ - *ret_key = NULL; - *ret_key_size = 0; - return 0; - } - - assert(fd >= 0); - key_file = discovered_path; - } - - if (key_file_size == 0) { - struct stat st; - - if (fstat(fd, &st) < 0) - return log_error_errno(errno, "Failed to stat key file '%s': %m", key_file); - - r = stat_verify_regular(&st); + r = read_full_file_full( + AT_FDCWD, key_file, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET, + bindname, + (char**) ret_key, ret_key_size); if (r < 0) - return log_error_errno(r, "Key file is not a regular file: %m"); + return log_error_errno(r, "Failed to load key file '%s': %m", key_file); - if (st.st_size == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing."); - if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) { - char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX]; - return log_error_errno(SYNTHETIC_ERRNO(ERANGE), - "Key file larger (%s) than allowed maximum size (%s), refusing.", - format_bytes(buf1, sizeof(buf1), st.st_size), - format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX)); - } - - if (key_file_offset >= (uint64_t) st.st_size) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing."); - - key_file_size = st.st_size - key_file_offset; + return 1; } - buffer = malloc(key_file_size); - if (!buffer) - return log_oom(); + STRV_FOREACH(i, search_path) { + _cleanup_free_ char *joined; - if (key_file_offset > 0) - n = pread(fd, buffer, key_file_size, key_file_offset); - else - n = read(fd, buffer, key_file_size); - if (n < 0) - return log_error_errno(errno, "Failed to read key file '%s': %m", key_file); - if (n == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing."); + joined = path_join(*i, key_file); + if (!joined) + return log_oom(); - *ret_key = TAKE_PTR(buffer); - *ret_key_size = (size_t) n; + r = read_full_file_full( + AT_FDCWD, joined, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET, + bindname, + (char**) ret_key, ret_key_size); + if (r >= 0) + return 1; + if (r != -ENOENT) + return log_error_errno(r, "Failed to load key file '%s': %m", key_file); + } - return 1; + /* Search path supplied, but file not found, report by returning NULL, but not failing */ + *ret_key = NULL; + *ret_key_size = 0; + return 0; } diff --git a/src/cryptsetup/cryptsetup-keyfile.h b/src/cryptsetup/cryptsetup-keyfile.h index 308f5ebd68..83bd1fbed2 100644 --- a/src/cryptsetup/cryptsetup-keyfile.h +++ b/src/cryptsetup/cryptsetup-keyfile.h @@ -4,10 +4,9 @@ #include #include -int load_key_file( +int find_key_file( const char *key_file, char **search_path, - size_t key_file_size, - uint64_t key_file_offset, + const char *bindname, void **ret_key, size_t *ret_key_size); diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index e32cc9207c..78d8eec1d7 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -908,16 +908,22 @@ static int run(int argc, char *argv[]) { (void) mlockall(MCL_FUTURE); if (!key_file) { + _cleanup_free_ char *bindname = NULL; const char *fn; + bindname = make_bindname(argv[2]); + if (!bindname) + return log_oom(); + /* If a key file is not explicitly specified, search for a key in a well defined * search path, and load it. */ fn = strjoina(argv[2], ".key"); - r = load_key_file(fn, - STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"), - 0, 0, /* Note we leave arg_keyfile_offset/arg_keyfile_size as something that only applies to arg_keyfile! */ - &key_data, &key_data_size); + r = find_key_file( + fn, + STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"), + bindname, + &key_data, &key_data_size); if (r < 0) return r; if (r > 0)