diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-28 18:05:13 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-28 18:05:13 -0500 |
| commit | 75f95da078b2891cd186f074ffc15a8e7c3f082d (patch) | |
| tree | 2ba8da10d0d1e20565e893a777d4349fe9d483dd /drivers | |
| parent | 4ed7bdc1eb4c82cf4bfdf6a94dd36fd695f6f387 (diff) | |
| parent | 4b5f747e82b12b6d8ab815fc259827a615c7f2c3 (diff) | |
Merge tag 'libnvdimm-for-4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull libnvdimm updates from Dan Williams:
"The vast bulk of this update is the new support for the security
capabilities of some nvdimms.
The userspace tooling for this capability is still a work in progress,
but the changes survive the existing libnvdimm unit tests. The changes
also pass manual checkout on hardware and the new nfit_test emulation
of the security capability.
The touches of the security/keys/ files have received the necessary
acks from Mimi and David. Those changes were necessary to allow for a
new generic encrypted-key type, and allow the nvdimm sub-system to
lookup key material referenced by the libnvdimm-sysfs interface.
Summary:
- Add support for the security features of nvdimm devices that
implement a security model similar to ATA hard drive security. The
security model supports locking access to the media at
device-power-loss, to be unlocked with a passphrase, and
secure-erase (crypto-scramble).
Unlike the ATA security case where the kernel expects device
security to be managed in a pre-OS environment, the libnvdimm
security implementation allows key provisioning and key-operations
at OS runtime. Keys are managed with the kernel's encrypted-keys
facility to provide data-at-rest security for the libnvdimm key
material. The usage model mirrors fscrypt key management, but is
driven via libnvdimm sysfs.
- Miscellaneous updates for api usage and comment fixes"
* tag 'libnvdimm-for-4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: (21 commits)
libnvdimm/security: Quiet security operations
libnvdimm/security: Add documentation for nvdimm security support
tools/testing/nvdimm: add Intel DSM 1.8 support for nfit_test
tools/testing/nvdimm: Add overwrite support for nfit_test
tools/testing/nvdimm: Add test support for Intel nvdimm security DSMs
acpi/nfit, libnvdimm/security: add Intel DSM 1.8 master passphrase support
acpi/nfit, libnvdimm/security: Add security DSM overwrite support
acpi/nfit, libnvdimm: Add support for issue secure erase DSM to Intel nvdimm
acpi/nfit, libnvdimm: Add enable/update passphrase support for Intel nvdimms
acpi/nfit, libnvdimm: Add disable passphrase support to Intel nvdimm.
acpi/nfit, libnvdimm: Add unlock of nvdimm support for Intel DIMMs
acpi/nfit, libnvdimm: Add freeze security support to Intel nvdimm
acpi/nfit, libnvdimm: Introduce nvdimm_security_ops
keys-encrypted: add nvdimm key format type to encrypted keys
keys: Export lookup_user_key to external users
acpi/nfit, libnvdimm: Store dimm id as a member to struct nvdimm
libnvdimm, namespace: Replace kmemdup() with kstrndup()
libnvdimm, label: Switch to bitmap_zalloc()
ACPI/nfit: Adjust annotation for why return 0 if fail to find NFIT at start
libnvdimm, bus: Check id immediately following ida_simple_get
...
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/acpi/nfit/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/acpi/nfit/Makefile | 1 | ||||
| -rw-r--r-- | drivers/acpi/nfit/core.c | 103 | ||||
| -rw-r--r-- | drivers/acpi/nfit/intel.c | 388 | ||||
| -rw-r--r-- | drivers/acpi/nfit/intel.h | 76 | ||||
| -rw-r--r-- | drivers/acpi/nfit/nfit.h | 24 | ||||
| -rw-r--r-- | drivers/nvdimm/Kconfig | 5 | ||||
| -rw-r--r-- | drivers/nvdimm/Makefile | 1 | ||||
| -rw-r--r-- | drivers/nvdimm/bus.c | 33 | ||||
| -rw-r--r-- | drivers/nvdimm/dimm.c | 16 | ||||
| -rw-r--r-- | drivers/nvdimm/dimm_devs.c | 210 | ||||
| -rw-r--r-- | drivers/nvdimm/label.c | 7 | ||||
| -rw-r--r-- | drivers/nvdimm/namespace_devs.c | 3 | ||||
| -rw-r--r-- | drivers/nvdimm/nd-core.h | 57 | ||||
| -rw-r--r-- | drivers/nvdimm/nd.h | 8 | ||||
| -rw-r--r-- | drivers/nvdimm/region_devs.c | 5 | ||||
| -rw-r--r-- | drivers/nvdimm/security.c | 454 |
17 files changed, 1365 insertions, 37 deletions
diff --git a/drivers/acpi/nfit/Kconfig b/drivers/acpi/nfit/Kconfig index f7c57e33499e..52eefd732cf2 100644 --- a/drivers/acpi/nfit/Kconfig +++ b/drivers/acpi/nfit/Kconfig | |||
| @@ -13,3 +13,14 @@ config ACPI_NFIT | |||
| 13 | 13 | ||
| 14 | To compile this driver as a module, choose M here: | 14 | To compile this driver as a module, choose M here: |
| 15 | the module will be called nfit. | 15 | the module will be called nfit. |
| 16 | |||
| 17 | config NFIT_SECURITY_DEBUG | ||
| 18 | bool "Enable debug for NVDIMM security commands" | ||
| 19 | depends on ACPI_NFIT | ||
| 20 | help | ||
| 21 | Some NVDIMM devices and controllers support encryption and | ||
| 22 | other security features. The payloads for the commands that | ||
| 23 | enable those features may contain sensitive clear-text | ||
| 24 | security material. Disable debug of those command payloads | ||
| 25 | by default. If you are a kernel developer actively working | ||
| 26 | on NVDIMM security enabling say Y, otherwise say N. | ||
diff --git a/drivers/acpi/nfit/Makefile b/drivers/acpi/nfit/Makefile index a407e769f103..751081c47886 100644 --- a/drivers/acpi/nfit/Makefile +++ b/drivers/acpi/nfit/Makefile | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | obj-$(CONFIG_ACPI_NFIT) := nfit.o | 1 | obj-$(CONFIG_ACPI_NFIT) := nfit.o |
| 2 | nfit-y := core.o | 2 | nfit-y := core.o |
| 3 | nfit-y += intel.o | ||
| 3 | nfit-$(CONFIG_X86_MCE) += mce.o | 4 | nfit-$(CONFIG_X86_MCE) += mce.o |
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 5912d30020c7..011d3db19c80 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/nd.h> | 24 | #include <linux/nd.h> |
| 25 | #include <asm/cacheflush.h> | 25 | #include <asm/cacheflush.h> |
| 26 | #include <acpi/nfit.h> | 26 | #include <acpi/nfit.h> |
| 27 | #include "intel.h" | ||
| 27 | #include "nfit.h" | 28 | #include "nfit.h" |
| 28 | #include "intel.h" | 29 | #include "intel.h" |
| 29 | 30 | ||
| @@ -380,6 +381,16 @@ static u8 nfit_dsm_revid(unsigned family, unsigned func) | |||
| 380 | [NVDIMM_INTEL_QUERY_FWUPDATE] = 2, | 381 | [NVDIMM_INTEL_QUERY_FWUPDATE] = 2, |
| 381 | [NVDIMM_INTEL_SET_THRESHOLD] = 2, | 382 | [NVDIMM_INTEL_SET_THRESHOLD] = 2, |
| 382 | [NVDIMM_INTEL_INJECT_ERROR] = 2, | 383 | [NVDIMM_INTEL_INJECT_ERROR] = 2, |
| 384 | [NVDIMM_INTEL_GET_SECURITY_STATE] = 2, | ||
| 385 | [NVDIMM_INTEL_SET_PASSPHRASE] = 2, | ||
| 386 | [NVDIMM_INTEL_DISABLE_PASSPHRASE] = 2, | ||
| 387 | [NVDIMM_INTEL_UNLOCK_UNIT] = 2, | ||
| 388 | [NVDIMM_INTEL_FREEZE_LOCK] = 2, | ||
| 389 | [NVDIMM_INTEL_SECURE_ERASE] = 2, | ||
| 390 | [NVDIMM_INTEL_OVERWRITE] = 2, | ||
| 391 | [NVDIMM_INTEL_QUERY_OVERWRITE] = 2, | ||
| 392 | [NVDIMM_INTEL_SET_MASTER_PASSPHRASE] = 2, | ||
| 393 | [NVDIMM_INTEL_MASTER_SECURE_ERASE] = 2, | ||
| 383 | }, | 394 | }, |
| 384 | }; | 395 | }; |
| 385 | u8 id; | 396 | u8 id; |
| @@ -394,6 +405,17 @@ static u8 nfit_dsm_revid(unsigned family, unsigned func) | |||
| 394 | return id; | 405 | return id; |
| 395 | } | 406 | } |
| 396 | 407 | ||
| 408 | static bool payload_dumpable(struct nvdimm *nvdimm, unsigned int func) | ||
| 409 | { | ||
| 410 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 411 | |||
| 412 | if (nfit_mem && nfit_mem->family == NVDIMM_FAMILY_INTEL | ||
| 413 | && func >= NVDIMM_INTEL_GET_SECURITY_STATE | ||
| 414 | && func <= NVDIMM_INTEL_MASTER_SECURE_ERASE) | ||
| 415 | return IS_ENABLED(CONFIG_NFIT_SECURITY_DEBUG); | ||
| 416 | return true; | ||
| 417 | } | ||
| 418 | |||
| 397 | int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, | 419 | int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, |
| 398 | unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) | 420 | unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc) |
| 399 | { | 421 | { |
| @@ -478,9 +500,10 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, | |||
| 478 | 500 | ||
| 479 | dev_dbg(dev, "%s cmd: %d: func: %d input length: %d\n", | 501 | dev_dbg(dev, "%s cmd: %d: func: %d input length: %d\n", |
| 480 | dimm_name, cmd, func, in_buf.buffer.length); | 502 | dimm_name, cmd, func, in_buf.buffer.length); |
| 481 | print_hex_dump_debug("nvdimm in ", DUMP_PREFIX_OFFSET, 4, 4, | 503 | if (payload_dumpable(nvdimm, func)) |
| 482 | in_buf.buffer.pointer, | 504 | print_hex_dump_debug("nvdimm in ", DUMP_PREFIX_OFFSET, 4, 4, |
| 483 | min_t(u32, 256, in_buf.buffer.length), true); | 505 | in_buf.buffer.pointer, |
| 506 | min_t(u32, 256, in_buf.buffer.length), true); | ||
| 484 | 507 | ||
| 485 | /* call the BIOS, prefer the named methods over _DSM if available */ | 508 | /* call the BIOS, prefer the named methods over _DSM if available */ |
| 486 | if (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE | 509 | if (nvdimm && cmd == ND_CMD_GET_CONFIG_SIZE |
| @@ -1573,18 +1596,10 @@ static DEVICE_ATTR_RO(flags); | |||
| 1573 | static ssize_t id_show(struct device *dev, | 1596 | static ssize_t id_show(struct device *dev, |
| 1574 | struct device_attribute *attr, char *buf) | 1597 | struct device_attribute *attr, char *buf) |
| 1575 | { | 1598 | { |
| 1576 | struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); | 1599 | struct nvdimm *nvdimm = to_nvdimm(dev); |
| 1600 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 1577 | 1601 | ||
| 1578 | if (dcr->valid_fields & ACPI_NFIT_CONTROL_MFG_INFO_VALID) | 1602 | return sprintf(buf, "%s\n", nfit_mem->id); |
| 1579 | return sprintf(buf, "%04x-%02x-%04x-%08x\n", | ||
| 1580 | be16_to_cpu(dcr->vendor_id), | ||
| 1581 | dcr->manufacturing_location, | ||
| 1582 | be16_to_cpu(dcr->manufacturing_date), | ||
| 1583 | be32_to_cpu(dcr->serial_number)); | ||
| 1584 | else | ||
| 1585 | return sprintf(buf, "%04x-%08x\n", | ||
| 1586 | be16_to_cpu(dcr->vendor_id), | ||
| 1587 | be32_to_cpu(dcr->serial_number)); | ||
| 1588 | } | 1603 | } |
| 1589 | static DEVICE_ATTR_RO(id); | 1604 | static DEVICE_ATTR_RO(id); |
| 1590 | 1605 | ||
| @@ -1780,10 +1795,23 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, | |||
| 1780 | const guid_t *guid; | 1795 | const guid_t *guid; |
| 1781 | int i; | 1796 | int i; |
| 1782 | int family = -1; | 1797 | int family = -1; |
| 1798 | struct acpi_nfit_control_region *dcr = nfit_mem->dcr; | ||
| 1783 | 1799 | ||
| 1784 | /* nfit test assumes 1:1 relationship between commands and dsms */ | 1800 | /* nfit test assumes 1:1 relationship between commands and dsms */ |
| 1785 | nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en; | 1801 | nfit_mem->dsm_mask = acpi_desc->dimm_cmd_force_en; |
| 1786 | nfit_mem->family = NVDIMM_FAMILY_INTEL; | 1802 | nfit_mem->family = NVDIMM_FAMILY_INTEL; |
| 1803 | |||
| 1804 | if (dcr->valid_fields & ACPI_NFIT_CONTROL_MFG_INFO_VALID) | ||
| 1805 | sprintf(nfit_mem->id, "%04x-%02x-%04x-%08x", | ||
| 1806 | be16_to_cpu(dcr->vendor_id), | ||
| 1807 | dcr->manufacturing_location, | ||
| 1808 | be16_to_cpu(dcr->manufacturing_date), | ||
| 1809 | be32_to_cpu(dcr->serial_number)); | ||
| 1810 | else | ||
| 1811 | sprintf(nfit_mem->id, "%04x-%08x", | ||
| 1812 | be16_to_cpu(dcr->vendor_id), | ||
| 1813 | be32_to_cpu(dcr->serial_number)); | ||
| 1814 | |||
| 1787 | adev = to_acpi_dev(acpi_desc); | 1815 | adev = to_acpi_dev(acpi_desc); |
| 1788 | if (!adev) { | 1816 | if (!adev) { |
| 1789 | /* unit test case */ | 1817 | /* unit test case */ |
| @@ -1904,6 +1932,16 @@ static void shutdown_dimm_notify(void *data) | |||
| 1904 | mutex_unlock(&acpi_desc->init_mutex); | 1932 | mutex_unlock(&acpi_desc->init_mutex); |
| 1905 | } | 1933 | } |
| 1906 | 1934 | ||
| 1935 | static const struct nvdimm_security_ops *acpi_nfit_get_security_ops(int family) | ||
| 1936 | { | ||
| 1937 | switch (family) { | ||
| 1938 | case NVDIMM_FAMILY_INTEL: | ||
| 1939 | return intel_security_ops; | ||
| 1940 | default: | ||
| 1941 | return NULL; | ||
| 1942 | } | ||
| 1943 | } | ||
| 1944 | |||
| 1907 | static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) | 1945 | static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) |
| 1908 | { | 1946 | { |
| 1909 | struct nfit_mem *nfit_mem; | 1947 | struct nfit_mem *nfit_mem; |
| @@ -1970,10 +2008,11 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) | |||
| 1970 | 2008 | ||
| 1971 | flush = nfit_mem->nfit_flush ? nfit_mem->nfit_flush->flush | 2009 | flush = nfit_mem->nfit_flush ? nfit_mem->nfit_flush->flush |
| 1972 | : NULL; | 2010 | : NULL; |
| 1973 | nvdimm = nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem, | 2011 | nvdimm = __nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem, |
| 1974 | acpi_nfit_dimm_attribute_groups, | 2012 | acpi_nfit_dimm_attribute_groups, |
| 1975 | flags, cmd_mask, flush ? flush->hint_count : 0, | 2013 | flags, cmd_mask, flush ? flush->hint_count : 0, |
| 1976 | nfit_mem->flush_wpq); | 2014 | nfit_mem->flush_wpq, &nfit_mem->id[0], |
| 2015 | acpi_nfit_get_security_ops(nfit_mem->family)); | ||
| 1977 | if (!nvdimm) | 2016 | if (!nvdimm) |
| 1978 | return -ENOMEM; | 2017 | return -ENOMEM; |
| 1979 | 2018 | ||
| @@ -2008,6 +2047,11 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) | |||
| 2008 | if (!nvdimm) | 2047 | if (!nvdimm) |
| 2009 | continue; | 2048 | continue; |
| 2010 | 2049 | ||
| 2050 | rc = nvdimm_security_setup_events(nvdimm); | ||
| 2051 | if (rc < 0) | ||
| 2052 | dev_warn(acpi_desc->dev, | ||
| 2053 | "security event setup failed: %d\n", rc); | ||
| 2054 | |||
| 2011 | nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit"); | 2055 | nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit"); |
| 2012 | if (nfit_kernfs) | 2056 | if (nfit_kernfs) |
| 2013 | nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs, | 2057 | nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs, |
| @@ -3337,7 +3381,7 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) | |||
| 3337 | return 0; | 3381 | return 0; |
| 3338 | } | 3382 | } |
| 3339 | 3383 | ||
| 3340 | static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, | 3384 | static int __acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, |
| 3341 | struct nvdimm *nvdimm, unsigned int cmd) | 3385 | struct nvdimm *nvdimm, unsigned int cmd) |
| 3342 | { | 3386 | { |
| 3343 | struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); | 3387 | struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); |
| @@ -3359,6 +3403,23 @@ static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, | |||
| 3359 | return 0; | 3403 | return 0; |
| 3360 | } | 3404 | } |
| 3361 | 3405 | ||
| 3406 | /* prevent security commands from being issued via ioctl */ | ||
| 3407 | static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, | ||
| 3408 | struct nvdimm *nvdimm, unsigned int cmd, void *buf) | ||
| 3409 | { | ||
| 3410 | struct nd_cmd_pkg *call_pkg = buf; | ||
| 3411 | unsigned int func; | ||
| 3412 | |||
| 3413 | if (nvdimm && cmd == ND_CMD_CALL && | ||
| 3414 | call_pkg->nd_family == NVDIMM_FAMILY_INTEL) { | ||
| 3415 | func = call_pkg->nd_command; | ||
| 3416 | if ((1 << func) & NVDIMM_INTEL_SECURITY_CMDMASK) | ||
| 3417 | return -EOPNOTSUPP; | ||
| 3418 | } | ||
| 3419 | |||
| 3420 | return __acpi_nfit_clear_to_send(nd_desc, nvdimm, cmd); | ||
| 3421 | } | ||
| 3422 | |||
| 3362 | int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, | 3423 | int acpi_nfit_ars_rescan(struct acpi_nfit_desc *acpi_desc, |
| 3363 | enum nfit_ars_state req_type) | 3424 | enum nfit_ars_state req_type) |
| 3364 | { | 3425 | { |
| @@ -3474,7 +3535,13 @@ static int acpi_nfit_add(struct acpi_device *adev) | |||
| 3474 | 3535 | ||
| 3475 | status = acpi_get_table(ACPI_SIG_NFIT, 0, &tbl); | 3536 | status = acpi_get_table(ACPI_SIG_NFIT, 0, &tbl); |
| 3476 | if (ACPI_FAILURE(status)) { | 3537 | if (ACPI_FAILURE(status)) { |
| 3477 | /* This is ok, we could have an nvdimm hotplugged later */ | 3538 | /* The NVDIMM root device allows OS to trigger enumeration of |
| 3539 | * NVDIMMs through NFIT at boot time and re-enumeration at | ||
| 3540 | * root level via the _FIT method during runtime. | ||
| 3541 | * This is ok to return 0 here, we could have an nvdimm | ||
| 3542 | * hotplugged later and evaluate _FIT method which returns | ||
| 3543 | * data in the format of a series of NFIT Structures. | ||
| 3544 | */ | ||
| 3478 | dev_dbg(dev, "failed to find NFIT at startup\n"); | 3545 | dev_dbg(dev, "failed to find NFIT at startup\n"); |
| 3479 | return 0; | 3546 | return 0; |
| 3480 | } | 3547 | } |
diff --git a/drivers/acpi/nfit/intel.c b/drivers/acpi/nfit/intel.c new file mode 100644 index 000000000000..850b2927b4e7 --- /dev/null +++ b/drivers/acpi/nfit/intel.c | |||
| @@ -0,0 +1,388 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* Copyright(c) 2018 Intel Corporation. All rights reserved. */ | ||
| 3 | #include <linux/libnvdimm.h> | ||
| 4 | #include <linux/ndctl.h> | ||
| 5 | #include <linux/acpi.h> | ||
| 6 | #include <asm/smp.h> | ||
| 7 | #include "intel.h" | ||
| 8 | #include "nfit.h" | ||
| 9 | |||
| 10 | static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm, | ||
| 11 | enum nvdimm_passphrase_type ptype) | ||
| 12 | { | ||
| 13 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 14 | struct { | ||
| 15 | struct nd_cmd_pkg pkg; | ||
| 16 | struct nd_intel_get_security_state cmd; | ||
| 17 | } nd_cmd = { | ||
| 18 | .pkg = { | ||
| 19 | .nd_command = NVDIMM_INTEL_GET_SECURITY_STATE, | ||
| 20 | .nd_family = NVDIMM_FAMILY_INTEL, | ||
| 21 | .nd_size_out = | ||
| 22 | sizeof(struct nd_intel_get_security_state), | ||
| 23 | .nd_fw_size = | ||
| 24 | sizeof(struct nd_intel_get_security_state), | ||
| 25 | }, | ||
| 26 | }; | ||
| 27 | int rc; | ||
| 28 | |||
| 29 | if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask)) | ||
| 30 | return -ENXIO; | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Short circuit the state retrieval while we are doing overwrite. | ||
| 34 | * The DSM spec states that the security state is indeterminate | ||
| 35 | * until the overwrite DSM completes. | ||
| 36 | */ | ||
| 37 | if (nvdimm_in_overwrite(nvdimm) && ptype == NVDIMM_USER) | ||
| 38 | return NVDIMM_SECURITY_OVERWRITE; | ||
| 39 | |||
| 40 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); | ||
| 41 | if (rc < 0) | ||
| 42 | return rc; | ||
| 43 | if (nd_cmd.cmd.status) | ||
| 44 | return -EIO; | ||
| 45 | |||
| 46 | /* check and see if security is enabled and locked */ | ||
| 47 | if (ptype == NVDIMM_MASTER) { | ||
| 48 | if (nd_cmd.cmd.extended_state & ND_INTEL_SEC_ESTATE_ENABLED) | ||
| 49 | return NVDIMM_SECURITY_UNLOCKED; | ||
| 50 | else if (nd_cmd.cmd.extended_state & | ||
| 51 | ND_INTEL_SEC_ESTATE_PLIMIT) | ||
| 52 | return NVDIMM_SECURITY_FROZEN; | ||
| 53 | } else { | ||
| 54 | if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED) | ||
| 55 | return -ENXIO; | ||
| 56 | else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) { | ||
| 57 | if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED) | ||
| 58 | return NVDIMM_SECURITY_LOCKED; | ||
| 59 | else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN | ||
| 60 | || nd_cmd.cmd.state & | ||
| 61 | ND_INTEL_SEC_STATE_PLIMIT) | ||
| 62 | return NVDIMM_SECURITY_FROZEN; | ||
| 63 | else | ||
| 64 | return NVDIMM_SECURITY_UNLOCKED; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | /* this should cover master security disabled as well */ | ||
| 69 | return NVDIMM_SECURITY_DISABLED; | ||
| 70 | } | ||
| 71 | |||
| 72 | static int intel_security_freeze(struct nvdimm *nvdimm) | ||
| 73 | { | ||
| 74 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 75 | struct { | ||
| 76 | struct nd_cmd_pkg pkg; | ||
| 77 | struct nd_intel_freeze_lock cmd; | ||
| 78 | } nd_cmd = { | ||
| 79 | .pkg = { | ||
| 80 | .nd_command = NVDIMM_INTEL_FREEZE_LOCK, | ||
| 81 | .nd_family = NVDIMM_FAMILY_INTEL, | ||
| 82 | .nd_size_out = ND_INTEL_STATUS_SIZE, | ||
| 83 | .nd_fw_size = ND_INTEL_STATUS_SIZE, | ||
| 84 | }, | ||
| 85 | }; | ||
| 86 | int rc; | ||
| 87 | |||
| 88 | if (!test_bit(NVDIMM_INTEL_FREEZE_LOCK, &nfit_mem->dsm_mask)) | ||
| 89 | return -ENOTTY; | ||
| 90 | |||
| 91 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); | ||
| 92 | if (rc < 0) | ||
| 93 | return rc; | ||
| 94 | if (nd_cmd.cmd.status) | ||
| 95 | return -EIO; | ||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int intel_security_change_key(struct nvdimm *nvdimm, | ||
| 100 | const struct nvdimm_key_data *old_data, | ||
| 101 | const struct nvdimm_key_data *new_data, | ||
| 102 | enum nvdimm_passphrase_type ptype) | ||
| 103 | { | ||
| 104 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 105 | unsigned int cmd = ptype == NVDIMM_MASTER ? | ||
| 106 | NVDIMM_INTEL_SET_MASTER_PASSPHRASE : | ||
| 107 | NVDIMM_INTEL_SET_PASSPHRASE; | ||
| 108 | struct { | ||
| 109 | struct nd_cmd_pkg pkg; | ||
| 110 | struct nd_intel_set_passphrase cmd; | ||
| 111 | } nd_cmd = { | ||
| 112 | .pkg = { | ||
| 113 | .nd_family = NVDIMM_FAMILY_INTEL, | ||
| 114 | .nd_size_in = ND_INTEL_PASSPHRASE_SIZE * 2, | ||
| 115 | .nd_size_out = ND_INTEL_STATUS_SIZE, | ||
| 116 | .nd_fw_size = ND_INTEL_STATUS_SIZE, | ||
| 117 | .nd_command = cmd, | ||
| 118 | }, | ||
| 119 | }; | ||
| 120 | int rc; | ||
| 121 | |||
| 122 | if (!test_bit(cmd, &nfit_mem->dsm_mask)) | ||
| 123 | return -ENOTTY; | ||
| 124 | |||
| 125 | if (old_data) | ||
| 126 | memcpy(nd_cmd.cmd.old_pass, old_data->data, | ||
| 127 | sizeof(nd_cmd.cmd.old_pass)); | ||
| 128 | memcpy(nd_cmd.cmd.new_pass, new_data->data, | ||
| 129 | sizeof(nd_cmd.cmd.new_pass)); | ||
| 130 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); | ||
| 131 | if (rc < 0) | ||
| 132 | return rc; | ||
| 133 | |||
| 134 | switch (nd_cmd.cmd.status) { | ||
| 135 | case 0: | ||
| 136 | return 0; | ||
| 137 | case ND_INTEL_STATUS_INVALID_PASS: | ||
| 138 | return -EINVAL; | ||
| 139 | case ND_INTEL_STATUS_NOT_SUPPORTED: | ||
| 140 | return -EOPNOTSUPP; | ||
| 141 | case ND_INTEL_STATUS_INVALID_STATE: | ||
| 142 | default: | ||
| 143 | return -EIO; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | static void nvdimm_invalidate_cache(void); | ||
| 148 | |||
| 149 | static int intel_security_unlock(struct nvdimm *nvdimm, | ||
| 150 | const struct nvdimm_key_data *key_data) | ||
| 151 | { | ||
| 152 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 153 | struct { | ||
| 154 | struct nd_cmd_pkg pkg; | ||
| 155 | struct nd_intel_unlock_unit cmd; | ||
| 156 | } nd_cmd = { | ||
| 157 | .pkg = { | ||
| 158 | .nd_command = NVDIMM_INTEL_UNLOCK_UNIT, | ||
| 159 | .nd_family = NVDIMM_FAMILY_INTEL, | ||
| 160 | .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, | ||
| 161 | .nd_size_out = ND_INTEL_STATUS_SIZE, | ||
| 162 | .nd_fw_size = ND_INTEL_STATUS_SIZE, | ||
| 163 | }, | ||
| 164 | }; | ||
| 165 | int rc; | ||
| 166 | |||
| 167 | if (!test_bit(NVDIMM_INTEL_UNLOCK_UNIT, &nfit_mem->dsm_mask)) | ||
| 168 | return -ENOTTY; | ||
| 169 | |||
| 170 | memcpy(nd_cmd.cmd.passphrase, key_data->data, | ||
| 171 | sizeof(nd_cmd.cmd.passphrase)); | ||
| 172 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); | ||
| 173 | if (rc < 0) | ||
| 174 | return rc; | ||
| 175 | switch (nd_cmd.cmd.status) { | ||
| 176 | case 0: | ||
| 177 | break; | ||
| 178 | case ND_INTEL_STATUS_INVALID_PASS: | ||
| 179 | return -EINVAL; | ||
| 180 | default: | ||
| 181 | return -EIO; | ||
| 182 | } | ||
| 183 | |||
| 184 | /* DIMM unlocked, invalidate all CPU caches before we read it */ | ||
| 185 | nvdimm_invalidate_cache(); | ||
| 186 | |||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | static int intel_security_disable(struct nvdimm *nvdimm, | ||
| 191 | const struct nvdimm_key_data *key_data) | ||
| 192 | { | ||
| 193 | int rc; | ||
| 194 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 195 | struct { | ||
| 196 | struct nd_cmd_pkg pkg; | ||
| 197 | struct nd_intel_disable_passphrase cmd; | ||
| 198 | } nd_cmd = { | ||
| 199 | .pkg = { | ||
| 200 | .nd_command = NVDIMM_INTEL_DISABLE_PASSPHRASE, | ||
| 201 | .nd_family = NVDIMM_FAMILY_INTEL, | ||
| 202 | .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, | ||
| 203 | .nd_size_out = ND_INTEL_STATUS_SIZE, | ||
| 204 | .nd_fw_size = ND_INTEL_STATUS_SIZE, | ||
| 205 | }, | ||
| 206 | }; | ||
| 207 | |||
| 208 | if (!test_bit(NVDIMM_INTEL_DISABLE_PASSPHRASE, &nfit_mem->dsm_mask)) | ||
| 209 | return -ENOTTY; | ||
| 210 | |||
| 211 | memcpy(nd_cmd.cmd.passphrase, key_data->data, | ||
| 212 | sizeof(nd_cmd.cmd.passphrase)); | ||
| 213 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); | ||
| 214 | if (rc < 0) | ||
| 215 | return rc; | ||
| 216 | |||
| 217 | switch (nd_cmd.cmd.status) { | ||
| 218 | case 0: | ||
| 219 | break; | ||
| 220 | case ND_INTEL_STATUS_INVALID_PASS: | ||
| 221 | return -EINVAL; | ||
| 222 | case ND_INTEL_STATUS_INVALID_STATE: | ||
| 223 | default: | ||
| 224 | return -ENXIO; | ||
| 225 | } | ||
| 226 | |||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | |||
| 230 | static int intel_security_erase(struct nvdimm *nvdimm, | ||
| 231 | const struct nvdimm_key_data *key, | ||
| 232 | enum nvdimm_passphrase_type ptype) | ||
| 233 | { | ||
| 234 | int rc; | ||
| 235 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 236 | unsigned int cmd = ptype == NVDIMM_MASTER ? | ||
| 237 | NVDIMM_INTEL_MASTER_SECURE_ERASE : NVDIMM_INTEL_SECURE_ERASE; | ||
| 238 | struct { | ||
| 239 | struct nd_cmd_pkg pkg; | ||
| 240 | struct nd_intel_secure_erase cmd; | ||
| 241 | } nd_cmd = { | ||
| 242 | .pkg = { | ||
| 243 | .nd_family = NVDIMM_FAMILY_INTEL, | ||
| 244 | .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, | ||
| 245 | .nd_size_out = ND_INTEL_STATUS_SIZE, | ||
| 246 | .nd_fw_size = ND_INTEL_STATUS_SIZE, | ||
| 247 | .nd_command = cmd, | ||
| 248 | }, | ||
| 249 | }; | ||
| 250 | |||
| 251 | if (!test_bit(cmd, &nfit_mem->dsm_mask)) | ||
| 252 | return -ENOTTY; | ||
| 253 | |||
| 254 | /* flush all cache before we erase DIMM */ | ||
| 255 | nvdimm_invalidate_cache(); | ||
| 256 | memcpy(nd_cmd.cmd.passphrase, key->data, | ||
| 257 | sizeof(nd_cmd.cmd.passphrase)); | ||
| 258 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); | ||
| 259 | if (rc < 0) | ||
| 260 | return rc; | ||
| 261 | |||
| 262 | switch (nd_cmd.cmd.status) { | ||
| 263 | case 0: | ||
| 264 | break; | ||
| 265 | case ND_INTEL_STATUS_NOT_SUPPORTED: | ||
| 266 | return -EOPNOTSUPP; | ||
| 267 | case ND_INTEL_STATUS_INVALID_PASS: | ||
| 268 | return -EINVAL; | ||
| 269 | case ND_INTEL_STATUS_INVALID_STATE: | ||
| 270 | default: | ||
| 271 | return -ENXIO; | ||
| 272 | } | ||
| 273 | |||
| 274 | /* DIMM erased, invalidate all CPU caches before we read it */ | ||
| 275 | nvdimm_invalidate_cache(); | ||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 279 | static int intel_security_query_overwrite(struct nvdimm *nvdimm) | ||
| 280 | { | ||
| 281 | int rc; | ||
| 282 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 283 | struct { | ||
| 284 | struct nd_cmd_pkg pkg; | ||
| 285 | struct nd_intel_query_overwrite cmd; | ||
| 286 | } nd_cmd = { | ||
| 287 | .pkg = { | ||
| 288 | .nd_command = NVDIMM_INTEL_QUERY_OVERWRITE, | ||
| 289 | .nd_family = NVDIMM_FAMILY_INTEL, | ||
| 290 | .nd_size_out = ND_INTEL_STATUS_SIZE, | ||
| 291 | .nd_fw_size = ND_INTEL_STATUS_SIZE, | ||
| 292 | }, | ||
| 293 | }; | ||
| 294 | |||
| 295 | if (!test_bit(NVDIMM_INTEL_QUERY_OVERWRITE, &nfit_mem->dsm_mask)) | ||
| 296 | return -ENOTTY; | ||
| 297 | |||
| 298 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); | ||
| 299 | if (rc < 0) | ||
| 300 | return rc; | ||
| 301 | |||
| 302 | switch (nd_cmd.cmd.status) { | ||
| 303 | case 0: | ||
| 304 | break; | ||
| 305 | case ND_INTEL_STATUS_OQUERY_INPROGRESS: | ||
| 306 | return -EBUSY; | ||
| 307 | default: | ||
| 308 | return -ENXIO; | ||
| 309 | } | ||
| 310 | |||
| 311 | /* flush all cache before we make the nvdimms available */ | ||
| 312 | nvdimm_invalidate_cache(); | ||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | static int intel_security_overwrite(struct nvdimm *nvdimm, | ||
| 317 | const struct nvdimm_key_data *nkey) | ||
| 318 | { | ||
| 319 | int rc; | ||
| 320 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
| 321 | struct { | ||
| 322 | struct nd_cmd_pkg pkg; | ||
| 323 | struct nd_intel_overwrite cmd; | ||
| 324 | } nd_cmd = { | ||
| 325 | .pkg = { | ||
| 326 | .nd_command = NVDIMM_INTEL_OVERWRITE, | ||
| 327 | .nd_family = NVDIMM_FAMILY_INTEL, | ||
| 328 | .nd_size_in = ND_INTEL_PASSPHRASE_SIZE, | ||
| 329 | .nd_size_out = ND_INTEL_STATUS_SIZE, | ||
| 330 | .nd_fw_size = ND_INTEL_STATUS_SIZE, | ||
| 331 | }, | ||
| 332 | }; | ||
| 333 | |||
| 334 | if (!test_bit(NVDIMM_INTEL_OVERWRITE, &nfit_mem->dsm_mask)) | ||
| 335 | return -ENOTTY; | ||
| 336 | |||
| 337 | /* flush all cache before we erase DIMM */ | ||
| 338 | nvdimm_invalidate_cache(); | ||
| 339 | if (nkey) | ||
| 340 | memcpy(nd_cmd.cmd.passphrase, nkey->data, | ||
| 341 | sizeof(nd_cmd.cmd.passphrase)); | ||
| 342 | rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL); | ||
| 343 | if (rc < 0) | ||
| 344 | return rc; | ||
| 345 | |||
| 346 | switch (nd_cmd.cmd.status) { | ||
| 347 | case 0: | ||
| 348 | return 0; | ||
| 349 | case ND_INTEL_STATUS_OVERWRITE_UNSUPPORTED: | ||
| 350 | return -ENOTSUPP; | ||
| 351 | case ND_INTEL_STATUS_INVALID_PASS: | ||
| 352 | return -EINVAL; | ||
| 353 | case ND_INTEL_STATUS_INVALID_STATE: | ||
| 354 | default: | ||
| 355 | return -ENXIO; | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 359 | /* | ||
| 360 | * TODO: define a cross arch wbinvd equivalent when/if | ||
| 361 | * NVDIMM_FAMILY_INTEL command support arrives on another arch. | ||
| 362 | */ | ||
| 363 | #ifdef CONFIG_X86 | ||
| 364 | static void nvdimm_invalidate_cache(void) | ||
| 365 | { | ||
| 366 | wbinvd_on_all_cpus(); | ||
| 367 | } | ||
| 368 | #else | ||
| 369 | static void nvdimm_invalidate_cache(void) | ||
| 370 | { | ||
| 371 | WARN_ON_ONCE("cache invalidation required after unlock\n"); | ||
| 372 | } | ||
| 373 | #endif | ||
| 374 | |||
| 375 | static const struct nvdimm_security_ops __intel_security_ops = { | ||
| 376 | .state = intel_security_state, | ||
| 377 | .freeze = intel_security_freeze, | ||
| 378 | .change_key = intel_security_change_key, | ||
| 379 | .disable = intel_security_disable, | ||
| 380 | #ifdef CONFIG_X86 | ||
| 381 | .unlock = intel_security_unlock, | ||
| 382 | .erase = intel_security_erase, | ||
| 383 | .overwrite = intel_security_overwrite, | ||
| 384 | .query_overwrite = intel_security_query_overwrite, | ||
| 385 | #endif | ||
| 386 | }; | ||
| 387 | |||
| 388 | const struct nvdimm_security_ops *intel_security_ops = &__intel_security_ops; | ||
diff --git a/drivers/acpi/nfit/intel.h b/drivers/acpi/nfit/intel.h index 86746312381f..0aca682ab9d7 100644 --- a/drivers/acpi/nfit/intel.h +++ b/drivers/acpi/nfit/intel.h | |||
| @@ -35,4 +35,80 @@ struct nd_intel_smart { | |||
| 35 | }; | 35 | }; |
| 36 | } __packed; | 36 | } __packed; |
| 37 | 37 | ||
| 38 | extern const struct nvdimm_security_ops *intel_security_ops; | ||
| 39 | |||
| 40 | #define ND_INTEL_STATUS_SIZE 4 | ||
| 41 | #define ND_INTEL_PASSPHRASE_SIZE 32 | ||
| 42 | |||
| 43 | #define ND_INTEL_STATUS_NOT_SUPPORTED 1 | ||
| 44 | #define ND_INTEL_STATUS_RETRY 5 | ||
| 45 | #define ND_INTEL_STATUS_NOT_READY 9 | ||
| 46 | #define ND_INTEL_STATUS_INVALID_STATE 10 | ||
| 47 | #define ND_INTEL_STATUS_INVALID_PASS 11 | ||
| 48 | #define ND_INTEL_STATUS_OVERWRITE_UNSUPPORTED 0x10007 | ||
| 49 | #define ND_INTEL_STATUS_OQUERY_INPROGRESS 0x10007 | ||
| 50 | #define ND_INTEL_STATUS_OQUERY_SEQUENCE_ERR 0x20007 | ||
| 51 | |||
| 52 | #define ND_INTEL_SEC_STATE_ENABLED 0x02 | ||
| 53 | #define ND_INTEL_SEC_STATE_LOCKED 0x04 | ||
| 54 | #define ND_INTEL_SEC_STATE_FROZEN 0x08 | ||
| 55 | #define ND_INTEL_SEC_STATE_PLIMIT 0x10 | ||
| 56 | #define ND_INTEL_SEC_STATE_UNSUPPORTED 0x20 | ||
| 57 | #define ND_INTEL_SEC_STATE_OVERWRITE 0x40 | ||
| 58 | |||
| 59 | #define ND_INTEL_SEC_ESTATE_ENABLED 0x01 | ||
| 60 | #define ND_INTEL_SEC_ESTATE_PLIMIT 0x02 | ||
| 61 | |||
| 62 | struct nd_intel_get_security_state { | ||
| 63 | u32 status; | ||
| 64 | u8 extended_state; | ||
| 65 | u8 reserved[3]; | ||
| 66 | u8 state; | ||
| 67 | u8 reserved1[3]; | ||
| 68 | } __packed; | ||
| 69 | |||
| 70 | struct nd_intel_set_passphrase { | ||
| 71 | u8 old_pass[ND_INTEL_PASSPHRASE_SIZE]; | ||
| 72 | u8 new_pass[ND_INTEL_PASSPHRASE_SIZE]; | ||
| 73 | u32 status; | ||
| 74 | } __packed; | ||
| 75 | |||
| 76 | struct nd_intel_unlock_unit { | ||
| 77 | u8 passphrase[ND_INTEL_PASSPHRASE_SIZE]; | ||
| 78 | u32 status; | ||
| 79 | } __packed; | ||
| 80 | |||
| 81 | struct nd_intel_disable_passphrase { | ||
| 82 | u8 passphrase[ND_INTEL_PASSPHRASE_SIZE]; | ||
| 83 | u32 status; | ||
| 84 | } __packed; | ||
| 85 | |||
| 86 | struct nd_intel_freeze_lock { | ||
| 87 | u32 status; | ||
| 88 | } __packed; | ||
| 89 | |||
| 90 | struct nd_intel_secure_erase { | ||
| 91 | u8 passphrase[ND_INTEL_PASSPHRASE_SIZE]; | ||
| 92 | u32 status; | ||
| 93 | } __packed; | ||
| 94 | |||
| 95 | struct nd_intel_overwrite { | ||
| 96 | u8 passphrase[ND_INTEL_PASSPHRASE_SIZE]; | ||
| 97 | u32 status; | ||
| 98 | } __packed; | ||
| 99 | |||
| 100 | struct nd_intel_query_overwrite { | ||
| 101 | u32 status; | ||
| 102 | } __packed; | ||
| 103 | |||
| 104 | struct nd_intel_set_master_passphrase { | ||
| 105 | u8 old_pass[ND_INTEL_PASSPHRASE_SIZE]; | ||
| 106 | u8 new_pass[ND_INTEL_PASSPHRASE_SIZE]; | ||
| 107 | u32 status; | ||
| 108 | } __packed; | ||
| 109 | |||
| 110 | struct nd_intel_master_secure_erase { | ||
| 111 | u8 passphrase[ND_INTEL_PASSPHRASE_SIZE]; | ||
| 112 | u32 status; | ||
| 113 | } __packed; | ||
| 38 | #endif | 114 | #endif |
diff --git a/drivers/acpi/nfit/nfit.h b/drivers/acpi/nfit/nfit.h index df0f6b8407e7..33691aecfcee 100644 --- a/drivers/acpi/nfit/nfit.h +++ b/drivers/acpi/nfit/nfit.h | |||
| @@ -60,14 +60,33 @@ enum nvdimm_family_cmds { | |||
| 60 | NVDIMM_INTEL_QUERY_FWUPDATE = 16, | 60 | NVDIMM_INTEL_QUERY_FWUPDATE = 16, |
| 61 | NVDIMM_INTEL_SET_THRESHOLD = 17, | 61 | NVDIMM_INTEL_SET_THRESHOLD = 17, |
| 62 | NVDIMM_INTEL_INJECT_ERROR = 18, | 62 | NVDIMM_INTEL_INJECT_ERROR = 18, |
| 63 | NVDIMM_INTEL_GET_SECURITY_STATE = 19, | ||
| 64 | NVDIMM_INTEL_SET_PASSPHRASE = 20, | ||
| 65 | NVDIMM_INTEL_DISABLE_PASSPHRASE = 21, | ||
| 66 | NVDIMM_INTEL_UNLOCK_UNIT = 22, | ||
| 67 | NVDIMM_INTEL_FREEZE_LOCK = 23, | ||
| 68 | NVDIMM_INTEL_SECURE_ERASE = 24, | ||
| 69 | NVDIMM_INTEL_OVERWRITE = 25, | ||
| 70 | NVDIMM_INTEL_QUERY_OVERWRITE = 26, | ||
| 71 | NVDIMM_INTEL_SET_MASTER_PASSPHRASE = 27, | ||
| 72 | NVDIMM_INTEL_MASTER_SECURE_ERASE = 28, | ||
| 63 | }; | 73 | }; |
| 64 | 74 | ||
| 75 | #define NVDIMM_INTEL_SECURITY_CMDMASK \ | ||
| 76 | (1 << NVDIMM_INTEL_GET_SECURITY_STATE | 1 << NVDIMM_INTEL_SET_PASSPHRASE \ | ||
| 77 | | 1 << NVDIMM_INTEL_DISABLE_PASSPHRASE | 1 << NVDIMM_INTEL_UNLOCK_UNIT \ | ||
| 78 | | 1 << NVDIMM_INTEL_FREEZE_LOCK | 1 << NVDIMM_INTEL_SECURE_ERASE \ | ||
| 79 | | 1 << NVDIMM_INTEL_OVERWRITE | 1 << NVDIMM_INTEL_QUERY_OVERWRITE \ | ||
| 80 | | 1 << NVDIMM_INTEL_SET_MASTER_PASSPHRASE \ | ||
| 81 | | 1 << NVDIMM_INTEL_MASTER_SECURE_ERASE) | ||
| 82 | |||
| 65 | #define NVDIMM_INTEL_CMDMASK \ | 83 | #define NVDIMM_INTEL_CMDMASK \ |
| 66 | (NVDIMM_STANDARD_CMDMASK | 1 << NVDIMM_INTEL_GET_MODES \ | 84 | (NVDIMM_STANDARD_CMDMASK | 1 << NVDIMM_INTEL_GET_MODES \ |
| 67 | | 1 << NVDIMM_INTEL_GET_FWINFO | 1 << NVDIMM_INTEL_START_FWUPDATE \ | 85 | | 1 << NVDIMM_INTEL_GET_FWINFO | 1 << NVDIMM_INTEL_START_FWUPDATE \ |
| 68 | | 1 << NVDIMM_INTEL_SEND_FWUPDATE | 1 << NVDIMM_INTEL_FINISH_FWUPDATE \ | 86 | | 1 << NVDIMM_INTEL_SEND_FWUPDATE | 1 << NVDIMM_INTEL_FINISH_FWUPDATE \ |
| 69 | | 1 << NVDIMM_INTEL_QUERY_FWUPDATE | 1 << NVDIMM_INTEL_SET_THRESHOLD \ | 87 | | 1 << NVDIMM_INTEL_QUERY_FWUPDATE | 1 << NVDIMM_INTEL_SET_THRESHOLD \ |
| 70 | | 1 << NVDIMM_INTEL_INJECT_ERROR | 1 << NVDIMM_INTEL_LATCH_SHUTDOWN) | 88 | | 1 << NVDIMM_INTEL_INJECT_ERROR | 1 << NVDIMM_INTEL_LATCH_SHUTDOWN \ |
| 89 | | NVDIMM_INTEL_SECURITY_CMDMASK) | ||
| 71 | 90 | ||
| 72 | enum nfit_uuids { | 91 | enum nfit_uuids { |
| 73 | /* for simplicity alias the uuid index with the family id */ | 92 | /* for simplicity alias the uuid index with the family id */ |
| @@ -164,6 +183,8 @@ enum nfit_mem_flags { | |||
| 164 | NFIT_MEM_DIRTY_COUNT, | 183 | NFIT_MEM_DIRTY_COUNT, |
| 165 | }; | 184 | }; |
| 166 | 185 | ||
| 186 | #define NFIT_DIMM_ID_LEN 22 | ||
| 187 | |||
| 167 | /* assembled tables for a given dimm/memory-device */ | 188 | /* assembled tables for a given dimm/memory-device */ |
| 168 | struct nfit_mem { | 189 | struct nfit_mem { |
| 169 | struct nvdimm *nvdimm; | 190 | struct nvdimm *nvdimm; |
| @@ -181,6 +202,7 @@ struct nfit_mem { | |||
| 181 | struct list_head list; | 202 | struct list_head list; |
| 182 | struct acpi_device *adev; | 203 | struct acpi_device *adev; |
| 183 | struct acpi_nfit_desc *acpi_desc; | 204 | struct acpi_nfit_desc *acpi_desc; |
| 205 | char id[NFIT_DIMM_ID_LEN+1]; | ||
| 184 | struct resource *flush_wpq; | 206 | struct resource *flush_wpq; |
| 185 | unsigned long dsm_mask; | 207 | unsigned long dsm_mask; |
| 186 | unsigned long flags; | 208 | unsigned long flags; |
diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index 9d36473dc2a2..5e27918e4624 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig | |||
| @@ -112,4 +112,9 @@ config OF_PMEM | |||
| 112 | 112 | ||
| 113 | Select Y if unsure. | 113 | Select Y if unsure. |
| 114 | 114 | ||
| 115 | config NVDIMM_KEYS | ||
| 116 | def_bool y | ||
| 117 | depends on ENCRYPTED_KEYS | ||
| 118 | depends on (LIBNVDIMM=ENCRYPTED_KEYS) || LIBNVDIMM=m | ||
| 119 | |||
| 115 | endif | 120 | endif |
diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile index e8847045dac0..6f2a088afad6 100644 --- a/drivers/nvdimm/Makefile +++ b/drivers/nvdimm/Makefile | |||
| @@ -27,3 +27,4 @@ libnvdimm-$(CONFIG_ND_CLAIM) += claim.o | |||
| 27 | libnvdimm-$(CONFIG_BTT) += btt_devs.o | 27 | libnvdimm-$(CONFIG_BTT) += btt_devs.o |
| 28 | libnvdimm-$(CONFIG_NVDIMM_PFN) += pfn_devs.o | 28 | libnvdimm-$(CONFIG_NVDIMM_PFN) += pfn_devs.o |
| 29 | libnvdimm-$(CONFIG_NVDIMM_DAX) += dax_devs.o | 29 | libnvdimm-$(CONFIG_NVDIMM_DAX) += dax_devs.o |
| 30 | libnvdimm-$(CONFIG_NVDIMM_KEYS) += security.o | ||
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index f1fb39921236..dca5f7a805cb 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c | |||
| @@ -331,6 +331,12 @@ struct nvdimm_bus *to_nvdimm_bus(struct device *dev) | |||
| 331 | } | 331 | } |
| 332 | EXPORT_SYMBOL_GPL(to_nvdimm_bus); | 332 | EXPORT_SYMBOL_GPL(to_nvdimm_bus); |
| 333 | 333 | ||
| 334 | struct nvdimm_bus *nvdimm_to_bus(struct nvdimm *nvdimm) | ||
| 335 | { | ||
| 336 | return to_nvdimm_bus(nvdimm->dev.parent); | ||
| 337 | } | ||
| 338 | EXPORT_SYMBOL_GPL(nvdimm_to_bus); | ||
| 339 | |||
| 334 | struct nvdimm_bus *nvdimm_bus_register(struct device *parent, | 340 | struct nvdimm_bus *nvdimm_bus_register(struct device *parent, |
| 335 | struct nvdimm_bus_descriptor *nd_desc) | 341 | struct nvdimm_bus_descriptor *nd_desc) |
| 336 | { | 342 | { |
| @@ -344,12 +350,12 @@ struct nvdimm_bus *nvdimm_bus_register(struct device *parent, | |||
| 344 | INIT_LIST_HEAD(&nvdimm_bus->mapping_list); | 350 | INIT_LIST_HEAD(&nvdimm_bus->mapping_list); |
| 345 | init_waitqueue_head(&nvdimm_bus->probe_wait); | 351 | init_waitqueue_head(&nvdimm_bus->probe_wait); |
| 346 | nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL); | 352 | nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL); |
| 347 | mutex_init(&nvdimm_bus->reconfig_mutex); | ||
| 348 | badrange_init(&nvdimm_bus->badrange); | ||
| 349 | if (nvdimm_bus->id < 0) { | 353 | if (nvdimm_bus->id < 0) { |
| 350 | kfree(nvdimm_bus); | 354 | kfree(nvdimm_bus); |
| 351 | return NULL; | 355 | return NULL; |
| 352 | } | 356 | } |
| 357 | mutex_init(&nvdimm_bus->reconfig_mutex); | ||
| 358 | badrange_init(&nvdimm_bus->badrange); | ||
| 353 | nvdimm_bus->nd_desc = nd_desc; | 359 | nvdimm_bus->nd_desc = nd_desc; |
| 354 | nvdimm_bus->dev.parent = parent; | 360 | nvdimm_bus->dev.parent = parent; |
| 355 | nvdimm_bus->dev.release = nvdimm_bus_release; | 361 | nvdimm_bus->dev.release = nvdimm_bus_release; |
| @@ -387,9 +393,24 @@ static int child_unregister(struct device *dev, void *data) | |||
| 387 | * i.e. remove classless children | 393 | * i.e. remove classless children |
| 388 | */ | 394 | */ |
| 389 | if (dev->class) | 395 | if (dev->class) |
| 390 | /* pass */; | 396 | return 0; |
| 391 | else | 397 | |
| 392 | nd_device_unregister(dev, ND_SYNC); | 398 | if (is_nvdimm(dev)) { |
| 399 | struct nvdimm *nvdimm = to_nvdimm(dev); | ||
| 400 | bool dev_put = false; | ||
| 401 | |||
| 402 | /* We are shutting down. Make state frozen artificially. */ | ||
| 403 | nvdimm_bus_lock(dev); | ||
| 404 | nvdimm->sec.state = NVDIMM_SECURITY_FROZEN; | ||
| 405 | if (test_and_clear_bit(NDD_WORK_PENDING, &nvdimm->flags)) | ||
| 406 | dev_put = true; | ||
| 407 | nvdimm_bus_unlock(dev); | ||
| 408 | cancel_delayed_work_sync(&nvdimm->dwork); | ||
| 409 | if (dev_put) | ||
| 410 | put_device(dev); | ||
| 411 | } | ||
| 412 | nd_device_unregister(dev, ND_SYNC); | ||
| 413 | |||
| 393 | return 0; | 414 | return 0; |
| 394 | } | 415 | } |
| 395 | 416 | ||
| @@ -902,7 +923,7 @@ static int nd_cmd_clear_to_send(struct nvdimm_bus *nvdimm_bus, | |||
| 902 | 923 | ||
| 903 | /* ask the bus provider if it would like to block this request */ | 924 | /* ask the bus provider if it would like to block this request */ |
| 904 | if (nd_desc->clear_to_send) { | 925 | if (nd_desc->clear_to_send) { |
| 905 | int rc = nd_desc->clear_to_send(nd_desc, nvdimm, cmd); | 926 | int rc = nd_desc->clear_to_send(nd_desc, nvdimm, cmd, data); |
| 906 | 927 | ||
| 907 | if (rc) | 928 | if (rc) |
| 908 | return rc; | 929 | return rc; |
diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index 9899c97138a3..0cf58cabc9ed 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c | |||
| @@ -34,7 +34,11 @@ static int nvdimm_probe(struct device *dev) | |||
| 34 | return rc; | 34 | return rc; |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | /* reset locked, to be validated below... */ | 37 | /* |
| 38 | * The locked status bit reflects explicit status codes from the | ||
| 39 | * label reading commands, revalidate it each time the driver is | ||
| 40 | * activated and re-reads the label area. | ||
| 41 | */ | ||
| 38 | nvdimm_clear_locked(dev); | 42 | nvdimm_clear_locked(dev); |
| 39 | 43 | ||
| 40 | ndd = kzalloc(sizeof(*ndd), GFP_KERNEL); | 44 | ndd = kzalloc(sizeof(*ndd), GFP_KERNEL); |
| @@ -52,6 +56,16 @@ static int nvdimm_probe(struct device *dev) | |||
| 52 | kref_init(&ndd->kref); | 56 | kref_init(&ndd->kref); |
| 53 | 57 | ||
| 54 | /* | 58 | /* |
| 59 | * Attempt to unlock, if the DIMM supports security commands, | ||
| 60 | * otherwise the locked indication is determined by explicit | ||
| 61 | * status codes from the label reading commands. | ||
| 62 | */ | ||
| 63 | rc = nvdimm_security_unlock(dev); | ||
| 64 | if (rc < 0) | ||
| 65 | dev_dbg(dev, "failed to unlock dimm: %d\n", rc); | ||
| 66 | |||
| 67 | |||
| 68 | /* | ||
| 55 | * EACCES failures reading the namespace label-area-properties | 69 | * EACCES failures reading the namespace label-area-properties |
| 56 | * are interpreted as the DIMM capacity being locked but the | 70 | * are interpreted as the DIMM capacity being locked but the |
| 57 | * namespace labels themselves being accessible. | 71 | * namespace labels themselves being accessible. |
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 6c3de2317390..4890310df874 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c | |||
| @@ -370,23 +370,172 @@ static ssize_t available_slots_show(struct device *dev, | |||
| 370 | } | 370 | } |
| 371 | static DEVICE_ATTR_RO(available_slots); | 371 | static DEVICE_ATTR_RO(available_slots); |
| 372 | 372 | ||
| 373 | __weak ssize_t security_show(struct device *dev, | ||
| 374 | struct device_attribute *attr, char *buf) | ||
| 375 | { | ||
| 376 | struct nvdimm *nvdimm = to_nvdimm(dev); | ||
| 377 | |||
| 378 | switch (nvdimm->sec.state) { | ||
| 379 | case NVDIMM_SECURITY_DISABLED: | ||
| 380 | return sprintf(buf, "disabled\n"); | ||
| 381 | case NVDIMM_SECURITY_UNLOCKED: | ||
| 382 | return sprintf(buf, "unlocked\n"); | ||
| 383 | case NVDIMM_SECURITY_LOCKED: | ||
| 384 | return sprintf(buf, "locked\n"); | ||
| 385 | case NVDIMM_SECURITY_FROZEN: | ||
| 386 | return sprintf(buf, "frozen\n"); | ||
| 387 | case NVDIMM_SECURITY_OVERWRITE: | ||
| 388 | return sprintf(buf, "overwrite\n"); | ||
| 389 | default: | ||
| 390 | return -ENOTTY; | ||
| 391 | } | ||
| 392 | |||
| 393 | return -ENOTTY; | ||
| 394 | } | ||
| 395 | |||
| 396 | #define OPS \ | ||
| 397 | C( OP_FREEZE, "freeze", 1), \ | ||
| 398 | C( OP_DISABLE, "disable", 2), \ | ||
| 399 | C( OP_UPDATE, "update", 3), \ | ||
| 400 | C( OP_ERASE, "erase", 2), \ | ||
| 401 | C( OP_OVERWRITE, "overwrite", 2), \ | ||
| 402 | C( OP_MASTER_UPDATE, "master_update", 3), \ | ||
| 403 | C( OP_MASTER_ERASE, "master_erase", 2) | ||
| 404 | #undef C | ||
| 405 | #define C(a, b, c) a | ||
| 406 | enum nvdimmsec_op_ids { OPS }; | ||
| 407 | #undef C | ||
| 408 | #define C(a, b, c) { b, c } | ||
| 409 | static struct { | ||
| 410 | const char *name; | ||
| 411 | int args; | ||
| 412 | } ops[] = { OPS }; | ||
| 413 | #undef C | ||
| 414 | |||
| 415 | #define SEC_CMD_SIZE 32 | ||
| 416 | #define KEY_ID_SIZE 10 | ||
| 417 | |||
| 418 | static ssize_t __security_store(struct device *dev, const char *buf, size_t len) | ||
| 419 | { | ||
| 420 | struct nvdimm *nvdimm = to_nvdimm(dev); | ||
| 421 | ssize_t rc; | ||
| 422 | char cmd[SEC_CMD_SIZE+1], keystr[KEY_ID_SIZE+1], | ||
| 423 | nkeystr[KEY_ID_SIZE+1]; | ||
| 424 | unsigned int key, newkey; | ||
| 425 | int i; | ||
| 426 | |||
| 427 | if (atomic_read(&nvdimm->busy)) | ||
| 428 | return -EBUSY; | ||
| 429 | |||
| 430 | rc = sscanf(buf, "%"__stringify(SEC_CMD_SIZE)"s" | ||
| 431 | " %"__stringify(KEY_ID_SIZE)"s" | ||
| 432 | " %"__stringify(KEY_ID_SIZE)"s", | ||
| 433 | cmd, keystr, nkeystr); | ||
| 434 | if (rc < 1) | ||
| 435 | return -EINVAL; | ||
| 436 | for (i = 0; i < ARRAY_SIZE(ops); i++) | ||
| 437 | if (sysfs_streq(cmd, ops[i].name)) | ||
| 438 | break; | ||
| 439 | if (i >= ARRAY_SIZE(ops)) | ||
| 440 | return -EINVAL; | ||
| 441 | if (ops[i].args > 1) | ||
| 442 | rc = kstrtouint(keystr, 0, &key); | ||
| 443 | if (rc >= 0 && ops[i].args > 2) | ||
| 444 | rc = kstrtouint(nkeystr, 0, &newkey); | ||
| 445 | if (rc < 0) | ||
| 446 | return rc; | ||
| 447 | |||
| 448 | if (i == OP_FREEZE) { | ||
| 449 | dev_dbg(dev, "freeze\n"); | ||
| 450 | rc = nvdimm_security_freeze(nvdimm); | ||
| 451 | } else if (i == OP_DISABLE) { | ||
| 452 | dev_dbg(dev, "disable %u\n", key); | ||
| 453 | rc = nvdimm_security_disable(nvdimm, key); | ||
| 454 | } else if (i == OP_UPDATE) { | ||
| 455 | dev_dbg(dev, "update %u %u\n", key, newkey); | ||
| 456 | rc = nvdimm_security_update(nvdimm, key, newkey, NVDIMM_USER); | ||
| 457 | } else if (i == OP_ERASE) { | ||
| 458 | dev_dbg(dev, "erase %u\n", key); | ||
| 459 | rc = nvdimm_security_erase(nvdimm, key, NVDIMM_USER); | ||
| 460 | } else if (i == OP_OVERWRITE) { | ||
| 461 | dev_dbg(dev, "overwrite %u\n", key); | ||
| 462 | rc = nvdimm_security_overwrite(nvdimm, key); | ||
| 463 | } else if (i == OP_MASTER_UPDATE) { | ||
| 464 | dev_dbg(dev, "master_update %u %u\n", key, newkey); | ||
| 465 | rc = nvdimm_security_update(nvdimm, key, newkey, | ||
| 466 | NVDIMM_MASTER); | ||
| 467 | } else if (i == OP_MASTER_ERASE) { | ||
| 468 | dev_dbg(dev, "master_erase %u\n", key); | ||
| 469 | rc = nvdimm_security_erase(nvdimm, key, | ||
| 470 | NVDIMM_MASTER); | ||
| 471 | } else | ||
| 472 | return -EINVAL; | ||
| 473 | |||
| 474 | if (rc == 0) | ||
| 475 | rc = len; | ||
| 476 | return rc; | ||
| 477 | } | ||
| 478 | |||
| 479 | static ssize_t security_store(struct device *dev, | ||
| 480 | struct device_attribute *attr, const char *buf, size_t len) | ||
| 481 | |||
| 482 | { | ||
| 483 | ssize_t rc; | ||
| 484 | |||
| 485 | /* | ||
| 486 | * Require all userspace triggered security management to be | ||
| 487 | * done while probing is idle and the DIMM is not in active use | ||
| 488 | * in any region. | ||
| 489 | */ | ||
| 490 | device_lock(dev); | ||
| 491 | nvdimm_bus_lock(dev); | ||
| 492 | wait_nvdimm_bus_probe_idle(dev); | ||
| 493 | rc = __security_store(dev, buf, len); | ||
| 494 | nvdimm_bus_unlock(dev); | ||
| 495 | device_unlock(dev); | ||
| 496 | |||
| 497 | return rc; | ||
| 498 | } | ||
| 499 | static DEVICE_ATTR_RW(security); | ||
| 500 | |||
| 373 | static struct attribute *nvdimm_attributes[] = { | 501 | static struct attribute *nvdimm_attributes[] = { |
| 374 | &dev_attr_state.attr, | 502 | &dev_attr_state.attr, |
| 375 | &dev_attr_flags.attr, | 503 | &dev_attr_flags.attr, |
| 376 | &dev_attr_commands.attr, | 504 | &dev_attr_commands.attr, |
| 377 | &dev_attr_available_slots.attr, | 505 | &dev_attr_available_slots.attr, |
| 506 | &dev_attr_security.attr, | ||
| 378 | NULL, | 507 | NULL, |
| 379 | }; | 508 | }; |
| 380 | 509 | ||
| 510 | static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n) | ||
| 511 | { | ||
| 512 | struct device *dev = container_of(kobj, typeof(*dev), kobj); | ||
| 513 | struct nvdimm *nvdimm = to_nvdimm(dev); | ||
| 514 | |||
| 515 | if (a != &dev_attr_security.attr) | ||
| 516 | return a->mode; | ||
| 517 | if (nvdimm->sec.state < 0) | ||
| 518 | return 0; | ||
| 519 | /* Are there any state mutation ops? */ | ||
| 520 | if (nvdimm->sec.ops->freeze || nvdimm->sec.ops->disable | ||
| 521 | || nvdimm->sec.ops->change_key | ||
| 522 | || nvdimm->sec.ops->erase | ||
| 523 | || nvdimm->sec.ops->overwrite) | ||
| 524 | return a->mode; | ||
| 525 | return 0444; | ||
| 526 | } | ||
| 527 | |||
| 381 | struct attribute_group nvdimm_attribute_group = { | 528 | struct attribute_group nvdimm_attribute_group = { |
| 382 | .attrs = nvdimm_attributes, | 529 | .attrs = nvdimm_attributes, |
| 530 | .is_visible = nvdimm_visible, | ||
| 383 | }; | 531 | }; |
| 384 | EXPORT_SYMBOL_GPL(nvdimm_attribute_group); | 532 | EXPORT_SYMBOL_GPL(nvdimm_attribute_group); |
| 385 | 533 | ||
| 386 | struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, | 534 | struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, |
| 387 | const struct attribute_group **groups, unsigned long flags, | 535 | void *provider_data, const struct attribute_group **groups, |
| 388 | unsigned long cmd_mask, int num_flush, | 536 | unsigned long flags, unsigned long cmd_mask, int num_flush, |
| 389 | struct resource *flush_wpq) | 537 | struct resource *flush_wpq, const char *dimm_id, |
| 538 | const struct nvdimm_security_ops *sec_ops) | ||
| 390 | { | 539 | { |
| 391 | struct nvdimm *nvdimm = kzalloc(sizeof(*nvdimm), GFP_KERNEL); | 540 | struct nvdimm *nvdimm = kzalloc(sizeof(*nvdimm), GFP_KERNEL); |
| 392 | struct device *dev; | 541 | struct device *dev; |
| @@ -399,6 +548,8 @@ struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, | |||
| 399 | kfree(nvdimm); | 548 | kfree(nvdimm); |
| 400 | return NULL; | 549 | return NULL; |
| 401 | } | 550 | } |
| 551 | |||
| 552 | nvdimm->dimm_id = dimm_id; | ||
| 402 | nvdimm->provider_data = provider_data; | 553 | nvdimm->provider_data = provider_data; |
| 403 | nvdimm->flags = flags; | 554 | nvdimm->flags = flags; |
| 404 | nvdimm->cmd_mask = cmd_mask; | 555 | nvdimm->cmd_mask = cmd_mask; |
| @@ -411,11 +562,60 @@ struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, | |||
| 411 | dev->type = &nvdimm_device_type; | 562 | dev->type = &nvdimm_device_type; |
| 412 | dev->devt = MKDEV(nvdimm_major, nvdimm->id); | 563 | dev->devt = MKDEV(nvdimm_major, nvdimm->id); |
| 413 | dev->groups = groups; | 564 | dev->groups = groups; |
| 565 | nvdimm->sec.ops = sec_ops; | ||
| 566 | nvdimm->sec.overwrite_tmo = 0; | ||
| 567 | INIT_DELAYED_WORK(&nvdimm->dwork, nvdimm_security_overwrite_query); | ||
| 568 | /* | ||
| 569 | * Security state must be initialized before device_add() for | ||
| 570 | * attribute visibility. | ||
| 571 | */ | ||
| 572 | /* get security state and extended (master) state */ | ||
| 573 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | ||
| 574 | nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); | ||
| 414 | nd_device_register(dev); | 575 | nd_device_register(dev); |
| 415 | 576 | ||
| 416 | return nvdimm; | 577 | return nvdimm; |
| 417 | } | 578 | } |
| 418 | EXPORT_SYMBOL_GPL(nvdimm_create); | 579 | EXPORT_SYMBOL_GPL(__nvdimm_create); |
| 580 | |||
| 581 | int nvdimm_security_setup_events(struct nvdimm *nvdimm) | ||
| 582 | { | ||
| 583 | nvdimm->sec.overwrite_state = sysfs_get_dirent(nvdimm->dev.kobj.sd, | ||
| 584 | "security"); | ||
| 585 | if (!nvdimm->sec.overwrite_state) | ||
| 586 | return -ENODEV; | ||
| 587 | return 0; | ||
| 588 | } | ||
| 589 | EXPORT_SYMBOL_GPL(nvdimm_security_setup_events); | ||
| 590 | |||
| 591 | int nvdimm_in_overwrite(struct nvdimm *nvdimm) | ||
| 592 | { | ||
| 593 | return test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); | ||
| 594 | } | ||
| 595 | EXPORT_SYMBOL_GPL(nvdimm_in_overwrite); | ||
| 596 | |||
| 597 | int nvdimm_security_freeze(struct nvdimm *nvdimm) | ||
| 598 | { | ||
| 599 | int rc; | ||
| 600 | |||
| 601 | WARN_ON_ONCE(!is_nvdimm_bus_locked(&nvdimm->dev)); | ||
| 602 | |||
| 603 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->freeze) | ||
| 604 | return -EOPNOTSUPP; | ||
| 605 | |||
| 606 | if (nvdimm->sec.state < 0) | ||
| 607 | return -EIO; | ||
| 608 | |||
| 609 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | ||
| 610 | dev_warn(&nvdimm->dev, "Overwrite operation in progress.\n"); | ||
| 611 | return -EBUSY; | ||
| 612 | } | ||
| 613 | |||
| 614 | rc = nvdimm->sec.ops->freeze(nvdimm); | ||
| 615 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | ||
| 616 | |||
| 617 | return rc; | ||
| 618 | } | ||
| 419 | 619 | ||
| 420 | int alias_dpa_busy(struct device *dev, void *data) | 620 | int alias_dpa_busy(struct device *dev, void *data) |
| 421 | { | 621 | { |
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index 750dbaa6ce82..a11bf4e6b451 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c | |||
| @@ -944,8 +944,7 @@ static int __blk_label_update(struct nd_region *nd_region, | |||
| 944 | victims = 0; | 944 | victims = 0; |
| 945 | if (old_num_resources) { | 945 | if (old_num_resources) { |
| 946 | /* convert old local-label-map to dimm-slot victim-map */ | 946 | /* convert old local-label-map to dimm-slot victim-map */ |
| 947 | victim_map = kcalloc(BITS_TO_LONGS(nslot), sizeof(long), | 947 | victim_map = bitmap_zalloc(nslot, GFP_KERNEL); |
| 948 | GFP_KERNEL); | ||
| 949 | if (!victim_map) | 948 | if (!victim_map) |
| 950 | return -ENOMEM; | 949 | return -ENOMEM; |
| 951 | 950 | ||
| @@ -968,7 +967,7 @@ static int __blk_label_update(struct nd_region *nd_region, | |||
| 968 | /* don't allow updates that consume the last label */ | 967 | /* don't allow updates that consume the last label */ |
| 969 | if (nfree - alloc < 0 || nfree - alloc + victims < 1) { | 968 | if (nfree - alloc < 0 || nfree - alloc + victims < 1) { |
| 970 | dev_info(&nsblk->common.dev, "insufficient label space\n"); | 969 | dev_info(&nsblk->common.dev, "insufficient label space\n"); |
| 971 | kfree(victim_map); | 970 | bitmap_free(victim_map); |
| 972 | return -ENOSPC; | 971 | return -ENOSPC; |
| 973 | } | 972 | } |
| 974 | /* from here on we need to abort on error */ | 973 | /* from here on we need to abort on error */ |
| @@ -1140,7 +1139,7 @@ static int __blk_label_update(struct nd_region *nd_region, | |||
| 1140 | 1139 | ||
| 1141 | out: | 1140 | out: |
| 1142 | kfree(old_res_list); | 1141 | kfree(old_res_list); |
| 1143 | kfree(victim_map); | 1142 | bitmap_free(victim_map); |
| 1144 | return rc; | 1143 | return rc; |
| 1145 | 1144 | ||
| 1146 | abort: | 1145 | abort: |
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 681af3a8fd62..4b077555ac70 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c | |||
| @@ -270,11 +270,10 @@ static ssize_t __alt_name_store(struct device *dev, const char *buf, | |||
| 270 | if (dev->driver || to_ndns(dev)->claim) | 270 | if (dev->driver || to_ndns(dev)->claim) |
| 271 | return -EBUSY; | 271 | return -EBUSY; |
| 272 | 272 | ||
| 273 | input = kmemdup(buf, len + 1, GFP_KERNEL); | 273 | input = kstrndup(buf, len, GFP_KERNEL); |
| 274 | if (!input) | 274 | if (!input) |
| 275 | return -ENOMEM; | 275 | return -ENOMEM; |
| 276 | 276 | ||
| 277 | input[len] = '\0'; | ||
| 278 | pos = strim(input); | 277 | pos = strim(input); |
| 279 | if (strlen(pos) + 1 > NSLABEL_NAME_LEN) { | 278 | if (strlen(pos) + 1 > NSLABEL_NAME_LEN) { |
| 280 | rc = -EINVAL; | 279 | rc = -EINVAL; |
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index d0c621b32f72..2b2cf4e554d3 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | extern struct list_head nvdimm_bus_list; | 21 | extern struct list_head nvdimm_bus_list; |
| 22 | extern struct mutex nvdimm_bus_list_mutex; | 22 | extern struct mutex nvdimm_bus_list_mutex; |
| 23 | extern int nvdimm_major; | 23 | extern int nvdimm_major; |
| 24 | extern struct workqueue_struct *nvdimm_wq; | ||
| 24 | 25 | ||
| 25 | struct nvdimm_bus { | 26 | struct nvdimm_bus { |
| 26 | struct nvdimm_bus_descriptor *nd_desc; | 27 | struct nvdimm_bus_descriptor *nd_desc; |
| @@ -41,8 +42,64 @@ struct nvdimm { | |||
| 41 | atomic_t busy; | 42 | atomic_t busy; |
| 42 | int id, num_flush; | 43 | int id, num_flush; |
| 43 | struct resource *flush_wpq; | 44 | struct resource *flush_wpq; |
| 45 | const char *dimm_id; | ||
| 46 | struct { | ||
| 47 | const struct nvdimm_security_ops *ops; | ||
| 48 | enum nvdimm_security_state state; | ||
| 49 | enum nvdimm_security_state ext_state; | ||
| 50 | unsigned int overwrite_tmo; | ||
| 51 | struct kernfs_node *overwrite_state; | ||
| 52 | } sec; | ||
| 53 | struct delayed_work dwork; | ||
| 44 | }; | 54 | }; |
| 45 | 55 | ||
| 56 | static inline enum nvdimm_security_state nvdimm_security_state( | ||
| 57 | struct nvdimm *nvdimm, bool master) | ||
| 58 | { | ||
| 59 | if (!nvdimm->sec.ops) | ||
| 60 | return -ENXIO; | ||
| 61 | |||
| 62 | return nvdimm->sec.ops->state(nvdimm, master); | ||
| 63 | } | ||
| 64 | int nvdimm_security_freeze(struct nvdimm *nvdimm); | ||
| 65 | #if IS_ENABLED(CONFIG_NVDIMM_KEYS) | ||
| 66 | int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid); | ||
| 67 | int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, | ||
| 68 | unsigned int new_keyid, | ||
| 69 | enum nvdimm_passphrase_type pass_type); | ||
| 70 | int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, | ||
| 71 | enum nvdimm_passphrase_type pass_type); | ||
| 72 | int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid); | ||
| 73 | void nvdimm_security_overwrite_query(struct work_struct *work); | ||
| 74 | #else | ||
| 75 | static inline int nvdimm_security_disable(struct nvdimm *nvdimm, | ||
| 76 | unsigned int keyid) | ||
| 77 | { | ||
| 78 | return -EOPNOTSUPP; | ||
| 79 | } | ||
| 80 | static inline int nvdimm_security_update(struct nvdimm *nvdimm, | ||
| 81 | unsigned int keyid, | ||
| 82 | unsigned int new_keyid, | ||
| 83 | enum nvdimm_passphrase_type pass_type) | ||
| 84 | { | ||
| 85 | return -EOPNOTSUPP; | ||
| 86 | } | ||
| 87 | static inline int nvdimm_security_erase(struct nvdimm *nvdimm, | ||
| 88 | unsigned int keyid, | ||
| 89 | enum nvdimm_passphrase_type pass_type) | ||
| 90 | { | ||
| 91 | return -EOPNOTSUPP; | ||
| 92 | } | ||
| 93 | static inline int nvdimm_security_overwrite(struct nvdimm *nvdimm, | ||
| 94 | unsigned int keyid) | ||
| 95 | { | ||
| 96 | return -EOPNOTSUPP; | ||
| 97 | } | ||
| 98 | static inline void nvdimm_security_overwrite_query(struct work_struct *work) | ||
| 99 | { | ||
| 100 | } | ||
| 101 | #endif | ||
| 102 | |||
| 46 | /** | 103 | /** |
| 47 | * struct blk_alloc_info - tracking info for BLK dpa scanning | 104 | * struct blk_alloc_info - tracking info for BLK dpa scanning |
| 48 | * @nd_mapping: blk region mapping boundaries | 105 | * @nd_mapping: blk region mapping boundaries |
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index e79cc8e5c114..cfde992684e7 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h | |||
| @@ -250,6 +250,14 @@ long nvdimm_clear_poison(struct device *dev, phys_addr_t phys, | |||
| 250 | void nvdimm_set_aliasing(struct device *dev); | 250 | void nvdimm_set_aliasing(struct device *dev); |
| 251 | void nvdimm_set_locked(struct device *dev); | 251 | void nvdimm_set_locked(struct device *dev); |
| 252 | void nvdimm_clear_locked(struct device *dev); | 252 | void nvdimm_clear_locked(struct device *dev); |
| 253 | #if IS_ENABLED(CONFIG_NVDIMM_KEYS) | ||
| 254 | int nvdimm_security_unlock(struct device *dev); | ||
| 255 | #else | ||
| 256 | static inline int nvdimm_security_unlock(struct device *dev) | ||
| 257 | { | ||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | #endif | ||
| 253 | struct nd_btt *to_nd_btt(struct device *dev); | 261 | struct nd_btt *to_nd_btt(struct device *dev); |
| 254 | 262 | ||
| 255 | struct nd_gen_sb { | 263 | struct nd_gen_sb { |
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index e7377f1028ef..e2818f94f292 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c | |||
| @@ -79,6 +79,11 @@ int nd_region_activate(struct nd_region *nd_region) | |||
| 79 | struct nd_mapping *nd_mapping = &nd_region->mapping[i]; | 79 | struct nd_mapping *nd_mapping = &nd_region->mapping[i]; |
| 80 | struct nvdimm *nvdimm = nd_mapping->nvdimm; | 80 | struct nvdimm *nvdimm = nd_mapping->nvdimm; |
| 81 | 81 | ||
| 82 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | ||
| 83 | nvdimm_bus_unlock(&nd_region->dev); | ||
| 84 | return -EBUSY; | ||
| 85 | } | ||
| 86 | |||
| 82 | /* at least one null hint slot per-dimm for the "no-hint" case */ | 87 | /* at least one null hint slot per-dimm for the "no-hint" case */ |
| 83 | flush_data_size += sizeof(void *); | 88 | flush_data_size += sizeof(void *); |
| 84 | num_flush = min_not_zero(num_flush, nvdimm->num_flush); | 89 | num_flush = min_not_zero(num_flush, nvdimm->num_flush); |
diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c new file mode 100644 index 000000000000..f8bb746a549f --- /dev/null +++ b/drivers/nvdimm/security.c | |||
| @@ -0,0 +1,454 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* Copyright(c) 2018 Intel Corporation. All rights reserved. */ | ||
| 3 | |||
| 4 | #include <linux/module.h> | ||
| 5 | #include <linux/device.h> | ||
| 6 | #include <linux/ndctl.h> | ||
| 7 | #include <linux/slab.h> | ||
| 8 | #include <linux/io.h> | ||
| 9 | #include <linux/mm.h> | ||
| 10 | #include <linux/cred.h> | ||
| 11 | #include <linux/key.h> | ||
| 12 | #include <linux/key-type.h> | ||
| 13 | #include <keys/user-type.h> | ||
| 14 | #include <keys/encrypted-type.h> | ||
| 15 | #include "nd-core.h" | ||
| 16 | #include "nd.h" | ||
| 17 | |||
| 18 | #define NVDIMM_BASE_KEY 0 | ||
| 19 | #define NVDIMM_NEW_KEY 1 | ||
| 20 | |||
| 21 | static bool key_revalidate = true; | ||
| 22 | module_param(key_revalidate, bool, 0444); | ||
| 23 | MODULE_PARM_DESC(key_revalidate, "Require key validation at init."); | ||
| 24 | |||
| 25 | static void *key_data(struct key *key) | ||
| 26 | { | ||
| 27 | struct encrypted_key_payload *epayload = dereference_key_locked(key); | ||
| 28 | |||
| 29 | lockdep_assert_held_read(&key->sem); | ||
| 30 | |||
| 31 | return epayload->decrypted_data; | ||
| 32 | } | ||
| 33 | |||
| 34 | static void nvdimm_put_key(struct key *key) | ||
| 35 | { | ||
| 36 | if (!key) | ||
| 37 | return; | ||
| 38 | |||
| 39 | up_read(&key->sem); | ||
| 40 | key_put(key); | ||
| 41 | } | ||
| 42 | |||
| 43 | /* | ||
| 44 | * Retrieve kernel key for DIMM and request from user space if | ||
| 45 | * necessary. Returns a key held for read and must be put by | ||
| 46 | * nvdimm_put_key() before the usage goes out of scope. | ||
| 47 | */ | ||
| 48 | static struct key *nvdimm_request_key(struct nvdimm *nvdimm) | ||
| 49 | { | ||
| 50 | struct key *key = NULL; | ||
| 51 | static const char NVDIMM_PREFIX[] = "nvdimm:"; | ||
| 52 | char desc[NVDIMM_KEY_DESC_LEN + sizeof(NVDIMM_PREFIX)]; | ||
| 53 | struct device *dev = &nvdimm->dev; | ||
| 54 | |||
| 55 | sprintf(desc, "%s%s", NVDIMM_PREFIX, nvdimm->dimm_id); | ||
| 56 | key = request_key(&key_type_encrypted, desc, ""); | ||
| 57 | if (IS_ERR(key)) { | ||
| 58 | if (PTR_ERR(key) == -ENOKEY) | ||
| 59 | dev_dbg(dev, "request_key() found no key\n"); | ||
| 60 | else | ||
| 61 | dev_dbg(dev, "request_key() upcall failed\n"); | ||
| 62 | key = NULL; | ||
| 63 | } else { | ||
| 64 | struct encrypted_key_payload *epayload; | ||
| 65 | |||
| 66 | down_read(&key->sem); | ||
| 67 | epayload = dereference_key_locked(key); | ||
| 68 | if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { | ||
| 69 | up_read(&key->sem); | ||
| 70 | key_put(key); | ||
| 71 | key = NULL; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | return key; | ||
| 76 | } | ||
| 77 | |||
| 78 | static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, | ||
| 79 | key_serial_t id, int subclass) | ||
| 80 | { | ||
| 81 | key_ref_t keyref; | ||
| 82 | struct key *key; | ||
| 83 | struct encrypted_key_payload *epayload; | ||
| 84 | struct device *dev = &nvdimm->dev; | ||
| 85 | |||
| 86 | keyref = lookup_user_key(id, 0, 0); | ||
| 87 | if (IS_ERR(keyref)) | ||
| 88 | return NULL; | ||
| 89 | |||
| 90 | key = key_ref_to_ptr(keyref); | ||
| 91 | if (key->type != &key_type_encrypted) { | ||
| 92 | key_put(key); | ||
| 93 | return NULL; | ||
| 94 | } | ||
| 95 | |||
| 96 | dev_dbg(dev, "%s: key found: %#x\n", __func__, key_serial(key)); | ||
| 97 | |||
| 98 | down_read_nested(&key->sem, subclass); | ||
| 99 | epayload = dereference_key_locked(key); | ||
| 100 | if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { | ||
| 101 | up_read(&key->sem); | ||
| 102 | key_put(key); | ||
| 103 | key = NULL; | ||
| 104 | } | ||
| 105 | return key; | ||
| 106 | } | ||
| 107 | |||
| 108 | static struct key *nvdimm_key_revalidate(struct nvdimm *nvdimm) | ||
| 109 | { | ||
| 110 | struct key *key; | ||
| 111 | int rc; | ||
| 112 | |||
| 113 | if (!nvdimm->sec.ops->change_key) | ||
| 114 | return NULL; | ||
| 115 | |||
| 116 | key = nvdimm_request_key(nvdimm); | ||
| 117 | if (!key) | ||
| 118 | return NULL; | ||
| 119 | |||
| 120 | /* | ||
| 121 | * Send the same key to the hardware as new and old key to | ||
| 122 | * verify that the key is good. | ||
| 123 | */ | ||
| 124 | rc = nvdimm->sec.ops->change_key(nvdimm, key_data(key), | ||
| 125 | key_data(key), NVDIMM_USER); | ||
| 126 | if (rc < 0) { | ||
| 127 | nvdimm_put_key(key); | ||
| 128 | key = NULL; | ||
| 129 | } | ||
| 130 | return key; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int __nvdimm_security_unlock(struct nvdimm *nvdimm) | ||
| 134 | { | ||
| 135 | struct device *dev = &nvdimm->dev; | ||
| 136 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | ||
| 137 | struct key *key = NULL; | ||
| 138 | int rc; | ||
| 139 | |||
| 140 | /* The bus lock should be held at the top level of the call stack */ | ||
| 141 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | ||
| 142 | |||
| 143 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->unlock | ||
| 144 | || nvdimm->sec.state < 0) | ||
| 145 | return -EIO; | ||
| 146 | |||
| 147 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | ||
| 148 | dev_dbg(dev, "Security operation in progress.\n"); | ||
| 149 | return -EBUSY; | ||
| 150 | } | ||
| 151 | |||
| 152 | /* | ||
| 153 | * If the pre-OS has unlocked the DIMM, attempt to send the key | ||
| 154 | * from request_key() to the hardware for verification. Failure | ||
| 155 | * to revalidate the key against the hardware results in a | ||
| 156 | * freeze of the security configuration. I.e. if the OS does not | ||
| 157 | * have the key, security is being managed pre-OS. | ||
| 158 | */ | ||
| 159 | if (nvdimm->sec.state == NVDIMM_SECURITY_UNLOCKED) { | ||
| 160 | if (!key_revalidate) | ||
| 161 | return 0; | ||
| 162 | |||
| 163 | key = nvdimm_key_revalidate(nvdimm); | ||
| 164 | if (!key) | ||
| 165 | return nvdimm_security_freeze(nvdimm); | ||
| 166 | } else | ||
| 167 | key = nvdimm_request_key(nvdimm); | ||
| 168 | |||
| 169 | if (!key) | ||
| 170 | return -ENOKEY; | ||
| 171 | |||
| 172 | rc = nvdimm->sec.ops->unlock(nvdimm, key_data(key)); | ||
| 173 | dev_dbg(dev, "key: %d unlock: %s\n", key_serial(key), | ||
| 174 | rc == 0 ? "success" : "fail"); | ||
| 175 | |||
| 176 | nvdimm_put_key(key); | ||
| 177 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | ||
| 178 | return rc; | ||
| 179 | } | ||
| 180 | |||
| 181 | int nvdimm_security_unlock(struct device *dev) | ||
| 182 | { | ||
| 183 | struct nvdimm *nvdimm = to_nvdimm(dev); | ||
| 184 | int rc; | ||
| 185 | |||
| 186 | nvdimm_bus_lock(dev); | ||
| 187 | rc = __nvdimm_security_unlock(nvdimm); | ||
| 188 | nvdimm_bus_unlock(dev); | ||
| 189 | return rc; | ||
| 190 | } | ||
| 191 | |||
| 192 | int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) | ||
| 193 | { | ||
| 194 | struct device *dev = &nvdimm->dev; | ||
| 195 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | ||
| 196 | struct key *key; | ||
| 197 | int rc; | ||
| 198 | |||
| 199 | /* The bus lock should be held at the top level of the call stack */ | ||
| 200 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | ||
| 201 | |||
| 202 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable | ||
| 203 | || nvdimm->sec.state < 0) | ||
| 204 | return -EOPNOTSUPP; | ||
| 205 | |||
| 206 | if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { | ||
| 207 | dev_dbg(dev, "Incorrect security state: %d\n", | ||
| 208 | nvdimm->sec.state); | ||
| 209 | return -EIO; | ||
| 210 | } | ||
| 211 | |||
| 212 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | ||
| 213 | dev_dbg(dev, "Security operation in progress.\n"); | ||
| 214 | return -EBUSY; | ||
| 215 | } | ||
| 216 | |||
| 217 | key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); | ||
| 218 | if (!key) | ||
| 219 | return -ENOKEY; | ||
| 220 | |||
| 221 | rc = nvdimm->sec.ops->disable(nvdimm, key_data(key)); | ||
| 222 | dev_dbg(dev, "key: %d disable: %s\n", key_serial(key), | ||
| 223 | rc == 0 ? "success" : "fail"); | ||
| 224 | |||
| 225 | nvdimm_put_key(key); | ||
| 226 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | ||
| 227 | return rc; | ||
| 228 | } | ||
| 229 | |||
| 230 | int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, | ||
| 231 | unsigned int new_keyid, | ||
| 232 | enum nvdimm_passphrase_type pass_type) | ||
| 233 | { | ||
| 234 | struct device *dev = &nvdimm->dev; | ||
| 235 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | ||
| 236 | struct key *key, *newkey; | ||
| 237 | int rc; | ||
| 238 | |||
| 239 | /* The bus lock should be held at the top level of the call stack */ | ||
| 240 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | ||
| 241 | |||
| 242 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key | ||
| 243 | || nvdimm->sec.state < 0) | ||
| 244 | return -EOPNOTSUPP; | ||
| 245 | |||
| 246 | if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { | ||
| 247 | dev_dbg(dev, "Incorrect security state: %d\n", | ||
| 248 | nvdimm->sec.state); | ||
| 249 | return -EIO; | ||
| 250 | } | ||
| 251 | |||
| 252 | if (keyid == 0) | ||
| 253 | key = NULL; | ||
| 254 | else { | ||
| 255 | key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); | ||
| 256 | if (!key) | ||
| 257 | return -ENOKEY; | ||
| 258 | } | ||
| 259 | |||
| 260 | newkey = nvdimm_lookup_user_key(nvdimm, new_keyid, NVDIMM_NEW_KEY); | ||
| 261 | if (!newkey) { | ||
| 262 | nvdimm_put_key(key); | ||
| 263 | return -ENOKEY; | ||
| 264 | } | ||
| 265 | |||
| 266 | rc = nvdimm->sec.ops->change_key(nvdimm, key ? key_data(key) : NULL, | ||
| 267 | key_data(newkey), pass_type); | ||
| 268 | dev_dbg(dev, "key: %d %d update%s: %s\n", | ||
| 269 | key_serial(key), key_serial(newkey), | ||
| 270 | pass_type == NVDIMM_MASTER ? "(master)" : "(user)", | ||
| 271 | rc == 0 ? "success" : "fail"); | ||
| 272 | |||
| 273 | nvdimm_put_key(newkey); | ||
| 274 | nvdimm_put_key(key); | ||
| 275 | if (pass_type == NVDIMM_MASTER) | ||
| 276 | nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, | ||
| 277 | NVDIMM_MASTER); | ||
| 278 | else | ||
| 279 | nvdimm->sec.state = nvdimm_security_state(nvdimm, | ||
| 280 | NVDIMM_USER); | ||
| 281 | return rc; | ||
| 282 | } | ||
| 283 | |||
| 284 | int nvdimm_security_erase(struct nvdimm *nvdimm, unsigned int keyid, | ||
| 285 | enum nvdimm_passphrase_type pass_type) | ||
| 286 | { | ||
| 287 | struct device *dev = &nvdimm->dev; | ||
| 288 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | ||
| 289 | struct key *key; | ||
| 290 | int rc; | ||
| 291 | |||
| 292 | /* The bus lock should be held at the top level of the call stack */ | ||
| 293 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | ||
| 294 | |||
| 295 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->erase | ||
| 296 | || nvdimm->sec.state < 0) | ||
| 297 | return -EOPNOTSUPP; | ||
| 298 | |||
| 299 | if (atomic_read(&nvdimm->busy)) { | ||
| 300 | dev_dbg(dev, "Unable to secure erase while DIMM active.\n"); | ||
| 301 | return -EBUSY; | ||
| 302 | } | ||
| 303 | |||
| 304 | if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { | ||
| 305 | dev_dbg(dev, "Incorrect security state: %d\n", | ||
| 306 | nvdimm->sec.state); | ||
| 307 | return -EIO; | ||
| 308 | } | ||
| 309 | |||
| 310 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | ||
| 311 | dev_dbg(dev, "Security operation in progress.\n"); | ||
| 312 | return -EBUSY; | ||
| 313 | } | ||
| 314 | |||
| 315 | if (nvdimm->sec.ext_state != NVDIMM_SECURITY_UNLOCKED | ||
| 316 | && pass_type == NVDIMM_MASTER) { | ||
| 317 | dev_dbg(dev, | ||
| 318 | "Attempt to secure erase in wrong master state.\n"); | ||
| 319 | return -EOPNOTSUPP; | ||
| 320 | } | ||
| 321 | |||
| 322 | key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); | ||
| 323 | if (!key) | ||
| 324 | return -ENOKEY; | ||
| 325 | |||
| 326 | rc = nvdimm->sec.ops->erase(nvdimm, key_data(key), pass_type); | ||
| 327 | dev_dbg(dev, "key: %d erase%s: %s\n", key_serial(key), | ||
| 328 | pass_type == NVDIMM_MASTER ? "(master)" : "(user)", | ||
| 329 | rc == 0 ? "success" : "fail"); | ||
| 330 | |||
| 331 | nvdimm_put_key(key); | ||
| 332 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | ||
| 333 | return rc; | ||
| 334 | } | ||
| 335 | |||
| 336 | int nvdimm_security_overwrite(struct nvdimm *nvdimm, unsigned int keyid) | ||
| 337 | { | ||
| 338 | struct device *dev = &nvdimm->dev; | ||
| 339 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | ||
| 340 | struct key *key; | ||
| 341 | int rc; | ||
| 342 | |||
| 343 | /* The bus lock should be held at the top level of the call stack */ | ||
| 344 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | ||
| 345 | |||
| 346 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->overwrite | ||
| 347 | || nvdimm->sec.state < 0) | ||
| 348 | return -EOPNOTSUPP; | ||
| 349 | |||
| 350 | if (atomic_read(&nvdimm->busy)) { | ||
| 351 | dev_dbg(dev, "Unable to overwrite while DIMM active.\n"); | ||
| 352 | return -EBUSY; | ||
| 353 | } | ||
| 354 | |||
| 355 | if (dev->driver == NULL) { | ||
| 356 | dev_dbg(dev, "Unable to overwrite while DIMM active.\n"); | ||
| 357 | return -EINVAL; | ||
| 358 | } | ||
| 359 | |||
| 360 | if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { | ||
| 361 | dev_dbg(dev, "Incorrect security state: %d\n", | ||
| 362 | nvdimm->sec.state); | ||
| 363 | return -EIO; | ||
| 364 | } | ||
| 365 | |||
| 366 | if (test_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags)) { | ||
| 367 | dev_dbg(dev, "Security operation in progress.\n"); | ||
| 368 | return -EBUSY; | ||
| 369 | } | ||
| 370 | |||
| 371 | if (keyid == 0) | ||
| 372 | key = NULL; | ||
| 373 | else { | ||
| 374 | key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); | ||
| 375 | if (!key) | ||
| 376 | return -ENOKEY; | ||
| 377 | } | ||
| 378 | |||
| 379 | rc = nvdimm->sec.ops->overwrite(nvdimm, key ? key_data(key) : NULL); | ||
| 380 | dev_dbg(dev, "key: %d overwrite submission: %s\n", key_serial(key), | ||
| 381 | rc == 0 ? "success" : "fail"); | ||
| 382 | |||
| 383 | nvdimm_put_key(key); | ||
| 384 | if (rc == 0) { | ||
| 385 | set_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); | ||
| 386 | set_bit(NDD_WORK_PENDING, &nvdimm->flags); | ||
| 387 | nvdimm->sec.state = NVDIMM_SECURITY_OVERWRITE; | ||
| 388 | /* | ||
| 389 | * Make sure we don't lose device while doing overwrite | ||
| 390 | * query. | ||
| 391 | */ | ||
| 392 | get_device(dev); | ||
| 393 | queue_delayed_work(system_wq, &nvdimm->dwork, 0); | ||
| 394 | } | ||
| 395 | |||
| 396 | return rc; | ||
| 397 | } | ||
| 398 | |||
| 399 | void __nvdimm_security_overwrite_query(struct nvdimm *nvdimm) | ||
| 400 | { | ||
| 401 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(&nvdimm->dev); | ||
| 402 | int rc; | ||
| 403 | unsigned int tmo; | ||
| 404 | |||
| 405 | /* The bus lock should be held at the top level of the call stack */ | ||
| 406 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | ||
| 407 | |||
| 408 | /* | ||
| 409 | * Abort and release device if we no longer have the overwrite | ||
| 410 | * flag set. It means the work has been canceled. | ||
| 411 | */ | ||
| 412 | if (!test_bit(NDD_WORK_PENDING, &nvdimm->flags)) | ||
| 413 | return; | ||
| 414 | |||
| 415 | tmo = nvdimm->sec.overwrite_tmo; | ||
| 416 | |||
| 417 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->query_overwrite | ||
| 418 | || nvdimm->sec.state < 0) | ||
| 419 | return; | ||
| 420 | |||
| 421 | rc = nvdimm->sec.ops->query_overwrite(nvdimm); | ||
| 422 | if (rc == -EBUSY) { | ||
| 423 | |||
| 424 | /* setup delayed work again */ | ||
| 425 | tmo += 10; | ||
| 426 | queue_delayed_work(system_wq, &nvdimm->dwork, tmo * HZ); | ||
| 427 | nvdimm->sec.overwrite_tmo = min(15U * 60U, tmo); | ||
| 428 | return; | ||
| 429 | } | ||
| 430 | |||
| 431 | if (rc < 0) | ||
| 432 | dev_dbg(&nvdimm->dev, "overwrite failed\n"); | ||
| 433 | else | ||
| 434 | dev_dbg(&nvdimm->dev, "overwrite completed\n"); | ||
| 435 | |||
| 436 | if (nvdimm->sec.overwrite_state) | ||
| 437 | sysfs_notify_dirent(nvdimm->sec.overwrite_state); | ||
| 438 | nvdimm->sec.overwrite_tmo = 0; | ||
| 439 | clear_bit(NDD_SECURITY_OVERWRITE, &nvdimm->flags); | ||
| 440 | clear_bit(NDD_WORK_PENDING, &nvdimm->flags); | ||
| 441 | put_device(&nvdimm->dev); | ||
| 442 | nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER); | ||
| 443 | nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER); | ||
| 444 | } | ||
| 445 | |||
| 446 | void nvdimm_security_overwrite_query(struct work_struct *work) | ||
| 447 | { | ||
| 448 | struct nvdimm *nvdimm = | ||
| 449 | container_of(work, typeof(*nvdimm), dwork.work); | ||
| 450 | |||
| 451 | nvdimm_bus_lock(&nvdimm->dev); | ||
| 452 | __nvdimm_security_overwrite_query(nvdimm); | ||
| 453 | nvdimm_bus_unlock(&nvdimm->dev); | ||
| 454 | } | ||
