diff options
author | David Howells <dhowells@redhat.com> | 2011-03-07 10:06:09 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2011-03-07 19:17:18 -0500 |
commit | fdd1b94581782a2ddf9124414e5b7a5f48ce2f9c (patch) | |
tree | ce83bfd1f0b1a7d4b9521bdb3d6afef1bff1d4f2 | |
parent | b9fffa3877a3ebbe0a5ad5a247358e2f7df15b24 (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>
-rw-r--r-- | Documentation/keys-request-key.txt | 9 | ||||
-rw-r--r-- | Documentation/keys.txt | 10 | ||||
-rw-r--r-- | include/linux/key-type.h | 11 | ||||
-rw-r--r-- | include/linux/key.h | 1 | ||||
-rw-r--r-- | include/linux/keyctl.h | 1 | ||||
-rw-r--r-- | security/keys/compat.c | 3 | ||||
-rw-r--r-- | security/keys/internal.h | 1 | ||||
-rw-r--r-- | security/keys/key.c | 19 | ||||
-rw-r--r-- | security/keys/keyctl.c | 40 | ||||
-rw-r--r-- | security/keys/keyring.c | 4 | ||||
-rw-r--r-- | security/keys/request_key.c | 2 |
11 files changed, 81 insertions, 20 deletions
diff --git a/Documentation/keys-request-key.txt b/Documentation/keys-request-key.txt index 09b55e461740..69686ad12c66 100644 --- a/Documentation/keys-request-key.txt +++ b/Documentation/keys-request-key.txt | |||
@@ -127,14 +127,15 @@ This is because process A's keyrings can't simply be attached to | |||
127 | of them, and (b) it requires the same UID/GID/Groups all the way through. | 127 | of them, and (b) it requires the same UID/GID/Groups all the way through. |
128 | 128 | ||
129 | 129 | ||
130 | ====================== | 130 | ==================================== |
131 | NEGATIVE INSTANTIATION | 131 | NEGATIVE INSTANTIATION AND REJECTION |
132 | ====================== | 132 | ==================================== |
133 | 133 | ||
134 | Rather than instantiating a key, it is possible for the possessor of an | 134 | Rather than instantiating a key, it is possible for the possessor of an |
135 | authorisation key to negatively instantiate a key that's under construction. | 135 | authorisation key to negatively instantiate a key that's under construction. |
136 | This is a short duration placeholder that causes any attempt at re-requesting | 136 | This is a short duration placeholder that causes any attempt at re-requesting |
137 | the key whilst it exists to fail with error ENOKEY. | 137 | the key whilst it exists to fail with error ENOKEY if negated or the specified |
138 | error if rejected. | ||
138 | 139 | ||
139 | This is provided to prevent excessive repeated spawning of /sbin/request-key | 140 | This is provided to prevent excessive repeated spawning of /sbin/request-key |
140 | processes for a key that will never be obtainable. | 141 | processes for a key that will never be obtainable. |
diff --git a/Documentation/keys.txt b/Documentation/keys.txt index cf68d1fed95d..a6a97fdfaddd 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt | |||
@@ -657,6 +657,8 @@ The keyctl syscall functions are: | |||
657 | 657 | ||
658 | long keyctl(KEYCTL_NEGATE, key_serial_t key, | 658 | long keyctl(KEYCTL_NEGATE, key_serial_t key, |
659 | unsigned timeout, key_serial_t keyring); | 659 | unsigned timeout, key_serial_t keyring); |
660 | long keyctl(KEYCTL_REJECT, key_serial_t key, | ||
661 | unsigned timeout, unsigned error, key_serial_t keyring); | ||
660 | 662 | ||
661 | If the kernel calls back to userspace to complete the instantiation of a | 663 | If the kernel calls back to userspace to complete the instantiation of a |
662 | key, userspace should use this call mark the key as negative before the | 664 | key, userspace should use this call mark the key as negative before the |
@@ -669,6 +671,10 @@ The keyctl syscall functions are: | |||
669 | that keyring, however all the constraints applying in KEYCTL_LINK apply in | 671 | that keyring, however all the constraints applying in KEYCTL_LINK apply in |
670 | this case too. | 672 | this case too. |
671 | 673 | ||
674 | If the key is rejected, future searches for it will return the specified | ||
675 | error code until the rejected key expires. Negating the key is the same | ||
676 | as rejecting the key with ENOKEY as the error code. | ||
677 | |||
672 | 678 | ||
673 | (*) Set the default request-key destination keyring. | 679 | (*) Set the default request-key destination keyring. |
674 | 680 | ||
@@ -1240,8 +1246,8 @@ example, the KDE desktop manager). | |||
1240 | The program (or whatever it calls) should finish construction of the key by | 1246 | The program (or whatever it calls) should finish construction of the key by |
1241 | calling KEYCTL_INSTANTIATE, which also permits it to cache the key in one of | 1247 | calling KEYCTL_INSTANTIATE, which also permits it to cache the key in one of |
1242 | the keyrings (probably the session ring) before returning. Alternatively, the | 1248 | the keyrings (probably the session ring) before returning. Alternatively, the |
1243 | key can be marked as negative with KEYCTL_NEGATE; this also permits the key to | 1249 | key can be marked as negative with KEYCTL_NEGATE or KEYCTL_REJECT; this also |
1244 | be cached in one of the keyrings. | 1250 | permits the key to be cached in one of the keyrings. |
1245 | 1251 | ||
1246 | If it returns with the key remaining in the unconstructed state, the key will | 1252 | If it returns with the key remaining in the unconstructed state, the key will |
1247 | be marked as being negative, it will be added to the session keyring, and an | 1253 | be marked as being negative, it will be added to the session keyring, and an |
diff --git a/include/linux/key-type.h b/include/linux/key-type.h index fc8525e838b7..9efd081bb31e 100644 --- a/include/linux/key-type.h +++ b/include/linux/key-type.h | |||
@@ -105,11 +105,20 @@ extern int key_instantiate_and_link(struct key *key, | |||
105 | size_t datalen, | 105 | size_t datalen, |
106 | struct key *keyring, | 106 | struct key *keyring, |
107 | struct key *instkey); | 107 | struct key *instkey); |
108 | extern int key_negate_and_link(struct key *key, | 108 | extern int key_reject_and_link(struct key *key, |
109 | unsigned timeout, | 109 | unsigned timeout, |
110 | unsigned error, | ||
110 | struct key *keyring, | 111 | struct key *keyring, |
111 | struct key *instkey); | 112 | struct key *instkey); |
112 | extern void complete_request_key(struct key_construction *cons, int error); | 113 | extern void complete_request_key(struct key_construction *cons, int error); |
113 | 114 | ||
115 | static inline int key_negate_and_link(struct key *key, | ||
116 | unsigned timeout, | ||
117 | struct key *keyring, | ||
118 | struct key *instkey) | ||
119 | { | ||
120 | return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey); | ||
121 | } | ||
122 | |||
114 | #endif /* CONFIG_KEYS */ | 123 | #endif /* CONFIG_KEYS */ |
115 | #endif /* _LINUX_KEY_TYPE_H */ | 124 | #endif /* _LINUX_KEY_TYPE_H */ |
diff --git a/include/linux/key.h b/include/linux/key.h index a6b1edcffc34..b2bb01719561 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
@@ -170,6 +170,7 @@ struct key { | |||
170 | struct list_head link; | 170 | struct list_head link; |
171 | unsigned long x[2]; | 171 | unsigned long x[2]; |
172 | void *p[2]; | 172 | void *p[2]; |
173 | int reject_error; | ||
173 | } type_data; | 174 | } type_data; |
174 | 175 | ||
175 | /* key data | 176 | /* key data |
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h index bd383f1944fb..7022974def0c 100644 --- a/include/linux/keyctl.h +++ b/include/linux/keyctl.h | |||
@@ -53,5 +53,6 @@ | |||
53 | #define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ | 53 | #define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ |
54 | #define KEYCTL_GET_SECURITY 17 /* get key security label */ | 54 | #define KEYCTL_GET_SECURITY 17 /* get key security label */ |
55 | #define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ | 55 | #define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ |
56 | #define KEYCTL_REJECT 19 /* reject a partially constructed key */ | ||
56 | 57 | ||
57 | #endif /* _LINUX_KEYCTL_H */ | 58 | #endif /* _LINUX_KEYCTL_H */ |
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); | |||
214 | extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, | 214 | extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, |
215 | size_t buflen); | 215 | size_t buflen); |
216 | extern long keyctl_session_to_parent(void); | 216 | extern long keyctl_session_to_parent(void); |
217 | extern 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, | |||
511 | EXPORT_SYMBOL(key_instantiate_and_link); | 511 | EXPORT_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 | */ |
532 | int key_negate_and_link(struct key *key, | 534 | int 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 | 592 | EXPORT_SYMBOL(key_reject_and_link); | |
589 | EXPORT_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 | */ |
1014 | long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) | 1014 | long 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 | */ | ||
1034 | long 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 | } |
591 | EXPORT_SYMBOL(wait_for_key_construction); | 591 | EXPORT_SYMBOL(wait_for_key_construction); |