aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-01-27 12:11:51 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2019-01-27 12:11:51 -0500
commit6a2651b55bcf5b56177d4ccaeb52adeeadb142ea (patch)
tree2c36e0a1e88fbf59adcb900494337bfc749a5734
parent78e372e6509bc2412e86afb11be65185f4c9c568 (diff)
parent11189c1089da413aa4b5fd6be4c4d47c78968819 (diff)
Merge tag 'libnvdimm-fixes-5.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm fixes from Dan Williams: "A fix for namespace label support for non-Intel NVDIMMs that implement the ACPI standard label method. This has apparently never worked and could wait for v5.1. However it has enough visibility with hardware vendors [1] and distro bug trackers [2], and low enough risk that I decided it should go in for -rc4. The other fixups target the new, for v5.0, nvdimm security functionality. The larger init path fixup closes a memory leak and a potential userspace lockup due to missed notifications. [1] https://github.com/pmem/ndctl/issues/78 [2] https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1811785 These have all soaked in -next for a week with no reported issues. Summary: - Fix support for NVDIMMs that implement the ACPI standard label methods. - Fix error handling for security overwrite (memory leak / userspace hang condition), and another one-line security cleanup" * tag 'libnvdimm-fixes-5.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: acpi/nfit: Fix command-supported detection acpi/nfit: Block function zero DSMs libnvdimm/security: Require nvdimm_security_setup_events() to succeed nfit_test: fix security state pull for nvdimm security nfit_test
-rw-r--r--drivers/acpi/nfit/core.c66
-rw-r--r--drivers/nvdimm/dimm.c6
-rw-r--r--drivers/nvdimm/dimm_devs.c22
-rw-r--r--drivers/nvdimm/nd.h1
-rw-r--r--include/linux/libnvdimm.h1
-rw-r--r--tools/testing/nvdimm/dimm_devs.c4
6 files changed, 73 insertions, 27 deletions
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 5143e11e3b0f..e18ade5d74e9 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -409,6 +409,32 @@ static bool payload_dumpable(struct nvdimm *nvdimm, unsigned int func)
409 return true; 409 return true;
410} 410}
411 411
412static int cmd_to_func(struct nfit_mem *nfit_mem, unsigned int cmd,
413 struct nd_cmd_pkg *call_pkg)
414{
415 if (call_pkg) {
416 int i;
417
418 if (nfit_mem->family != call_pkg->nd_family)
419 return -ENOTTY;
420
421 for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++)
422 if (call_pkg->nd_reserved2[i])
423 return -EINVAL;
424 return call_pkg->nd_command;
425 }
426
427 /* Linux ND commands == NVDIMM_FAMILY_INTEL function numbers */
428 if (nfit_mem->family == NVDIMM_FAMILY_INTEL)
429 return cmd;
430
431 /*
432 * Force function number validation to fail since 0 is never
433 * published as a valid function in dsm_mask.
434 */
435 return 0;
436}
437
412int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, 438int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
413 unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) 439 unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc)
414{ 440{
@@ -422,30 +448,23 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
422 unsigned long cmd_mask, dsm_mask; 448 unsigned long cmd_mask, dsm_mask;
423 u32 offset, fw_status = 0; 449 u32 offset, fw_status = 0;
424 acpi_handle handle; 450 acpi_handle handle;
425 unsigned int func;
426 const guid_t *guid; 451 const guid_t *guid;
427 int rc, i; 452 int func, rc, i;
428 453
429 if (cmd_rc) 454 if (cmd_rc)
430 *cmd_rc = -EINVAL; 455 *cmd_rc = -EINVAL;
431 func = cmd;
432 if (cmd == ND_CMD_CALL) {
433 call_pkg = buf;
434 func = call_pkg->nd_command;
435
436 for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++)
437 if (call_pkg->nd_reserved2[i])
438 return -EINVAL;
439 }
440 456
441 if (nvdimm) { 457 if (nvdimm) {
442 struct acpi_device *adev = nfit_mem->adev; 458 struct acpi_device *adev = nfit_mem->adev;
443 459
444 if (!adev) 460 if (!adev)
445 return -ENOTTY; 461 return -ENOTTY;
446 if (call_pkg && nfit_mem->family != call_pkg->nd_family)
447 return -ENOTTY;
448 462
463 if (cmd == ND_CMD_CALL)
464 call_pkg = buf;
465 func = cmd_to_func(nfit_mem, cmd, call_pkg);
466 if (func < 0)
467 return func;
449 dimm_name = nvdimm_name(nvdimm); 468 dimm_name = nvdimm_name(nvdimm);
450 cmd_name = nvdimm_cmd_name(cmd); 469 cmd_name = nvdimm_cmd_name(cmd);
451 cmd_mask = nvdimm_cmd_mask(nvdimm); 470 cmd_mask = nvdimm_cmd_mask(nvdimm);
@@ -456,6 +475,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
456 } else { 475 } else {
457 struct acpi_device *adev = to_acpi_dev(acpi_desc); 476 struct acpi_device *adev = to_acpi_dev(acpi_desc);
458 477
478 func = cmd;
459 cmd_name = nvdimm_bus_cmd_name(cmd); 479 cmd_name = nvdimm_bus_cmd_name(cmd);
460 cmd_mask = nd_desc->cmd_mask; 480 cmd_mask = nd_desc->cmd_mask;
461 dsm_mask = cmd_mask; 481 dsm_mask = cmd_mask;
@@ -470,7 +490,13 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
470 if (!desc || (cmd && (desc->out_num + desc->in_num == 0))) 490 if (!desc || (cmd && (desc->out_num + desc->in_num == 0)))
471 return -ENOTTY; 491 return -ENOTTY;
472 492
473 if (!test_bit(cmd, &cmd_mask) || !test_bit(func, &dsm_mask)) 493 /*
494 * Check for a valid command. For ND_CMD_CALL, we also have to
495 * make sure that the DSM function is supported.
496 */
497 if (cmd == ND_CMD_CALL && !test_bit(func, &dsm_mask))
498 return -ENOTTY;
499 else if (!test_bit(cmd, &cmd_mask))
474 return -ENOTTY; 500 return -ENOTTY;
475 501
476 in_obj.type = ACPI_TYPE_PACKAGE; 502 in_obj.type = ACPI_TYPE_PACKAGE;
@@ -1867,6 +1893,13 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
1867 return 0; 1893 return 0;
1868 } 1894 }
1869 1895
1896 /*
1897 * Function 0 is the command interrogation function, don't
1898 * export it to potential userspace use, and enable it to be
1899 * used as an error value in acpi_nfit_ctl().
1900 */
1901 dsm_mask &= ~1UL;
1902
1870 guid = to_nfit_uuid(nfit_mem->family); 1903 guid = to_nfit_uuid(nfit_mem->family);
1871 for_each_set_bit(i, &dsm_mask, BITS_PER_LONG) 1904 for_each_set_bit(i, &dsm_mask, BITS_PER_LONG)
1872 if (acpi_check_dsm(adev_dimm->handle, guid, 1905 if (acpi_check_dsm(adev_dimm->handle, guid,
@@ -2042,11 +2075,6 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
2042 if (!nvdimm) 2075 if (!nvdimm)
2043 continue; 2076 continue;
2044 2077
2045 rc = nvdimm_security_setup_events(nvdimm);
2046 if (rc < 0)
2047 dev_warn(acpi_desc->dev,
2048 "security event setup failed: %d\n", rc);
2049
2050 nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit"); 2078 nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit");
2051 if (nfit_kernfs) 2079 if (nfit_kernfs)
2052 nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs, 2080 nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs,
diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c
index 0cf58cabc9ed..3cf50274fadb 100644
--- a/drivers/nvdimm/dimm.c
+++ b/drivers/nvdimm/dimm.c
@@ -26,6 +26,12 @@ static int nvdimm_probe(struct device *dev)
26 struct nvdimm_drvdata *ndd; 26 struct nvdimm_drvdata *ndd;
27 int rc; 27 int rc;
28 28
29 rc = nvdimm_security_setup_events(dev);
30 if (rc < 0) {
31 dev_err(dev, "security event setup failed: %d\n", rc);
32 return rc;
33 }
34
29 rc = nvdimm_check_config_data(dev); 35 rc = nvdimm_check_config_data(dev);
30 if (rc) { 36 if (rc) {
31 /* not required for non-aliased nvdimm, ex. NVDIMM-N */ 37 /* not required for non-aliased nvdimm, ex. NVDIMM-N */
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index 4890310df874..efe412a6b5b9 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -578,13 +578,25 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
578} 578}
579EXPORT_SYMBOL_GPL(__nvdimm_create); 579EXPORT_SYMBOL_GPL(__nvdimm_create);
580 580
581int nvdimm_security_setup_events(struct nvdimm *nvdimm) 581static void shutdown_security_notify(void *data)
582{ 582{
583 nvdimm->sec.overwrite_state = sysfs_get_dirent(nvdimm->dev.kobj.sd, 583 struct nvdimm *nvdimm = data;
584 "security"); 584
585 sysfs_put(nvdimm->sec.overwrite_state);
586}
587
588int nvdimm_security_setup_events(struct device *dev)
589{
590 struct nvdimm *nvdimm = to_nvdimm(dev);
591
592 if (nvdimm->sec.state < 0 || !nvdimm->sec.ops
593 || !nvdimm->sec.ops->overwrite)
594 return 0;
595 nvdimm->sec.overwrite_state = sysfs_get_dirent(dev->kobj.sd, "security");
585 if (!nvdimm->sec.overwrite_state) 596 if (!nvdimm->sec.overwrite_state)
586 return -ENODEV; 597 return -ENOMEM;
587 return 0; 598
599 return devm_add_action_or_reset(dev, shutdown_security_notify, nvdimm);
588} 600}
589EXPORT_SYMBOL_GPL(nvdimm_security_setup_events); 601EXPORT_SYMBOL_GPL(nvdimm_security_setup_events);
590 602
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index cfde992684e7..379bf4305e61 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -250,6 +250,7 @@ long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
250void nvdimm_set_aliasing(struct device *dev); 250void nvdimm_set_aliasing(struct device *dev);
251void nvdimm_set_locked(struct device *dev); 251void nvdimm_set_locked(struct device *dev);
252void nvdimm_clear_locked(struct device *dev); 252void nvdimm_clear_locked(struct device *dev);
253int nvdimm_security_setup_events(struct device *dev);
253#if IS_ENABLED(CONFIG_NVDIMM_KEYS) 254#if IS_ENABLED(CONFIG_NVDIMM_KEYS)
254int nvdimm_security_unlock(struct device *dev); 255int nvdimm_security_unlock(struct device *dev);
255#else 256#else
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 7315977b64da..ad609617aeb8 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -235,7 +235,6 @@ static inline struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus,
235 cmd_mask, num_flush, flush_wpq, NULL, NULL); 235 cmd_mask, num_flush, flush_wpq, NULL, NULL);
236} 236}
237 237
238int nvdimm_security_setup_events(struct nvdimm *nvdimm);
239const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd); 238const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd);
240const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd); 239const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd);
241u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd, 240u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
diff --git a/tools/testing/nvdimm/dimm_devs.c b/tools/testing/nvdimm/dimm_devs.c
index e75238404555..2d4baf57822f 100644
--- a/tools/testing/nvdimm/dimm_devs.c
+++ b/tools/testing/nvdimm/dimm_devs.c
@@ -18,8 +18,8 @@ ssize_t security_show(struct device *dev,
18 * For the test version we need to poll the "hardware" in order 18 * For the test version we need to poll the "hardware" in order
19 * to get the updated status for unlock testing. 19 * to get the updated status for unlock testing.
20 */ 20 */
21 nvdimm->sec.state = nvdimm_security_state(nvdimm, false); 21 nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER);
22 nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, true); 22 nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER);
23 23
24 switch (nvdimm->sec.state) { 24 switch (nvdimm->sec.state) {
25 case NVDIMM_SECURITY_DISABLED: 25 case NVDIMM_SECURITY_DISABLED: