From f2989396553a0bd13f4b25f567a3dee3d722ce40 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 5 Dec 2018 23:39:29 -0800 Subject: acpi/nfit, libnvdimm: Introduce nvdimm_security_ops Some NVDIMMs, like the ones defined by the NVDIMM_FAMILY_INTEL command set, expose a security capability to lock the DIMMs at poweroff and require a passphrase to unlock them. The security model is derived from ATA security. In anticipation of other DIMMs implementing a similar scheme, and to abstract the core security implementation away from the device-specific details, introduce nvdimm_security_ops. Initially only a status retrieval operation, ->state(), is defined, along with the base infrastructure and definitions for future operations. Signed-off-by: Dave Jiang Co-developed-by: Dan Williams Signed-off-by: Dan Williams --- drivers/nvdimm/bus.c | 6 ++++++ drivers/nvdimm/dimm_devs.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- drivers/nvdimm/nd-core.h | 13 +++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) (limited to 'drivers/nvdimm') diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 9743d8083538..eae17d8ee539 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -331,6 +331,12 @@ struct nvdimm_bus *to_nvdimm_bus(struct device *dev) } EXPORT_SYMBOL_GPL(to_nvdimm_bus); +struct nvdimm_bus *nvdimm_to_bus(struct nvdimm *nvdimm) +{ + return to_nvdimm_bus(nvdimm->dev.parent); +} +EXPORT_SYMBOL_GPL(nvdimm_to_bus); + struct nvdimm_bus *nvdimm_bus_register(struct device *parent, struct nvdimm_bus_descriptor *nd_desc) { diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index 508dd405f84f..9609b671311b 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -370,23 +370,60 @@ static ssize_t available_slots_show(struct device *dev, } static DEVICE_ATTR_RO(available_slots); +static ssize_t security_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + + switch (nvdimm->sec.state) { + case NVDIMM_SECURITY_DISABLED: + return sprintf(buf, "disabled\n"); + case NVDIMM_SECURITY_UNLOCKED: + return sprintf(buf, "unlocked\n"); + case NVDIMM_SECURITY_LOCKED: + return sprintf(buf, "locked\n"); + case NVDIMM_SECURITY_FROZEN: + return sprintf(buf, "frozen\n"); + case NVDIMM_SECURITY_OVERWRITE: + return sprintf(buf, "overwrite\n"); + } + + return -ENOTTY; +} +static DEVICE_ATTR_RO(security); + static struct attribute *nvdimm_attributes[] = { &dev_attr_state.attr, &dev_attr_flags.attr, &dev_attr_commands.attr, &dev_attr_available_slots.attr, + &dev_attr_security.attr, NULL, }; +static umode_t nvdimm_visible(struct kobject *kobj, struct attribute *a, int n) +{ + struct device *dev = container_of(kobj, typeof(*dev), kobj); + struct nvdimm *nvdimm = to_nvdimm(dev); + + if (a != &dev_attr_security.attr) + return a->mode; + if (nvdimm->sec.state < 0) + return 0; + return a->mode; +} + struct attribute_group nvdimm_attribute_group = { .attrs = nvdimm_attributes, + .is_visible = nvdimm_visible, }; EXPORT_SYMBOL_GPL(nvdimm_attribute_group); struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, void *provider_data, const struct attribute_group **groups, unsigned long flags, unsigned long cmd_mask, int num_flush, - struct resource *flush_wpq, const char *dimm_id) + struct resource *flush_wpq, const char *dimm_id, + const struct nvdimm_security_ops *sec_ops) { struct nvdimm *nvdimm = kzalloc(sizeof(*nvdimm), GFP_KERNEL); struct device *dev; @@ -413,6 +450,12 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus, dev->type = &nvdimm_device_type; dev->devt = MKDEV(nvdimm_major, nvdimm->id); dev->groups = groups; + nvdimm->sec.ops = sec_ops; + /* + * Security state must be initialized before device_add() for + * attribute visibility. + */ + nvdimm->sec.state = nvdimm_security_state(nvdimm); nd_device_register(dev); return nvdimm; diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index ff26876e6ea3..1919f5c0d581 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -42,8 +42,21 @@ struct nvdimm { int id, num_flush; struct resource *flush_wpq; const char *dimm_id; + struct { + const struct nvdimm_security_ops *ops; + enum nvdimm_security_state state; + } sec; }; +static inline enum nvdimm_security_state nvdimm_security_state( + struct nvdimm *nvdimm) +{ + if (!nvdimm->sec.ops) + return -ENXIO; + + return nvdimm->sec.ops->state(nvdimm); +} + /** * struct blk_alloc_info - tracking info for BLK dpa scanning * @nd_mapping: blk region mapping boundaries -- cgit v1.2.3-59-g8ed1b