diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/acpi/nfit/intel.c | 10 | ||||
| -rw-r--r-- | drivers/nvdimm/security.c | 117 |
2 files changed, 73 insertions, 54 deletions
diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c index f70de71f79d6..cddd0fcf622c 100644 --- a/drivers/acpi/nfit/intel.c +++ b/drivers/acpi/nfit/intel.c | |||
| @@ -122,9 +122,8 @@ static int intel_security_change_key(struct nvdimm *nvdimm, | |||
| 122 | if (!test_bit(cmd, &nfit_mem->dsm_mask)) | 122 | if (!test_bit(cmd, &nfit_mem->dsm_mask)) |
| 123 | return -ENOTTY; | 123 | return -ENOTTY; |
| 124 | 124 | ||
| 125 | if (old_data) | 125 | memcpy(nd_cmd.cmd.old_pass, old_data->data, |
| 126 | memcpy(nd_cmd.cmd.old_pass, old_data->data, | 126 | sizeof(nd_cmd.cmd.old_pass)); |
| 127 | sizeof(nd_cmd.cmd.old_pass)); | ||
| 128 | memcpy(nd_cmd.cmd.new_pass, new_data->data, | 127 | memcpy(nd_cmd.cmd.new_pass, new_data->data, |
| 129 | sizeof(nd_cmd.cmd.new_pass)); | 128 | sizeof(nd_cmd.cmd.new_pass)); |
| 130 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); | 129 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); |
| @@ -336,9 +335,8 @@ static int __maybe_unused intel_security_overwrite(struct nvdimm *nvdimm, | |||
| 336 | 335 | ||
| 337 | /* flush all cache before we erase DIMM */ | 336 | /* flush all cache before we erase DIMM */ |
| 338 | nvdimm_invalidate_cache(); | 337 | nvdimm_invalidate_cache(); |
| 339 | if (nkey) | 338 | memcpy(nd_cmd.cmd.passphrase, nkey->data, |
| 340 | memcpy(nd_cmd.cmd.passphrase, nkey->data, | 339 | sizeof(nd_cmd.cmd.passphrase)); |
| 341 | sizeof(nd_cmd.cmd.passphrase)); | ||
| 342 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); | 340 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); |
| 343 | if (rc < 0) | 341 | if (rc < 0) |
| 344 | return rc; | 342 | return rc; |
diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index 6bea6852bf27..a570f2263a42 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c | |||
| @@ -77,6 +77,16 @@ static struct key *nvdimm_request_key(struct nvdimm *nvdimm) | |||
| 77 | return key; | 77 | return key; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | static const void *nvdimm_get_key_payload(struct nvdimm *nvdimm, | ||
| 81 | struct key **key) | ||
| 82 | { | ||
| 83 | *key = nvdimm_request_key(nvdimm); | ||
| 84 | if (!*key) | ||
| 85 | return zero_key; | ||
| 86 | |||
| 87 | return key_data(*key); | ||
| 88 | } | ||
| 89 | |||
| 80 | static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, | 90 | static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, |
| 81 | key_serial_t id, int subclass) | 91 | key_serial_t id, int subclass) |
| 82 | { | 92 | { |
| @@ -107,36 +117,57 @@ static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, | |||
| 107 | return key; | 117 | return key; |
| 108 | } | 118 | } |
| 109 | 119 | ||
| 110 | static struct key *nvdimm_key_revalidate(struct nvdimm *nvdimm) | 120 | static const void *nvdimm_get_user_key_payload(struct nvdimm *nvdimm, |
| 121 | key_serial_t id, int subclass, struct key **key) | ||
| 122 | { | ||
| 123 | *key = NULL; | ||
| 124 | if (id == 0) { | ||
| 125 | if (subclass == NVDIMM_BASE_KEY) | ||
| 126 | return zero_key; | ||
| 127 | else | ||
| 128 | return NULL; | ||
| 129 | } | ||
| 130 | |||
| 131 | *key = nvdimm_lookup_user_key(nvdimm, id, subclass); | ||
| 132 | if (!*key) | ||
| 133 | return NULL; | ||
| 134 | |||
| 135 | return key_data(*key); | ||
| 136 | } | ||
| 137 | |||
| 138 | |||
| 139 | static int nvdimm_key_revalidate(struct nvdimm *nvdimm) | ||
| 111 | { | 140 | { |
| 112 | struct key *key; | 141 | struct key *key; |
| 113 | int rc; | 142 | int rc; |
| 143 | const void *data; | ||
| 114 | 144 | ||
| 115 | if (!nvdimm->sec.ops->change_key) | 145 | if (!nvdimm->sec.ops->change_key) |
| 116 | return NULL; | 146 | return -EOPNOTSUPP; |
| 117 | 147 | ||
| 118 | key = nvdimm_request_key(nvdimm); | 148 | data = nvdimm_get_key_payload(nvdimm, &key); |
| 119 | if (!key) | ||
| 120 | return NULL; | ||
| 121 | 149 | ||
| 122 | /* | 150 | /* |
| 123 | * Send the same key to the hardware as new and old key to | 151 | * Send the same key to the hardware as new and old key to |
| 124 | * verify that the key is good. | 152 | * verify that the key is good. |
| 125 | */ | 153 | */ |
| 126 | rc = nvdimm->sec.ops->change_key(nvdimm, key_data(key), | 154 | rc = nvdimm->sec.ops->change_key(nvdimm, data, data, NVDIMM_USER); |
| 127 | key_data(key), NVDIMM_USER); | ||
| 128 | if (rc < 0) { | 155 | if (rc < 0) { |
| 129 | nvdimm_put_key(key); | 156 | nvdimm_put_key(key); |
| 130 | key = NULL; | 157 | return rc; |
| 131 | } | 158 | } |
| 132 | return key; | 159 | |
| 160 | nvdimm_put_key(key); | ||
| 161 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | ||
| 162 | return 0; | ||
| 133 | } | 163 | } |
| 134 | 164 | ||
| 135 | static int __nvdimm_security_unlock(struct nvdimm *nvdimm) | 165 | static int __nvdimm_security_unlock(struct nvdimm *nvdimm) |
| 136 | { | 166 | { |
| 137 | struct device *dev = &nvdimm->dev; | 167 | struct device *dev = &nvdimm->dev; |
| 138 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | 168 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); |
| 139 | struct key *key = NULL; | 169 | struct key *key; |
| 170 | const void *data; | ||
| 140 | int rc; | 171 | int rc; |
| 141 | 172 | ||
| 142 | /* The bus lock should be held at the top level of the call stack */ | 173 | /* The bus lock should be held at the top level of the call stack */ |
| @@ -162,16 +193,11 @@ static int __nvdimm_security_unlock(struct nvdimm *nvdimm) | |||
| 162 | if (!key_revalidate) | 193 | if (!key_revalidate) |
| 163 | return 0; | 194 | return 0; |
| 164 | 195 | ||
| 165 | key = nvdimm_key_revalidate(nvdimm); | 196 | return nvdimm_key_revalidate(nvdimm); |
| 166 | if (!key) | ||
| 167 | return nvdimm_security_freeze(nvdimm); | ||
| 168 | } else | 197 | } else |
| 169 | key = nvdimm_request_key(nvdimm); | 198 | data = nvdimm_get_key_payload(nvdimm, &key); |
| 170 | 199 | ||
| 171 | if (!key) | 200 | rc = nvdimm->sec.ops->unlock(nvdimm, data); |
| 172 | return -ENOKEY; | ||
| 173 | |||
| 174 | rc = nvdimm->sec.ops->unlock(nvdimm, key_data(key)); | ||
| 175 | dev_dbg(dev, "key: %d unlock: %s\n", key_serial(key), | 201 | dev_dbg(dev, "key: %d unlock: %s\n", key_serial(key), |
| 176 | rc == 0 ? "success" : "fail"); | 202 | rc == 0 ? "success" : "fail"); |
| 177 | 203 | ||
| @@ -197,6 +223,7 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) | |||
| 197 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | 223 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); |
| 198 | struct key *key; | 224 | struct key *key; |
| 199 | int rc; | 225 | int rc; |
| 226 | const void *data; | ||
| 200 | 227 | ||
| 201 | /* The bus lock should be held at the top level of the call stack */ | 228 | /* The bus lock should be held at the top level of the call stack */ |
| 202 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | 229 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); |
| @@ -216,11 +243,12 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) | |||
| 216 | return -EBUSY; | 243 | return -EBUSY; |
| 217 | } | 244 | } |
| 218 | 245 | ||
| 219 | key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); | 246 | data = nvdimm_get_user_key_payload(nvdimm, keyid, |
| 220 | if (!key) | 247 | NVDIMM_BASE_KEY, &key); |
| 248 | if (!data) | ||
| 221 | return -ENOKEY; | 249 | return -ENOKEY; |
| 222 | 250 | ||
| 223 | rc = nvdimm->sec.ops->disable(nvdimm, key_data(key)); | 251 | rc = nvdimm->sec.ops->disable(nvdimm, data); |
| 224 | dev_dbg(dev, "key: %d disable: %s\n", key_serial(key), | 252 | dev_dbg(dev, "key: %d disable: %s\n", key_serial(key), |
| 225 | rc == 0 ? "success" : "fail"); | 253 | rc == 0 ? "success" : "fail"); |
| 226 | 254 | ||
| @@ -237,6 +265,7 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, | |||
| 237 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | 265 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); |
| 238 | struct key *key, *newkey; | 266 | struct key *key, *newkey; |
| 239 | int rc; | 267 | int rc; |
| 268 | const void *data, *newdata; | ||
| 240 | 269 | ||
| 241 | /* The bus lock should be held at the top level of the call stack */ | 270 | /* The bus lock should be held at the top level of the call stack */ |
| 242 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | 271 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); |
| @@ -251,22 +280,19 @@ int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, | |||
| 251 | return -EIO; | 280 | return -EIO; |
| 252 | } | 281 | } |
| 253 | 282 | ||
| 254 | if (keyid == 0) | 283 | data = nvdimm_get_user_key_payload(nvdimm, keyid, |
| 255 | key = NULL; | 284 | NVDIMM_BASE_KEY, &key); |
| 256 | else { | 285 | if (!data) |
| 257 | key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); | 286 | return -ENOKEY; |
| 258 | if (!key) | ||
| 259 | return -ENOKEY; | ||
| 260 | } | ||
| 261 | 287 | ||
| 262 | newkey = nvdimm_lookup_user_key(nvdimm, new_keyid, NVDIMM_NEW_KEY); | 288 | newdata = nvdimm_get_user_key_payload(nvdimm, new_keyid, |
| 263 | if (!newkey) { | 289 | NVDIMM_NEW_KEY, &newkey); |
| 290 | if (!newdata) { | ||
| 264 | nvdimm_put_key(key); | 291 | nvdimm_put_key(key); |
| 265 | return -ENOKEY; | 292 | return -ENOKEY; |
| 266 | } | 293 | } |
| 267 | 294 | ||
| 268 | rc = nvdimm->sec.ops->change_key(nvdimm, key ? key_data(key) : NULL, | 295 | rc = nvdimm->sec.ops->change_key(nvdimm, data, newdata, pass_type); |
| 269 | key_data(newkey), pass_type); | ||
| 270 | dev_dbg(dev, "key: %d %d update%s: %s\n", | 296 | dev_dbg(dev, "key: %d %d update%s: %s\n", |
| 271 | key_serial(key), key_serial(newkey), | 297 | key_serial(key), key_serial(newkey), |
| 272 | pass_type == NVDIMM_MASTER ? "(master)" : "(user)", | 298 | pass_type == NVDIMM_MASTER ? "(master)" : "(user)", |
| @@ -322,13 +348,10 @@ int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, | |||
| 322 | return -EOPNOTSUPP; | 348 | return -EOPNOTSUPP; |
| 323 | } | 349 | } |
| 324 | 350 | ||
| 325 | if (keyid != 0) { | 351 | data = nvdimm_get_user_key_payload(nvdimm, keyid, |
| 326 | key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); | 352 | NVDIMM_BASE_KEY, &key); |
| 327 | if (!key) | 353 | if (!data) |
| 328 | return -ENOKEY; | 354 | return -ENOKEY; |
| 329 | data = key_data(key); | ||
| 330 | } else | ||
| 331 | data = zero_key; | ||
| 332 | 355 | ||
| 333 | rc = nvdimm->sec.ops->erase(nvdimm, data, pass_type); | 356 | rc = nvdimm->sec.ops->erase(nvdimm, data, pass_type); |
| 334 | dev_dbg(dev, "key: %d erase%s: %s\n", key_serial(key), | 357 | dev_dbg(dev, "key: %d erase%s: %s\n", key_serial(key), |
| @@ -344,8 +367,9 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) | |||
| 344 | { | 367 | { |
| 345 | struct device *dev = &nvdimm->dev; | 368 | struct device *dev = &nvdimm->dev; |
| 346 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | 369 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); |
| 347 | struct key *key; | 370 | struct key *key = NULL; |
| 348 | int rc; | 371 | int rc; |
| 372 | const void *data; | ||
| 349 | 373 | ||
| 350 | /* The bus lock should be held at the top level of the call stack */ | 374 | /* The bus lock should be held at the top level of the call stack */ |
| 351 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | 375 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); |
| @@ -375,15 +399,12 @@ int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) | |||
| 375 | return -EBUSY; | 399 | return -EBUSY; |
| 376 | } | 400 | } |
| 377 | 401 | ||
| 378 | if (keyid == 0) | 402 | data = nvdimm_get_user_key_payload(nvdimm, keyid, |
| 379 | key = NULL; | 403 | NVDIMM_BASE_KEY, &key); |
| 380 | else { | 404 | if (!data) |
| 381 | key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); | 405 | return -ENOKEY; |
| 382 | if (!key) | ||
| 383 | return -ENOKEY; | ||
| 384 | } | ||
| 385 | 406 | ||
| 386 | rc = nvdimm->sec.ops->overwrite(nvdimm, key ? key_data(key) : NULL); | 407 | rc = nvdimm->sec.ops->overwrite(nvdimm, data); |
| 387 | dev_dbg(dev, "key: %d overwrite submission: %s\n", key_serial(key), | 408 | dev_dbg(dev, "key: %d overwrite submission: %s\n", key_serial(key), |
| 388 | rc == 0 ? "success" : "fail"); | 409 | rc == 0 ? "success" : "fail"); |
| 389 | 410 | ||
