aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2011-03-07 10:06:09 -0500
committerJames Morris <jmorris@namei.org>2011-03-07 19:17:18 -0500
commitfdd1b94581782a2ddf9124414e5b7a5f48ce2f9c (patch)
treece83bfd1f0b1a7d4b9521bdb3d6afef1bff1d4f2 /security/keys
parentb9fffa3877a3ebbe0a5ad5a247358e2f7df15b24 (diff)
KEYS: Add a new keyctl op to reject a key with a specified error code
Add a new keyctl op to reject a key with a specified error code. This works much the same as negating a key, and so keyctl_negate_key() is made a special case of keyctl_reject_key(). The difference is that keyctl_negate_key() selects ENOKEY as the error to be reported. Typically the key would be rejected with EKEYEXPIRED, EKEYREVOKED or EKEYREJECTED, but this is not mandatory. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/keys')
-rw-r--r--security/keys/compat.c3
-rw-r--r--security/keys/internal.h1
-rw-r--r--security/keys/key.c19
-rw-r--r--security/keys/keyctl.c40
-rw-r--r--security/keys/keyring.c4
-rw-r--r--security/keys/request_key.c2
6 files changed, 56 insertions, 13 deletions
diff --git a/security/keys/compat.c b/security/keys/compat.c
index 07a5f35e3970..17c99d0149ec 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -85,6 +85,9 @@ asmlinkage long compat_sys_keyctl(u32 option,
85 case KEYCTL_SESSION_TO_PARENT: 85 case KEYCTL_SESSION_TO_PARENT:
86 return keyctl_session_to_parent(); 86 return keyctl_session_to_parent();
87 87
88 case KEYCTL_REJECT:
89 return keyctl_reject_key(arg2, arg3, arg4, arg5);
90
88 default: 91 default:
89 return -EOPNOTSUPP; 92 return -EOPNOTSUPP;
90 } 93 }
diff --git a/security/keys/internal.h b/security/keys/internal.h
index a52aa7c88b41..286c0959ee51 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -214,6 +214,7 @@ extern long keyctl_assume_authority(key_serial_t);
214extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, 214extern long keyctl_get_security(key_serial_t keyid, char __user *buffer,
215 size_t buflen); 215 size_t buflen);
216extern long keyctl_session_to_parent(void); 216extern long keyctl_session_to_parent(void);
217extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t);
217 218
218/* 219/*
219 * Debugging key validation 220 * Debugging key validation
diff --git a/security/keys/key.c b/security/keys/key.c
index 8e315ef2e88e..f7f9d93f08d9 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -511,26 +511,29 @@ int key_instantiate_and_link(struct key *key,
511EXPORT_SYMBOL(key_instantiate_and_link); 511EXPORT_SYMBOL(key_instantiate_and_link);
512 512
513/** 513/**
514 * key_negate_and_link - Negatively instantiate a key and link it into the keyring. 514 * key_reject_and_link - Negatively instantiate a key and link it into the keyring.
515 * @key: The key to instantiate. 515 * @key: The key to instantiate.
516 * @timeout: The timeout on the negative key. 516 * @timeout: The timeout on the negative key.
517 * @error: The error to return when the key is hit.
517 * @keyring: Keyring to create a link in on success (or NULL). 518 * @keyring: Keyring to create a link in on success (or NULL).
518 * @authkey: The authorisation token permitting instantiation. 519 * @authkey: The authorisation token permitting instantiation.
519 * 520 *
520 * Negatively instantiate a key that's in the uninstantiated state and, if 521 * Negatively instantiate a key that's in the uninstantiated state and, if
521 * successful, set its timeout and link it in to the destination keyring if one 522 * successful, set its timeout and stored error and link it in to the
522 * is supplied. The key and any links to the key will be automatically garbage 523 * destination keyring if one is supplied. The key and any links to the key
523 * collected after the timeout expires. 524 * will be automatically garbage collected after the timeout expires.
524 * 525 *
525 * Negative keys are used to rate limit repeated request_key() calls by causing 526 * Negative keys are used to rate limit repeated request_key() calls by causing
526 * them to return -ENOKEY until the negative key expires. 527 * them to return the stored error code (typically ENOKEY) until the negative
528 * key expires.
527 * 529 *
528 * If successful, 0 is returned, the authorisation token is revoked and anyone 530 * If successful, 0 is returned, the authorisation token is revoked and anyone
529 * waiting for the key is woken up. If the key was already instantiated, 531 * waiting for the key is woken up. If the key was already instantiated,
530 * -EBUSY will be returned. 532 * -EBUSY will be returned.
531 */ 533 */
532int key_negate_and_link(struct key *key, 534int key_reject_and_link(struct key *key,
533 unsigned timeout, 535 unsigned timeout,
536 unsigned error,
534 struct key *keyring, 537 struct key *keyring,
535 struct key *authkey) 538 struct key *authkey)
536{ 539{
@@ -556,6 +559,7 @@ int key_negate_and_link(struct key *key,
556 atomic_inc(&key->user->nikeys); 559 atomic_inc(&key->user->nikeys);
557 set_bit(KEY_FLAG_NEGATIVE, &key->flags); 560 set_bit(KEY_FLAG_NEGATIVE, &key->flags);
558 set_bit(KEY_FLAG_INSTANTIATED, &key->flags); 561 set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
562 key->type_data.reject_error = -error;
559 now = current_kernel_time(); 563 now = current_kernel_time();
560 key->expiry = now.tv_sec + timeout; 564 key->expiry = now.tv_sec + timeout;
561 key_schedule_gc(key->expiry + key_gc_delay); 565 key_schedule_gc(key->expiry + key_gc_delay);
@@ -585,8 +589,7 @@ int key_negate_and_link(struct key *key,
585 589
586 return ret == 0 ? link_ret : ret; 590 return ret == 0 ? link_ret : ret;
587} 591}
588 592EXPORT_SYMBOL(key_reject_and_link);
589EXPORT_SYMBOL(key_negate_and_link);
590 593
591/* 594/*
592 * Garbage collect keys in process context so that we don't have to disable 595 * Garbage collect keys in process context so that we don't have to disable
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 31a0fd8189f1..0d7b1946ff94 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1013,12 +1013,42 @@ error:
1013 */ 1013 */
1014long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) 1014long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
1015{ 1015{
1016 return keyctl_reject_key(id, timeout, ENOKEY, ringid);
1017}
1018
1019/*
1020 * Negatively instantiate the key with the given timeout (in seconds) and error
1021 * code and link the key into the destination keyring if one is given.
1022 *
1023 * The caller must have the appropriate instantiation permit set for this to
1024 * work (see keyctl_assume_authority). No other permissions are required.
1025 *
1026 * The key and any links to the key will be automatically garbage collected
1027 * after the timeout expires.
1028 *
1029 * Negative keys are used to rate limit repeated request_key() calls by causing
1030 * them to return the specified error code until the negative key expires.
1031 *
1032 * If successful, 0 will be returned.
1033 */
1034long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
1035 key_serial_t ringid)
1036{
1016 const struct cred *cred = current_cred(); 1037 const struct cred *cred = current_cred();
1017 struct request_key_auth *rka; 1038 struct request_key_auth *rka;
1018 struct key *instkey, *dest_keyring; 1039 struct key *instkey, *dest_keyring;
1019 long ret; 1040 long ret;
1020 1041
1021 kenter("%d,%u,%d", id, timeout, ringid); 1042 kenter("%d,%u,%u,%d", id, timeout, error, ringid);
1043
1044 /* must be a valid error code and mustn't be a kernel special */
1045 if (error <= 0 ||
1046 error >= MAX_ERRNO ||
1047 error == ERESTARTSYS ||
1048 error == ERESTARTNOINTR ||
1049 error == ERESTARTNOHAND ||
1050 error == ERESTART_RESTARTBLOCK)
1051 return -EINVAL;
1022 1052
1023 /* the appropriate instantiation authorisation key must have been 1053 /* the appropriate instantiation authorisation key must have been
1024 * assumed before calling this */ 1054 * assumed before calling this */
@@ -1038,7 +1068,7 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
1038 goto error; 1068 goto error;
1039 1069
1040 /* instantiate the key and link it into a keyring */ 1070 /* instantiate the key and link it into a keyring */
1041 ret = key_negate_and_link(rka->target_key, timeout, 1071 ret = key_reject_and_link(rka->target_key, timeout, error,
1042 dest_keyring, instkey); 1072 dest_keyring, instkey);
1043 1073
1044 key_put(dest_keyring); 1074 key_put(dest_keyring);
@@ -1492,6 +1522,12 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
1492 case KEYCTL_SESSION_TO_PARENT: 1522 case KEYCTL_SESSION_TO_PARENT:
1493 return keyctl_session_to_parent(); 1523 return keyctl_session_to_parent();
1494 1524
1525 case KEYCTL_REJECT:
1526 return keyctl_reject_key((key_serial_t) arg2,
1527 (unsigned) arg3,
1528 (unsigned) arg4,
1529 (key_serial_t) arg5);
1530
1495 default: 1531 default:
1496 return -EOPNOTSUPP; 1532 return -EOPNOTSUPP;
1497 } 1533 }
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 5620f084dede..cdd2f3f88c88 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -352,7 +352,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
352 goto error_2; 352 goto error_2;
353 if (key->expiry && now.tv_sec >= key->expiry) 353 if (key->expiry && now.tv_sec >= key->expiry)
354 goto error_2; 354 goto error_2;
355 key_ref = ERR_PTR(-ENOKEY); 355 key_ref = ERR_PTR(key->type_data.reject_error);
356 if (kflags & (1 << KEY_FLAG_NEGATIVE)) 356 if (kflags & (1 << KEY_FLAG_NEGATIVE))
357 goto error_2; 357 goto error_2;
358 goto found; 358 goto found;
@@ -401,7 +401,7 @@ descend:
401 401
402 /* we set a different error code if we pass a negative key */ 402 /* we set a different error code if we pass a negative key */
403 if (kflags & (1 << KEY_FLAG_NEGATIVE)) { 403 if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
404 err = -ENOKEY; 404 err = key->type_data.reject_error;
405 continue; 405 continue;
406 } 406 }
407 407
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index a3dc0d460def..df3c0417ee40 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -585,7 +585,7 @@ int wait_for_key_construction(struct key *key, bool intr)
585 if (ret < 0) 585 if (ret < 0)
586 return ret; 586 return ret;
587 if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) 587 if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
588 return -ENOKEY; 588 return key->type_data.reject_error;
589 return key_validate(key); 589 return key_validate(key);
590} 590}
591EXPORT_SYMBOL(wait_for_key_construction); 591EXPORT_SYMBOL(wait_for_key_construction);