libnvdimm v5.0-rc4
* 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 -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJcTOoMAAoJEB7SkWpmfYgCVxAP/0YiOcsf6gtloMIfKLZr7Y0N R/8gH6ChWqv+aXQJ7UOA7MDkSSzL5y9SXRFy8a7lO7jb/V4OiNpqEejB4++J9AZO n55V1J6nGrPo6qk7r1nm7KL6s2PX38UKJE2lc73D/geyVhAunhfCkDRUVNVFSpbo zwNrWb25NxnB5wgBzvg1nsmMOVp0yPGe+D+4UeIZKzXN6bkupAk0cgBIl3JComDy aad/id0loClhD6Wu7OJFRutC/eMokRNveEQUSK6fZrRqgJeonkjRetehGGzfdOtO W/YqlvwRe3fpuCAmJQfdMZba+h9WDmpwL1KA5txWJmA2oy4IF28xyhRoOAzkcx2/ WAYv/Zad47Lr39t2zcupvqMj9DgxObBDmTbpkuGsYnvKGp6qEFfO7EEmoan8JuMN QURgCIWTwdDTqinETHi6OXgZLwOTyDV0COQV+YD6Jop8gh0UZNayLQGn79P2FJDm rF304QfzKrPcnGRfbJf3WTeofOHcfHp0Q0E6oyHvzhgxWy3gIDJo30+J0oLgk7cR 5WZnlg1k6ySrrOzqAvdm/xKMX4lQ/OlZ2uswFenPBPO7OKzQ3cBCY2WCfUuLH9Xx RlK7t5O2MBwx8VtUDCbN/+AIlDRbPjS+r6NiJcHXFgnrMI9EDJqIFLZI500b5hkj np5nqzdEs4Akd7YANvKj =E4Rz -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
6a2651b55b
|
@ -409,6 +409,32 @@ static bool payload_dumpable(struct nvdimm *nvdimm, unsigned int func)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int cmd_to_func(struct nfit_mem *nfit_mem, unsigned int cmd,
|
||||
struct nd_cmd_pkg *call_pkg)
|
||||
{
|
||||
if (call_pkg) {
|
||||
int i;
|
||||
|
||||
if (nfit_mem->family != call_pkg->nd_family)
|
||||
return -ENOTTY;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++)
|
||||
if (call_pkg->nd_reserved2[i])
|
||||
return -EINVAL;
|
||||
return call_pkg->nd_command;
|
||||
}
|
||||
|
||||
/* Linux ND commands == NVDIMM_FAMILY_INTEL function numbers */
|
||||
if (nfit_mem->family == NVDIMM_FAMILY_INTEL)
|
||||
return cmd;
|
||||
|
||||
/*
|
||||
* Force function number validation to fail since 0 is never
|
||||
* published as a valid function in dsm_mask.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
|
||||
unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc)
|
||||
{
|
||||
|
@ -422,30 +448,23 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
|
|||
unsigned long cmd_mask, dsm_mask;
|
||||
u32 offset, fw_status = 0;
|
||||
acpi_handle handle;
|
||||
unsigned int func;
|
||||
const guid_t *guid;
|
||||
int rc, i;
|
||||
int func, rc, i;
|
||||
|
||||
if (cmd_rc)
|
||||
*cmd_rc = -EINVAL;
|
||||
func = cmd;
|
||||
if (cmd == ND_CMD_CALL) {
|
||||
call_pkg = buf;
|
||||
func = call_pkg->nd_command;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(call_pkg->nd_reserved2); i++)
|
||||
if (call_pkg->nd_reserved2[i])
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (nvdimm) {
|
||||
struct acpi_device *adev = nfit_mem->adev;
|
||||
|
||||
if (!adev)
|
||||
return -ENOTTY;
|
||||
if (call_pkg && nfit_mem->family != call_pkg->nd_family)
|
||||
return -ENOTTY;
|
||||
|
||||
if (cmd == ND_CMD_CALL)
|
||||
call_pkg = buf;
|
||||
func = cmd_to_func(nfit_mem, cmd, call_pkg);
|
||||
if (func < 0)
|
||||
return func;
|
||||
dimm_name = nvdimm_name(nvdimm);
|
||||
cmd_name = nvdimm_cmd_name(cmd);
|
||||
cmd_mask = nvdimm_cmd_mask(nvdimm);
|
||||
|
@ -456,6 +475,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
|
|||
} else {
|
||||
struct acpi_device *adev = to_acpi_dev(acpi_desc);
|
||||
|
||||
func = cmd;
|
||||
cmd_name = nvdimm_bus_cmd_name(cmd);
|
||||
cmd_mask = nd_desc->cmd_mask;
|
||||
dsm_mask = cmd_mask;
|
||||
|
@ -470,7 +490,13 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
|
|||
if (!desc || (cmd && (desc->out_num + desc->in_num == 0)))
|
||||
return -ENOTTY;
|
||||
|
||||
if (!test_bit(cmd, &cmd_mask) || !test_bit(func, &dsm_mask))
|
||||
/*
|
||||
* Check for a valid command. For ND_CMD_CALL, we also have to
|
||||
* make sure that the DSM function is supported.
|
||||
*/
|
||||
if (cmd == ND_CMD_CALL && !test_bit(func, &dsm_mask))
|
||||
return -ENOTTY;
|
||||
else if (!test_bit(cmd, &cmd_mask))
|
||||
return -ENOTTY;
|
||||
|
||||
in_obj.type = ACPI_TYPE_PACKAGE;
|
||||
|
@ -1867,6 +1893,13 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function 0 is the command interrogation function, don't
|
||||
* export it to potential userspace use, and enable it to be
|
||||
* used as an error value in acpi_nfit_ctl().
|
||||
*/
|
||||
dsm_mask &= ~1UL;
|
||||
|
||||
guid = to_nfit_uuid(nfit_mem->family);
|
||||
for_each_set_bit(i, &dsm_mask, BITS_PER_LONG)
|
||||
if (acpi_check_dsm(adev_dimm->handle, guid,
|
||||
|
@ -2042,11 +2075,6 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
|
|||
if (!nvdimm)
|
||||
continue;
|
||||
|
||||
rc = nvdimm_security_setup_events(nvdimm);
|
||||
if (rc < 0)
|
||||
dev_warn(acpi_desc->dev,
|
||||
"security event setup failed: %d\n", rc);
|
||||
|
||||
nfit_kernfs = sysfs_get_dirent(nvdimm_kobj(nvdimm)->sd, "nfit");
|
||||
if (nfit_kernfs)
|
||||
nfit_mem->flags_attr = sysfs_get_dirent(nfit_kernfs,
|
||||
|
|
|
@ -26,6 +26,12 @@ static int nvdimm_probe(struct device *dev)
|
|||
struct nvdimm_drvdata *ndd;
|
||||
int rc;
|
||||
|
||||
rc = nvdimm_security_setup_events(dev);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "security event setup failed: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = nvdimm_check_config_data(dev);
|
||||
if (rc) {
|
||||
/* not required for non-aliased nvdimm, ex. NVDIMM-N */
|
||||
|
|
|
@ -578,13 +578,25 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(__nvdimm_create);
|
||||
|
||||
int nvdimm_security_setup_events(struct nvdimm *nvdimm)
|
||||
static void shutdown_security_notify(void *data)
|
||||
{
|
||||
nvdimm->sec.overwrite_state = sysfs_get_dirent(nvdimm->dev.kobj.sd,
|
||||
"security");
|
||||
struct nvdimm *nvdimm = data;
|
||||
|
||||
sysfs_put(nvdimm->sec.overwrite_state);
|
||||
}
|
||||
|
||||
int nvdimm_security_setup_events(struct device *dev)
|
||||
{
|
||||
struct nvdimm *nvdimm = to_nvdimm(dev);
|
||||
|
||||
if (nvdimm->sec.state < 0 || !nvdimm->sec.ops
|
||||
|| !nvdimm->sec.ops->overwrite)
|
||||
return 0;
|
||||
nvdimm->sec.overwrite_state = sysfs_get_dirent(dev->kobj.sd, "security");
|
||||
if (!nvdimm->sec.overwrite_state)
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
return -ENOMEM;
|
||||
|
||||
return devm_add_action_or_reset(dev, shutdown_security_notify, nvdimm);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nvdimm_security_setup_events);
|
||||
|
||||
|
|
|
@ -250,6 +250,7 @@ long nvdimm_clear_poison(struct device *dev, phys_addr_t phys,
|
|||
void nvdimm_set_aliasing(struct device *dev);
|
||||
void nvdimm_set_locked(struct device *dev);
|
||||
void nvdimm_clear_locked(struct device *dev);
|
||||
int nvdimm_security_setup_events(struct device *dev);
|
||||
#if IS_ENABLED(CONFIG_NVDIMM_KEYS)
|
||||
int nvdimm_security_unlock(struct device *dev);
|
||||
#else
|
||||
|
|
|
@ -235,7 +235,6 @@ static inline struct nvdimm *nvdimm_create(struct nvdimm_bus *nvdimm_bus,
|
|||
cmd_mask, num_flush, flush_wpq, NULL, NULL);
|
||||
}
|
||||
|
||||
int nvdimm_security_setup_events(struct nvdimm *nvdimm);
|
||||
const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd);
|
||||
const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd);
|
||||
u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
|
||||
|
|
|
@ -18,8 +18,8 @@ ssize_t security_show(struct device *dev,
|
|||
* For the test version we need to poll the "hardware" in order
|
||||
* to get the updated status for unlock testing.
|
||||
*/
|
||||
nvdimm->sec.state = nvdimm_security_state(nvdimm, false);
|
||||
nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, true);
|
||||
nvdimm->sec.state = nvdimm_security_state(nvdimm, NVDIMM_USER);
|
||||
nvdimm->sec.ext_state = nvdimm_security_state(nvdimm, NVDIMM_MASTER);
|
||||
|
||||
switch (nvdimm->sec.state) {
|
||||
case NVDIMM_SECURITY_DISABLED:
|
||||
|
|
Loading…
Reference in New Issue