Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2989396 authored by Dave Jiang's avatar Dave Jiang Committed by Dan Williams
Browse files

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: default avatarDave Jiang <dave.jiang@intel.com>
Co-developed-by: default avatarDan Williams <dan.j.williams@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 9db67581
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
obj-$(CONFIG_ACPI_NFIT) := nfit.o
nfit-y := core.o
nfit-y += intel.o
nfit-$(CONFIG_X86_MCE) += mce.o
+12 −1
Original line number Diff line number Diff line
@@ -1930,6 +1930,16 @@ static void shutdown_dimm_notify(void *data)
	mutex_unlock(&acpi_desc->init_mutex);
}

static const struct nvdimm_security_ops *acpi_nfit_get_security_ops(int family)
{
	switch (family) {
	case NVDIMM_FAMILY_INTEL:
		return intel_security_ops;
	default:
		return NULL;
	}
}

static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
{
	struct nfit_mem *nfit_mem;
@@ -1999,7 +2009,8 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
		nvdimm = __nvdimm_create(acpi_desc->nvdimm_bus, nfit_mem,
				acpi_nfit_dimm_attribute_groups,
				flags, cmd_mask, flush ? flush->hint_count : 0,
				nfit_mem->flush_wpq, &nfit_mem->id[0]);
				nfit_mem->flush_wpq, &nfit_mem->id[0],
				acpi_nfit_get_security_ops(nfit_mem->family));
		if (!nvdimm)
			return -ENOMEM;

+54 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2018 Intel Corporation. All rights reserved. */
#include <linux/libnvdimm.h>
#include <linux/ndctl.h>
#include <linux/acpi.h>
#include "intel.h"
#include "nfit.h"

static enum nvdimm_security_state intel_security_state(struct nvdimm *nvdimm)
{
	struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
	struct {
		struct nd_cmd_pkg pkg;
		struct nd_intel_get_security_state cmd;
	} nd_cmd = {
		.pkg = {
			.nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,
			.nd_family = NVDIMM_FAMILY_INTEL,
			.nd_size_out =
				sizeof(struct nd_intel_get_security_state),
			.nd_fw_size =
				sizeof(struct nd_intel_get_security_state),
		},
	};
	int rc;

	if (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &nfit_mem->dsm_mask))
		return -ENXIO;

	rc = nvdimm_ctl(nvdimm, ND_CMD_CALL, &nd_cmd, sizeof(nd_cmd), NULL);
	if (rc < 0)
		return rc;
	if (nd_cmd.cmd.status)
		return -EIO;

	/* check and see if security is enabled and locked */
	if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_UNSUPPORTED)
		return -ENXIO;
	else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_ENABLED) {
		if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_LOCKED)
			return NVDIMM_SECURITY_LOCKED;
		else if (nd_cmd.cmd.state & ND_INTEL_SEC_STATE_FROZEN ||
				nd_cmd.cmd.state & ND_INTEL_SEC_STATE_PLIMIT)
			return NVDIMM_SECURITY_FROZEN;
		else
			return NVDIMM_SECURITY_UNLOCKED;
	}
	return NVDIMM_SECURITY_DISABLED;
}

static const struct nvdimm_security_ops __intel_security_ops = {
	.state = intel_security_state,
};
const struct nvdimm_security_ops *intel_security_ops = &__intel_security_ops;
+2 −0
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ struct nd_intel_smart {
	};
} __packed;

extern const struct nvdimm_security_ops *intel_security_ops;

#define ND_INTEL_STATUS_SIZE		4
#define ND_INTEL_PASSPHRASE_SIZE	32

+6 −0
Original line number Diff line number Diff line
@@ -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)
{
Loading