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

Configure Feed

Select the types of activity you want to include in your feed.

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

+73 -27
+47 -19
drivers/acpi/nfit/core.c
··· 409 409 return true; 410 410 } 411 411 412 + static 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 + 412 438 int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, 413 439 unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) 414 440 { ··· 448 422 unsigned long cmd_mask, dsm_mask; 449 423 u32 offset, fw_status = 0; 450 424 acpi_handle handle; 451 - unsigned int func; 452 425 const guid_t *guid; 453 - int rc, i; 426 + int func, rc, i; 454 427 455 428 if (cmd_rc) 456 429 *cmd_rc = -EINVAL; 457 - func = cmd; 458 - if (cmd == ND_CMD_CALL) { 459 - call_pkg = buf; 460 - func = call_pkg->nd_command; 461 - 462 - for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++) 463 - if (call_pkg->nd_reserved2[i]) 464 - return -EINVAL; 465 - } 466 430 467 431 if (nvdimm) { 468 432 struct acpi_device *adev = nfit_mem->adev; 469 433 470 434 if (!adev) 471 435 return -ENOTTY; 472 - if (call_pkg && nfit_mem->family != call_pkg->nd_family) 473 - return -ENOTTY; 474 436 437 + if (cmd == ND_CMD_CALL) 438 + call_pkg = buf; 439 + func = cmd_to_func(nfit_mem, cmd, call_pkg); 440 + if (func < 0) 441 + return func; 475 442 dimm_name = nvdimm_name(nvdimm); 476 443 cmd_name = nvdimm_cmd_name(cmd); 477 444 cmd_mask = nvdimm_cmd_mask(nvdimm); ··· 475 456 } else { 476 457 struct acpi_device *adev = to_acpi_dev(acpi_desc); 477 458 459 + func = cmd; 478 460 cmd_name = nvdimm_bus_cmd_name(cmd); 479 461 cmd_mask = nd_desc->cmd_mask; 480 462 dsm_mask = cmd_mask; ··· 490 470 if (!desc || (cmd && (desc->out_num + desc->in_num == 0))) 491 471 return -ENOTTY; 492 472 493 - if (!test_bit(cmd, &cmd_mask) || !test_bit(func, &dsm_mask)) 473 + /* 474 + * Check for a valid command. For ND_CMD_CALL, we also have to 475 + * make sure that the DSM function is supported. 476 + */ 477 + if (cmd == ND_CMD_CALL && !test_bit(func, &dsm_mask)) 478 + return -ENOTTY; 479 + else if (!test_bit(cmd, &cmd_mask)) 494 480 return -ENOTTY; 495 481 496 482 in_obj.type = ACPI_TYPE_PACKAGE; ··· 1893 1867 return 0; 1894 1868 } 1895 1869 1870 + /* 1871 + * Function 0 is the command interrogation function, don't 1872 + * export it to potential userspace use, and enable it to be 1873 + * used as an error value in acpi_nfit_ctl(). 1874 + */ 1875 + dsm_mask &= ~1UL; 1876 + 1896 1877 guid = to_nfit_uuid(nfit_mem->family); 1897 1878 for_each_set_bit(i, &dsm_mask, BITS_PER_LONG) 1898 1879 if (acpi_check_dsm(adev_dimm->handle, guid, ··· 2074 2041 nvdimm = nfit_mem->nvdimm; 2075 2042 if (!nvdimm) 2076 2043 continue; 2077 - 2078 - rc = nvdimm_security_setup_events(nvdimm); 2079 - if (rc < 0) 2080 - dev_warn(acpi_desc->dev, 2081 - "security event setup failed: %d\n", rc); 2082 2044 2083 2045 nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit"); 2084 2046 if (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,
+2 -2
tools/testing/nvdimm/dimm_devs.c
··· 18 18 * For the test version we need to poll the "hardware" in order 19 19 * to get the updated status for unlock testing. 20 20 */ 21 - nvdimm->sec.state = nvdimm_security_state(nvdimm, false); 22 - nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, true); 21 + nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); 22 + nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); 23 23 24 24 switch (nvdimm->sec.state) { 25 25 case NVDIMM_SECURITY_DISABLED: