]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/crypto/luks/LoadRequest.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / librbd / crypto / luks / LoadRequest.cc
CommitLineData
f67539c2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "LoadRequest.h"
5
6#include "common/dout.h"
7#include "common/errno.h"
8#include "librbd/Utils.h"
9#include "librbd/crypto/Utils.h"
1e59de90
TL
10#include "librbd/crypto/LoadRequest.h"
11#include "librbd/crypto/luks/Magic.h"
f67539c2
TL
12#include "librbd/io/AioCompletion.h"
13#include "librbd/io/ImageDispatchSpec.h"
14#include "librbd/io/ReadResult.h"
15
16#define dout_subsys ceph_subsys_rbd
17#undef dout_prefix
18#define dout_prefix *_dout << "librbd::crypto::luks::LoadRequest: " << this \
19 << " " << __func__ << ": "
20
21namespace librbd {
22namespace crypto {
23namespace luks {
24
25using librbd::util::create_context_callback;
26
27template <typename I>
28LoadRequest<I>::LoadRequest(
1e59de90
TL
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,
f67539c2
TL
32 Context* on_finish) : m_image_ctx(image_ctx),
33 m_format(format),
1e59de90 34 m_passphrase(passphrase),
f67539c2
TL
35 m_on_finish(on_finish),
36 m_result_crypto(result_crypto),
1e59de90 37 m_detected_format_name(detected_format_name),
f67539c2
TL
38 m_initial_read_size(DEFAULT_INITIAL_READ_SIZE),
39 m_header(image_ctx->cct), m_offset(0) {
40}
41
42template <typename I>
43void LoadRequest<I>::set_initial_read_size(uint64_t read_size) {
44 m_initial_read_size = read_size;
45}
46
47template <typename I>
48void LoadRequest<I>::send() {
f67539c2
TL
49 auto ctx = create_context_callback<
50 LoadRequest<I>, &LoadRequest<I>::handle_read_header>(this);
51 read(m_initial_read_size, ctx);
52}
53
54template <typename I>
55void 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),
59 io::AIO_TYPE_READ);
60 ZTracer::Trace trace;
61 auto req = io::ImageDispatchSpec::create_read(
62 *m_image_ctx, io::IMAGE_DISPATCH_LAYER_API_START, aio_comp,
1e59de90 63 {{m_offset, length}}, io::ImageArea::DATA, io::ReadResult{&m_bl},
f67539c2
TL
64 m_image_ctx->get_data_io_context(), 0, 0, trace);
65 req->send();
66}
67
68template <typename I>
69bool LoadRequest<I>::handle_read(int r) {
1e59de90
TL
70 ldout(m_image_ctx->cct, 20) << "r=" << r << dendl;
71
f67539c2
TL
72 if (r < 0) {
73 lderr(m_image_ctx->cct) << "error reading from image: " << cpp_strerror(r)
74 << dendl;
75 finish(r);
76 return false;
77 }
78
1e59de90
TL
79 // first, check LUKS magic at the beginning of the image
80 // If no magic is detected, caller may assume image is actually plaintext
81 if (m_offset == 0) {
82 if (Magic::is_luks(m_bl) > 0 || Magic::is_rbd_clone(m_bl) > 0) {
83 *m_detected_format_name = "LUKS";
84 } else {
85 *m_detected_format_name = crypto::LoadRequest<I>::UNKNOWN_FORMAT;
86 finish(-EINVAL);
87 return false;
88 }
89
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);
92 if (r < 0) {
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();
96
97 auto max_header_size = std::min(MAXIMUM_HEADER_SIZE, image_size);
98
99 if (r == -EINVAL && m_bl.length() < max_header_size) {
100 m_bl.clear();
101 auto ctx = create_context_callback<
102 LoadRequest<I>, &LoadRequest<I>::handle_read_header>(this);
103 read(max_header_size, ctx);
104 return false;
105 }
106
107 lderr(m_image_ctx->cct) << "error replacing rbd clone magic: "
108 << cpp_strerror(r) << dendl;
109 finish(r);
110 return false;
111 }
112 }
113 }
114
115 // setup interface with libcryptsetup
116 r = m_header.init();
117 if (r < 0) {
118 finish(r);
119 return false;
120 }
121
122 m_offset += m_bl.length();
123
f67539c2
TL
124 // write header to libcryptsetup interface
125 r = m_header.write(m_bl);
126 if (r < 0) {
127 finish(r);
128 return false;
129 }
130
f67539c2 131 m_bl.clear();
1e59de90 132
f67539c2
TL
133 return true;
134}
135
136template <typename I>
137void LoadRequest<I>::handle_read_header(int r) {
1e59de90
TL
138 ldout(m_image_ctx->cct, 20) << "r=" << r << dendl;
139
f67539c2
TL
140 if (!handle_read(r)) {
141 return;
142 }
143
144 const char* type;
145 switch (m_format) {
1e59de90
TL
146 case RBD_ENCRYPTION_FORMAT_LUKS:
147 type = CRYPT_LUKS;
148 break;
149 case RBD_ENCRYPTION_FORMAT_LUKS1:
150 type = CRYPT_LUKS1;
151 break;
152 case RBD_ENCRYPTION_FORMAT_LUKS2:
153 type = CRYPT_LUKS2;
154 break;
155 default:
156 lderr(m_image_ctx->cct) << "unsupported format type: " << m_format
157 << dendl;
158 finish(-EINVAL);
159 return;
f67539c2
TL
160 }
161
162 // parse header via libcryptsetup
163 r = m_header.load(type);
164 if (r != 0) {
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);
170 return;
171 }
172
173 finish(r);
174 return;
175 }
176
1e59de90
TL
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();
180
f67539c2
TL
181 auto cipher = m_header.get_cipher();
182 if (strcmp(cipher, "aes") != 0) {
183 lderr(m_image_ctx->cct) << "unsupported cipher: " << cipher << dendl;
184 finish(-ENOTSUP);
185 return;
186 }
187
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
191 << dendl;
192 finish(-ENOTSUP);
193 return;
194 }
195
1e59de90
TL
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();
199
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;
203 finish(-EINVAL);
204 return;
205 }
206
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;
211 finish(-EINVAL);
212 return;
213 }
214
f67539c2
TL
215 read_volume_key();
216 return;
217}
218
219template <typename I>
220void LoadRequest<I>::handle_read_keyslots(int r) {
1e59de90
TL
221 ldout(m_image_ctx->cct, 20) << "r=" << r << dendl;
222
f67539c2
TL
223 if (!handle_read(r)) {
224 return;
225 }
226
227 read_volume_key();
228}
229
230template <typename I>
231void LoadRequest<I>::read_volume_key() {
232 char volume_key[64];
233 size_t volume_key_size = sizeof(volume_key);
234
235 auto r = m_header.read_volume_key(
1e59de90 236 m_passphrase.data(), m_passphrase.size(),
f67539c2
TL
237 reinterpret_cast<char*>(volume_key), &volume_key_size);
238 if (r != 0) {
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);
245 return;
246 }
247
248 finish(r);
249 return;
250 }
251
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);
1e59de90 256 ceph_memzero_s(volume_key, 64, 64);
f67539c2
TL
257 finish(r);
258}
259
260template <typename I>
261void LoadRequest<I>::finish(int r) {
1e59de90
TL
262 ldout(m_image_ctx->cct, 20) << "r=" << r << dendl;
263
f67539c2
TL
264 m_on_finish->complete(r);
265 delete this;
266}
267
268} // namespace luks
269} // namespace crypto
270} // namespace librbd
271
272template class librbd::crypto::luks::LoadRequest<librbd::ImageCtx>;