diff options
Diffstat (limited to 'drivers/nvdimm/security.c')
-rw-r--r-- | drivers/nvdimm/security.c | 58 |
1 files changed, 54 insertions, 4 deletions
diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c index 647a99dd3182..df7f070e96fb 100644 --- a/drivers/nvdimm/security.c +++ b/drivers/nvdimm/security.c | |||
@@ -15,6 +15,9 @@ | |||
15 | #include "nd-core.h" | 15 | #include "nd-core.h" |
16 | #include "nd.h" | 16 | #include "nd.h" |
17 | 17 | ||
18 | #define NVDIMM_BASE_KEY 0 | ||
19 | #define NVDIMM_NEW_KEY 1 | ||
20 | |||
18 | static bool key_revalidate = true; | 21 | static bool key_revalidate = true; |
19 | module_param(key_revalidate, bool, 0444); | 22 | module_param(key_revalidate, bool, 0444); |
20 | MODULE_PARM_DESC(key_revalidate, "Require key validation at init."); | 23 | MODULE_PARM_DESC(key_revalidate, "Require key validation at init."); |
@@ -70,7 +73,7 @@ static struct key *nvdimm_request_key(struct nvdimm *nvdimm) | |||
70 | } | 73 | } |
71 | 74 | ||
72 | static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, | 75 | static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, |
73 | key_serial_t id) | 76 | key_serial_t id, int subclass) |
74 | { | 77 | { |
75 | key_ref_t keyref; | 78 | key_ref_t keyref; |
76 | struct key *key; | 79 | struct key *key; |
@@ -86,10 +89,10 @@ static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, | |||
86 | key_put(key); | 89 | key_put(key); |
87 | return NULL; | 90 | return NULL; |
88 | } | 91 | } |
89 | dev_dbg(dev, "%s: key found: %#x\n", __func__, key_serial(key)); | ||
90 | 92 | ||
93 | dev_dbg(dev, "%s: key found: %#x\n", __func__, key_serial(key)); | ||
91 | 94 | ||
92 | down_read(&key->sem); | 95 | down_read_nested(&key->sem, subclass); |
93 | epayload = dereference_key_locked(key); | 96 | epayload = dereference_key_locked(key); |
94 | if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { | 97 | if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { |
95 | up_read(&key->sem); | 98 | up_read(&key->sem); |
@@ -197,7 +200,7 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) | |||
197 | return -EIO; | 200 | return -EIO; |
198 | } | 201 | } |
199 | 202 | ||
200 | key = nvdimm_lookup_user_key(nvdimm, keyid); | 203 | key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); |
201 | if (!key) | 204 | if (!key) |
202 | return -ENOKEY; | 205 | return -ENOKEY; |
203 | 206 | ||
@@ -209,3 +212,50 @@ int nvdimm_security_disable(struct nvdimm *nvdimm, unsigned int keyid) | |||
209 | nvdimm->sec.state = nvdimm_security_state(nvdimm); | 212 | nvdimm->sec.state = nvdimm_security_state(nvdimm); |
210 | return rc; | 213 | return rc; |
211 | } | 214 | } |
215 | |||
216 | int nvdimm_security_update(struct nvdimm *nvdimm, unsigned int keyid, | ||
217 | unsigned int new_keyid) | ||
218 | { | ||
219 | struct device *dev = &nvdimm->dev; | ||
220 | struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(dev); | ||
221 | struct key *key, *newkey; | ||
222 | int rc; | ||
223 | |||
224 | /* The bus lock should be held at the top level of the call stack */ | ||
225 | lockdep_assert_held(&nvdimm_bus->reconfig_mutex); | ||
226 | |||
227 | if (!nvdimm->sec.ops || !nvdimm->sec.ops->change_key | ||
228 | || nvdimm->sec.state < 0) | ||
229 | return -EOPNOTSUPP; | ||
230 | |||
231 | if (nvdimm->sec.state >= NVDIMM_SECURITY_FROZEN) { | ||
232 | dev_warn(dev, "Incorrect security state: %d\n", | ||
233 | nvdimm->sec.state); | ||
234 | return -EIO; | ||
235 | } | ||
236 | |||
237 | if (keyid == 0) | ||
238 | key = NULL; | ||
239 | else { | ||
240 | key = nvdimm_lookup_user_key(nvdimm, keyid, NVDIMM_BASE_KEY); | ||
241 | if (!key) | ||
242 | return -ENOKEY; | ||
243 | } | ||
244 | |||
245 | newkey = nvdimm_lookup_user_key(nvdimm, new_keyid, NVDIMM_NEW_KEY); | ||
246 | if (!newkey) { | ||
247 | nvdimm_put_key(key); | ||
248 | return -ENOKEY; | ||
249 | } | ||
250 | |||
251 | rc = nvdimm->sec.ops->change_key(nvdimm, key ? key_data(key) : NULL, | ||
252 | key_data(newkey)); | ||
253 | dev_dbg(dev, "key: %d %d update: %s\n", | ||
254 | key_serial(key), key_serial(newkey), | ||
255 | rc == 0 ? "success" : "fail"); | ||
256 | |||
257 | nvdimm_put_key(newkey); | ||
258 | nvdimm_put_key(key); | ||
259 | nvdimm->sec.state = nvdimm_security_state(nvdimm); | ||
260 | return rc; | ||
261 | } | ||