During key construction, search the calling process' session keyring for a keyagent key with a description that matches the requested key_type. If found, link the authkey into the keyagent's process_keyring, and signal the keyagent task with a realtime signal containing the serial number of the key that needs to be constructed. Signed-off-by: Benjamin Coddington <bcodding@xxxxxxxxxx> --- include/uapi/asm-generic/siginfo.h | 1 + security/keys/internal.h | 4 ++ security/keys/keyagent.c | 85 ++++++++++++++++++++++++++++++ security/keys/request_key.c | 9 ++++ 4 files changed, 99 insertions(+) diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h index ffbe4cec9f32..542e297f4466 100644 --- a/include/uapi/asm-generic/siginfo.h +++ b/include/uapi/asm-generic/siginfo.h @@ -185,6 +185,7 @@ typedef struct siginfo { #define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_TKILL -6 /* sent by tkill system call */ #define SI_DETHREAD -7 /* sent by execve() killing subsidiary threads */ +#define SI_KEYAGENT -8 /* sent by request-key */ #define SI_ASYNCNL -60 /* sent by glibc async name lookup completion */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) diff --git a/security/keys/internal.h b/security/keys/internal.h index 9b9cf3b6fcbb..a6db6eecfff5 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -372,5 +372,9 @@ static inline void key_check(const struct key *key) #define key_check(key) do {} while(0) +#endif + +#ifdef CONFIG_KEYAGENT +extern int keyagent_request_key(struct key *authkey, void *aux); #endif #endif /* _INTERNAL_H */ diff --git a/security/keys/keyagent.c b/security/keys/keyagent.c index 87ebfe00c710..cf70146925f0 100644 --- a/security/keys/keyagent.c +++ b/security/keys/keyagent.c @@ -9,8 +9,11 @@ #include <linux/slab.h> #include <linux/key.h> #include <linux/key-type.h> +#include <linux/sched/signal.h> +#include <linux/sched/task.h> #include <keys/user-type.h> +#include <keys/request_key_auth-type.h> /* * Keyagent key payload. @@ -20,6 +23,88 @@ struct keyagent { int sig; }; +struct key_type key_type_keyagent; + +/* + * Given a key representing a keyagent and a target_key to construct, link + * the the authkey into the keyagent's process_keyring and signal the + * keyagent to construct the target_key. + */ +static int keyagent_signal(struct key *ka_key, struct key *target_key, + struct key *authkey) +{ + struct keyagent *ka = ka_key->payload.data[0]; + struct task_struct *task; + const struct cred *cred; + kernel_siginfo_t info = { + .si_code = SI_KEYAGENT, + .si_signo = ka->sig, + .si_int = target_key->serial, + }; + int ret = -ENOKEY; + + task = get_pid_task(ka->pid, PIDTYPE_PID); + /* If the task is gone, should we revoke the keyagent key? */ + if (!task) { + key_revoke(ka_key); + goto out; + } + + /* We're expecting valid keyagents to have a process keyring, + * if not, should we warn? */ + cred = get_cred(task->cred); + if (!cred->process_keyring) + goto out_nolink; + + /* Link the autkey to the keyagent's process_keyring */ + ret = key_link(cred->process_keyring, authkey); + if (ret < 0) + goto out_nolink; + + ret = send_sig_info(ka->sig, &info, task); + +out_nolink: + put_cred(cred); + put_task_struct(task); +out: + return ret; +} + +/* + * Search the calling process' keyrings for a keyagent that + * matches the requested key type. If found, signal the keyagent + * to construct and link the key, else return -ENOKEY. + */ +int keyagent_request_key(struct key *authkey, void *aux) +{ + struct key *ka_key, *target_key; + struct request_key_auth *rka; + key_ref_t ka_ref; + const struct cred *cred = current_cred(); + int ret; + + /* We must be careful not to touch authkey and aux if + * returning -ENOKEY, since it will be reused. */ + rka = get_request_key_auth(authkey); + target_key = rka->target_key; + + /* Does the calling process have a keyagent in its session keyring? */ + ka_ref = keyring_search( + make_key_ref(cred->session_keyring, 1), + &key_type_keyagent, + target_key->type->name, false); + + if (IS_ERR(ka_ref)) + return -ENOKEY; + + /* We found a keyagent, let's call out to it. */ + ka_key = key_ref_to_ptr(ka_ref); + ret = keyagent_signal(ka_key, target_key, authkey); + key_put(key_ref_to_ptr(ka_ref)); + + return ret; +} + /* * Instantiate takes a reference to the current task's struct pid * and the requested realtime signal number. diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 2da4404276f0..4c1f5ef55856 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -240,9 +240,18 @@ static int construct_key(struct key *key, const void *callout_info, actor = call_sbin_request_key; if (key->type->request_key) actor = key->type->request_key; +#ifdef CONFIG_KEYAGENT + else { + ret = keyagent_request_key(authkey, aux); + /* ENOKEY: no keyagents match on calling process' keyrings */ + if (ret != -ENOKEY) + goto done; + } +#endif ret = actor(authkey, aux); +done: /* check that the actor called complete_request_key() prior to * returning an error */ WARN_ON(ret < 0 && -- 2.31.1