/src/cryptsetup/lib/luks2/hw_opal/hw_opal.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: LGPL-2.1-or-later |
2 | | /* |
3 | | * OPAL utilities |
4 | | * |
5 | | * Copyright (C) 2022-2023 Luca Boccassi <bluca@debian.org> |
6 | | * Copyright (C) 2023-2025 Ondrej Kozina <okozina@redhat.com> |
7 | | * Copyright (C) 2024-2025 Milan Broz |
8 | | */ |
9 | | |
10 | | #include <stdio.h> |
11 | | #include <stdlib.h> |
12 | | #include <stdint.h> |
13 | | #include <string.h> |
14 | | #include <unistd.h> |
15 | | #include <errno.h> |
16 | | #include <assert.h> |
17 | | #include <sys/ioctl.h> |
18 | | #include <sys/types.h> |
19 | | #include <sys/stat.h> |
20 | | #if HAVE_SYS_SYSMACROS_H |
21 | | # include <sys/sysmacros.h> /* for major, minor */ |
22 | | #endif |
23 | | |
24 | | #include "internal.h" |
25 | | #include "libcryptsetup.h" |
26 | | #include "luks2/hw_opal/hw_opal.h" |
27 | | #include "utils_device_locking.h" |
28 | | |
29 | | #if HAVE_HW_OPAL |
30 | | |
31 | | #include <linux/sed-opal.h> |
32 | | #include <linux/fs.h> |
33 | | |
34 | | /* Error codes are defined in the specification: |
35 | | * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 |
36 | | * Section 5.1.5: Method Status Codes |
37 | | * Names and values from table 166 */ |
38 | | typedef enum OpalStatus { |
39 | | OPAL_STATUS_SUCCESS = 0x00, |
40 | | OPAL_STATUS_NOT_AUTHORIZED = 0x01, |
41 | | OPAL_STATUS_OBSOLETE0 = 0x02, /* Undefined but possible return values are called 'obsolete' */ |
42 | | OPAL_STATUS_SP_BUSY = 0x03, |
43 | | OPAL_STATUS_SP_FAILED = 0x04, |
44 | | OPAL_STATUS_SP_DISABLED = 0x05, |
45 | | OPAL_STATUS_SP_FROZEN = 0x06, |
46 | | OPAL_STATUS_NO_SESSIONS_AVAILABLE = 0x07, |
47 | | OPAL_STATUS_UNIQUENESS_CONFLICT = 0x08, |
48 | | OPAL_STATUS_INSUFFICIENT_SPACE = 0x09, |
49 | | OPAL_STATUS_INSUFFICIENT_ROWS = 0x0a, |
50 | | OPAL_STATUS_OBSOLETE1 = 0x0b, /* Undefined but possible return values are called 'obsolete' */ |
51 | | OPAL_STATUS_INVALID_PARAMETER = 0x0c, |
52 | | OPAL_STATUS_OBSOLETE2 = 0x0d, |
53 | | OPAL_STATUS_OBSOLETE3 = 0x0e, |
54 | | OPAL_STATUS_TPER_MALFUNCTION = 0x0f, |
55 | | OPAL_STATUS_TRANSACTION_FAILURE = 0x10, |
56 | | OPAL_STATUS_RESPONSE_OVERFLOW = 0x11, |
57 | | OPAL_STATUS_AUTHORITY_LOCKED_OUT = 0x12, |
58 | | _OPAL_STATUS_MAX = 0x13, |
59 | | } OpalStatus; |
60 | | |
61 | | /* |
62 | | * Also defined in TCG Core spec Section 5.1.5 but |
63 | | * do not inflate the opal_status_table below |
64 | | */ |
65 | | #define OPAL_STATUS_FAIL 0x3f |
66 | | |
67 | | static const char* const opal_status_table[_OPAL_STATUS_MAX] = { |
68 | | [OPAL_STATUS_SUCCESS] = "success", |
69 | | [OPAL_STATUS_NOT_AUTHORIZED] = "not authorized", |
70 | | [OPAL_STATUS_OBSOLETE0] = "obsolete (0x02)", |
71 | | [OPAL_STATUS_SP_BUSY] = "SP busy", |
72 | | [OPAL_STATUS_SP_FAILED] = "SP failed", |
73 | | [OPAL_STATUS_SP_DISABLED] = "SP disabled", |
74 | | [OPAL_STATUS_SP_FROZEN] = "SP frozen", |
75 | | [OPAL_STATUS_NO_SESSIONS_AVAILABLE] = "no sessions available", |
76 | | [OPAL_STATUS_UNIQUENESS_CONFLICT] = "uniqueness conflict", |
77 | | [OPAL_STATUS_INSUFFICIENT_SPACE] = "insufficient space", |
78 | | [OPAL_STATUS_INSUFFICIENT_ROWS] = "insufficient rows", |
79 | | [OPAL_STATUS_OBSOLETE1] = "obsolete (0x0b)", |
80 | | [OPAL_STATUS_INVALID_PARAMETER] = "invalid parameter", |
81 | | [OPAL_STATUS_OBSOLETE2] = "obsolete (0x0d)", |
82 | | [OPAL_STATUS_OBSOLETE3] = "obsolete (0x0e)", |
83 | | [OPAL_STATUS_TPER_MALFUNCTION] = "TPer malfunction", |
84 | | [OPAL_STATUS_TRANSACTION_FAILURE] = "transaction failure", |
85 | | [OPAL_STATUS_RESPONSE_OVERFLOW] = "response overflow", |
86 | | [OPAL_STATUS_AUTHORITY_LOCKED_OUT] = "authority locked out", |
87 | | }; |
88 | | |
89 | | static const char *opal_status_to_string(int t) |
90 | | { |
91 | | if (t < 0) |
92 | | return strerror(-t); |
93 | | |
94 | | /* This will be checked upon 'Reactivate' method */ |
95 | | if (t == OPAL_STATUS_FAIL) |
96 | | return "FAIL status"; |
97 | | |
98 | | if (t >= _OPAL_STATUS_MAX) |
99 | | return "unknown error"; |
100 | | |
101 | | return opal_status_table[t]; |
102 | | } |
103 | | |
104 | | static const char *opal_ioctl_to_string(unsigned long rq) |
105 | | { |
106 | | switch(rq) { |
107 | | case IOC_OPAL_GET_STATUS: return "GET_STATUS"; |
108 | | case IOC_OPAL_GET_GEOMETRY: return "GET_GEOMETRY"; |
109 | | case IOC_OPAL_GET_LR_STATUS: return "GET_LR_STATUS"; |
110 | | case IOC_OPAL_TAKE_OWNERSHIP: return "TAKE_OWNERSHIP"; |
111 | | case IOC_OPAL_ACTIVATE_USR: return "ACTIVATE_USR"; |
112 | | case IOC_OPAL_ACTIVATE_LSP: return "ACTIVATE_LSP"; |
113 | | case IOC_OPAL_ERASE_LR: return "ERASE_LR"; |
114 | | case IOC_OPAL_SECURE_ERASE_LR: return "SECURE_ERASE_LR"; |
115 | | case IOC_OPAL_ADD_USR_TO_LR: return "ADD_USR_TO_LR"; |
116 | | case IOC_OPAL_SET_PW: return "SET_PW"; |
117 | | case IOC_OPAL_LR_SETUP: return "LR_SETUP"; |
118 | | case IOC_OPAL_LOCK_UNLOCK: return "LOCK_UNLOCK"; |
119 | | case IOC_OPAL_SAVE: return "SAVE"; |
120 | | case IOC_OPAL_PSID_REVERT_TPR: return "PSID_REVERT_TPR"; |
121 | | } |
122 | | |
123 | | assert(false && "unknown OPAL ioctl"); |
124 | | return NULL; |
125 | | } |
126 | | |
127 | | static void opal_ioctl_debug(struct crypt_device *cd, |
128 | | unsigned long rq, |
129 | | void *args, |
130 | | bool post, |
131 | | int ret) |
132 | | { |
133 | | const char *cmd = opal_ioctl_to_string(rq); |
134 | | |
135 | | if (ret) { |
136 | | log_dbg(cd, "OPAL %s failed: %s", cmd, opal_status_to_string(ret)); |
137 | | return; |
138 | | } |
139 | | |
140 | | if (post) switch(rq) { |
141 | | case IOC_OPAL_GET_STATUS: { /* OUT */ |
142 | | struct opal_status *st = args; |
143 | | log_dbg(cd, "OPAL %s: flags:%" PRIu32, cmd, st->flags); |
144 | | }; |
145 | | break; |
146 | | case IOC_OPAL_GET_GEOMETRY: { /* OUT */ |
147 | | struct opal_geometry *geo = args; |
148 | | log_dbg(cd, "OPAL %s: align:%" PRIu8 ", lb_size:%" PRIu32 ", gran:%" PRIu64 ", lowest_lba:%" PRIu64, |
149 | | cmd, geo->align, geo->logical_block_size, geo->alignment_granularity, geo->lowest_aligned_lba); |
150 | | }; |
151 | | break; |
152 | | case IOC_OPAL_GET_LR_STATUS: { /* OUT */ |
153 | | struct opal_lr_status *lrs = args; |
154 | | log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8 |
155 | | ", start:%" PRIu64 ", length:%" PRIu64 ", rle:%" PRIu32 ", rwe:%" PRIu32 ", state:%" PRIu32, |
156 | | cmd, lrs->session.sum, lrs->session.who, lrs->session.opal_key.lr, |
157 | | lrs->range_start, lrs->range_length, lrs->RLE, lrs->WLE, lrs->l_state); |
158 | | }; |
159 | | break; |
160 | | } else switch (rq) { |
161 | | case IOC_OPAL_TAKE_OWNERSHIP: { /* IN */ |
162 | | log_dbg(cd, "OPAL %s", cmd); |
163 | | }; |
164 | | break; |
165 | | case IOC_OPAL_ACTIVATE_USR: { /* IN */ |
166 | | struct opal_session_info *ui = args; |
167 | | log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8, |
168 | | cmd, ui->sum, ui->who, ui->opal_key.lr); |
169 | | }; |
170 | | break; |
171 | | case IOC_OPAL_ACTIVATE_LSP: { /* IN */ |
172 | | struct opal_lr_act *act = args; |
173 | | log_dbg(cd, "OPAL %s: k.lr:%" PRIu8 ", sum:%" PRIu32 ", num_lrs:%" PRIu8 ", lr:" |
174 | | "%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8"|%"PRIu8, |
175 | | cmd, act->key.lr, act->sum, act->num_lrs, |
176 | | act->lr[0], act->lr[1], act->lr[2], act->lr[3], act->lr[4], |
177 | | act->lr[5], act->lr[6], act->lr[7], act->lr[8]); |
178 | | }; |
179 | | break; |
180 | | case IOC_OPAL_ERASE_LR: { /* IN */ |
181 | | struct opal_session_info *ui = args; |
182 | | log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8, |
183 | | cmd, ui->sum, ui->who, ui->opal_key.lr); |
184 | | }; |
185 | | break; |
186 | | case IOC_OPAL_SECURE_ERASE_LR: { /* IN */ |
187 | | struct opal_session_info *ui = args; |
188 | | log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8, |
189 | | cmd, ui->sum, ui->who, ui->opal_key.lr); |
190 | | }; |
191 | | break; |
192 | | case IOC_OPAL_ADD_USR_TO_LR: { /* IN */ |
193 | | struct opal_lock_unlock *lu = args; |
194 | | log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8 |
195 | | ", l_state:%" PRIu32 ", flags:%" PRIu16, |
196 | | cmd, lu->session.sum, lu->session.who, lu->session.opal_key.lr, |
197 | | lu->l_state, lu->flags); |
198 | | }; |
199 | | break; |
200 | | case IOC_OPAL_SET_PW: { /* IN */ |
201 | | struct opal_new_pw *pw = args; |
202 | | log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8, |
203 | | cmd, pw->session.sum, pw->session.who, pw->session.opal_key.lr); |
204 | | }; |
205 | | break; |
206 | | case IOC_OPAL_LR_SETUP: { /* IN */ |
207 | | struct opal_user_lr_setup *lrs = args; |
208 | | log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8 |
209 | | ", start:%" PRIu64 ", length:%" PRIu64 ", rle:%" PRIu32 ", rwe:%" PRIu32, |
210 | | cmd, lrs->session.sum, lrs->session.who, lrs->session.opal_key.lr, |
211 | | lrs->range_start, lrs->range_length, lrs->RLE, lrs->WLE); |
212 | | }; |
213 | | break; |
214 | | case IOC_OPAL_LOCK_UNLOCK: { /* IN */ |
215 | | struct opal_lock_unlock *lu = args; |
216 | | log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8 |
217 | | ", l_state:%" PRIu32 ", flags:%" PRIu16, |
218 | | cmd, lu->session.sum, lu->session.who, lu->session.opal_key.lr, |
219 | | lu->l_state, lu->flags); |
220 | | }; |
221 | | break; |
222 | | case IOC_OPAL_SAVE: { /* IN */ |
223 | | struct opal_lock_unlock *lu = args; |
224 | | log_dbg(cd, "OPAL %s: sum:%" PRIu32 ", who:%" PRIu32 ", lr:%" PRIu8 |
225 | | ", l_state:%" PRIu32 ", flags:%" PRIu16, |
226 | | cmd, lu->session.sum, lu->session.who, lu->session.opal_key.lr, |
227 | | lu->l_state, lu->flags); |
228 | | }; |
229 | | break; |
230 | | case IOC_OPAL_PSID_REVERT_TPR: { /* IN */ |
231 | | struct opal_key *key = args; |
232 | | log_dbg(cd, "OPAL %s: lr:%" PRIu8, |
233 | | cmd, key->lr); |
234 | | }; |
235 | | break; |
236 | | } |
237 | | } |
238 | | |
239 | | static int opal_ioctl(struct crypt_device *cd, int fd, unsigned long rq, void *args) |
240 | | { |
241 | | int r; |
242 | | |
243 | | opal_ioctl_debug(cd, rq, args, false, 0); |
244 | | r = ioctl(fd, rq, args); |
245 | | if (r < 0) |
246 | | r = -errno; |
247 | | opal_ioctl_debug(cd, rq, args, true, r); |
248 | | |
249 | | return r; |
250 | | } |
251 | | |
252 | | static int opal_geometry_fd(struct crypt_device *cd, |
253 | | int fd, |
254 | | bool *ret_align, |
255 | | uint32_t *ret_block_size, |
256 | | uint64_t *ret_alignment_granularity_blocks, |
257 | | uint64_t *ret_lowest_lba_blocks) |
258 | | { |
259 | | int r; |
260 | | struct opal_geometry geo; |
261 | | |
262 | | assert(fd >= 0); |
263 | | |
264 | | r = opal_ioctl(cd, fd, IOC_OPAL_GET_GEOMETRY, &geo); |
265 | | if (r != OPAL_STATUS_SUCCESS) |
266 | | return r; |
267 | | |
268 | | if (ret_align) |
269 | | *ret_align = (geo.align == 1); |
270 | | if (ret_block_size) |
271 | | *ret_block_size = geo.logical_block_size; |
272 | | if (ret_alignment_granularity_blocks) |
273 | | *ret_alignment_granularity_blocks = geo.alignment_granularity; |
274 | | if (ret_lowest_lba_blocks) |
275 | | *ret_lowest_lba_blocks = geo.lowest_aligned_lba; |
276 | | |
277 | | return r; |
278 | | } |
279 | | |
280 | | static int opal_range_check_attributes_fd(struct crypt_device *cd, |
281 | | int fd, |
282 | | uint32_t segment_number, |
283 | | const struct volume_key *vk, |
284 | | const uint64_t *check_offset_sectors, |
285 | | const uint64_t *check_length_sectors, |
286 | | bool *check_read_locked, |
287 | | bool *check_write_locked, |
288 | | bool *ret_read_locked, |
289 | | bool *ret_write_locked) |
290 | | { |
291 | | int r; |
292 | | struct opal_lr_status *lrs; |
293 | | int device_block_bytes; |
294 | | uint32_t opal_block_bytes = 0; |
295 | | uint64_t offset, length; |
296 | | bool read_locked, write_locked; |
297 | | |
298 | | assert(fd >= 0); |
299 | | assert(cd); |
300 | | assert(vk); |
301 | | assert(check_offset_sectors); |
302 | | assert(check_length_sectors); |
303 | | |
304 | | r = opal_geometry_fd(cd, fd, NULL, &opal_block_bytes, NULL, NULL); |
305 | | if (r != OPAL_STATUS_SUCCESS) |
306 | | return -EINVAL; |
307 | | |
308 | | /* Keep this as warning only */ |
309 | | if (ioctl(fd, BLKSSZGET, &device_block_bytes) < 0 || |
310 | | (uint32_t)device_block_bytes != opal_block_bytes) |
311 | | log_err(cd, _("Bogus OPAL logical block size differs from device block size.")); |
312 | | |
313 | | lrs = crypt_safe_alloc(sizeof(*lrs)); |
314 | | if (!lrs) |
315 | | return -ENOMEM; |
316 | | |
317 | | *lrs = (struct opal_lr_status) { |
318 | | .session = { |
319 | | .who = segment_number + 1, |
320 | | .opal_key = { |
321 | | .key_len = crypt_volume_key_length(vk), |
322 | | .lr = segment_number |
323 | | } |
324 | | } |
325 | | }; |
326 | | crypt_safe_memcpy(lrs->session.opal_key.key, crypt_volume_key_get_key(vk), |
327 | | crypt_volume_key_length(vk)); |
328 | | |
329 | | r = opal_ioctl(cd, fd, IOC_OPAL_GET_LR_STATUS, lrs); |
330 | | if (r != OPAL_STATUS_SUCCESS) { |
331 | | log_dbg(cd, "Failed to get locking range status on device '%s'.", |
332 | | crypt_get_device_name(cd)); |
333 | | r = -EINVAL; |
334 | | goto out; |
335 | | } |
336 | | |
337 | | r = 0; |
338 | | |
339 | | offset = lrs->range_start * opal_block_bytes / SECTOR_SIZE; |
340 | | if (offset != *check_offset_sectors) { |
341 | | log_err(cd, _("OPAL range %d offset %" PRIu64 " does not match expected values %" PRIu64 "."), |
342 | | segment_number, offset, *check_offset_sectors); |
343 | | r = -EINVAL; |
344 | | } |
345 | | |
346 | | length = lrs->range_length * opal_block_bytes / SECTOR_SIZE; |
347 | | if (length != *check_length_sectors) { |
348 | | log_err(cd, _("OPAL range %d length %" PRIu64" does not match device length %" PRIu64 "."), |
349 | | segment_number, length, *check_length_sectors); |
350 | | r = -EINVAL; |
351 | | } |
352 | | |
353 | | if (!lrs->RLE || !lrs->WLE) { |
354 | | log_err(cd, _("OPAL range %d locking is disabled."), segment_number); |
355 | | r = -EINVAL; |
356 | | } |
357 | | |
358 | | read_locked = (lrs->l_state == OPAL_LK); |
359 | | write_locked = !!(lrs->l_state & (OPAL_RO | OPAL_LK)); |
360 | | |
361 | | if (check_read_locked && (read_locked != *check_read_locked)) { |
362 | | log_dbg(cd, "OPAL range %d read lock is %slocked.", |
363 | | segment_number, *check_read_locked ? "" : "not "); |
364 | | log_err(cd, _("Unexpected OPAL range %d lock state."), segment_number); |
365 | | r = -EINVAL; |
366 | | } |
367 | | |
368 | | if (check_write_locked && (write_locked != *check_write_locked)) { |
369 | | log_dbg(cd, "OPAL range %d write lock is %slocked.", |
370 | | segment_number, *check_write_locked ? "" : "not "); |
371 | | log_err(cd, _("Unexpected OPAL range %d lock state."), segment_number); |
372 | | r = -EINVAL; |
373 | | } |
374 | | |
375 | | if (ret_read_locked) |
376 | | *ret_read_locked = read_locked; |
377 | | if (ret_write_locked) |
378 | | *ret_write_locked = write_locked; |
379 | | out: |
380 | | crypt_safe_free(lrs); |
381 | | |
382 | | return r; |
383 | | } |
384 | | |
385 | | static int opal_query_status(struct crypt_device *cd, struct device *dev, unsigned expected) |
386 | | { |
387 | | struct opal_status st = { }; |
388 | | int fd, r; |
389 | | |
390 | | assert(cd); |
391 | | assert(dev); |
392 | | |
393 | | fd = device_open(cd, dev, O_RDONLY); |
394 | | if (fd < 0) |
395 | | return -EIO; |
396 | | |
397 | | r = opal_ioctl(cd, fd, IOC_OPAL_GET_STATUS, &st); |
398 | | |
399 | | return r < 0 ? -EINVAL : (st.flags & expected) ? 1 : 0; |
400 | | } |
401 | | |
402 | | static int opal_enabled(struct crypt_device *cd, struct device *dev) |
403 | | { |
404 | | return opal_query_status(cd, dev, OPAL_FL_LOCKING_ENABLED); |
405 | | } |
406 | | |
407 | | static int opal_activate_lsp(struct crypt_device *cd, int fd, |
408 | | const void *admin_key, size_t admin_key_len) |
409 | | { |
410 | | int r; |
411 | | struct opal_lr_act *activate = crypt_safe_alloc(sizeof(*activate)); |
412 | | |
413 | | if (!activate) |
414 | | return -ENOMEM; |
415 | | |
416 | | *activate = (struct opal_lr_act) { |
417 | | .key = { |
418 | | .key_len = admin_key_len, |
419 | | }, |
420 | | /* useless but due to kernel bug it requires (num_lrs > 0 && num_lrs <= 9) */ |
421 | | .num_lrs = 1, |
422 | | }; |
423 | | crypt_safe_memcpy(activate->key.key, admin_key, admin_key_len); |
424 | | |
425 | | r = opal_ioctl(cd, fd, IOC_OPAL_TAKE_OWNERSHIP, &activate->key); |
426 | | if (r < 0) { |
427 | | r = -ENOTSUP; |
428 | | log_dbg(cd, "OPAL not supported on this kernel version, refusing."); |
429 | | goto out; |
430 | | } |
431 | | if (r == OPAL_STATUS_NOT_AUTHORIZED) /* We'll try again with a different key. */ { |
432 | | r = -EPERM; |
433 | | log_dbg(cd, "Failed to take ownership of OPAL device '%s': permission denied", |
434 | | crypt_get_device_name(cd)); |
435 | | goto out; |
436 | | } |
437 | | if (r != OPAL_STATUS_SUCCESS) { |
438 | | log_dbg(cd, "Failed to take ownership of OPAL device '%s': %s", |
439 | | crypt_get_device_name(cd), opal_status_to_string(r)); |
440 | | r = -EINVAL; |
441 | | goto out; |
442 | | } |
443 | | |
444 | | r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_LSP, activate); |
445 | | if (r < 0) |
446 | | goto out; |
447 | | if (r != OPAL_STATUS_SUCCESS) { |
448 | | log_dbg(cd, "Failed to activate OPAL device '%s': %s", |
449 | | crypt_get_device_name(cd), opal_status_to_string(r)); |
450 | | r = -EINVAL; |
451 | | } |
452 | | out: |
453 | | crypt_safe_free(activate); |
454 | | |
455 | | return r; |
456 | | } |
457 | | |
458 | | static int opal_reuse_active_lsp(struct crypt_device *cd, int fd, |
459 | | uint32_t segment_number, |
460 | | const void *admin_key, size_t admin_key_len) |
461 | | { |
462 | | int r; |
463 | | struct opal_session_info *user_session = crypt_safe_alloc(sizeof(*user_session)); |
464 | | |
465 | | if (!user_session) |
466 | | return -ENOMEM; |
467 | | |
468 | | *user_session = (struct opal_session_info) { |
469 | | .who = OPAL_ADMIN1, /* irrelevant in SUM */ |
470 | | .opal_key = { |
471 | | .lr = segment_number, |
472 | | .key_len = admin_key_len, |
473 | | }, |
474 | | }; |
475 | | |
476 | | /* If it is already enabled, wipe the locking range first */ |
477 | | crypt_safe_memcpy(user_session->opal_key.key, admin_key, admin_key_len); |
478 | | |
479 | | r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session); |
480 | | if (r < 0) |
481 | | goto out; |
482 | | if (r != OPAL_STATUS_SUCCESS) { |
483 | | log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s", |
484 | | segment_number, crypt_get_device_name(cd), opal_status_to_string(r)); |
485 | | r = -EINVAL; |
486 | | } |
487 | | out: |
488 | | crypt_safe_free(user_session); |
489 | | |
490 | | return r; |
491 | | } |
492 | | |
493 | | static int opal_setup_range(struct crypt_device *cd, int fd, uint32_t segment_number, |
494 | | uint64_t range_start_blocks, uint64_t range_length_blocks, |
495 | | const void *admin_key, size_t admin_key_len) |
496 | | { |
497 | | int r; |
498 | | struct opal_user_lr_setup *setup = crypt_safe_alloc(sizeof(*setup)); |
499 | | |
500 | | if (!setup) |
501 | | return -ENOMEM; |
502 | | |
503 | | *setup = (struct opal_user_lr_setup) { |
504 | | .range_start = range_start_blocks, |
505 | | .range_length = range_length_blocks, |
506 | | /* Some drives do not enable Locking Ranges on setup. This have some |
507 | | * interesting consequences: Lock command called later below will pass, |
508 | | * but locking range will _not_ be locked at all. |
509 | | */ |
510 | | .RLE = 1, |
511 | | .WLE = 1, |
512 | | .session = { |
513 | | .who = OPAL_ADMIN1, |
514 | | .opal_key = { |
515 | | .key_len = admin_key_len, |
516 | | .lr = segment_number, |
517 | | }, |
518 | | }, |
519 | | }; |
520 | | crypt_safe_memcpy(setup->session.opal_key.key, admin_key, admin_key_len); |
521 | | |
522 | | r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup); |
523 | | if (r < 0) |
524 | | goto out; |
525 | | if (r != OPAL_STATUS_SUCCESS) { |
526 | | log_dbg(cd, "Failed to setup locking range of length %llu at offset %llu on OPAL device '%s': %s", |
527 | | setup->range_length, setup->range_start, crypt_get_device_name(cd), |
528 | | opal_status_to_string(r)); |
529 | | r = -EINVAL; |
530 | | } |
531 | | out: |
532 | | crypt_safe_free(setup); |
533 | | |
534 | | return r; |
535 | | } |
536 | | |
537 | | static int opal_setup_user(struct crypt_device *cd, int fd, uint32_t segment_number, |
538 | | const void *admin_key, size_t admin_key_len) |
539 | | { |
540 | | int r; |
541 | | struct opal_lock_unlock *user_add_to_lr = crypt_safe_alloc(sizeof(*user_add_to_lr)); |
542 | | |
543 | | if (!user_add_to_lr) |
544 | | return -ENOMEM; |
545 | | |
546 | | *user_add_to_lr = (struct opal_lock_unlock) { |
547 | | .session = { |
548 | | .who = segment_number + 1, |
549 | | .opal_key = { |
550 | | .lr = segment_number, |
551 | | .key_len = admin_key_len, |
552 | | }, |
553 | | }, |
554 | | .l_state = OPAL_RO, |
555 | | }; |
556 | | |
557 | | crypt_safe_memcpy(user_add_to_lr->session.opal_key.key, admin_key, admin_key_len); |
558 | | |
559 | | r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_USR, &user_add_to_lr->session); |
560 | | if (r < 0) |
561 | | goto out; |
562 | | if (r != OPAL_STATUS_SUCCESS) { |
563 | | log_dbg(cd, "Failed to activate OPAL user on device '%s': %s", |
564 | | crypt_get_device_name(cd), opal_status_to_string(r)); |
565 | | r = -EINVAL; |
566 | | goto out; |
567 | | } |
568 | | |
569 | | r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr); |
570 | | if (r < 0) |
571 | | goto out; |
572 | | if (r != OPAL_STATUS_SUCCESS) { |
573 | | log_dbg(cd, "Failed to add OPAL user to locking range %u (RO) on device '%s': %s", |
574 | | segment_number, crypt_get_device_name(cd), opal_status_to_string(r)); |
575 | | r = -EINVAL; |
576 | | goto out; |
577 | | } |
578 | | |
579 | | user_add_to_lr->l_state = OPAL_RW; |
580 | | |
581 | | r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr); |
582 | | if (r < 0) |
583 | | goto out; |
584 | | if (r != OPAL_STATUS_SUCCESS) { |
585 | | log_dbg(cd, "Failed to add OPAL user to locking range %u (RW) on device '%s': %s", |
586 | | segment_number, crypt_get_device_name(cd), opal_status_to_string(r)); |
587 | | r = -EINVAL; |
588 | | } |
589 | | out: |
590 | | crypt_safe_free(user_add_to_lr); |
591 | | |
592 | | return r; |
593 | | } |
594 | | |
595 | | /* requires opal lock */ |
596 | | int opal_setup_ranges(struct crypt_device *cd, |
597 | | struct device *dev, |
598 | | const struct volume_key *vk, |
599 | | uint64_t range_start_blocks, |
600 | | uint64_t range_length_blocks, |
601 | | uint32_t opal_block_bytes, |
602 | | uint32_t segment_number, |
603 | | const void *admin_key, |
604 | | size_t admin_key_len) |
605 | | { |
606 | | struct opal_lock_unlock *lock = NULL; |
607 | | struct opal_new_pw *new_pw = NULL; |
608 | | int r, fd; |
609 | | |
610 | | assert(cd); |
611 | | assert(dev); |
612 | | assert(vk); |
613 | | assert(admin_key); |
614 | | assert(crypt_volume_key_length(vk) <= OPAL_KEY_MAX); |
615 | | assert(opal_block_bytes >= SECTOR_SIZE); |
616 | | |
617 | | if (admin_key_len > OPAL_KEY_MAX) |
618 | | return -EINVAL; |
619 | | |
620 | | if (((UINT64_MAX / opal_block_bytes) < range_start_blocks) || |
621 | | ((UINT64_MAX / opal_block_bytes) < range_length_blocks)) |
622 | | return -EINVAL; |
623 | | |
624 | | fd = device_open(cd, dev, O_RDONLY); |
625 | | if (fd < 0) |
626 | | return -EIO; |
627 | | |
628 | | r = opal_enabled(cd, dev); |
629 | | if (r < 0) |
630 | | return r; |
631 | | |
632 | | /* If OPAL has never been enabled, we need to take ownership and do basic setup first */ |
633 | | if (r == 0) |
634 | | r = opal_activate_lsp(cd, fd, admin_key, admin_key_len); |
635 | | else |
636 | | r = opal_reuse_active_lsp(cd, fd, segment_number, admin_key, admin_key_len); |
637 | | if (r < 0) |
638 | | goto out; |
639 | | |
640 | | r = opal_setup_user(cd, fd, segment_number, admin_key, admin_key_len); |
641 | | if (r < 0) |
642 | | goto out; |
643 | | |
644 | | new_pw = crypt_safe_alloc(sizeof(struct opal_new_pw)); |
645 | | if (!new_pw) { |
646 | | r = -ENOMEM; |
647 | | goto out; |
648 | | } |
649 | | *new_pw = (struct opal_new_pw) { |
650 | | .session = { |
651 | | .who = OPAL_ADMIN1, |
652 | | .opal_key = { |
653 | | .lr = segment_number, |
654 | | .key_len = admin_key_len, |
655 | | }, |
656 | | }, |
657 | | .new_user_pw = { |
658 | | .who = segment_number + 1, |
659 | | .opal_key = { |
660 | | .key_len = crypt_volume_key_length(vk), |
661 | | .lr = segment_number, |
662 | | }, |
663 | | }, |
664 | | }; |
665 | | crypt_safe_memcpy(new_pw->new_user_pw.opal_key.key, crypt_volume_key_get_key(vk), |
666 | | crypt_volume_key_length(vk)); |
667 | | crypt_safe_memcpy(new_pw->session.opal_key.key, admin_key, admin_key_len); |
668 | | |
669 | | r = opal_ioctl(cd, fd, IOC_OPAL_SET_PW, new_pw); |
670 | | if (r < 0) |
671 | | goto out; |
672 | | if (r != OPAL_STATUS_SUCCESS) { |
673 | | log_dbg(cd, "Failed to set OPAL user password on device '%s': (%d) %s", |
674 | | crypt_get_device_name(cd), r, opal_status_to_string(r)); |
675 | | r = -EINVAL; |
676 | | goto out; |
677 | | } |
678 | | |
679 | | r = opal_setup_range(cd, fd, segment_number, range_start_blocks, range_length_blocks, |
680 | | admin_key, admin_key_len); |
681 | | if (r < 0) |
682 | | goto out; |
683 | | |
684 | | /* After setup an OPAL device is unlocked, but the expectation with cryptsetup is that it needs |
685 | | * to be activated separately, so lock it immediately. */ |
686 | | lock = crypt_safe_alloc(sizeof(struct opal_lock_unlock)); |
687 | | if (!lock) { |
688 | | r = -ENOMEM; |
689 | | goto out; |
690 | | } |
691 | | *lock = (struct opal_lock_unlock) { |
692 | | .l_state = OPAL_LK, |
693 | | .session = { |
694 | | .who = segment_number + 1, |
695 | | .opal_key = { |
696 | | .key_len = crypt_volume_key_length(vk), |
697 | | .lr = segment_number, |
698 | | }, |
699 | | } |
700 | | }; |
701 | | crypt_safe_memcpy(lock->session.opal_key.key, crypt_volume_key_get_key(vk), |
702 | | crypt_volume_key_length(vk)); |
703 | | |
704 | | r = opal_ioctl(cd, fd, IOC_OPAL_LOCK_UNLOCK, lock); |
705 | | if (r < 0) |
706 | | goto out; |
707 | | if (r != OPAL_STATUS_SUCCESS) { |
708 | | log_dbg(cd, "Failed to lock OPAL device '%s': %s", |
709 | | crypt_get_device_name(cd), opal_status_to_string(r)); |
710 | | r = -EINVAL; |
711 | | goto out; |
712 | | } |
713 | | |
714 | | /* Double check the locking range is locked and the ranges are set up as configured */ |
715 | | r = opal_range_check_attributes_fd(cd, fd, segment_number, vk, |
716 | | &(uint64_t) {range_start_blocks * opal_block_bytes / SECTOR_SIZE}, |
717 | | &(uint64_t) {range_length_blocks * opal_block_bytes / SECTOR_SIZE}, |
718 | | &(bool) {true}, &(bool){true}, NULL, NULL); |
719 | | out: |
720 | | crypt_safe_free(new_pw); |
721 | | crypt_safe_free(lock); |
722 | | |
723 | | return r; |
724 | | } |
725 | | |
726 | | static int opal_lock_unlock(struct crypt_device *cd, |
727 | | struct device *dev, |
728 | | uint32_t segment_number, |
729 | | const struct volume_key *vk, |
730 | | bool lock) |
731 | | { |
732 | | struct opal_lock_unlock unlock = { |
733 | | .l_state = lock ? OPAL_LK : OPAL_RW, |
734 | | .session = { |
735 | | .who = segment_number + 1, |
736 | | .opal_key = { |
737 | | .lr = segment_number, |
738 | | }, |
739 | | }, |
740 | | }; |
741 | | int r, fd; |
742 | | |
743 | | if (opal_supported(cd, dev) <= 0) |
744 | | return -ENOTSUP; |
745 | | if (!lock && !vk) |
746 | | return -EINVAL; |
747 | | |
748 | | fd = device_open(cd, dev, O_RDONLY); |
749 | | if (fd < 0) |
750 | | return -EIO; |
751 | | |
752 | | if (!lock) { |
753 | | assert(crypt_volume_key_length(vk) <= OPAL_KEY_MAX); |
754 | | |
755 | | unlock.session.opal_key.key_len = crypt_volume_key_length(vk); |
756 | | crypt_safe_memcpy(unlock.session.opal_key.key, crypt_volume_key_get_key(vk), |
757 | | crypt_volume_key_length(vk)); |
758 | | } |
759 | | |
760 | | r = opal_ioctl(cd, fd, IOC_OPAL_LOCK_UNLOCK, &unlock); |
761 | | if (r < 0) { |
762 | | r = -ENOTSUP; |
763 | | log_dbg(cd, "OPAL not supported on this kernel version, refusing."); |
764 | | goto out; |
765 | | } |
766 | | if (r == OPAL_STATUS_NOT_AUTHORIZED) /* We'll try again with a different key. */ { |
767 | | r = -EPERM; |
768 | | log_dbg(cd, "Failed to %slock OPAL device '%s': permission denied", |
769 | | lock ? "" : "un", crypt_get_device_name(cd)); |
770 | | goto out; |
771 | | } |
772 | | if (r != OPAL_STATUS_SUCCESS) { |
773 | | log_dbg(cd, "Failed to %slock OPAL device '%s': %s", |
774 | | lock ? "" : "un", crypt_get_device_name(cd), opal_status_to_string(r)); |
775 | | r = -EINVAL; |
776 | | goto out; |
777 | | } |
778 | | |
779 | | /* If we are unlocking, also tell the kernel to automatically unlock when resuming |
780 | | * from suspend, otherwise the drive will be locked and everything will go up in flames. |
781 | | * Also set the flag to allow locking without having to pass the key again. |
782 | | * But do not error out if this fails, as the device will already be unlocked. |
783 | | * |
784 | | * On a lock path we have to overwrite the cached key from kernel otherwise the locking range |
785 | | * gets unlocked automatically after system resume even when cryptsetup previously locked it |
786 | | * on purpose (crypt_deactivate* or crypt_suspend) |
787 | | */ |
788 | | if (!lock) |
789 | | unlock.flags = OPAL_SAVE_FOR_LOCK; |
790 | | |
791 | | r = opal_ioctl(cd, fd, IOC_OPAL_SAVE, &unlock); |
792 | | if (r < 0) |
793 | | goto out; |
794 | | if (r != OPAL_STATUS_SUCCESS) { |
795 | | if (!lock) |
796 | | log_std(cd, "Failed to prepare OPAL device '%s' for sleep resume, be aware before suspending: %s", |
797 | | crypt_get_device_name(cd), opal_status_to_string(r)); |
798 | | else |
799 | | log_std(cd, "Failed to erase OPAL key for device '%s' from kernel: %s", |
800 | | crypt_get_device_name(cd), opal_status_to_string(r)); |
801 | | r = 0; |
802 | | } |
803 | | out: |
804 | | if (!lock) |
805 | | crypt_safe_memzero(unlock.session.opal_key.key, unlock.session.opal_key.key_len); |
806 | | |
807 | | return r; |
808 | | } |
809 | | |
810 | | /* requires opal lock */ |
811 | | int opal_lock(struct crypt_device *cd, struct device *dev, uint32_t segment_number) |
812 | | { |
813 | | return opal_lock_unlock(cd, dev, segment_number, NULL, /* lock= */ true); |
814 | | } |
815 | | |
816 | | /* requires opal lock */ |
817 | | int opal_unlock(struct crypt_device *cd, |
818 | | struct device *dev, |
819 | | uint32_t segment_number, |
820 | | const struct volume_key *vk) |
821 | | { |
822 | | return opal_lock_unlock(cd, dev, segment_number, vk, /* lock= */ false); |
823 | | } |
824 | | |
825 | | /* |
826 | | * It does not require opal lock. This completely destroys |
827 | | * data on whole OPAL block device. Serialization does not |
828 | | * make sense here. |
829 | | */ |
830 | | int opal_factory_reset(struct crypt_device *cd, |
831 | | struct device *dev, |
832 | | const char *password, |
833 | | size_t password_len) |
834 | | { |
835 | | struct opal_key reset = { |
836 | | .key_len = password_len, |
837 | | }; |
838 | | int r, fd; |
839 | | |
840 | | assert(cd); |
841 | | assert(dev); |
842 | | assert(password); |
843 | | |
844 | | if (password_len > OPAL_KEY_MAX) |
845 | | return -EINVAL; |
846 | | |
847 | | /* |
848 | | * Submit PSID reset on R/W file descriptor so it |
849 | | * triggers blkid rescan after we close it. |
850 | | */ |
851 | | fd = device_open(cd, dev, O_RDWR); |
852 | | if (fd < 0) |
853 | | return -EIO; |
854 | | |
855 | | crypt_safe_memcpy(reset.key, password, password_len); |
856 | | |
857 | | r = opal_ioctl(cd, fd, IOC_OPAL_PSID_REVERT_TPR, &reset); |
858 | | if (r < 0) { |
859 | | r = -ENOTSUP; |
860 | | log_dbg(cd, "OPAL not supported on this kernel version, refusing."); |
861 | | goto out; |
862 | | } |
863 | | if (r == OPAL_STATUS_NOT_AUTHORIZED) /* We'll try again with a different key. */ { |
864 | | r = -EPERM; |
865 | | log_dbg(cd, "Failed to reset OPAL device '%s', incorrect PSID?", |
866 | | crypt_get_device_name(cd)); |
867 | | goto out; |
868 | | } |
869 | | if (r != OPAL_STATUS_SUCCESS) { |
870 | | r = -EINVAL; |
871 | | log_dbg(cd, "Failed to reset OPAL device '%s' with PSID: %s", |
872 | | crypt_get_device_name(cd), opal_status_to_string(r)); |
873 | | goto out; |
874 | | } |
875 | | out: |
876 | | crypt_safe_memzero(reset.key, reset.key_len); |
877 | | |
878 | | return r; |
879 | | } |
880 | | |
881 | | /* requires opal lock */ |
882 | | int opal_reset_segment(struct crypt_device *cd, |
883 | | struct device *dev, |
884 | | uint32_t segment_number, |
885 | | const char *password, |
886 | | size_t password_len) |
887 | | { |
888 | | struct opal_session_info *user_session = NULL; |
889 | | struct opal_user_lr_setup *setup = NULL; |
890 | | int r, fd; |
891 | | |
892 | | assert(cd); |
893 | | assert(dev); |
894 | | assert(password); |
895 | | |
896 | | if (password_len > OPAL_KEY_MAX) |
897 | | return -EINVAL; |
898 | | |
899 | | if (opal_enabled(cd, dev) <= 0) |
900 | | return -EINVAL; |
901 | | |
902 | | user_session = crypt_safe_alloc(sizeof(struct opal_session_info)); |
903 | | if (!user_session) |
904 | | return -ENOMEM; |
905 | | *user_session = (struct opal_session_info) { |
906 | | .who = OPAL_ADMIN1, |
907 | | .opal_key = { |
908 | | .lr = segment_number, |
909 | | .key_len = password_len, |
910 | | }, |
911 | | }; |
912 | | crypt_safe_memcpy(user_session->opal_key.key, password, password_len); |
913 | | |
914 | | fd = device_open(cd, dev, O_RDONLY); |
915 | | if (fd < 0) { |
916 | | r = -EIO; |
917 | | goto out; |
918 | | } |
919 | | |
920 | | r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session); |
921 | | if (r < 0) |
922 | | goto out; |
923 | | if (r != OPAL_STATUS_SUCCESS) { |
924 | | log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s", |
925 | | segment_number, crypt_get_device_name(cd), opal_status_to_string(r)); |
926 | | r = -EINVAL; |
927 | | goto out; |
928 | | } |
929 | | |
930 | | /* Disable the locking range */ |
931 | | setup = crypt_safe_alloc(sizeof(struct opal_user_lr_setup)); |
932 | | if (!setup) { |
933 | | r = -ENOMEM; |
934 | | goto out; |
935 | | } |
936 | | *setup = (struct opal_user_lr_setup) { |
937 | | .range_start = 0, |
938 | | .range_length = 0, |
939 | | .session = { |
940 | | .who = OPAL_ADMIN1, |
941 | | .opal_key = user_session->opal_key, |
942 | | }, |
943 | | }; |
944 | | |
945 | | r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup); |
946 | | if (r < 0) |
947 | | goto out; |
948 | | if (r != OPAL_STATUS_SUCCESS) { |
949 | | log_dbg(cd, "Failed to disable locking range on OPAL device '%s': %s", |
950 | | crypt_get_device_name(cd), opal_status_to_string(r)); |
951 | | r = -EINVAL; |
952 | | goto out; |
953 | | } |
954 | | out: |
955 | | crypt_safe_free(user_session); |
956 | | crypt_safe_free(setup); |
957 | | |
958 | | return r; |
959 | | } |
960 | | |
961 | | /* |
962 | | * Does not require opal lock (immutable). |
963 | | */ |
964 | | int opal_supported(struct crypt_device *cd, struct device *dev) |
965 | | { |
966 | | return opal_query_status(cd, dev, OPAL_FL_SUPPORTED|OPAL_FL_LOCKING_SUPPORTED); |
967 | | } |
968 | | |
969 | | /* |
970 | | * Does not require opal lock (immutable). |
971 | | */ |
972 | | int opal_geometry(struct crypt_device *cd, |
973 | | struct device *dev, |
974 | | bool *ret_align, |
975 | | uint32_t *ret_block_size, |
976 | | uint64_t *ret_alignment_granularity_blocks, |
977 | | uint64_t *ret_lowest_lba_blocks) |
978 | | { |
979 | | int fd; |
980 | | |
981 | | assert(cd); |
982 | | assert(dev); |
983 | | |
984 | | fd = device_open(cd, dev, O_RDONLY); |
985 | | if (fd < 0) |
986 | | return -EIO; |
987 | | |
988 | | return opal_geometry_fd(cd, fd, ret_align, ret_block_size, |
989 | | ret_alignment_granularity_blocks, ret_lowest_lba_blocks); |
990 | | } |
991 | | |
992 | | /* requires opal lock */ |
993 | | int opal_range_check_attributes_and_get_lock_state(struct crypt_device *cd, |
994 | | struct device *dev, |
995 | | uint32_t segment_number, |
996 | | const struct volume_key *vk, |
997 | | const uint64_t *check_offset_sectors, |
998 | | const uint64_t *check_length_sectors, |
999 | | bool *ret_read_locked, |
1000 | | bool *ret_write_locked) |
1001 | | { |
1002 | | int fd; |
1003 | | |
1004 | | assert(cd); |
1005 | | assert(dev); |
1006 | | assert(vk); |
1007 | | |
1008 | | fd = device_open(cd, dev, O_RDONLY); |
1009 | | if (fd < 0) |
1010 | | return -EIO; |
1011 | | |
1012 | | return opal_range_check_attributes_fd(cd, fd, segment_number, vk, |
1013 | | check_offset_sectors, check_length_sectors, NULL, |
1014 | | NULL, ret_read_locked, ret_write_locked); |
1015 | | } |
1016 | | |
1017 | | static int opal_lock_internal(struct crypt_device *cd, struct device *opal_device, struct crypt_lock_handle **opal_lock) |
1018 | | { |
1019 | | char *lock_resource; |
1020 | | int devfd, r; |
1021 | | struct stat st; |
1022 | | |
1023 | | if (!crypt_metadata_locking_enabled()) { |
1024 | | *opal_lock = NULL; |
1025 | | return 0; |
1026 | | } |
1027 | | |
1028 | | /* |
1029 | | * This also asserts we do not hold any metadata lock on the same device to |
1030 | | * avoid deadlock (OPAL lock must be taken first) |
1031 | | */ |
1032 | | devfd = device_open(cd, opal_device, O_RDONLY); |
1033 | | if (devfd < 0) |
1034 | | return -EINVAL; |
1035 | | |
1036 | | if (fstat(devfd, &st) || !S_ISBLK(st.st_mode)) |
1037 | | return -EINVAL; |
1038 | | |
1039 | | r = asprintf(&lock_resource, "OPAL_%d:%d", major(st.st_rdev), minor(st.st_rdev)); |
1040 | | if (r < 0) |
1041 | | return -ENOMEM; |
1042 | | |
1043 | | r = crypt_write_lock(cd, lock_resource, true, opal_lock); |
1044 | | |
1045 | | free(lock_resource); |
1046 | | |
1047 | | return r; |
1048 | | } |
1049 | | |
1050 | | int opal_exclusive_lock(struct crypt_device *cd, struct device *opal_device, struct crypt_lock_handle **opal_lock) |
1051 | | { |
1052 | | if (!cd || !opal_device || (crypt_get_type(cd) && strcmp(crypt_get_type(cd), CRYPT_LUKS2))) |
1053 | | return -EINVAL; |
1054 | | |
1055 | | return opal_lock_internal(cd, opal_device, opal_lock); |
1056 | | } |
1057 | | |
1058 | | void opal_exclusive_unlock(struct crypt_device *cd, struct crypt_lock_handle *opal_lock) |
1059 | | { |
1060 | | crypt_unlock_internal(cd, opal_lock); |
1061 | | } |
1062 | | |
1063 | | #else |
1064 | | #pragma GCC diagnostic ignored "-Wunused-parameter" |
1065 | | |
1066 | | int opal_setup_ranges(struct crypt_device *cd, |
1067 | | struct device *dev, |
1068 | | const struct volume_key *vk, |
1069 | | uint64_t range_start_blocks, |
1070 | | uint64_t range_length_blocks, |
1071 | | uint32_t opal_block_bytes, |
1072 | | uint32_t segment_number, |
1073 | | const void *admin_key, |
1074 | | size_t admin_key_len) |
1075 | 0 | { |
1076 | 0 | return -ENOTSUP; |
1077 | 0 | } |
1078 | | |
1079 | | int opal_lock(struct crypt_device *cd, struct device *dev, uint32_t segment_number) |
1080 | 0 | { |
1081 | 0 | return -ENOTSUP; |
1082 | 0 | } |
1083 | | |
1084 | | int opal_unlock(struct crypt_device *cd, |
1085 | | struct device *dev, |
1086 | | uint32_t segment_number, |
1087 | | const struct volume_key *vk) |
1088 | 0 | { |
1089 | 0 | return -ENOTSUP; |
1090 | 0 | } |
1091 | | |
1092 | | int opal_supported(struct crypt_device *cd, struct device *dev) |
1093 | 0 | { |
1094 | 0 | return -ENOTSUP; |
1095 | 0 | } |
1096 | | |
1097 | | int opal_factory_reset(struct crypt_device *cd, |
1098 | | struct device *dev, |
1099 | | const char *password, |
1100 | | size_t password_len) |
1101 | 0 | { |
1102 | 0 | return -ENOTSUP; |
1103 | 0 | } |
1104 | | |
1105 | | int opal_reset_segment(struct crypt_device *cd, |
1106 | | struct device *dev, |
1107 | | uint32_t segment_number, |
1108 | | const char *password, |
1109 | | size_t password_len) |
1110 | 0 | { |
1111 | 0 | return -ENOTSUP; |
1112 | 0 | } |
1113 | | |
1114 | | int opal_geometry(struct crypt_device *cd, |
1115 | | struct device *dev, |
1116 | | bool *ret_align, |
1117 | | uint32_t *ret_block_size, |
1118 | | uint64_t *ret_alignment_granularity_blocks, |
1119 | | uint64_t *ret_lowest_lba_blocks) |
1120 | 0 | { |
1121 | 0 | return -ENOTSUP; |
1122 | 0 | } |
1123 | | |
1124 | | int opal_range_check_attributes_and_get_lock_state(struct crypt_device *cd, |
1125 | | struct device *dev, |
1126 | | uint32_t segment_number, |
1127 | | const struct volume_key *vk, |
1128 | | const uint64_t *check_offset_sectors, |
1129 | | const uint64_t *check_length_sectors, |
1130 | | bool *ret_read_locked, |
1131 | | bool *ret_write_locked) |
1132 | 0 | { |
1133 | 0 | return -ENOTSUP; |
1134 | 0 | } |
1135 | | |
1136 | | int opal_exclusive_lock(struct crypt_device *cd, struct device *opal_device, struct crypt_lock_handle **opal_lock) |
1137 | 0 | { |
1138 | 0 | return -ENOTSUP; |
1139 | 0 | } |
1140 | | |
1141 | | void opal_exclusive_unlock(struct crypt_device *cd, struct crypt_lock_handle *opal_lock) |
1142 | 0 | { |
1143 | 0 | } |
1144 | | |
1145 | | #endif |