Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libnvdimm/security: Require nvdimm_security_setup_events() to succeed

The following warning:

ACPI0012:00: security event setup failed: -19

...is meant to capture exceptional failures of sysfs_get_dirent(),
however it will also fail in the common case when security support is
disabled. A few issues:

1/ A dev_warn() report for a common case is too chatty
2/ The setup of this notifier is generic, no need for it to be driven
from the nfit driver, it can exist completely in the core.
3/ If it fails for any reason besides security support being disabled,
that's fatal and should abort DIMM activation. Userspace may hang if
it never gets overwrite notifications.
4/ The dirent needs to be released.

Move the call to the core 'dimm' driver, make it conditional on security
support being active, make it fatal for the exceptional case, add the
missing sysfs_put() at device disable time.

Fixes: 7d988097c546 ("...Add security DSM overwrite support")
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+24 -11
-5
drivers/acpi/nfit/core.c
··· 2042 2042 if (!nvdimm) 2043 2043 continue; 2044 2044 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 2045 nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit"); 2051 2046 if (nfit_kernfs) 2052 2047 nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs,
+6
drivers/nvdimm/dimm.c
··· 26 26 struct nvdimm_drvdata *ndd; 27 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 35 rc = nvdimm_check_config_data(dev); 30 36 if (rc) { 31 37 /* not required for non-aliased nvdimm, ex. NVDIMM-N */
+17 -5
drivers/nvdimm/dimm_devs.c
··· 578 578 } 579 579 EXPORT_SYMBOL_GPL(__nvdimm_create); 580 580 581 - int nvdimm_security_setup_events(struct nvdimm *nvdimm) 581 + static void shutdown_security_notify(void *data) 582 582 { 583 - nvdimm->sec.overwrite_state = sysfs_get_dirent(nvdimm->dev.kobj.sd, 584 - "security"); 583 + struct nvdimm *nvdimm = data; 584 + 585 + sysfs_put(nvdimm->sec.overwrite_state); 586 + } 587 + 588 + int 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 596 if (!nvdimm->sec.overwrite_state) 586 - return -ENODEV; 587 - return 0; 597 + return -ENOMEM; 598 + 599 + return devm_add_action_or_reset(dev, shutdown_security_notify, nvdimm); 588 600 } 589 601 EXPORT_SYMBOL_GPL(nvdimm_security_setup_events); 590 602
+1
drivers/nvdimm/nd.h
··· 250 250 void nvdimm_set_aliasing(struct device *dev); 251 251 void nvdimm_set_locked(struct device *dev); 252 252 void nvdimm_clear_locked(struct device *dev); 253 + int nvdimm_security_setup_events(struct device *dev); 253 254 #if IS_ENABLED(CONFIG_NVDIMM_KEYS) 254 255 int nvdimm_security_unlock(struct device *dev); 255 256 #else
-1
include/linux/libnvdimm.h
··· 235 235 cmd_mask, num_flush, flush_wpq, NULL, NULL); 236 236 } 237 237 238 - int nvdimm_security_setup_events(struct nvdimm *nvdimm); 239 238 const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd); 240 239 const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd); 241 240 u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,