Commit fdd1b94581782a2ddf9124414e5b7a5f48ce2f9c
Committed by
James Morris
1 parent
b9fffa3877
Exists in
master
and in
39 other branches
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>
Showing 11 changed files with 81 additions and 20 deletions Side-by-side Diff
Documentation/keys-request-key.txt
... | ... | @@ -127,14 +127,15 @@ |
127 | 127 | of them, and (b) it requires the same UID/GID/Groups all the way through. |
128 | 128 | |
129 | 129 | |
130 | -====================== | |
131 | -NEGATIVE INSTANTIATION | |
132 | -====================== | |
130 | +==================================== | |
131 | +NEGATIVE INSTANTIATION AND REJECTION | |
132 | +==================================== | |
133 | 133 | |
134 | 134 | Rather than instantiating a key, it is possible for the possessor of an |
135 | 135 | authorisation key to negatively instantiate a key that's under construction. |
136 | 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 | 140 | This is provided to prevent excessive repeated spawning of /sbin/request-key |
140 | 141 | processes for a key that will never be obtainable. |
Documentation/keys.txt
... | ... | @@ -657,6 +657,8 @@ |
657 | 657 | |
658 | 658 | long keyctl(KEYCTL_NEGATE, key_serial_t key, |
659 | 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 | 663 | If the kernel calls back to userspace to complete the instantiation of a |
662 | 664 | key, userspace should use this call mark the key as negative before the |
663 | 665 | |
... | ... | @@ -669,7 +671,11 @@ |
669 | 671 | that keyring, however all the constraints applying in KEYCTL_LINK apply in |
670 | 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. | |
672 | 677 | |
678 | + | |
673 | 679 | (*) Set the default request-key destination keyring. |
674 | 680 | |
675 | 681 | long keyctl(KEYCTL_SET_REQKEY_KEYRING, int reqkey_defl); |
... | ... | @@ -1240,8 +1246,8 @@ |
1240 | 1246 | The program (or whatever it calls) should finish construction of the key by |
1241 | 1247 | calling KEYCTL_INSTANTIATE, which also permits it to cache the key in one of |
1242 | 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 | |
1244 | -be cached in one of the keyrings. | |
1249 | +key can be marked as negative with KEYCTL_NEGATE or KEYCTL_REJECT; this also | |
1250 | +permits the key to be cached in one of the keyrings. | |
1245 | 1251 | |
1246 | 1252 | If it returns with the key remaining in the unconstructed state, the key will |
1247 | 1253 | be marked as being negative, it will be added to the session keyring, and an |
include/linux/key-type.h
... | ... | @@ -105,11 +105,20 @@ |
105 | 105 | size_t datalen, |
106 | 106 | struct key *keyring, |
107 | 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 | 109 | unsigned timeout, |
110 | + unsigned error, | |
110 | 111 | struct key *keyring, |
111 | 112 | struct key *instkey); |
112 | 113 | extern void complete_request_key(struct key_construction *cons, int error); |
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 | +} | |
113 | 122 | |
114 | 123 | #endif /* CONFIG_KEYS */ |
115 | 124 | #endif /* _LINUX_KEY_TYPE_H */ |
include/linux/key.h
include/linux/keyctl.h
... | ... | @@ -53,6 +53,7 @@ |
53 | 53 | #define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ |
54 | 54 | #define KEYCTL_GET_SECURITY 17 /* get key security label */ |
55 | 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 | 58 | #endif /* _LINUX_KEYCTL_H */ |
security/keys/compat.c
security/keys/internal.h
... | ... | @@ -214,6 +214,7 @@ |
214 | 214 | extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, |
215 | 215 | size_t buflen); |
216 | 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 | 220 | * Debugging key validation |
security/keys/key.c
... | ... | @@ -511,26 +511,29 @@ |
511 | 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 | 515 | * @key: The key to instantiate. |
516 | 516 | * @timeout: The timeout on the negative key. |
517 | + * @error: The error to return when the key is hit. | |
517 | 518 | * @keyring: Keyring to create a link in on success (or NULL). |
518 | 519 | * @authkey: The authorisation token permitting instantiation. |
519 | 520 | * |
520 | 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 | - * is supplied. The key and any links to the key will be automatically garbage | |
523 | - * collected after the timeout expires. | |
522 | + * successful, set its timeout and stored error and link it in to the | |
523 | + * destination keyring if one is supplied. The key and any links to the key | |
524 | + * will be automatically garbage collected after the timeout expires. | |
524 | 525 | * |
525 | 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 | 530 | * If successful, 0 is returned, the authorisation token is revoked and anyone |
529 | 531 | * waiting for the key is woken up. If the key was already instantiated, |
530 | 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 | 535 | unsigned timeout, |
536 | + unsigned error, | |
534 | 537 | struct key *keyring, |
535 | 538 | struct key *authkey) |
536 | 539 | { |
... | ... | @@ -556,6 +559,7 @@ |
556 | 559 | atomic_inc(&key->user->nikeys); |
557 | 560 | set_bit(KEY_FLAG_NEGATIVE, &key->flags); |
558 | 561 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); |
562 | + key->type_data.reject_error = -error; | |
559 | 563 | now = current_kernel_time(); |
560 | 564 | key->expiry = now.tv_sec + timeout; |
561 | 565 | key_schedule_gc(key->expiry + key_gc_delay); |
... | ... | @@ -585,8 +589,7 @@ |
585 | 589 | |
586 | 590 | return ret == 0 ? link_ret : ret; |
587 | 591 | } |
588 | - | |
589 | -EXPORT_SYMBOL(key_negate_and_link); | |
592 | +EXPORT_SYMBOL(key_reject_and_link); | |
590 | 593 | |
591 | 594 | /* |
592 | 595 | * Garbage collect keys in process context so that we don't have to disable |
security/keys/keyctl.c
... | ... | @@ -1013,13 +1013,43 @@ |
1013 | 1013 | */ |
1014 | 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 | 1037 | const struct cred *cred = current_cred(); |
1017 | 1038 | struct request_key_auth *rka; |
1018 | 1039 | struct key *instkey, *dest_keyring; |
1019 | 1040 | long ret; |
1020 | 1041 | |
1021 | - kenter("%d,%u,%d", id, timeout, ringid); | |
1042 | + kenter("%d,%u,%u,%d", id, timeout, error, ringid); | |
1022 | 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; | |
1052 | + | |
1023 | 1053 | /* the appropriate instantiation authorisation key must have been |
1024 | 1054 | * assumed before calling this */ |
1025 | 1055 | ret = -EPERM; |
... | ... | @@ -1038,7 +1068,7 @@ |
1038 | 1068 | goto error; |
1039 | 1069 | |
1040 | 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 | 1072 | dest_keyring, instkey); |
1043 | 1073 | |
1044 | 1074 | key_put(dest_keyring); |
... | ... | @@ -1491,6 +1521,12 @@ |
1491 | 1521 | |
1492 | 1522 | case KEYCTL_SESSION_TO_PARENT: |
1493 | 1523 | return keyctl_session_to_parent(); |
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); | |
1494 | 1530 | |
1495 | 1531 | default: |
1496 | 1532 | return -EOPNOTSUPP; |
security/keys/keyring.c
... | ... | @@ -352,7 +352,7 @@ |
352 | 352 | goto error_2; |
353 | 353 | if (key->expiry && now.tv_sec >= key->expiry) |
354 | 354 | goto error_2; |
355 | - key_ref = ERR_PTR(-ENOKEY); | |
355 | + key_ref = ERR_PTR(key->type_data.reject_error); | |
356 | 356 | if (kflags & (1 << KEY_FLAG_NEGATIVE)) |
357 | 357 | goto error_2; |
358 | 358 | goto found; |
... | ... | @@ -401,7 +401,7 @@ |
401 | 401 | |
402 | 402 | /* we set a different error code if we pass a negative key */ |
403 | 403 | if (kflags & (1 << KEY_FLAG_NEGATIVE)) { |
404 | - err = -ENOKEY; | |
404 | + err = key->type_data.reject_error; | |
405 | 405 | continue; |
406 | 406 | } |
407 | 407 |
security/keys/request_key.c