From e62e3b6613f93ffd40208d68d400c59a1c32edf9 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Sat, 19 Nov 2022 13:30:55 +0100 Subject: [PATCH] rbd, rbd-nbd: accept "luks", "luks1" and "luks2" formats Since RBD_ENCRYPTION_FORMAT_LUKS1, RBD_ENCRYPTION_FORMAT_LUKS2 and RBD_ENCRYPTION_FORMAT_LUKS aren't treated the same when loading encryption anymore, "luks1" and "luks2" formats need to be accepted in addition to "luks" format. Signed-off-by: Ilya Dryomov --- doc/man/8/rbd-nbd.rst | 2 +- qa/workunits/rbd/luks-encryption.sh | 3 +- src/test/cli/rbd/help.t | 4 +- src/tools/rbd/ArgumentTypes.cc | 15 +-- src/tools/rbd/Utils.cc | 74 +++++++-------- src/tools/rbd/Utils.h | 41 +++++++-- src/tools/rbd_nbd/rbd-nbd.cc | 138 +++++++++++++++++----------- 7 files changed, 165 insertions(+), 112 deletions(-) diff --git a/doc/man/8/rbd-nbd.rst b/doc/man/8/rbd-nbd.rst index a7bf15332e5..5ec7ce40f44 100644 --- a/doc/man/8/rbd-nbd.rst +++ b/doc/man/8/rbd-nbd.rst @@ -54,7 +54,7 @@ Options .. option:: --encryption-format Image encryption format. - Possible values: *luks* + Possible values: *luks*, *luks1*, *luks2* .. option:: --encryption-passphrase-file diff --git a/qa/workunits/rbd/luks-encryption.sh b/qa/workunits/rbd/luks-encryption.sh index 52105a6cc36..91e8758e267 100755 --- a/qa/workunits/rbd/luks-encryption.sh +++ b/qa/workunits/rbd/luks-encryption.sh @@ -94,7 +94,8 @@ function test_clone_encryption() { sudo rbd device unmap -t nbd $LIBRBD_DEV # flatten - rbd flatten testimg2 --encryption-format luks --encryption-format luks --encryption-passphrase-file /tmp/passphrase2 --encryption-passphrase-file /tmp/passphrase + expect_false rbd flatten testimg2 --encryption-format luks1 --encryption-format luks2 --encryption-passphrase-file /tmp/passphrase2 --encryption-passphrase-file /tmp/passphrase + rbd flatten testimg2 --encryption-format luks2 --encryption-format luks1 --encryption-passphrase-file /tmp/passphrase2 --encryption-passphrase-file /tmp/passphrase # verify with cryptsetup RAW_FLAT_DEV=$(_sudo rbd -p rbd map testimg2 -t nbd) diff --git a/src/test/cli/rbd/help.t b/src/test/cli/rbd/help.t index 5c2a38031a5..c70d76f4cd7 100644 --- a/src/test/cli/rbd/help.t +++ b/src/test/cli/rbd/help.t @@ -878,7 +878,7 @@ --namespace arg namespace name --image arg image name --no-progress disable progress output - --encryption-format arg encryption formats [possible values: luks] + --encryption-format arg encryption format (luks, luks1, luks2) --encryption-passphrase-file arg path to file containing passphrase for unlocking the image @@ -2253,7 +2253,7 @@ -s [ --size ] arg image size (in M/G/T) [default: M] --allow-shrink permit shrinking --no-progress disable progress output - --encryption-format arg encryption formats [possible values: luks] + --encryption-format arg encryption format (luks, luks1, luks2) --encryption-passphrase-file arg path to file containing passphrase for unlocking the image diff --git a/src/tools/rbd/ArgumentTypes.cc b/src/tools/rbd/ArgumentTypes.cc index 5d75d02abb3..231264e57b2 100644 --- a/src/tools/rbd/ArgumentTypes.cc +++ b/src/tools/rbd/ArgumentTypes.cc @@ -331,9 +331,9 @@ void add_snap_create_options(po::options_description *opt) { void add_encryption_options(boost::program_options::options_description *opt) { opt->add_options() - (ENCRYPTION_FORMAT.c_str(), - po::value>(), - "encryption formats [possible values: luks]"); + (ENCRYPTION_FORMAT.c_str(), + po::value>(), + "encryption format (luks, luks1, luks2)"); opt->add_options() (ENCRYPTION_PASSPHRASE_FILE.c_str(), @@ -538,14 +538,15 @@ void validate(boost::any& v, const std::vector& values, EncryptionFormat *target_type, int) { po::validators::check_first_occurrence(v); const std::string &s = po::validators::get_single_string(values); - EncryptionFormat format; if (s == "luks") { - format.format = RBD_ENCRYPTION_FORMAT_LUKS; + v = boost::any(EncryptionFormat{RBD_ENCRYPTION_FORMAT_LUKS}); + } else if (s == "luks1") { + v = boost::any(EncryptionFormat{RBD_ENCRYPTION_FORMAT_LUKS1}); + } else if (s == "luks2") { + v = boost::any(EncryptionFormat{RBD_ENCRYPTION_FORMAT_LUKS2}); } else { throw po::validation_error(po::validation_error::invalid_option_value); } - - v = boost::any(format); } void validate(boost::any& v, const std::vector& values, diff --git a/src/tools/rbd/Utils.cc b/src/tools/rbd/Utils.cc index e3a1f6c8ced..47203dcba1c 100644 --- a/src/tools/rbd/Utils.cc +++ b/src/tools/rbd/Utils.cc @@ -721,20 +721,16 @@ int get_snap_create_flags(const po::variables_map &vm, uint32_t *flags) { } int get_encryption_options(const boost::program_options::variables_map &vm, - EncryptionOptions* opts) { + EncryptionOptions* result) { std::vector passphrase_files; if (vm.count(at::ENCRYPTION_PASSPHRASE_FILE)) { passphrase_files = vm[at::ENCRYPTION_PASSPHRASE_FILE].as>(); } - std::vector formats; + std::vector formats; if (vm.count(at::ENCRYPTION_FORMAT)) { - auto& format_structs = - vm[at::ENCRYPTION_FORMAT].as>(); - for (auto& format_struct : format_structs) { - formats.push_back((librbd::encryption_format_t)format_struct.format); - } + formats = vm[at::ENCRYPTION_FORMAT].as(); } if (formats.size() != passphrase_files.size()) { @@ -743,45 +739,45 @@ int get_encryption_options(const boost::program_options::variables_map &vm, return -EINVAL; } - auto spec_count = formats.size(); - if (spec_count == 0) { - return 0; - } - - opts->luks_opts.reserve(spec_count); - - auto& specs = opts->specs; - specs.resize(spec_count); - for (size_t i = 0; i < spec_count; ++i) { + result->specs.clear(); + result->specs.reserve(formats.size()); + for (size_t i = 0; i < formats.size(); ++i) { std::ifstream file(passphrase_files[i], std::ios::in | std::ios::binary); - auto sg = make_scope_guard([&] { file.close(); }); - - specs[i].format = formats[i]; - std::string* passphrase; - switch (specs[i].format) { - case RBD_ENCRYPTION_FORMAT_LUKS: { - auto& luks_opts = opts->luks_opts; - luks_opts.emplace_back(); - specs[i].opts = &luks_opts.back(); - specs[i].opts_size = sizeof(luks_opts.back()); - passphrase = &luks_opts.back().passphrase; - break; - } - default: - std::cerr << "rbd: unsupported encryption format: " << specs[i].format - << std::endl; - return -ENOTSUP; - } - - passphrase->assign((std::istreambuf_iterator(file)), - (std::istreambuf_iterator())); - if (file.fail()) { std::cerr << "rbd: unable to open passphrase file '" << passphrase_files[i] << "': " << cpp_strerror(errno) << std::endl; return -errno; } + std::string passphrase((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); + file.close(); + + switch (formats[i].format) { + case RBD_ENCRYPTION_FORMAT_LUKS: { + auto opts = new librbd::encryption_luks_format_options_t{ + std::move(passphrase)}; + result->specs.push_back( + {RBD_ENCRYPTION_FORMAT_LUKS, opts, sizeof(*opts)}); + break; + } + case RBD_ENCRYPTION_FORMAT_LUKS1: { + auto opts = new librbd::encryption_luks1_format_options_t{ + .passphrase = std::move(passphrase)}; + result->specs.push_back( + {RBD_ENCRYPTION_FORMAT_LUKS1, opts, sizeof(*opts)}); + break; + } + case RBD_ENCRYPTION_FORMAT_LUKS2: { + auto opts = new librbd::encryption_luks2_format_options_t{ + .passphrase = std::move(passphrase)}; + result->specs.push_back( + {RBD_ENCRYPTION_FORMAT_LUKS2, opts, sizeof(*opts)}); + break; + } + default: + ceph_abort(); + } } return 0; diff --git a/src/tools/rbd/Utils.h b/src/tools/rbd/Utils.h index 5bfdeae0659..5076fd7fe9c 100644 --- a/src/tools/rbd/Utils.h +++ b/src/tools/rbd/Utils.h @@ -86,15 +86,40 @@ struct ProgressContext : public librbd::ProgressContext { int get_percentage(uint64_t part, uint64_t whole); struct EncryptionOptions { - std::vector specs; - std::vector luks_opts; - - ~EncryptionOptions() { - for (auto& opts : luks_opts) { - auto& passphrase = opts.passphrase; - ceph_memzero_s(&passphrase[0], passphrase.size(), passphrase.size()); + std::vector specs; + + ~EncryptionOptions() { + for (auto& spec : specs) { + switch (spec.format) { + case RBD_ENCRYPTION_FORMAT_LUKS: { + auto opts = + static_cast(spec.opts); + ceph_memzero_s(opts->passphrase.data(), opts->passphrase.size(), + opts->passphrase.size()); + delete opts; + break; + } + case RBD_ENCRYPTION_FORMAT_LUKS1: { + auto opts = + static_cast(spec.opts); + ceph_memzero_s(opts->passphrase.data(), opts->passphrase.size(), + opts->passphrase.size()); + delete opts; + break; + } + case RBD_ENCRYPTION_FORMAT_LUKS2: { + auto opts = + static_cast(spec.opts); + ceph_memzero_s(opts->passphrase.data(), opts->passphrase.size(), + opts->passphrase.size()); + delete opts; + break; + } + default: + ceph_abort(); } } + } }; template @@ -176,7 +201,7 @@ int get_snap_create_flags(const boost::program_options::variables_map &vm, uint32_t *flags); int get_encryption_options(const boost::program_options::variables_map &vm, - EncryptionOptions* opts); + EncryptionOptions* result); void init_context(); diff --git a/src/tools/rbd_nbd/rbd-nbd.cc b/src/tools/rbd_nbd/rbd-nbd.cc index b5af8b5fd11..cc42491ca08 100644 --- a/src/tools/rbd_nbd/rbd-nbd.cc +++ b/src/tools/rbd_nbd/rbd-nbd.cc @@ -119,8 +119,8 @@ struct Config { std::string format; bool pretty_format = false; - std::vector encryption_format; - std::vector encryption_passphrase_file; + std::vector encryption_formats; + std::vector encryption_passphrase_files; Command command = None; int pid = 0; @@ -152,8 +152,8 @@ static void usage() << " [options] list-mapped List mapped nbd devices\n" << "Map and attach options:\n" << " --device Specify nbd device path (/dev/nbd{num})\n" - << " --encryption-format Image encryption format\n" - << " (possible values: luks)\n" + << " --encryption-format luks|luks1|luks2\n" + << " Image encryption format\n" << " --encryption-passphrase-file Path of file containing passphrase for unlocking image encryption\n" << " --exclusive Forbid writes by other clients\n" << " --notrim Turn off trim/discard\n" @@ -943,6 +943,43 @@ private: } }; +struct EncryptionOptions { + std::vector specs; + + ~EncryptionOptions() { + for (auto& spec : specs) { + switch (spec.format) { + case RBD_ENCRYPTION_FORMAT_LUKS: { + auto opts = + static_cast(spec.opts); + ceph_memzero_s(opts->passphrase.data(), opts->passphrase.size(), + opts->passphrase.size()); + delete opts; + break; + } + case RBD_ENCRYPTION_FORMAT_LUKS1: { + auto opts = + static_cast(spec.opts); + ceph_memzero_s(opts->passphrase.data(), opts->passphrase.size(), + opts->passphrase.size()); + delete opts; + break; + } + case RBD_ENCRYPTION_FORMAT_LUKS2: { + auto opts = + static_cast(spec.opts); + ceph_memzero_s(opts->passphrase.data(), opts->passphrase.size(), + opts->passphrase.size()); + delete opts; + break; + } + default: + ceph_abort(); + } + } + } +}; + static std::string get_cookie(const std::string &devpath) { std::string cookie; @@ -1588,7 +1625,6 @@ static int do_map(int argc, const char *argv[], Config *cfg, bool reconnect) unsigned long size; unsigned long blksize = RBD_NBD_BLKSIZE; bool use_netlink; - auto encryption_format_count = cfg->encryption_format.size(); int fd[2]; @@ -1679,55 +1715,53 @@ static int do_map(int argc, const char *argv[], Config *cfg, bool reconnect) } } - if (encryption_format_count > 0) { - std::vector specs(encryption_format_count); - std::vector luks_opts; - - luks_opts.reserve(encryption_format_count); + if (!cfg->encryption_formats.empty()) { + EncryptionOptions encryption_options; + encryption_options.specs.reserve(cfg->encryption_formats.size()); - auto sg = make_scope_guard([&] { - for (auto& opts : luks_opts) { - auto& passphrase = opts.passphrase; - ceph_memzero_s(&passphrase[0], passphrase.size(), passphrase.size()); - } - }); - - for (size_t i = 0; i < encryption_format_count; ++i) { - std::ifstream file(cfg->encryption_passphrase_file[i], + for (size_t i = 0; i < cfg->encryption_formats.size(); ++i) { + std::ifstream file(cfg->encryption_passphrase_files[i], std::ios::in | std::ios::binary); - auto sg2 = make_scope_guard([&] { file.close(); }); - - specs[i].format = cfg->encryption_format[i]; - std::string* passphrase; - switch (specs[i].format) { - case RBD_ENCRYPTION_FORMAT_LUKS: { - luks_opts.emplace_back(); - specs[i].opts = &luks_opts.back(); - specs[i].opts_size = sizeof(luks_opts.back()); - passphrase = &luks_opts.back().passphrase; - break; - } - default: - r = -ENOTSUP; - cerr << "rbd-nbd: unsupported encryption format: " << specs[i].format - << std::endl; - goto close_fd; - } - - passphrase->assign((std::istreambuf_iterator(file)), - (std::istreambuf_iterator())); - if (file.fail()) { r = -errno; std::cerr << "rbd-nbd: unable to open passphrase file '" - << cfg->encryption_passphrase_file[i] << "': " - << cpp_strerror(errno) << std::endl; + << cfg->encryption_passphrase_files[i] << "': " + << cpp_strerror(r) << std::endl; goto close_fd; } + std::string passphrase((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); + file.close(); + + switch (cfg->encryption_formats[i]) { + case RBD_ENCRYPTION_FORMAT_LUKS: { + auto opts = new librbd::encryption_luks_format_options_t{ + std::move(passphrase)}; + encryption_options.specs.push_back( + {RBD_ENCRYPTION_FORMAT_LUKS, opts, sizeof(*opts)}); + break; + } + case RBD_ENCRYPTION_FORMAT_LUKS1: { + auto opts = new librbd::encryption_luks1_format_options_t{ + .passphrase = std::move(passphrase)}; + encryption_options.specs.push_back( + {RBD_ENCRYPTION_FORMAT_LUKS1, opts, sizeof(*opts)}); + break; + } + case RBD_ENCRYPTION_FORMAT_LUKS2: { + auto opts = new librbd::encryption_luks2_format_options_t{ + .passphrase = std::move(passphrase)}; + encryption_options.specs.push_back( + {RBD_ENCRYPTION_FORMAT_LUKS2, opts, sizeof(*opts)}); + break; + } + default: + ceph_abort(); + } } - r = image.encryption_load2(&specs[0], encryption_format_count); - + r = image.encryption_load2(encryption_options.specs.data(), + encryption_options.specs.size()); if (r != 0) { cerr << "rbd-nbd: failed to load encryption: " << cpp_strerror(r) << std::endl; @@ -2142,15 +2176,11 @@ static int parse_args(vector& args, std::ostream *err_msg, } else if (ceph_argparse_witharg(args, i, &arg_value, "--encryption-format", (char *)NULL)) { if (arg_value == "luks1") { - cfg->encryption_format.push_back(RBD_ENCRYPTION_FORMAT_LUKS); - *err_msg << "rbd-nbd: specifying luks1 when loading encryption " - "is deprecated, use luks"; + cfg->encryption_formats.push_back(RBD_ENCRYPTION_FORMAT_LUKS1); } else if (arg_value == "luks2") { - cfg->encryption_format.push_back(RBD_ENCRYPTION_FORMAT_LUKS); - *err_msg << "rbd-nbd: specifying luks2 when loading encryption " - "is deprecated, use luks"; + cfg->encryption_formats.push_back(RBD_ENCRYPTION_FORMAT_LUKS2); } else if (arg_value == "luks") { - cfg->encryption_format.push_back(RBD_ENCRYPTION_FORMAT_LUKS); + cfg->encryption_formats.push_back(RBD_ENCRYPTION_FORMAT_LUKS); } else { *err_msg << "rbd-nbd: Invalid encryption format"; return -EINVAL; @@ -2158,13 +2188,13 @@ static int parse_args(vector& args, std::ostream *err_msg, } else if (ceph_argparse_witharg(args, i, &arg_value, "--encryption-passphrase-file", (char *)NULL)) { - cfg->encryption_passphrase_file.push_back(arg_value); + cfg->encryption_passphrase_files.push_back(arg_value); } else { ++i; } } - if (cfg->encryption_format.size() != cfg->encryption_passphrase_file.size()) { + if (cfg->encryption_formats.size() != cfg->encryption_passphrase_files.size()) { *err_msg << "rbd-nbd: Encryption formats count does not match " << "passphrase files count"; return -EINVAL; -- 2.39.5