diff options
author | Dave Jiang <dave.jiang@intel.com> | 2018-12-07 12:33:30 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2018-12-21 15:44:41 -0500 |
commit | 03b65b22ada8115a7a7bfdf0789f6a94adfd6070 (patch) | |
tree | d8ac0a260db2dcac8b52ed36566bd9b89ab2d116 /drivers/nvdimm/security.c | |
parent | 4c6926a23b76ea23403976290cd45a7a143f6500 (diff) |
acpi/nfit, libnvdimm: Add disable passphrase support to Intel nvdimm.
Add support to disable passphrase (security) for the Intel nvdimm. The
passphrase used for disabling is pulled from an encrypted-key in the kernel
user keyring. The action is triggered by writing "disable <keyid>" to the
sysfs attribute "security".
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/nvdimm/security.c')
-rw-r--r-- | drivers/nvdimm/security.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index 51d77a67a9fb..647a99dd3182 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c | |||
@@ -69,6 +69,36 @@ static struct key *nvdimm_request_key(struct nvdimm *nvdimm) | |||
69 | return key; | 69 | return key; |
70 | } | 70 | } |
71 | 71 | ||
72 | static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, | ||
73 | key_serial_t id) | ||
74 | { | ||
75 | key_ref_t keyref; | ||
76 | struct key *key; | ||
77 | struct encrypted_key_payload *epayload; | ||
78 | struct device *dev = &nvdimm->dev; | ||
79 | |||
80 | keyref = lookup_user_key(id, 0, 0); | ||
81 | if (IS_ERR(keyref)) | ||
82 | return NULL; | ||
83 | |||
84 | key = key_ref_to_ptr(keyref); | ||
85 | if (key->type != &key_type_encrypted) { | ||
86 | key_put(key); | ||
87 | return NULL; | ||
88 | } | ||
89 | dev_dbg(dev, "%s: key found: %#x\n", __func__, key_serial(key)); | ||
90 | |||
91 | |||
92 | down_read(&key->sem); | ||
93 | epayload = dereference_key_locked(key); | ||
94 | if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { | ||
95 | up_read(&key->sem); | ||
96 | key_put(key); | ||
97 | key = NULL; | ||
98 | } | ||
99 | return key; | ||
100 | } | ||
101 | |||
72 | static struct key *nvdimm_key_revalidate(struct nvdimm *nvdimm) | 102 | static struct key *nvdimm_key_revalidate(struct nvdimm *nvdimm) |
73 | { | 103 | { |
74 | struct key *key; | 104 | struct key *key; |
@@ -146,3 +176,36 @@ int nvdimm_security_unlock(struct device *dev) | |||
146 | nvdimm_bus_unlock(dev); | 176 | nvdimm_bus_unlock(dev); |
147 | return rc; | 177 | return rc; |
148 | } | 178 | } |
179 | |||
180 | int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) | ||
181 | { | ||
182 | struct device *dev = &nvdimm->dev; | ||
183 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | ||
184 | struct key *key; | ||
185 | int rc; | ||
186 | |||
187 | /* The bus lock should be held at the top level of the call stack */ | ||
188 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | ||
189 | |||
190 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->disable | ||
191 | || nvdimm->sec.state < 0) | ||
192 | return -EOPNOTSUPP; | ||
193 | |||
194 | if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { | ||
195 | dev_warn(dev, "Incorrect security state: %d\n", | ||
196 | nvdimm->sec.state); | ||
197 | return -EIO; | ||
198 | } | ||
199 | |||
200 | key = nvdimm_lookup_user_key(nvdimm, keyid); | ||
201 | if (!key) | ||
202 | return -ENOKEY; | ||
203 | |||
204 | rc = nvdimm->sec.ops->disable(nvdimm, key_data(key)); | ||
205 | dev_dbg(dev, "key: %d disable: %s\n", key_serial(key), | ||
206 | rc == 0 ? "success" : "fail"); | ||
207 | |||
208 | nvdimm_put_key(key); | ||
209 | nvdimm->sec.state = nvdimm_security_state(nvdimm); | ||
210 | return rc; | ||
211 | } | ||