1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "LoadRequest.h"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "librbd/Utils.h"
9 #include "librbd/crypto/Utils.h"
10 #include "librbd/crypto/LoadRequest.h"
11 #include "librbd/crypto/luks/Magic.h"
12 #include "librbd/io/AioCompletion.h"
13 #include "librbd/io/ImageDispatchSpec.h"
14 #include "librbd/io/ReadResult.h"
16 #define dout_subsys ceph_subsys_rbd
18 #define dout_prefix *_dout << "librbd::crypto::luks::LoadRequest: " << this \
19 << " " << __func__ << ": "
25 using librbd::util::create_context_callback
;
28 LoadRequest
<I
>::LoadRequest(
29 I
* image_ctx
, encryption_format_t format
, std::string_view passphrase
,
30 std::unique_ptr
<CryptoInterface
>* result_crypto
,
31 std::string
* detected_format_name
,
32 Context
* on_finish
) : m_image_ctx(image_ctx
),
34 m_passphrase(passphrase
),
35 m_on_finish(on_finish
),
36 m_result_crypto(result_crypto
),
37 m_detected_format_name(detected_format_name
),
38 m_initial_read_size(DEFAULT_INITIAL_READ_SIZE
),
39 m_header(image_ctx
->cct
), m_offset(0) {
43 void LoadRequest
<I
>::set_initial_read_size(uint64_t read_size
) {
44 m_initial_read_size
= read_size
;
48 void LoadRequest
<I
>::send() {
49 auto ctx
= create_context_callback
<
50 LoadRequest
<I
>, &LoadRequest
<I
>::handle_read_header
>(this);
51 read(m_initial_read_size
, ctx
);
55 void LoadRequest
<I
>::read(uint64_t end_offset
, Context
* on_finish
) {
56 auto length
= end_offset
- m_offset
;
57 auto aio_comp
= io::AioCompletion::create_and_start(
58 on_finish
, librbd::util::get_image_ctx(m_image_ctx
),
61 auto req
= io::ImageDispatchSpec::create_read(
62 *m_image_ctx
, io::IMAGE_DISPATCH_LAYER_API_START
, aio_comp
,
63 {{m_offset
, length
}}, io::ImageArea::DATA
, io::ReadResult
{&m_bl
},
64 m_image_ctx
->get_data_io_context(), 0, 0, trace
);
69 bool LoadRequest
<I
>::handle_read(int r
) {
70 ldout(m_image_ctx
->cct
, 20) << "r=" << r
<< dendl
;
73 lderr(m_image_ctx
->cct
) << "error reading from image: " << cpp_strerror(r
)
79 // first, check LUKS magic at the beginning of the image
80 // If no magic is detected, caller may assume image is actually plaintext
82 if (Magic::is_luks(m_bl
) > 0 || Magic::is_rbd_clone(m_bl
) > 0) {
83 *m_detected_format_name
= "LUKS";
85 *m_detected_format_name
= crypto::LoadRequest
<I
>::UNKNOWN_FORMAT
;
90 if (m_image_ctx
->parent
!= nullptr && Magic::is_rbd_clone(m_bl
) > 0) {
91 r
= Magic::replace_magic(m_image_ctx
->cct
, m_bl
);
93 m_image_ctx
->image_lock
.lock_shared();
94 auto image_size
= m_image_ctx
->get_image_size(m_image_ctx
->snap_id
);
95 m_image_ctx
->image_lock
.unlock_shared();
97 auto max_header_size
= std::min(MAXIMUM_HEADER_SIZE
, image_size
);
99 if (r
== -EINVAL
&& m_bl
.length() < max_header_size
) {
101 auto ctx
= create_context_callback
<
102 LoadRequest
<I
>, &LoadRequest
<I
>::handle_read_header
>(this);
103 read(max_header_size
, ctx
);
107 lderr(m_image_ctx
->cct
) << "error replacing rbd clone magic: "
108 << cpp_strerror(r
) << dendl
;
115 // setup interface with libcryptsetup
122 m_offset
+= m_bl
.length();
124 // write header to libcryptsetup interface
125 r
= m_header
.write(m_bl
);
136 template <typename I
>
137 void LoadRequest
<I
>::handle_read_header(int r
) {
138 ldout(m_image_ctx
->cct
, 20) << "r=" << r
<< dendl
;
140 if (!handle_read(r
)) {
146 case RBD_ENCRYPTION_FORMAT_LUKS
:
149 case RBD_ENCRYPTION_FORMAT_LUKS1
:
152 case RBD_ENCRYPTION_FORMAT_LUKS2
:
156 lderr(m_image_ctx
->cct
) << "unsupported format type: " << m_format
162 // parse header via libcryptsetup
163 r
= m_header
.load(type
);
165 if (m_offset
< MAXIMUM_HEADER_SIZE
) {
166 // perhaps we did not feed the entire header to libcryptsetup, retry
167 auto ctx
= create_context_callback
<
168 LoadRequest
<I
>, &LoadRequest
<I
>::handle_read_header
>(this);
169 read(MAXIMUM_HEADER_SIZE
, ctx
);
177 // gets actual LUKS version (only used for logging)
178 ceph_assert(*m_detected_format_name
== "LUKS");
179 *m_detected_format_name
= m_header
.get_format_name();
181 auto cipher
= m_header
.get_cipher();
182 if (strcmp(cipher
, "aes") != 0) {
183 lderr(m_image_ctx
->cct
) << "unsupported cipher: " << cipher
<< dendl
;
188 auto cipher_mode
= m_header
.get_cipher_mode();
189 if (strcmp(cipher_mode
, "xts-plain64") != 0) {
190 lderr(m_image_ctx
->cct
) << "unsupported cipher mode: " << cipher_mode
196 m_image_ctx
->image_lock
.lock_shared();
197 uint64_t image_size
= m_image_ctx
->get_image_size(CEPH_NOSNAP
);
198 m_image_ctx
->image_lock
.unlock_shared();
200 if (m_header
.get_data_offset() > image_size
) {
201 lderr(m_image_ctx
->cct
) << "image is too small, data offset "
202 << m_header
.get_data_offset() << dendl
;
207 uint64_t stripe_period
= m_image_ctx
->get_stripe_period();
208 if (m_header
.get_data_offset() % stripe_period
!= 0) {
209 lderr(m_image_ctx
->cct
) << "incompatible stripe pattern, data offset "
210 << m_header
.get_data_offset() << dendl
;
219 template <typename I
>
220 void LoadRequest
<I
>::handle_read_keyslots(int r
) {
221 ldout(m_image_ctx
->cct
, 20) << "r=" << r
<< dendl
;
223 if (!handle_read(r
)) {
230 template <typename I
>
231 void LoadRequest
<I
>::read_volume_key() {
233 size_t volume_key_size
= sizeof(volume_key
);
235 auto r
= m_header
.read_volume_key(
236 m_passphrase
.data(), m_passphrase
.size(),
237 reinterpret_cast<char*>(volume_key
), &volume_key_size
);
239 auto keyslots_end_offset
= m_header
.get_data_offset();
240 if (m_offset
< keyslots_end_offset
) {
241 // perhaps we did not feed the the necessary keyslot, retry
242 auto ctx
= create_context_callback
<
243 LoadRequest
<I
>, &LoadRequest
<I
>::handle_read_keyslots
>(this);
244 read(keyslots_end_offset
, ctx
);
252 r
= util::build_crypto(
253 m_image_ctx
->cct
, reinterpret_cast<unsigned char*>(volume_key
),
254 volume_key_size
, m_header
.get_sector_size(),
255 m_header
.get_data_offset(), m_result_crypto
);
256 ceph_memzero_s(volume_key
, 64, 64);
260 template <typename I
>
261 void LoadRequest
<I
>::finish(int r
) {
262 ldout(m_image_ctx
->cct
, 20) << "r=" << r
<< dendl
;
264 m_on_finish
->complete(r
);
269 } // namespace crypto
270 } // namespace librbd
272 template class librbd::crypto::luks::LoadRequest
<librbd::ImageCtx
>;