]>
Commit | Line | Data |
---|---|---|
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 | ||
18 | namespace librbd { | |
19 | namespace crypto { | |
20 | namespace luks { | |
21 | ||
22 | Header::Header(CephContext* cct) : m_cct(cct), m_fd(-1), m_cd(nullptr) { | |
23 | } | |
24 | ||
25 | Header::~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 | ||
36 | void Header::libcryptsetup_log_wrapper(int level, const char* msg, void* header) { | |
37 | ((Header*)header)->libcryptsetup_log(level, msg); | |
38 | } | |
39 | ||
40 | void 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 | ||
57 | int 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 | ||
85 | int 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 | ||
95 | ssize_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 | ||
117 | int 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 | ||
181 | int 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 | ||
195 | int 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 | ||
218 | int 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 | ||
234 | int Header::get_sector_size() { | |
235 | ceph_assert(m_cd != nullptr); | |
236 | return crypt_get_sector_size(m_cd); | |
237 | } | |
238 | ||
239 | uint64_t Header::get_data_offset() { | |
240 | ceph_assert(m_cd != nullptr); | |
241 | return crypt_get_data_offset(m_cd) << 9; | |
242 | } | |
243 | ||
244 | const char* Header::get_cipher() { | |
245 | ceph_assert(m_cd != nullptr); | |
246 | return crypt_get_cipher(m_cd); | |
247 | } | |
248 | ||
249 | const 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 |