]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/crypto/luks/Header.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / librbd / crypto / luks / Header.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 "Header.h"
5
6#include <errno.h>
7#include <unistd.h>
8#include <sys/stat.h>
9#include <sys/syscall.h>
10#include "common/dout.h"
11#include "common/errno.h"
12
13#define dout_subsys ceph_subsys_rbd
14#undef dout_prefix
15#define dout_prefix *_dout << "librbd::crypto::luks::Header: " << this << " " \
16 << __func__ << ": "
17
18namespace librbd {
19namespace crypto {
20namespace luks {
21
22Header::Header(CephContext* cct) : m_cct(cct), m_fd(-1), m_cd(nullptr) {
23}
24
25Header::~Header() {
26 if (m_fd != -1) {
27 close(m_fd);
28 m_fd = -1;
29 }
30 if (m_cd != nullptr) {
31 crypt_free(m_cd);
32 m_cd = nullptr;
33 }
34}
35
36void Header::libcryptsetup_log_wrapper(int level, const char* msg, void* header) {
37 ((Header*)header)->libcryptsetup_log(level, msg);
38}
39
40void Header::libcryptsetup_log(int level, const char* msg) {
41 switch (level) {
42 case CRYPT_LOG_NORMAL:
43 ldout(m_cct, 5) << "[libcryptsetup] " << msg << dendl;
44 break;
45 case CRYPT_LOG_ERROR:
46 lderr(m_cct) << "[libcryptsetup] " << msg << dendl;
47 break;
48 case CRYPT_LOG_VERBOSE:
49 ldout(m_cct, 10) << "[libcryptsetup] " << msg << dendl;
50 break;
51 case CRYPT_LOG_DEBUG:
52 ldout(m_cct, 20) << "[libcryptsetup] " << msg << dendl;
53 break;
54 }
55}
56
57int Header::init() {
58 // create anonymous file
59 m_fd = syscall(SYS_memfd_create, "LibcryptsetupInterface", 0);
60 if (m_fd == -1) {
61 lderr(m_cct) << "error creating anonymous file: " << cpp_strerror(-errno)
62 << dendl;
63 return -errno;
64 }
65 std::string path =
66 "/proc/" + std::to_string(getpid()) + "/fd/" + std::to_string(m_fd);
67
68 if (m_cct->_conf->subsys.should_gather<dout_subsys, 20>()) {
69 crypt_set_debug_level(CRYPT_DEBUG_ALL);
70 }
71
72 // init libcryptsetup handle
73 auto r = crypt_init(&m_cd, path.c_str());
74 if (r != 0) {
75 lderr(m_cct) << "crypt_init failed: " << cpp_strerror(r) << dendl;
76 return r;
77 }
78
79 // redirect logging
80 crypt_set_log_callback(m_cd, &libcryptsetup_log_wrapper, this);
81
82 return 0;
83}
84
85int Header::write(const ceph::bufferlist& bl) {
86 ceph_assert(m_fd != -1);
87
88 auto r = bl.write_fd(m_fd);
89 if (r != 0) {
90 lderr(m_cct) << "error writing header: " << cpp_strerror(r) << dendl;
91 }
92 return r;
93}
94
95ssize_t Header::read(ceph::bufferlist* bl) {
96 ceph_assert(m_fd != -1);
97
98 // get current header size
99 struct stat st;
100 ssize_t r = fstat(m_fd, &st);
101 if (r < 0) {
102 r = -errno;
103 lderr(m_cct) << "failed to stat anonymous file: " << cpp_strerror(r)
104 << dendl;
105 return r;
106 }
107
108 r = bl->read_fd(m_fd, st.st_size);
109 if (r < 0) {
110 lderr(m_cct) << "error reading header: " << cpp_strerror(r) << dendl;
111 }
112
113 ldout(m_cct, 20) << "read size = " << r << dendl;
114 return r;
115}
116
117int Header::format(const char* type, const char* alg, const char* key,
118 size_t key_size, const char* cipher_mode,
119 uint32_t sector_size, uint32_t data_alignment,
120 bool insecure_fast_mode) {
121 ceph_assert(m_cd != nullptr);
122
123 ldout(m_cct, 20) << "sector size: " << sector_size << ", data alignment: "
124 << data_alignment << dendl;
125
126 // required for passing libcryptsetup device size check
127 if (ftruncate(m_fd, 4096) != 0) {
128 lderr(m_cct) << "failed to truncate anonymous file: "
129 << cpp_strerror(-errno) << dendl;
130 return -errno;
131 }
132
133 struct crypt_params_luks1 luks1params;
134 struct crypt_params_luks2 luks2params;
135
136#ifdef LIBCRYPTSETUP_LEGACY_DATA_ALIGNMENT
137 size_t converted_data_alignment = data_alignment / sector_size;
138#else
139 size_t converted_data_alignment = data_alignment / 512;
140#endif
141
142 void* params = nullptr;
143 if (strcmp(type, CRYPT_LUKS1) == 0) {
144 memset(&luks1params, 0, sizeof(luks1params));
145 luks1params.data_alignment = converted_data_alignment;
146 params = &luks1params;
147 } else if (strcmp(type, CRYPT_LUKS2) == 0) {
148 memset(&luks2params, 0, sizeof(luks2params));
149 luks2params.data_alignment = converted_data_alignment;
150 luks2params.sector_size = sector_size;
151 params = &luks2params;
152 }
153
154 // this mode should be used for testing only
155 if (insecure_fast_mode) {
156 struct crypt_pbkdf_type pbkdf;
157 memset(&pbkdf, 0, sizeof(pbkdf));
158 pbkdf.type = CRYPT_KDF_PBKDF2;
159 pbkdf.flags = CRYPT_PBKDF_NO_BENCHMARK;
160 pbkdf.hash = "sha256";
161 pbkdf.iterations = 1000;
162 pbkdf.time_ms = 1;
163 auto r = crypt_set_pbkdf_type(m_cd, &pbkdf);
164 if (r != 0) {
165 lderr(m_cct) << "crypt_set_pbkdf_type failed: " << cpp_strerror(r)
166 << dendl;
167 return r;
168 }
169 }
170
171 auto r = crypt_format(
172 m_cd, type, alg, cipher_mode, NULL, key, key_size, params);
173 if (r != 0) {
174 lderr(m_cct) << "crypt_format failed: " << cpp_strerror(r) << dendl;
175 return r;
176 }
177
178 return 0;
179}
180
181int Header::add_keyslot(const char* passphrase, size_t passphrase_size) {
182 ceph_assert(m_cd != nullptr);
183
184 auto r = crypt_keyslot_add_by_volume_key(
185 m_cd, CRYPT_ANY_SLOT, NULL, 0, passphrase, passphrase_size);
186 if (r != 0) {
187 lderr(m_cct) << "crypt_keyslot_add_by_volume_key failed: "
188 << cpp_strerror(r) << dendl;
189 return r;
190 }
191
192 return 0;
193}
194
195int Header::load(const char* type) {
196 ceph_assert(m_cd != nullptr);
197
198 // libcryptsetup checks if device size matches the header and keyslots size
199 // in LUKS2, 2 X 4MB header + 128MB keyslots
200 if (ftruncate(m_fd, 136 * 1024 * 1024) != 0) {
201 lderr(m_cct) << "failed to truncate anonymous file: "
202 << cpp_strerror(-errno) << dendl;
203 return -errno;
204 }
205
206 auto r = crypt_load(m_cd, type, NULL);
207 if (r != 0) {
208 lderr(m_cct) << "crypt_load failed: " << cpp_strerror(r) << dendl;
209 return r;
210 }
211
212 ldout(m_cct, 20) << "sector size: " << get_sector_size() << ", data offset: "
213 << get_data_offset() << dendl;
214
215 return 0;
216}
217
218int Header::read_volume_key(const char* passphrase, size_t passphrase_size,
219 char* volume_key, size_t* volume_key_size) {
220 ceph_assert(m_cd != nullptr);
221
222 auto r = crypt_volume_key_get(
223 m_cd, CRYPT_ANY_SLOT, volume_key, volume_key_size, passphrase,
224 passphrase_size);
225 if (r != 0) {
226 lderr(m_cct) << "crypt_volume_key_get failed: " << cpp_strerror(r)
227 << dendl;
228 return r;
229 }
230
231 return 0;
232}
233
234int Header::get_sector_size() {
235 ceph_assert(m_cd != nullptr);
236 return crypt_get_sector_size(m_cd);
237}
238
239uint64_t Header::get_data_offset() {
240 ceph_assert(m_cd != nullptr);
241 return crypt_get_data_offset(m_cd) << 9;
242}
243
244const char* Header::get_cipher() {
245 ceph_assert(m_cd != nullptr);
246 return crypt_get_cipher(m_cd);
247}
248
249const char* Header::get_cipher_mode() {
250 ceph_assert(m_cd != nullptr);
251 return crypt_get_cipher_mode(m_cd);
252}
253
254} // namespace luks
255} // namespace crypto
256} // namespace librbd