[PATCH 2/2] KEYS: Add keyagent request_key

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux