summaryrefslogtreecommitdiff
path: root/security/keys
diff options
context:
space:
mode:
authorJames Morris <james.l.morris@oracle.com>2013-10-31 09:46:36 +1100
committerJames Morris <james.l.morris@oracle.com>2013-10-31 09:46:36 +1100
commit42a20ba5c90ded07f79992d222fa0814b8448cf6 (patch)
treef19f8c5fd0ce043fcae5455489e552fc70217cad /security/keys
parent51775fe736f053329faf0f5de7c679ee4cb0023d (diff)
parent6ef4d2eaf5a46d4ab6db02612b5e883b834017b8 (diff)
Merge branch 'keys-devel' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs into ra-next
Diffstat (limited to 'security/keys')
-rw-r--r--security/keys/Kconfig2
-rw-r--r--security/keys/big_key.c4
-rw-r--r--security/keys/key.c3
-rw-r--r--security/keys/keyring.c28
-rw-r--r--security/keys/request_key.c4
5 files changed, 25 insertions, 16 deletions
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index 53d8748c9564..a4f3f8c48d6e 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -38,7 +38,7 @@ config PERSISTENT_KEYRINGS
removed if they expire (a default timeout is set upon creation).
config BIG_KEYS
- tristate "Large payload keys"
+ bool "Large payload keys"
depends on KEYS
depends on TMPFS
help
diff --git a/security/keys/big_key.c b/security/keys/big_key.c
index 5f9defc4a807..2cf5e62d67af 100644
--- a/security/keys/big_key.c
+++ b/security/keys/big_key.c
@@ -71,8 +71,10 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
* TODO: Encrypt the stored data with a temporary key.
*/
file = shmem_file_setup("", datalen, 0);
- if (IS_ERR(file))
+ if (IS_ERR(file)) {
+ ret = PTR_ERR(file);
goto err_quota;
+ }
written = kernel_write(file, prep->data, prep->datalen, 0);
if (written != datalen) {
diff --git a/security/keys/key.c b/security/keys/key.c
index d331ea9ef380..55d110f0aced 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -557,9 +557,10 @@ int key_reject_and_link(struct key *key,
if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
/* mark the key as being negatively instantiated */
atomic_inc(&key->user->nikeys);
+ key->type_data.reject_error = -error;
+ smp_wmb();
set_bit(KEY_FLAG_NEGATIVE, &key->flags);
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
- key->type_data.reject_error = -error;
now = current_kernel_time();
key->expiry = now.tv_sec + timeout;
key_schedule_gc(key->expiry + key_gc_delay);
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 9b6f6e09b50c..d80311e571c3 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -551,6 +551,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) {
/* we set a different error code if we pass a negative key */
if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
+ smp_rmb();
ctx->result = ERR_PTR(key->type_data.reject_error);
kleave(" = %d [neg]", ctx->skipped_ret);
goto skipped;
@@ -1062,12 +1063,6 @@ int __key_link_begin(struct key *keyring,
if (index_key->type == &key_type_keyring)
down_write(&keyring_serialise_link_sem);
- /* check that we aren't going to overrun the user's quota */
- ret = key_payload_reserve(keyring,
- keyring->datalen + KEYQUOTA_LINK_BYTES);
- if (ret < 0)
- goto error_sem;
-
/* Create an edit script that will insert/replace the key in the
* keyring tree.
*/
@@ -1077,17 +1072,25 @@ int __key_link_begin(struct key *keyring,
NULL);
if (IS_ERR(edit)) {
ret = PTR_ERR(edit);
- goto error_quota;
+ goto error_sem;
+ }
+
+ /* If we're not replacing a link in-place then we're going to need some
+ * extra quota.
+ */
+ if (!edit->dead_leaf) {
+ ret = key_payload_reserve(keyring,
+ keyring->datalen + KEYQUOTA_LINK_BYTES);
+ if (ret < 0)
+ goto error_cancel;
}
*_edit = edit;
kleave(" = 0");
return 0;
-error_quota:
- /* undo the quota changes */
- key_payload_reserve(keyring,
- keyring->datalen - KEYQUOTA_LINK_BYTES);
+error_cancel:
+ assoc_array_cancel_edit(edit);
error_sem:
if (index_key->type == &key_type_keyring)
up_write(&keyring_serialise_link_sem);
@@ -1145,7 +1148,7 @@ void __key_link_end(struct key *keyring,
if (index_key->type == &key_type_keyring)
up_write(&keyring_serialise_link_sem);
- if (edit) {
+ if (edit && !edit->dead_leaf) {
key_payload_reserve(keyring,
keyring->datalen - KEYQUOTA_LINK_BYTES);
assoc_array_cancel_edit(edit);
@@ -1242,6 +1245,7 @@ int key_unlink(struct key *keyring, struct key *key)
goto error;
assoc_array_apply_edit(edit);
+ key_payload_reserve(keyring, keyring->datalen - KEYQUOTA_LINK_BYTES);
ret = 0;
error:
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index df94827103d0..381411941cc1 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -596,8 +596,10 @@ int wait_for_key_construction(struct key *key, bool intr)
intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
if (ret < 0)
return ret;
- if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+ if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
+ smp_rmb();
return key->type_data.reject_error;
+ }
return key_validate(key);
}
EXPORT_SYMBOL(wait_for_key_construction);