Blame view
drivers/nvdimm/security.c
13.9 KB
4c6926a23 acpi/nfit, libnvd... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2018 Intel Corporation. All rights reserved. */ #include <linux/module.h> #include <linux/device.h> #include <linux/ndctl.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/mm.h> #include <linux/cred.h> #include <linux/key.h> #include <linux/key-type.h> #include <keys/user-type.h> #include <keys/encrypted-type.h> #include "nd-core.h" #include "nd.h" |
d2a4ac73f acpi/nfit, libnvd... |
17 18 |
#define NVDIMM_BASE_KEY 0 #define NVDIMM_NEW_KEY 1 |
4c6926a23 acpi/nfit, libnvd... |
19 20 21 |
static bool key_revalidate = true; module_param(key_revalidate, bool, 0444); MODULE_PARM_DESC(key_revalidate, "Require key validation at init."); |
037c8489a libnvdimm/securit... |
22 |
static const char zero_key[NVDIMM_PASSPHRASE_LEN]; |
4c6926a23 acpi/nfit, libnvd... |
23 24 25 26 27 28 29 30 31 32 33 |
static void *key_data(struct key *key) { struct encrypted_key_payload *epayload = dereference_key_locked(key); lockdep_assert_held_read(&key->sem); return epayload->decrypted_data; } static void nvdimm_put_key(struct key *key) { |
64e77c8c0 acpi/nfit, libnvd... |
34 35 |
if (!key) return; |
4c6926a23 acpi/nfit, libnvd... |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
up_read(&key->sem); key_put(key); } /* * Retrieve kernel key for DIMM and request from user space if * necessary. Returns a key held for read and must be put by * nvdimm_put_key() before the usage goes out of scope. */ static struct key *nvdimm_request_key(struct nvdimm *nvdimm) { struct key *key = NULL; static const char NVDIMM_PREFIX[] = "nvdimm:"; char desc[NVDIMM_KEY_DESC_LEN + sizeof(NVDIMM_PREFIX)]; struct device *dev = &nvdimm->dev; sprintf(desc, "%s%s", NVDIMM_PREFIX, nvdimm->dimm_id); |
028db3e29 Revert "Merge tag... |
53 |
key = request_key(&key_type_encrypted, desc, ""); |
4c6926a23 acpi/nfit, libnvd... |
54 55 |
if (IS_ERR(key)) { if (PTR_ERR(key) == -ENOKEY) |
37379cfc6 libnvdimm/securit... |
56 57 |
dev_dbg(dev, "request_key() found no key "); |
4c6926a23 acpi/nfit, libnvd... |
58 |
else |
37379cfc6 libnvdimm/securit... |
59 60 |
dev_dbg(dev, "request_key() upcall failed "); |
4c6926a23 acpi/nfit, libnvd... |
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
key = NULL; } else { struct encrypted_key_payload *epayload; down_read(&key->sem); epayload = dereference_key_locked(key); if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { up_read(&key->sem); key_put(key); key = NULL; } } return key; } |
d2e5b6436 libnvdimm/securit... |
76 77 78 79 80 81 82 83 84 |
static const void *nvdimm_get_key_payload(struct nvdimm *nvdimm, struct key **key) { *key = nvdimm_request_key(nvdimm); if (!*key) return zero_key; return key_data(*key); } |
03b65b22a acpi/nfit, libnvd... |
85 |
static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, |
d2a4ac73f acpi/nfit, libnvd... |
86 |
key_serial_t id, int subclass) |
03b65b22a acpi/nfit, libnvd... |
87 88 89 90 91 |
{ key_ref_t keyref; struct key *key; struct encrypted_key_payload *epayload; struct device *dev = &nvdimm->dev; |
813357fea libnvdimm/securit... |
92 |
keyref = lookup_user_key(id, 0, KEY_NEED_SEARCH); |
03b65b22a acpi/nfit, libnvd... |
93 94 95 96 97 98 99 100 |
if (IS_ERR(keyref)) return NULL; key = key_ref_to_ptr(keyref); if (key->type != &key_type_encrypted) { key_put(key); return NULL; } |
03b65b22a acpi/nfit, libnvd... |
101 |
|
d2a4ac73f acpi/nfit, libnvd... |
102 103 |
dev_dbg(dev, "%s: key found: %#x ", __func__, key_serial(key)); |
03b65b22a acpi/nfit, libnvd... |
104 |
|
d2a4ac73f acpi/nfit, libnvd... |
105 |
down_read_nested(&key->sem, subclass); |
03b65b22a acpi/nfit, libnvd... |
106 107 108 109 110 111 112 113 |
epayload = dereference_key_locked(key); if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { up_read(&key->sem); key_put(key); key = NULL; } return key; } |
d2e5b6436 libnvdimm/securit... |
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
static const void *nvdimm_get_user_key_payload(struct nvdimm *nvdimm, key_serial_t id, int subclass, struct key **key) { *key = NULL; if (id == 0) { if (subclass == NVDIMM_BASE_KEY) return zero_key; else return NULL; } *key = nvdimm_lookup_user_key(nvdimm, id, subclass); if (!*key) return NULL; return key_data(*key); } static int nvdimm_key_revalidate(struct nvdimm *nvdimm) |
4c6926a23 acpi/nfit, libnvd... |
134 135 136 |
{ struct key *key; int rc; |
d2e5b6436 libnvdimm/securit... |
137 |
const void *data; |
4c6926a23 acpi/nfit, libnvd... |
138 139 |
if (!nvdimm->sec.ops->change_key) |
d2e5b6436 libnvdimm/securit... |
140 |
return -EOPNOTSUPP; |
4c6926a23 acpi/nfit, libnvd... |
141 |
|
d2e5b6436 libnvdimm/securit... |
142 |
data = nvdimm_get_key_payload(nvdimm, &key); |
4c6926a23 acpi/nfit, libnvd... |
143 144 145 146 147 |
/* * Send the same key to the hardware as new and old key to * verify that the key is good. */ |
d2e5b6436 libnvdimm/securit... |
148 |
rc = nvdimm->sec.ops->change_key(nvdimm, data, data, NVDIMM_USER); |
4c6926a23 acpi/nfit, libnvd... |
149 150 |
if (rc < 0) { nvdimm_put_key(key); |
d2e5b6436 libnvdimm/securit... |
151 |
return rc; |
4c6926a23 acpi/nfit, libnvd... |
152 |
} |
d2e5b6436 libnvdimm/securit... |
153 154 |
nvdimm_put_key(key); |
d78c620a2 libnvdimm/securit... |
155 |
nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
d2e5b6436 libnvdimm/securit... |
156 |
return 0; |
4c6926a23 acpi/nfit, libnvd... |
157 158 159 160 161 162 |
} static int __nvdimm_security_unlock(struct nvdimm *nvdimm) { struct device *dev = &nvdimm->dev; struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); |
d2e5b6436 libnvdimm/securit... |
163 164 |
struct key *key; const void *data; |
4c6926a23 acpi/nfit, libnvd... |
165 166 167 168 169 170 |
int rc; /* The bus lock should be held at the top level of the call stack */ lockdep_assert_held(&nvdimm_bus->reconfig_mutex); if (!nvdimm->sec.ops || !nvdimm->sec.ops->unlock |
d78c620a2 libnvdimm/securit... |
171 |
|| !nvdimm->sec.flags) |
4c6926a23 acpi/nfit, libnvd... |
172 |
return -EIO; |
674f31a35 libnvdimm: preven... |
173 174 175 |
/* No need to go further if security is disabled */ if (test_bit(NVDIMM_SECURITY_DISABLED, &nvdimm->sec.flags)) return 0; |
7d988097c acpi/nfit, libnvd... |
176 |
if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { |
37379cfc6 libnvdimm/securit... |
177 178 |
dev_dbg(dev, "Security operation in progress. "); |
7d988097c acpi/nfit, libnvd... |
179 180 |
return -EBUSY; } |
4c6926a23 acpi/nfit, libnvd... |
181 182 183 184 185 186 187 |
/* * If the pre-OS has unlocked the DIMM, attempt to send the key * from request_key() to the hardware for verification. Failure * to revalidate the key against the hardware results in a * freeze of the security configuration. I.e. if the OS does not * have the key, security is being managed pre-OS. */ |
d78c620a2 libnvdimm/securit... |
188 |
if (test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.flags)) { |
4c6926a23 acpi/nfit, libnvd... |
189 190 |
if (!key_revalidate) return 0; |
d2e5b6436 libnvdimm/securit... |
191 |
return nvdimm_key_revalidate(nvdimm); |
4c6926a23 acpi/nfit, libnvd... |
192 |
} else |
d2e5b6436 libnvdimm/securit... |
193 |
data = nvdimm_get_key_payload(nvdimm, &key); |
4c6926a23 acpi/nfit, libnvd... |
194 |
|
d2e5b6436 libnvdimm/securit... |
195 |
rc = nvdimm->sec.ops->unlock(nvdimm, data); |
4c6926a23 acpi/nfit, libnvd... |
196 197 198 199 200 |
dev_dbg(dev, "key: %d unlock: %s ", key_serial(key), rc == 0 ? "success" : "fail"); nvdimm_put_key(key); |
d78c620a2 libnvdimm/securit... |
201 |
nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
4c6926a23 acpi/nfit, libnvd... |
202 203 204 205 206 207 208 209 210 211 212 213 214 |
return rc; } int nvdimm_security_unlock(struct device *dev) { struct nvdimm *nvdimm = to_nvdimm(dev); int rc; nvdimm_bus_lock(dev); rc = __nvdimm_security_unlock(nvdimm); nvdimm_bus_unlock(dev); return rc; } |
03b65b22a acpi/nfit, libnvd... |
215 |
|
d78c620a2 libnvdimm/securit... |
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
static int check_security_state(struct nvdimm *nvdimm) { struct device *dev = &nvdimm->dev; if (test_bit(NVDIMM_SECURITY_FROZEN, &nvdimm->sec.flags)) { dev_dbg(dev, "Incorrect security state: %#lx ", nvdimm->sec.flags); return -EIO; } if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { dev_dbg(dev, "Security operation in progress. "); return -EBUSY; } return 0; } |
7b60422cb libnvdimm/securit... |
235 |
static int security_disable(struct nvdimm *nvdimm, unsigned int keyid) |
03b65b22a acpi/nfit, libnvd... |
236 237 238 239 240 |
{ struct device *dev = &nvdimm->dev; struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); struct key *key; int rc; |
d2e5b6436 libnvdimm/securit... |
241 |
const void *data; |
03b65b22a acpi/nfit, libnvd... |
242 243 244 245 246 |
/* The bus lock should be held at the top level of the call stack */ lockdep_assert_held(&nvdimm_bus->reconfig_mutex); if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable |
d78c620a2 libnvdimm/securit... |
247 |
|| !nvdimm->sec.flags) |
03b65b22a acpi/nfit, libnvd... |
248 |
return -EOPNOTSUPP; |
d78c620a2 libnvdimm/securit... |
249 250 251 |
rc = check_security_state(nvdimm); if (rc) return rc; |
7d988097c acpi/nfit, libnvd... |
252 |
|
d2e5b6436 libnvdimm/securit... |
253 254 255 |
data = nvdimm_get_user_key_payload(nvdimm, keyid, NVDIMM_BASE_KEY, &key); if (!data) |
03b65b22a acpi/nfit, libnvd... |
256 |
return -ENOKEY; |
d2e5b6436 libnvdimm/securit... |
257 |
rc = nvdimm->sec.ops->disable(nvdimm, data); |
03b65b22a acpi/nfit, libnvd... |
258 259 260 261 262 |
dev_dbg(dev, "key: %d disable: %s ", key_serial(key), rc == 0 ? "success" : "fail"); nvdimm_put_key(key); |
d78c620a2 libnvdimm/securit... |
263 |
nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
03b65b22a acpi/nfit, libnvd... |
264 265 |
return rc; } |
d2a4ac73f acpi/nfit, libnvd... |
266 |
|
7b60422cb libnvdimm/securit... |
267 |
static int security_update(struct nvdimm *nvdimm, unsigned int keyid, |
89fa9d8ea acpi/nfit, libnvd... |
268 269 |
unsigned int new_keyid, enum nvdimm_passphrase_type pass_type) |
d2a4ac73f acpi/nfit, libnvd... |
270 271 272 273 274 |
{ struct device *dev = &nvdimm->dev; struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); struct key *key, *newkey; int rc; |
d2e5b6436 libnvdimm/securit... |
275 |
const void *data, *newdata; |
d2a4ac73f acpi/nfit, libnvd... |
276 277 278 279 280 |
/* The bus lock should be held at the top level of the call stack */ lockdep_assert_held(&nvdimm_bus->reconfig_mutex); if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key |
d78c620a2 libnvdimm/securit... |
281 |
|| !nvdimm->sec.flags) |
d2a4ac73f acpi/nfit, libnvd... |
282 |
return -EOPNOTSUPP; |
d78c620a2 libnvdimm/securit... |
283 284 285 |
rc = check_security_state(nvdimm); if (rc) return rc; |
d2a4ac73f acpi/nfit, libnvd... |
286 |
|
d2e5b6436 libnvdimm/securit... |
287 288 289 290 |
data = nvdimm_get_user_key_payload(nvdimm, keyid, NVDIMM_BASE_KEY, &key); if (!data) return -ENOKEY; |
d2a4ac73f acpi/nfit, libnvd... |
291 |
|
d2e5b6436 libnvdimm/securit... |
292 293 294 |
newdata = nvdimm_get_user_key_payload(nvdimm, new_keyid, NVDIMM_NEW_KEY, &newkey); if (!newdata) { |
d2a4ac73f acpi/nfit, libnvd... |
295 296 297 |
nvdimm_put_key(key); return -ENOKEY; } |
d2e5b6436 libnvdimm/securit... |
298 |
rc = nvdimm->sec.ops->change_key(nvdimm, data, newdata, pass_type); |
89fa9d8ea acpi/nfit, libnvd... |
299 300 |
dev_dbg(dev, "key: %d %d update%s: %s ", |
d2a4ac73f acpi/nfit, libnvd... |
301 |
key_serial(key), key_serial(newkey), |
89fa9d8ea acpi/nfit, libnvd... |
302 |
pass_type == NVDIMM_MASTER ? "(master)" : "(user)", |
d2a4ac73f acpi/nfit, libnvd... |
303 304 305 306 |
rc == 0 ? "success" : "fail"); nvdimm_put_key(newkey); nvdimm_put_key(key); |
89fa9d8ea acpi/nfit, libnvd... |
307 |
if (pass_type == NVDIMM_MASTER) |
d78c620a2 libnvdimm/securit... |
308 |
nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, |
89fa9d8ea acpi/nfit, libnvd... |
309 310 |
NVDIMM_MASTER); else |
d78c620a2 libnvdimm/securit... |
311 |
nvdimm->sec.flags = nvdimm_security_flags(nvdimm, |
89fa9d8ea acpi/nfit, libnvd... |
312 |
NVDIMM_USER); |
d2a4ac73f acpi/nfit, libnvd... |
313 314 |
return rc; } |
64e77c8c0 acpi/nfit, libnvd... |
315 |
|
7b60422cb libnvdimm/securit... |
316 |
static int security_erase(struct nvdimm *nvdimm, unsigned int keyid, |
89fa9d8ea acpi/nfit, libnvd... |
317 |
enum nvdimm_passphrase_type pass_type) |
64e77c8c0 acpi/nfit, libnvd... |
318 319 320 |
{ struct device *dev = &nvdimm->dev; struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); |
037c8489a libnvdimm/securit... |
321 |
struct key *key = NULL; |
64e77c8c0 acpi/nfit, libnvd... |
322 |
int rc; |
037c8489a libnvdimm/securit... |
323 |
const void *data; |
64e77c8c0 acpi/nfit, libnvd... |
324 325 326 327 328 |
/* The bus lock should be held at the top level of the call stack */ lockdep_assert_held(&nvdimm_bus->reconfig_mutex); if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase |
d78c620a2 libnvdimm/securit... |
329 |
|| !nvdimm->sec.flags) |
64e77c8c0 acpi/nfit, libnvd... |
330 |
return -EOPNOTSUPP; |
d78c620a2 libnvdimm/securit... |
331 332 333 |
rc = check_security_state(nvdimm); if (rc) return rc; |
7d988097c acpi/nfit, libnvd... |
334 |
|
d78c620a2 libnvdimm/securit... |
335 |
if (!test_bit(NVDIMM_SECURITY_UNLOCKED, &nvdimm->sec.ext_flags) |
89fa9d8ea acpi/nfit, libnvd... |
336 |
&& pass_type == NVDIMM_MASTER) { |
37379cfc6 libnvdimm/securit... |
337 |
dev_dbg(dev, |
89fa9d8ea acpi/nfit, libnvd... |
338 339 340 341 |
"Attempt to secure erase in wrong master state. "); return -EOPNOTSUPP; } |
d2e5b6436 libnvdimm/securit... |
342 343 344 345 |
data = nvdimm_get_user_key_payload(nvdimm, keyid, NVDIMM_BASE_KEY, &key); if (!data) return -ENOKEY; |
64e77c8c0 acpi/nfit, libnvd... |
346 |
|
037c8489a libnvdimm/securit... |
347 |
rc = nvdimm->sec.ops->erase(nvdimm, data, pass_type); |
89fa9d8ea acpi/nfit, libnvd... |
348 349 350 |
dev_dbg(dev, "key: %d erase%s: %s ", key_serial(key), pass_type == NVDIMM_MASTER ? "(master)" : "(user)", |
64e77c8c0 acpi/nfit, libnvd... |
351 352 353 |
rc == 0 ? "success" : "fail"); nvdimm_put_key(key); |
d78c620a2 libnvdimm/securit... |
354 |
nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
64e77c8c0 acpi/nfit, libnvd... |
355 356 |
return rc; } |
7d988097c acpi/nfit, libnvd... |
357 |
|
7b60422cb libnvdimm/securit... |
358 |
static int security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) |
7d988097c acpi/nfit, libnvd... |
359 360 361 |
{ struct device *dev = &nvdimm->dev; struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); |
d2e5b6436 libnvdimm/securit... |
362 |
struct key *key = NULL; |
7d988097c acpi/nfit, libnvd... |
363 |
int rc; |
d2e5b6436 libnvdimm/securit... |
364 |
const void *data; |
7d988097c acpi/nfit, libnvd... |
365 366 367 368 369 |
/* The bus lock should be held at the top level of the call stack */ lockdep_assert_held(&nvdimm_bus->reconfig_mutex); if (!nvdimm->sec.ops || !nvdimm->sec.ops->overwrite |
d78c620a2 libnvdimm/securit... |
370 |
|| !nvdimm->sec.flags) |
7d988097c acpi/nfit, libnvd... |
371 |
return -EOPNOTSUPP; |
7d988097c acpi/nfit, libnvd... |
372 |
if (dev->driver == NULL) { |
37379cfc6 libnvdimm/securit... |
373 374 |
dev_dbg(dev, "Unable to overwrite while DIMM active. "); |
7d988097c acpi/nfit, libnvd... |
375 376 |
return -EINVAL; } |
d78c620a2 libnvdimm/securit... |
377 378 379 |
rc = check_security_state(nvdimm); if (rc) return rc; |
7d988097c acpi/nfit, libnvd... |
380 |
|
d2e5b6436 libnvdimm/securit... |
381 382 383 384 |
data = nvdimm_get_user_key_payload(nvdimm, keyid, NVDIMM_BASE_KEY, &key); if (!data) return -ENOKEY; |
7d988097c acpi/nfit, libnvd... |
385 |
|
d2e5b6436 libnvdimm/securit... |
386 |
rc = nvdimm->sec.ops->overwrite(nvdimm, data); |
7d988097c acpi/nfit, libnvd... |
387 388 389 390 391 392 393 394 |
dev_dbg(dev, "key: %d overwrite submission: %s ", key_serial(key), rc == 0 ? "success" : "fail"); nvdimm_put_key(key); if (rc == 0) { set_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); set_bit(NDD_WORK_PENDING, &nvdimm->flags); |
d78c620a2 libnvdimm/securit... |
395 |
set_bit(NVDIMM_SECURITY_OVERWRITE, &nvdimm->sec.flags); |
7d988097c acpi/nfit, libnvd... |
396 397 398 399 400 401 402 |
/* * Make sure we don't lose device while doing overwrite * query. */ get_device(dev); queue_delayed_work(system_wq, &nvdimm->dwork, 0); } |
89fa9d8ea acpi/nfit, libnvd... |
403 |
|
7d988097c acpi/nfit, libnvd... |
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
return rc; } void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm) { struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(&nvdimm->dev); int rc; unsigned int tmo; /* The bus lock should be held at the top level of the call stack */ lockdep_assert_held(&nvdimm_bus->reconfig_mutex); /* * Abort and release device if we no longer have the overwrite * flag set. It means the work has been canceled. */ if (!test_bit(NDD_WORK_PENDING, &nvdimm->flags)) return; tmo = nvdimm->sec.overwrite_tmo; if (!nvdimm->sec.ops || !nvdimm->sec.ops->query_overwrite |
d78c620a2 libnvdimm/securit... |
426 |
|| !nvdimm->sec.flags) |
7d988097c acpi/nfit, libnvd... |
427 428 429 430 431 432 433 434 435 436 437 438 439 |
return; rc = nvdimm->sec.ops->query_overwrite(nvdimm); if (rc == -EBUSY) { /* setup delayed work again */ tmo += 10; queue_delayed_work(system_wq, &nvdimm->dwork, tmo * HZ); nvdimm->sec.overwrite_tmo = min(15U * 60U, tmo); return; } if (rc < 0) |
37379cfc6 libnvdimm/securit... |
440 441 |
dev_dbg(&nvdimm->dev, "overwrite failed "); |
7d988097c acpi/nfit, libnvd... |
442 443 444 |
else dev_dbg(&nvdimm->dev, "overwrite completed "); |
7f674025d libnvdimm/securit... |
445 446 447 448 449 |
/* * Mark the overwrite work done and update dimm security flags, * then send a sysfs event notification to wake up userspace * poll threads to picked up the changed state. */ |
7d988097c acpi/nfit, libnvd... |
450 451 452 |
nvdimm->sec.overwrite_tmo = 0; clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); clear_bit(NDD_WORK_PENDING, &nvdimm->flags); |
d78c620a2 libnvdimm/securit... |
453 |
nvdimm->sec.flags = nvdimm_security_flags(nvdimm, NVDIMM_USER); |
dad42d175 libnvdimm/securit... |
454 |
nvdimm->sec.ext_flags = nvdimm_security_flags(nvdimm, NVDIMM_MASTER); |
7f674025d libnvdimm/securit... |
455 456 457 |
if (nvdimm->sec.overwrite_state) sysfs_notify_dirent(nvdimm->sec.overwrite_state); put_device(&nvdimm->dev); |
7d988097c acpi/nfit, libnvd... |
458 459 460 461 462 463 464 465 466 467 468 |
} void nvdimm_security_overwrite_query(struct work_struct *work) { struct nvdimm *nvdimm = container_of(work, typeof(*nvdimm), dwork.work); nvdimm_bus_lock(&nvdimm->dev); __nvdimm_security_overwrite_query(nvdimm); nvdimm_bus_unlock(&nvdimm->dev); } |
7b60422cb libnvdimm/securit... |
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 |
#define OPS \ C( OP_FREEZE, "freeze", 1), \ C( OP_DISABLE, "disable", 2), \ C( OP_UPDATE, "update", 3), \ C( OP_ERASE, "erase", 2), \ C( OP_OVERWRITE, "overwrite", 2), \ C( OP_MASTER_UPDATE, "master_update", 3), \ C( OP_MASTER_ERASE, "master_erase", 2) #undef C #define C(a, b, c) a enum nvdimmsec_op_ids { OPS }; #undef C #define C(a, b, c) { b, c } static struct { const char *name; int args; } ops[] = { OPS }; #undef C #define SEC_CMD_SIZE 32 #define KEY_ID_SIZE 10 ssize_t nvdimm_security_store(struct device *dev, const char *buf, size_t len) { struct nvdimm *nvdimm = to_nvdimm(dev); ssize_t rc; char cmd[SEC_CMD_SIZE+1], keystr[KEY_ID_SIZE+1], nkeystr[KEY_ID_SIZE+1]; unsigned int key, newkey; int i; rc = sscanf(buf, "%"__stringify(SEC_CMD_SIZE)"s" " %"__stringify(KEY_ID_SIZE)"s" " %"__stringify(KEY_ID_SIZE)"s", cmd, keystr, nkeystr); if (rc < 1) return -EINVAL; for (i = 0; i < ARRAY_SIZE(ops); i++) if (sysfs_streq(cmd, ops[i].name)) break; if (i >= ARRAY_SIZE(ops)) return -EINVAL; if (ops[i].args > 1) rc = kstrtouint(keystr, 0, &key); if (rc >= 0 && ops[i].args > 2) rc = kstrtouint(nkeystr, 0, &newkey); if (rc < 0) return rc; if (i == OP_FREEZE) { dev_dbg(dev, "freeze "); rc = nvdimm_security_freeze(nvdimm); } else if (i == OP_DISABLE) { dev_dbg(dev, "disable %u ", key); rc = security_disable(nvdimm, key); } else if (i == OP_UPDATE || i == OP_MASTER_UPDATE) { dev_dbg(dev, "%s %u %u ", ops[i].name, key, newkey); rc = security_update(nvdimm, key, newkey, i == OP_UPDATE ? NVDIMM_USER : NVDIMM_MASTER); } else if (i == OP_ERASE || i == OP_MASTER_ERASE) { dev_dbg(dev, "%s %u ", ops[i].name, key); if (atomic_read(&nvdimm->busy)) { dev_dbg(dev, "Unable to secure erase while DIMM active. "); return -EBUSY; } rc = security_erase(nvdimm, key, i == OP_ERASE ? NVDIMM_USER : NVDIMM_MASTER); } else if (i == OP_OVERWRITE) { dev_dbg(dev, "overwrite %u ", key); if (atomic_read(&nvdimm->busy)) { dev_dbg(dev, "Unable to overwrite while DIMM active. "); return -EBUSY; } rc = security_overwrite(nvdimm, key); } else return -EINVAL; if (rc == 0) rc = len; return rc; } |