mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-21 06:01:23 +00:00
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>
This commit is contained in:
parent
b9fffa3877
commit
fdd1b94581
11 changed files with 81 additions and 20 deletions
|
@ -127,14 +127,15 @@ This is because process A's keyrings can't simply be attached to
|
||||||
of them, and (b) it requires the same UID/GID/Groups all the way through.
|
of them, and (b) it requires the same UID/GID/Groups all the way through.
|
||||||
|
|
||||||
|
|
||||||
======================
|
====================================
|
||||||
NEGATIVE INSTANTIATION
|
NEGATIVE INSTANTIATION AND REJECTION
|
||||||
======================
|
====================================
|
||||||
|
|
||||||
Rather than instantiating a key, it is possible for the possessor of an
|
Rather than instantiating a key, it is possible for the possessor of an
|
||||||
authorisation key to negatively instantiate a key that's under construction.
|
authorisation key to negatively instantiate a key that's under construction.
|
||||||
This is a short duration placeholder that causes any attempt at re-requesting
|
This is a short duration placeholder that causes any attempt at re-requesting
|
||||||
the key whilst it exists to fail with error ENOKEY.
|
the key whilst it exists to fail with error ENOKEY if negated or the specified
|
||||||
|
error if rejected.
|
||||||
|
|
||||||
This is provided to prevent excessive repeated spawning of /sbin/request-key
|
This is provided to prevent excessive repeated spawning of /sbin/request-key
|
||||||
processes for a key that will never be obtainable.
|
processes for a key that will never be obtainable.
|
||||||
|
|
|
@ -657,6 +657,8 @@ The keyctl syscall functions are:
|
||||||
|
|
||||||
long keyctl(KEYCTL_NEGATE, key_serial_t key,
|
long keyctl(KEYCTL_NEGATE, key_serial_t key,
|
||||||
unsigned timeout, key_serial_t keyring);
|
unsigned timeout, key_serial_t keyring);
|
||||||
|
long keyctl(KEYCTL_REJECT, key_serial_t key,
|
||||||
|
unsigned timeout, unsigned error, key_serial_t keyring);
|
||||||
|
|
||||||
If the kernel calls back to userspace to complete the instantiation of a
|
If the kernel calls back to userspace to complete the instantiation of a
|
||||||
key, userspace should use this call mark the key as negative before the
|
key, userspace should use this call mark the key as negative before the
|
||||||
|
@ -669,6 +671,10 @@ The keyctl syscall functions are:
|
||||||
that keyring, however all the constraints applying in KEYCTL_LINK apply in
|
that keyring, however all the constraints applying in KEYCTL_LINK apply in
|
||||||
this case too.
|
this case too.
|
||||||
|
|
||||||
|
If the key is rejected, future searches for it will return the specified
|
||||||
|
error code until the rejected key expires. Negating the key is the same
|
||||||
|
as rejecting the key with ENOKEY as the error code.
|
||||||
|
|
||||||
|
|
||||||
(*) Set the default request-key destination keyring.
|
(*) Set the default request-key destination keyring.
|
||||||
|
|
||||||
|
@ -1240,8 +1246,8 @@ example, the KDE desktop manager).
|
||||||
The program (or whatever it calls) should finish construction of the key by
|
The program (or whatever it calls) should finish construction of the key by
|
||||||
calling KEYCTL_INSTANTIATE, which also permits it to cache the key in one of
|
calling KEYCTL_INSTANTIATE, which also permits it to cache the key in one of
|
||||||
the keyrings (probably the session ring) before returning. Alternatively, the
|
the keyrings (probably the session ring) before returning. Alternatively, the
|
||||||
key can be marked as negative with KEYCTL_NEGATE; this also permits the key to
|
key can be marked as negative with KEYCTL_NEGATE or KEYCTL_REJECT; this also
|
||||||
be cached in one of the keyrings.
|
permits the key to be cached in one of the keyrings.
|
||||||
|
|
||||||
If it returns with the key remaining in the unconstructed state, the key will
|
If it returns with the key remaining in the unconstructed state, the key will
|
||||||
be marked as being negative, it will be added to the session keyring, and an
|
be marked as being negative, it will be added to the session keyring, and an
|
||||||
|
|
|
@ -105,11 +105,20 @@ extern int key_instantiate_and_link(struct key *key,
|
||||||
size_t datalen,
|
size_t datalen,
|
||||||
struct key *keyring,
|
struct key *keyring,
|
||||||
struct key *instkey);
|
struct key *instkey);
|
||||||
extern int key_negate_and_link(struct key *key,
|
extern int key_reject_and_link(struct key *key,
|
||||||
unsigned timeout,
|
unsigned timeout,
|
||||||
|
unsigned error,
|
||||||
struct key *keyring,
|
struct key *keyring,
|
||||||
struct key *instkey);
|
struct key *instkey);
|
||||||
extern void complete_request_key(struct key_construction *cons, int error);
|
extern void complete_request_key(struct key_construction *cons, int error);
|
||||||
|
|
||||||
|
static inline int key_negate_and_link(struct key *key,
|
||||||
|
unsigned timeout,
|
||||||
|
struct key *keyring,
|
||||||
|
struct key *instkey)
|
||||||
|
{
|
||||||
|
return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_KEYS */
|
#endif /* CONFIG_KEYS */
|
||||||
#endif /* _LINUX_KEY_TYPE_H */
|
#endif /* _LINUX_KEY_TYPE_H */
|
||||||
|
|
|
@ -170,6 +170,7 @@ struct key {
|
||||||
struct list_head link;
|
struct list_head link;
|
||||||
unsigned long x[2];
|
unsigned long x[2];
|
||||||
void *p[2];
|
void *p[2];
|
||||||
|
int reject_error;
|
||||||
} type_data;
|
} type_data;
|
||||||
|
|
||||||
/* key data
|
/* key data
|
||||||
|
|
|
@ -53,5 +53,6 @@
|
||||||
#define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */
|
#define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */
|
||||||
#define KEYCTL_GET_SECURITY 17 /* get key security label */
|
#define KEYCTL_GET_SECURITY 17 /* get key security label */
|
||||||
#define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */
|
#define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */
|
||||||
|
#define KEYCTL_REJECT 19 /* reject a partially constructed key */
|
||||||
|
|
||||||
#endif /* _LINUX_KEYCTL_H */
|
#endif /* _LINUX_KEYCTL_H */
|
||||||
|
|
|
@ -85,6 +85,9 @@ asmlinkage long compat_sys_keyctl(u32 option,
|
||||||
case KEYCTL_SESSION_TO_PARENT:
|
case KEYCTL_SESSION_TO_PARENT:
|
||||||
return keyctl_session_to_parent();
|
return keyctl_session_to_parent();
|
||||||
|
|
||||||
|
case KEYCTL_REJECT:
|
||||||
|
return keyctl_reject_key(arg2, arg3, arg4, arg5);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,6 +214,7 @@ extern long keyctl_assume_authority(key_serial_t);
|
||||||
extern long keyctl_get_security(key_serial_t keyid, char __user *buffer,
|
extern long keyctl_get_security(key_serial_t keyid, char __user *buffer,
|
||||||
size_t buflen);
|
size_t buflen);
|
||||||
extern long keyctl_session_to_parent(void);
|
extern long keyctl_session_to_parent(void);
|
||||||
|
extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Debugging key validation
|
* Debugging key validation
|
||||||
|
|
|
@ -511,26 +511,29 @@ int key_instantiate_and_link(struct key *key,
|
||||||
EXPORT_SYMBOL(key_instantiate_and_link);
|
EXPORT_SYMBOL(key_instantiate_and_link);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* key_negate_and_link - Negatively instantiate a key and link it into the keyring.
|
* key_reject_and_link - Negatively instantiate a key and link it into the keyring.
|
||||||
* @key: The key to instantiate.
|
* @key: The key to instantiate.
|
||||||
* @timeout: The timeout on the negative key.
|
* @timeout: The timeout on the negative key.
|
||||||
|
* @error: The error to return when the key is hit.
|
||||||
* @keyring: Keyring to create a link in on success (or NULL).
|
* @keyring: Keyring to create a link in on success (or NULL).
|
||||||
* @authkey: The authorisation token permitting instantiation.
|
* @authkey: The authorisation token permitting instantiation.
|
||||||
*
|
*
|
||||||
* Negatively instantiate a key that's in the uninstantiated state and, if
|
* Negatively instantiate a key that's in the uninstantiated state and, if
|
||||||
* successful, set its timeout and link it in to the destination keyring if one
|
* successful, set its timeout and stored error and link it in to the
|
||||||
* is supplied. The key and any links to the key will be automatically garbage
|
* destination keyring if one is supplied. The key and any links to the key
|
||||||
* collected after the timeout expires.
|
* will be automatically garbage collected after the timeout expires.
|
||||||
*
|
*
|
||||||
* Negative keys are used to rate limit repeated request_key() calls by causing
|
* Negative keys are used to rate limit repeated request_key() calls by causing
|
||||||
* them to return -ENOKEY until the negative key expires.
|
* them to return the stored error code (typically ENOKEY) until the negative
|
||||||
|
* key expires.
|
||||||
*
|
*
|
||||||
* If successful, 0 is returned, the authorisation token is revoked and anyone
|
* If successful, 0 is returned, the authorisation token is revoked and anyone
|
||||||
* waiting for the key is woken up. If the key was already instantiated,
|
* waiting for the key is woken up. If the key was already instantiated,
|
||||||
* -EBUSY will be returned.
|
* -EBUSY will be returned.
|
||||||
*/
|
*/
|
||||||
int key_negate_and_link(struct key *key,
|
int key_reject_and_link(struct key *key,
|
||||||
unsigned timeout,
|
unsigned timeout,
|
||||||
|
unsigned error,
|
||||||
struct key *keyring,
|
struct key *keyring,
|
||||||
struct key *authkey)
|
struct key *authkey)
|
||||||
{
|
{
|
||||||
|
@ -556,6 +559,7 @@ int key_negate_and_link(struct key *key,
|
||||||
atomic_inc(&key->user->nikeys);
|
atomic_inc(&key->user->nikeys);
|
||||||
set_bit(KEY_FLAG_NEGATIVE, &key->flags);
|
set_bit(KEY_FLAG_NEGATIVE, &key->flags);
|
||||||
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
|
set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
|
||||||
|
key->type_data.reject_error = -error;
|
||||||
now = current_kernel_time();
|
now = current_kernel_time();
|
||||||
key->expiry = now.tv_sec + timeout;
|
key->expiry = now.tv_sec + timeout;
|
||||||
key_schedule_gc(key->expiry + key_gc_delay);
|
key_schedule_gc(key->expiry + key_gc_delay);
|
||||||
|
@ -585,8 +589,7 @@ int key_negate_and_link(struct key *key,
|
||||||
|
|
||||||
return ret == 0 ? link_ret : ret;
|
return ret == 0 ? link_ret : ret;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(key_reject_and_link);
|
||||||
EXPORT_SYMBOL(key_negate_and_link);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Garbage collect keys in process context so that we don't have to disable
|
* Garbage collect keys in process context so that we don't have to disable
|
||||||
|
|
|
@ -1012,13 +1012,43 @@ error:
|
||||||
* If successful, 0 will be returned.
|
* If successful, 0 will be returned.
|
||||||
*/
|
*/
|
||||||
long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
|
long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
|
||||||
|
{
|
||||||
|
return keyctl_reject_key(id, timeout, ENOKEY, ringid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Negatively instantiate the key with the given timeout (in seconds) and error
|
||||||
|
* code and link the key into the destination keyring if one is given.
|
||||||
|
*
|
||||||
|
* The caller must have the appropriate instantiation permit set for this to
|
||||||
|
* work (see keyctl_assume_authority). No other permissions are required.
|
||||||
|
*
|
||||||
|
* The key and any links to the key will be automatically garbage collected
|
||||||
|
* after the timeout expires.
|
||||||
|
*
|
||||||
|
* Negative keys are used to rate limit repeated request_key() calls by causing
|
||||||
|
* them to return the specified error code until the negative key expires.
|
||||||
|
*
|
||||||
|
* If successful, 0 will be returned.
|
||||||
|
*/
|
||||||
|
long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
|
||||||
|
key_serial_t ringid)
|
||||||
{
|
{
|
||||||
const struct cred *cred = current_cred();
|
const struct cred *cred = current_cred();
|
||||||
struct request_key_auth *rka;
|
struct request_key_auth *rka;
|
||||||
struct key *instkey, *dest_keyring;
|
struct key *instkey, *dest_keyring;
|
||||||
long ret;
|
long ret;
|
||||||
|
|
||||||
kenter("%d,%u,%d", id, timeout, ringid);
|
kenter("%d,%u,%u,%d", id, timeout, error, ringid);
|
||||||
|
|
||||||
|
/* must be a valid error code and mustn't be a kernel special */
|
||||||
|
if (error <= 0 ||
|
||||||
|
error >= MAX_ERRNO ||
|
||||||
|
error == ERESTARTSYS ||
|
||||||
|
error == ERESTARTNOINTR ||
|
||||||
|
error == ERESTARTNOHAND ||
|
||||||
|
error == ERESTART_RESTARTBLOCK)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/* the appropriate instantiation authorisation key must have been
|
/* the appropriate instantiation authorisation key must have been
|
||||||
* assumed before calling this */
|
* assumed before calling this */
|
||||||
|
@ -1038,7 +1068,7 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* instantiate the key and link it into a keyring */
|
/* instantiate the key and link it into a keyring */
|
||||||
ret = key_negate_and_link(rka->target_key, timeout,
|
ret = key_reject_and_link(rka->target_key, timeout, error,
|
||||||
dest_keyring, instkey);
|
dest_keyring, instkey);
|
||||||
|
|
||||||
key_put(dest_keyring);
|
key_put(dest_keyring);
|
||||||
|
@ -1492,6 +1522,12 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
|
||||||
case KEYCTL_SESSION_TO_PARENT:
|
case KEYCTL_SESSION_TO_PARENT:
|
||||||
return keyctl_session_to_parent();
|
return keyctl_session_to_parent();
|
||||||
|
|
||||||
|
case KEYCTL_REJECT:
|
||||||
|
return keyctl_reject_key((key_serial_t) arg2,
|
||||||
|
(unsigned) arg3,
|
||||||
|
(unsigned) arg4,
|
||||||
|
(key_serial_t) arg5);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
|
@ -352,7 +352,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
|
||||||
goto error_2;
|
goto error_2;
|
||||||
if (key->expiry && now.tv_sec >= key->expiry)
|
if (key->expiry && now.tv_sec >= key->expiry)
|
||||||
goto error_2;
|
goto error_2;
|
||||||
key_ref = ERR_PTR(-ENOKEY);
|
key_ref = ERR_PTR(key->type_data.reject_error);
|
||||||
if (kflags & (1 << KEY_FLAG_NEGATIVE))
|
if (kflags & (1 << KEY_FLAG_NEGATIVE))
|
||||||
goto error_2;
|
goto error_2;
|
||||||
goto found;
|
goto found;
|
||||||
|
@ -401,7 +401,7 @@ descend:
|
||||||
|
|
||||||
/* we set a different error code if we pass a negative key */
|
/* we set a different error code if we pass a negative key */
|
||||||
if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
|
if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
|
||||||
err = -ENOKEY;
|
err = key->type_data.reject_error;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -585,7 +585,7 @@ int wait_for_key_construction(struct key *key, bool intr)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
|
if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
|
||||||
return -ENOKEY;
|
return key->type_data.reject_error;
|
||||||
return key_validate(key);
|
return key_validate(key);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(wait_for_key_construction);
|
EXPORT_SYMBOL(wait_for_key_construction);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue