[PATCH 2/3] Process Notification / pnotify user: keyrings

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

 



Here is an example implementation showing keyrings using pnotify as
a proof of concecpt.  Not all the callouts that keyrings needs are
currently implemented in pnotify (but most could be if desired). 

Signed-off-by: Erik Jacobson <[email protected]>
---

 include/linux/key.h          |   21 +++++
 include/linux/sched.h        |    4 -
 kernel/exit.c                |    1
 kernel/fork.c                |    6 -
 security/keys/key.c          |   22 ++++++
 security/keys/keyctl.c       |   28 ++++++-
 security/keys/process_keys.c |  152 ++++++++++++++++++++++++++++++++++++-------
 security/keys/request_key.c  |   31 +++++++-
 8 files changed, 222 insertions(+), 43 deletions(-)


Index: linux/include/linux/key.h
===================================================================
--- linux.orig/include/linux/key.h	2005-09-19 22:00:41.000000000 -0500
+++ linux/include/linux/key.h	2005-09-27 09:46:07.501801117 -0500
@@ -19,6 +19,7 @@
 #include <linux/list.h>
 #include <linux/rbtree.h>
 #include <linux/rcupdate.h>
+#include <linux/pnotify.h>
 #include <asm/atomic.h>
 
 #ifdef __KERNEL__
@@ -262,9 +263,9 @@
 extern struct key root_user_keyring, root_session_keyring;
 extern int alloc_uid_keyring(struct user_struct *user);
 extern void switch_uid_keyring(struct user_struct *new_user);
-extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
+extern int copy_keys(struct task_struct *tsk, struct pnotify_subscriber *sub, void *olddata);
 extern int copy_thread_group_keys(struct task_struct *tsk);
-extern void exit_keys(struct task_struct *tsk);
+extern void exit_keys(struct task_struct *task, struct pnotify_subscriber *sub);
 extern void exit_thread_group_keys(struct signal_struct *tg);
 extern int suid_keys(struct task_struct *tsk);
 extern int exec_keys(struct task_struct *tsk);
@@ -279,6 +280,22 @@
 	old_session;						\
 })
 
+/* pnotify subscriber service request */
+static struct pnotify_events key_events = {
+	.module = NULL,
+	.name = "key",
+	.data = NULL,
+	.entry = LIST_HEAD_INIT(key_events.entry),
+	.fork = copy_keys,
+	.exit = exit_keys,
+};
+
+/* key info associated with the task struct and managed by pnotify */
+struct key_task {
+	struct key *thread_keyring; /* keyring private to this thread */
+	unsigned char jit_keyring; /* default keyring to attach requested keys to */
+};
+
 #else /* CONFIG_KEYS */
 
 #define key_validate(k)			0
Index: linux/kernel/exit.c
===================================================================
--- linux.orig/kernel/exit.c	2005-09-27 09:45:59.500655412 -0500
+++ linux/kernel/exit.c	2005-09-27 09:46:07.505706973 -0500
@@ -857,7 +857,6 @@
 	exit_namespace(tsk);
 	exit_thread();
 	cpuset_exit(tsk);
-	exit_keys(tsk);
 
 	if (group_dead && tsk->signal->leader)
 		disassociate_ctty(1);
Index: linux/kernel/fork.c
===================================================================
--- linux.orig/kernel/fork.c	2005-09-27 09:40:40.824808451 -0500
+++ linux/kernel/fork.c	2005-09-27 09:46:07.506683436 -0500
@@ -1009,10 +1009,8 @@
 		goto bad_fork_cleanup_sighand;
 	if ((retval = copy_mm(clone_flags, p)))
 		goto bad_fork_cleanup_signal;
-	if ((retval = copy_keys(clone_flags, p)))
-		goto bad_fork_cleanup_mm;
 	if ((retval = copy_namespace(clone_flags, p)))
-		goto bad_fork_cleanup_keys;
+		goto bad_fork_cleanup_mm;
 	retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
 	if (retval)
 		goto bad_fork_cleanup_namespace;
@@ -1175,8 +1173,6 @@
 bad_fork_cleanup_namespace:
 	pnotify_exit(p);
 	exit_namespace(p);
-bad_fork_cleanup_keys:
-	exit_keys(p);
 bad_fork_cleanup_mm:
 	if (p->mm)
 		mmput(p->mm);
Index: linux/security/keys/key.c
===================================================================
--- linux.orig/security/keys/key.c	2005-09-19 22:00:41.000000000 -0500
+++ linux/security/keys/key.c	2005-09-27 09:46:07.511565756 -0500
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/err.h>
+#include <linux/pnotify.h>
 #include "internal.h"
 
 static kmem_cache_t	*key_jar;
@@ -1009,6 +1010,9 @@
  */
 void __init key_init(void)
 {
+	struct key_task *kt;
+	struct pnotify_subscriber *sub;
+
 	/* allocate a slab in which we can store keys */
 	key_jar = kmem_cache_create("key_jar", sizeof(struct key),
 			0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
@@ -1039,4 +1043,22 @@
 	/* link the two root keyrings together */
 	key_link(&root_session_keyring, &root_user_keyring);
 
+	/* Allocate memory for task assocated key_task structure */
+	kt = (struct key_task *)kmalloc(sizeof(struct key_task),GFP_KERNEL);
+	if (!kt) {
+		printk(KERN_ERR "Insufficient memory to allocate key_task structure"
+		  " in key_init function.\n");
+		return;
+   }
+	kt->thread_keyring = NULL;
+
+	/* subscribe this kernel entity to the subscriber list for current task */
+	sub = pnotify_subscribe(current, &key_events);
+	if (!sub) {
+		printk(KERN_ERR "Insufficient memory to add to subscriber list structure"
+		  " in key_init function.\n");
+	}
+	/* Associate the kt structure with this task via pnotify subscriber */
+	sub->data = (void *)kt;
+
 } /* end key_init() */
Index: linux/security/keys/process_keys.c
===================================================================
--- linux.orig/security/keys/process_keys.c	2005-09-19 22:00:41.000000000 -0500
+++ linux/security/keys/process_keys.c	2005-09-27 09:46:07.513518684 -0500
@@ -16,6 +16,7 @@
 #include <linux/keyctl.h>
 #include <linux/fs.h>
 #include <linux/err.h>
+#include <linux/pnotify.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
@@ -137,6 +138,8 @@
 int install_thread_keyring(struct task_struct *tsk)
 {
 	struct key *keyring, *old;
+	struct key_task *kt;
+	struct pnotify_subscriber *sub;
 	char buf[20];
 	int ret;
 
@@ -149,9 +152,21 @@
 	}
 
 	task_lock(tsk);
-	old = tsk->thread_keyring;
-	tsk->thread_keyring = keyring;
+	down_write(&tsk->pnotify_subscriber_list_sem);
+	sub = pnotify_get_subscriber(tsk, key_events.name);
+	if (sub == NULL || sub->data == NULL) { /* shouldn't happen */
+		printk(KERN_ERR "install_thread_keyring pnotify subscriber or data ptr null, task: %d\n", tsk->pid);
+		task_unlock(tsk);
+		up_write(&tsk->pnotify_subscriber_list_sem);
+		ret = PTR_ERR(sub);
+		goto error;
+	}
+	kt = (struct key_task *)sub->data;
+
+	old = kt->thread_keyring;
+	kt->thread_keyring = keyring;
 	task_unlock(tsk);
+	up_write(&tsk->pnotify_subscriber_list_sem);
 
 	ret = 0;
 
@@ -267,13 +282,25 @@
 /*
  * copy the keys for fork
  */
-int copy_keys(unsigned long clone_flags, struct task_struct *tsk)
+int copy_keys(struct task_struct *tsk, struct pnotify_subscriber *sub, void *olddata)
 {
-	key_check(tsk->thread_keyring);
+	struct key_task *kt = ((struct key_task *)(sub->data));
+
+	/* Allocate memory for task-associated key_task structure */
+	kt = (struct key_task *)kmalloc(sizeof(struct key_task),GFP_KERNEL);
+	if (!kt) {
+		printk(KERN_ERR "Insufficient memory to allocate key_task structure"
+		  " in copy_keys function.  Task was: %d", tsk->pid);
+		return PNOTIFY_ERROR;
+	}
+	/* Associate key_task structure with the new child via pnotify subscriber */
+	sub->data = (void *)kt;
+
+	key_check(kt->thread_keyring);
 
 	/* no thread keyring yet */
-	tsk->thread_keyring = NULL;
-	return 0;
+	kt->thread_keyring = NULL;
+	return PNOTIFY_OK;
 
 } /* end copy_keys() */
 
@@ -292,9 +319,16 @@
 /*
  * dispose of keys upon thread exit
  */
-void exit_keys(struct task_struct *tsk)
+void exit_keys(struct task_struct *task, struct pnotify_subscriber *sub)
 {
-	key_put(tsk->thread_keyring);
+	struct key_task *kt = ((struct key_task *)(sub->data));
+	if (kt == NULL) { /* shouldn't ever happen */
+		printk(KERN_ERR "exit_keys pnotify subscriber data ptr null, task: %d\n", task->pid);
+		return;
+	}
+	key_put(kt->thread_keyring);
+	kfree(kt); /* Free pnotify subscriber data for this task */
+	sub->data = NULL;
 
 } /* end exit_keys() */
 
@@ -306,12 +340,28 @@
 {
 	unsigned long flags;
 	struct key *old;
+	struct key_task *kt;
+	struct pnotify_subscriber *sub;
 
-	/* newly exec'd tasks don't get a thread keyring */
 	task_lock(tsk);
-	old = tsk->thread_keyring;
-	tsk->thread_keyring = NULL;
+	/* pnotify doesn't have a compute_creds event at this time, so we
+	 * need to retrieve the data */
+
+	down_write(&tsk->pnotify_subscriber_list_sem);
+	sub = pnotify_get_subscriber(tsk, key_events.name);
+	if (sub == NULL || sub->data == NULL) { /* shouldn't happen */
+		printk(KERN_ERR "exec_keys pnotify subscriber or data ptr null, task: %d\n", tsk->pid);
+		task_unlock(tsk);
+		up_write(&tsk->pnotify_subscriber_list_sem);
+		return PNOTIFY_OK; /* key structures not populated yet */
+	}
+	kt = (struct key_task *)sub->data;
+
+	/* newly exec'd tasks don't get a thread keyring */
+	old = kt->thread_keyring;
+	kt->thread_keyring = NULL;
 	task_unlock(tsk);
+	up_write(&tsk->pnotify_subscriber_list_sem);
 
 	key_put(old);
 
@@ -344,12 +394,26 @@
  */
 void key_fsuid_changed(struct task_struct *tsk)
 {
+	struct key_task *kt;
+	struct pnotify_subscriber *sub;
+
+	/* no pnotify event for this, so we need to grab the data */
+	down_write(&tsk->pnotify_subscriber_list_sem);
+	sub = pnotify_get_subscriber(tsk, key_events.name);
+	if (sub == NULL || sub->data == NULL) { /* shouldn't happen */
+		printk(KERN_ERR "key_fsuid_changed pnotify subscriber or data ptr null, task: %d\n", tsk->pid);
+		up_write(&tsk->pnotify_subscriber_list_sem);
+		return;
+	}
+	kt = (struct key_task *)sub->data;
+
 	/* update the ownership of the thread keyring */
-	if (tsk->thread_keyring) {
-		down_write(&tsk->thread_keyring->sem);
-		tsk->thread_keyring->uid = tsk->fsuid;
-		up_write(&tsk->thread_keyring->sem);
+	if (kt->thread_keyring) {
+		down_write(&kt->thread_keyring->sem);
+		kt->thread_keyring->uid = tsk->fsuid;
+		up_write(&kt->thread_keyring->sem);
 	}
+	up_write(&tsk->pnotify_subscriber_list_sem);
 
 } /* end key_fsuid_changed() */
 
@@ -359,12 +423,26 @@
  */
 void key_fsgid_changed(struct task_struct *tsk)
 {
+	struct key_task *kt;
+	struct pnotify_subscriber *sub;
+
+	/* pnotify doesn't have an event for this, so we need to grab the data */
+	down_write(&tsk->pnotify_subscriber_list_sem);
+	sub = pnotify_get_subscriber(tsk, key_events.name);
+	if (sub == NULL || sub->data == NULL) { /* shouldn't happen */
+		printk(KERN_ERR "key_fsgid_changed pnotify subscriber or data ptr was null, task: %d\n", tsk->pid);
+		up_write(&tsk->pnotify_subscriber_list_sem);
+		return;
+	}
+	kt = (struct key_task *)sub->data;
+
 	/* update the ownership of the thread keyring */
-	if (tsk->thread_keyring) {
-		down_write(&tsk->thread_keyring->sem);
-		tsk->thread_keyring->gid = tsk->fsgid;
-		up_write(&tsk->thread_keyring->sem);
+	if (kt->thread_keyring) {
+		down_write(&kt->thread_keyring->sem);
+		kt->thread_keyring->gid = tsk->fsgid;
+		up_write(&kt->thread_keyring->sem);
 	}
+	up_write(&tsk->pnotify_subscriber_list_sem);
 
 } /* end key_fsgid_changed() */
 
@@ -383,6 +461,8 @@
 {
 	struct request_key_auth *rka;
 	struct key *key, *ret, *err, *instkey;
+	struct pnotify_subscriber *sub;
+	struct key_task *kt;
 
 	/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
 	 * searchable, but we failed to find a key or we found a negative key;
@@ -395,12 +475,23 @@
 	ret = NULL;
 	err = ERR_PTR(-EAGAIN);
 
+	down_write(&context->pnotify_subscriber_list_sem);
+	sub = pnotify_get_subscriber(context, key_events.name);
+	if (sub == NULL || sub->data == NULL) {
+		printk(KERN_ERR "search_process_keyrings pnotify subscriber or data ptr null, task: %d\n", context->pid);
+		up_write(&context->pnotify_subscriber_list_sem);
+		return (struct key *)-EFAULT;
+	}
+	kt = (struct key_task *)sub->data;
+
 	/* search the thread keyring first */
-	if (context->thread_keyring) {
-		key = keyring_search_aux(context->thread_keyring,
+	if (kt->thread_keyring) {
+		key = keyring_search_aux(kt->thread_keyring,
 					 context, type, description, match);
-		if (!IS_ERR(key))
+		if (!IS_ERR(key)) {
+			up_write(&context->pnotify_subscriber_list_sem);
 			goto found;
+		}
 
 		switch (PTR_ERR(key)) {
 		case -EAGAIN: /* no key */
@@ -414,6 +505,7 @@
 			break;
 		}
 	}
+	up_write(&context->pnotify_subscriber_list_sem);
 
 	/* search the process keyring second */
 	if (context->signal->process_keyring) {
@@ -535,15 +627,26 @@
 {
 	struct key *key;
 	int ret;
+	struct pnotify_subscriber *sub;
+	struct key_task *kt;
 
 	if (!context)
 		context = current;
 
 	key = ERR_PTR(-ENOKEY);
 
+	down_write(&context->pnotify_subscriber_list_sem);
+	sub = pnotify_get_subscriber(context, key_events.name);
+	if (sub == NULL || sub->data == NULL) { /* shouldn't happen */
+		printk(KERN_ERR "search_process_keyrings pnotify subscriber or data ptr null, task: %d\n", context->pid);
+		up_write(&context->pnotify_subscriber_list_sem);
+		return (struct key *)-EFAULT;
+	}
+	kt = (struct key_task *)sub->data;
+
 	switch (id) {
 	case KEY_SPEC_THREAD_KEYRING:
-		if (!context->thread_keyring) {
+		if (!kt->thread_keyring) {
 			if (!create)
 				goto error;
 
@@ -554,7 +657,7 @@
 			}
 		}
 
-		key = context->thread_keyring;
+		key = kt->thread_keyring;
 		atomic_inc(&key->usage);
 		break;
 
@@ -634,6 +737,7 @@
 		goto invalid_key;
 
  error:
+	up_write(&context->pnotify_subscriber_list_sem);
 	return key;
 
  invalid_key:
Index: linux/include/linux/sched.h
===================================================================
--- linux.orig/include/linux/sched.h	2005-09-27 09:40:40.817973203 -0500
+++ linux/include/linux/sched.h	2005-09-27 09:46:07.515471612 -0500
@@ -718,10 +718,6 @@
 	kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
 	unsigned keep_capabilities:1;
 	struct user_struct *user;
-#ifdef CONFIG_KEYS
-	struct key *thread_keyring;	/* keyring private to this thread */
-	unsigned char jit_keyring;	/* default keyring to attach requested keys to */
-#endif
 	int oomkilladj; /* OOM kill score adjustment (bit shift). */
 	char comm[TASK_COMM_LEN]; /* executable name excluding path
 				     - access with [gs]et_task_comm (which lock
Index: linux/security/keys/keyctl.c
===================================================================
--- linux.orig/security/keys/keyctl.c	2005-09-19 22:00:41.000000000 -0500
+++ linux/security/keys/keyctl.c	2005-09-27 09:46:07.517424540 -0500
@@ -931,31 +931,51 @@
 long keyctl_set_reqkey_keyring(int reqkey_defl)
 {
 	int ret;
+	unsigned char jit_return;
+	struct pnotify_subscriber *sub;
+	struct key_task *kt;
+
+	down_write(&current->pnotify_subscriber_list_sem);
+	sub = pnotify_get_subscriber(current, key_events.name);
+	if (sub == NULL || sub->data == NULL) { /* shouldn't happen */
+		printk(KERN_ERR "keyctl_set_reqkey_keyring pnotify subscriber or data ptr null, task: %d\n", current->pid);
+		up_write(&current->pnotify_subscriber_list_sem);
+		return -EFAULT;
+	}
+	kt = (struct key_task *)sub->data;
 
 	switch (reqkey_defl) {
 	case KEY_REQKEY_DEFL_THREAD_KEYRING:
 		ret = install_thread_keyring(current);
-		if (ret < 0)
+		if (ret < 0) {
+			up_write(&current->pnotify_subscriber_list_sem);
 			return ret;
+		}
 		goto set;
 
 	case KEY_REQKEY_DEFL_PROCESS_KEYRING:
 		ret = install_process_keyring(current);
-		if (ret < 0)
+		if (ret < 0) {
+			up_write(&current->pnotify_subscriber_list_sem);
 			return ret;
+		}
 
 	case KEY_REQKEY_DEFL_DEFAULT:
 	case KEY_REQKEY_DEFL_SESSION_KEYRING:
 	case KEY_REQKEY_DEFL_USER_KEYRING:
 	case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
 	set:
-		current->jit_keyring = reqkey_defl;
+
+		kt->jit_keyring = reqkey_defl;
 
 	case KEY_REQKEY_DEFL_NO_CHANGE:
-		return current->jit_keyring;
+		jit_return = kt->jit_keyring;
+		up_write(&current->pnotify_subscriber_list_sem);
+		return jit_return;
 
 	case KEY_REQKEY_DEFL_GROUP_KEYRING:
 	default:
+		up_write(&current->pnotify_subscriber_list_sem);
 		return -EINVAL;
 	}
 
Index: linux/security/keys/request_key.c
===================================================================
--- linux.orig/security/keys/request_key.c	2005-09-19 22:00:41.000000000 -0500
+++ linux/security/keys/request_key.c	2005-09-27 09:46:07.517424540 -0500
@@ -14,6 +14,7 @@
 #include <linux/kmod.h>
 #include <linux/err.h>
 #include <linux/keyctl.h>
+#include <linux/pnotify.h>
 #include "internal.h"
 
 struct key_construction {
@@ -39,6 +40,17 @@
 	char *argv[10], *envp[3], uid_str[12], gid_str[12];
 	char key_str[12], keyring_str[3][12];
 	int ret, i;
+	struct pnotify_subscriber *sub;
+	struct key_task *kt;
+
+	down_write(&tsk->pnotify_subscriber_list_sem);
+	sub = pnotify_get_subscriber(current, key_events.name);
+	if (sub == NULL || sub->data == NULL) { /* shouldn't happen */
+		printk(KERN_ERR "call_request_key pnotify subscriber or data ptr null, task: %d\n", tsk->pid);
+		up_write(&tsk->pnotify_subscriber_list_sem);
+		return -EFAULT;
+	}
+	kt = (struct key_task *)sub->data;
 
 	kenter("{%d},%s,%s", key->serial, op, callout_info);
 
@@ -58,7 +70,7 @@
 
 	/* we specify the process's default keyrings */
 	sprintf(keyring_str[0], "%d",
-		tsk->thread_keyring ? tsk->thread_keyring->serial : 0);
+		kt->thread_keyring ? kt->thread_keyring->serial : 0);
 
 	prkey = 0;
 	if (tsk->signal->process_keyring)
@@ -105,6 +117,7 @@
 	key_put(session_keyring);
 
  error:
+	up_write(&tsk->pnotify_subscriber_list_sem);
 	kleave(" = %d", ret);
 	return ret;
 
@@ -300,15 +313,26 @@
 {
 	struct task_struct *tsk = current;
 	struct key *drop = NULL;
+	struct pnotify_subscriber *sub;
+	struct key_task *kt;
+
+	down_write(&tsk->pnotify_subscriber_list_sem);
+	sub = pnotify_get_subscriber(current, key_events.name);
+	if (sub == NULL || sub->data == NULL) { /* shouldn't happen */
+		printk(KERN_ERR "request_key_link pnotify subscriber or data ptr null, task: %d\n", tsk->pid);
+		up_write(&tsk->pnotify_subscriber_list_sem);
+		return;
+	}
+	kt = (struct key_task *)sub->data;
 
 	kenter("{%d},%p", key->serial, dest_keyring);
 
 	/* find the appropriate keyring */
 	if (!dest_keyring) {
-		switch (tsk->jit_keyring) {
+		switch (kt->jit_keyring) {
 		case KEY_REQKEY_DEFL_DEFAULT:
 		case KEY_REQKEY_DEFL_THREAD_KEYRING:
-			dest_keyring = tsk->thread_keyring;
+			dest_keyring = kt->thread_keyring;
 			if (dest_keyring)
 				break;
 
@@ -347,6 +371,7 @@
 	key_put(drop);
 
 	kleave("");
+	down_write(&tsk->pnotify_subscriber_list_sem);
 
 } /* end request_key_link() */
 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux