linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Keys: Add possessor permissions to keys
       [not found] <5378.1127211442@warthog.cambridge.redhat.com>
@ 2005-09-21 14:48 ` David Howells
  2005-09-21 15:05   ` Linus Torvalds
                     ` (4 more replies)
  2005-09-21 18:33 ` [PATCH] Keys: Add possessor permissions to keys [try #2] David Howells
  2005-09-28 16:03 ` [PATCH] Keys: Add possessor permissions to keys [try #3] David Howells
  2 siblings, 5 replies; 14+ messages in thread
From: David Howells @ 2005-09-21 14:48 UTC (permalink / raw)
  To: torvalds, akpm; +Cc: keyrings, linux-kernel


The attached patch adds extra permission grants to keys for the possessor of a
key in addition to the owner, group and other permissions bits. This makes
SUID binaries easier to support without going as far as labelling keys and key
targets using the LSM facilities.

This patch adds a second "pointer type" to key structures (struct key_ref *)
that can have the bottom bit of the address set to indicate the possession of
a key. This is propagated through searches from the keyring to the discovered
key. It has been made a separate type so that the compiler can spot attempts
to dereference a potentially incorrect pointer.

The "possession" attribute can't be attached to a key structure directly as
it's not an intrinsic property of a key.

Pointers to keys have been replaced with struct key_ref *'s wherever
possession information needs to be passed through.

This does assume that the bottom bit of the pointer will always be zero on
return from kmem_cache_alloc().

Signed-Off-By: David Howells <dhowells@redhat.com>
---
warthog>diffstat -p1 keys-possess-2614rc1mm1.diff 
 Documentation/keys.txt           |   64 ++++++++++----
 include/linux/key-ui.h           |   28 ++++--
 include/linux/key.h              |   59 +++++++++----
 security/keys/internal.h         |   28 +++---
 security/keys/key.c              |   82 ++++++++++--------
 security/keys/keyctl.c           |  172 +++++++++++++++++++--------------------
 security/keys/keyring.c          |   84 ++++++++++---------
 security/keys/proc.c             |    2 
 security/keys/process_keys.c     |  101 +++++++++++++++-------
 security/keys/request_key.c      |   36 ++++++--
 security/keys/request_key_auth.c |    2 
 11 files changed, 401 insertions(+), 257 deletions(-)

diff -uNrp linux-2.6.14-rc1-mm1/Documentation/keys.txt linux-2.6.14-rc1-mm1-keys/Documentation/keys.txt
--- linux-2.6.14-rc1-mm1/Documentation/keys.txt	2005-08-30 13:56:09.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/Documentation/keys.txt	2005-09-21 15:19:22.000000000 +0100
@@ -195,8 +195,8 @@ KEY ACCESS PERMISSIONS
 ======================
 
 Keys have an owner user ID, a group access ID, and a permissions mask. The mask
-has up to eight bits each for user, group and other access. Only five of each
-set of eight bits are defined. These permissions granted are:
+has up to eight bits each for possessor, user, group and other access. Only
+five of each set of eight bits are defined. These permissions granted are:
 
  (*) View
 
@@ -241,16 +241,16 @@ about the status of the key service:
      type, description and permissions. The payload of the key is not available
      this way:
 
-	SERIAL   FLAGS  USAGE EXPY PERM   UID   GID   TYPE      DESCRIPTION: SUMMARY
-	00000001 I-----    39 perm 1f0000     0     0 keyring   _uid_ses.0: 1/4
-	00000002 I-----     2 perm 1f0000     0     0 keyring   _uid.0: empty
-	00000007 I-----     1 perm 1f0000     0     0 keyring   _pid.1: empty
-	0000018d I-----     1 perm 1f0000     0     0 keyring   _pid.412: empty
-	000004d2 I--Q--     1 perm 1f0000    32    -1 keyring   _uid.32: 1/4
-	000004d3 I--Q--     3 perm 1f0000    32    -1 keyring   _uid_ses.32: empty
-	00000892 I--QU-     1 perm 1f0000     0     0 user      metal:copper: 0
-	00000893 I--Q-N     1  35s 1f0000     0     0 user      metal:silver: 0
-	00000894 I--Q--     1  10h 1f0000     0     0 user      metal:gold: 0
+	SERIAL   FLAGS  USAGE EXPY PERM     UID   GID   TYPE      DESCRIPTION: SUMMARY
+	00000001 I-----    39 perm 1f1f0000     0     0 keyring   _uid_ses.0: 1/4
+	00000002 I-----     2 perm 1f1f0000     0     0 keyring   _uid.0: empty
+	00000007 I-----     1 perm 1f1f0000     0     0 keyring   _pid.1: empty
+	0000018d I-----     1 perm 1f1f0000     0     0 keyring   _pid.412: empty
+	000004d2 I--Q--     1 perm 1f1f0000    32    -1 keyring   _uid.32: 1/4
+	000004d3 I--Q--     3 perm 1f1f0000    32    -1 keyring   _uid_ses.32: empty
+	00000892 I--QU-     1 perm 1f000000     0     0 user      metal:copper: 0
+	00000893 I--Q-N     1  35s 1f1f0000     0     0 user      metal:silver: 0
+	00000894 I--Q--     1  10h 001f0000     0     0 user      metal:gold: 0
 
      The flags are:
 
@@ -637,6 +637,34 @@ call, and the key released upon close. H
 two different users opening the same file is left to the filesystem author to
 solve.
 
+Note that there are two different types of pointers to keys that may be
+encountered:
+
+ (*) struct key *
+
+     This simply points to the key structure itself. Key structures will be at
+     least four-byte aligned.
+
+ (*) struct key_ref *
+
+     This is equivalent to a struct key *, but the least significant bit is set
+     if the caller "possesses" the key. By "possession" it is meant that the
+     calling processes has a searchable link to the key from one of its
+     keyrings. Their are three functions for dealing with these:
+
+	struct key_ref *key_mkref(const struct key *key,
+				  unsigned long possession);
+
+	struct key *key_deref(const struct key_ref *key_ref);
+
+	unsigned long is_key_possessed(const struct key_ref *key_ref);
+
+     The first function constructs a key reference from a key pointer and
+     possession information (which must be 0 or 1 and no other value).
+
+     The second function retrieves the key pointer and the third retrieves the
+     possession flag).
+
 When accessing a key's payload contents, certain precautions must be taken to
 prevent access vs modification races. See the section "Notes on accessing
 payload contents" for more information.
@@ -689,14 +717,18 @@ payload contents" for more information.
 
 (*) If a keyring was found in the search, this can be further searched by:
 
-	struct key *keyring_search(struct key *keyring,
-				   const struct key_type *type,
-				   const char *description)
+	struct key_ref *keyring_search(struct key_ref *keyring,
+				       const struct key_type *type,
+				       const char *description)
 
     This searches the keyring tree specified for a matching key. Error ENOKEY
     is returned upon failure. If successful, the returned key will need to be
     released.
 
+    The possession attribute from the keyring reference pointer is used to
+    control access through the permissions mask and is propagated to the
+    returned key reference pointer if successful.
+
 
 (*) To check the validity of a key, this function can be called:
 
@@ -732,7 +764,7 @@ More complex payload contents must be al
 key->payload.data. One of the following ways must be selected to access the
 data:
 
- (1) Unmodifyable key type.
+ (1) Unmodifiable key type.
 
      If the key type does not have a modify method, then the key's payload can
      be accessed without any form of locking, provided that it's known to be
diff -uNrp linux-2.6.14-rc1-mm1/include/linux/key.h linux-2.6.14-rc1-mm1-keys/include/linux/key.h
--- linux-2.6.14-rc1-mm1/include/linux/key.h	2005-08-30 13:56:36.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/include/linux/key.h	2005-09-21 13:26:39.000000000 +0100
@@ -30,16 +30,24 @@ typedef int32_t key_serial_t;
 typedef uint32_t key_perm_t;
 
 struct key;
+struct key_ref;		/* pointer to a key with a possession flag */
 
 #ifdef CONFIG_KEYS
 
 #undef KEY_DEBUGGING
 
-#define KEY_USR_VIEW	0x00010000	/* user can view a key's attributes */
-#define KEY_USR_READ	0x00020000	/* user can read key payload / view keyring */
-#define KEY_USR_WRITE	0x00040000	/* user can update key payload / add link to keyring */
-#define KEY_USR_SEARCH	0x00080000	/* user can find a key in search / search a keyring */
-#define KEY_USR_LINK	0x00100000	/* user can create a link to a key/keyring */
+#define KEY_POS_VIEW	0x01000000	/* possessor can view a key's attributes */
+#define KEY_POS_READ	0x02000000	/* possessor can read key payload / view keyring */
+#define KEY_POS_WRITE	0x04000000	/* possessor can update key payload / add link to keyring */
+#define KEY_POS_SEARCH	0x08000000	/* possessor can find a key in search / search a keyring */
+#define KEY_POS_LINK	0x10000000	/* possessor can create a link to a key/keyring */
+#define KEY_POS_ALL	0x1f000000
+
+#define KEY_USR_VIEW	0x00010000	/* user permissions... */
+#define KEY_USR_READ	0x00020000
+#define KEY_USR_WRITE	0x00040000
+#define KEY_USR_SEARCH	0x00080000
+#define KEY_USR_LINK	0x00100000
 #define KEY_USR_ALL	0x001f0000
 
 #define KEY_GRP_VIEW	0x00000100	/* group permissions... */
@@ -221,14 +229,14 @@ extern struct key *request_key(struct ke
 
 extern int key_validate(struct key *key);
 
-extern struct key *key_create_or_update(struct key *keyring,
-					const char *type,
-					const char *description,
-					const void *payload,
-					size_t plen,
-					int not_in_quota);
+extern struct key_ref *key_create_or_update(struct key_ref *keyring,
+					    const char *type,
+					    const char *description,
+					    const void *payload,
+					    size_t plen,
+					    int not_in_quota);
 
-extern int key_update(struct key *key,
+extern int key_update(struct key_ref *key,
 		      const void *payload,
 		      size_t plen);
 
@@ -243,9 +251,9 @@ extern struct key *keyring_alloc(const c
 
 extern int keyring_clear(struct key *keyring);
 
-extern struct key *keyring_search(struct key *keyring,
-				  struct key_type *type,
-				  const char *description);
+extern struct key_ref *keyring_search(struct key_ref *keyring,
+				      struct key_type *type,
+				      const char *description);
 
 extern int keyring_add_key(struct key *keyring,
 			   struct key *key);
@@ -257,6 +265,24 @@ extern void keyring_replace_payload(stru
 #define key_serial(key) ((key) ? (key)->serial : 0)
 
 /*
+ * key reference with possession flag handling
+ */
+static inline struct key_ref *key_mkref(const struct key *key, unsigned long possession)
+{
+	return (struct key_ref *) ((unsigned long) key | possession);
+}
+
+static inline struct key *key_deref(const struct key_ref *key)
+{
+	return (struct key *) ((unsigned long) key & ~1UL);
+}
+
+static inline unsigned long is_key_possessed(const struct key_ref *key)
+{
+	return (unsigned long) key & 1UL;
+}
+
+/*
  * the userspace interface
  */
 extern struct key root_user_keyring, root_session_keyring;
@@ -285,6 +311,9 @@ extern void key_init(void);
 #define key_serial(k)			0
 #define key_get(k) 			({ NULL; })
 #define key_put(k)			do { } while(0)
+#define key_mkref(k)			({ NULL; })
+#define key_deref(k)			({ NULL; })
+#define is_key_possessed(k)		0
 #define alloc_uid_keyring(u)		0
 #define switch_uid_keyring(u)		do { } while(0)
 #define __install_session_keyring(t, k)	({ NULL; })
diff -uNrp linux-2.6.14-rc1-mm1/include/linux/key-ui.h linux-2.6.14-rc1-mm1-keys/include/linux/key-ui.h
--- linux-2.6.14-rc1-mm1/include/linux/key-ui.h	2005-08-30 13:56:36.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/include/linux/key-ui.h	2005-09-21 12:00:23.000000000 +0100
@@ -42,11 +42,14 @@ struct keyring_list {
 /*
  * check to see whether permission is granted to use a key in the desired way
  */
-static inline int key_permission(const struct key *key, key_perm_t perm)
+static inline int key_permission(const struct key_ref *key_ref, key_perm_t perm)
 {
+	struct key *key = key_deref(key_ref);
 	key_perm_t kperm;
 
-	if (key->uid == current->fsuid)
+	if (is_key_possessed(key_ref))
+		kperm = key->perm >> 24;
+	else if (key->uid == current->fsuid)
 		kperm = key->perm >> 16;
 	else if (key->gid != -1 &&
 		 key->perm & KEY_GRP_ALL &&
@@ -65,11 +68,14 @@ static inline int key_permission(const s
  * check to see whether permission is granted to use a key in at least one of
  * the desired ways
  */
-static inline int key_any_permission(const struct key *key, key_perm_t perm)
+static inline int key_any_permission(const struct key_ref *key_ref, key_perm_t perm)
 {
+	struct key *key = key_deref(key_ref);
 	key_perm_t kperm;
 
-	if (key->uid == current->fsuid)
+	if (is_key_possessed(key_ref))
+		kperm = key->perm >> 24;
+	else if (key->uid == current->fsuid)
 		kperm = key->perm >> 16;
 	else if (key->gid != -1 &&
 		 key->perm & KEY_GRP_ALL &&
@@ -94,13 +100,17 @@ static inline int key_task_groups_search
 	return ret;
 }
 
-static inline int key_task_permission(const struct key *key,
+static inline int key_task_permission(const struct key_ref *key_ref,
 				      struct task_struct *context,
 				      key_perm_t perm)
 {
+	struct key *key = key_deref(key_ref);
 	key_perm_t kperm;
 
-	if (key->uid == context->fsuid) {
+	if (is_key_possessed(key_ref)) {
+		kperm = key->perm >> 24;
+	}
+	else if (key->uid == context->fsuid) {
 		kperm = key->perm >> 16;
 	}
 	else if (key->gid != -1 &&
@@ -121,9 +131,9 @@ static inline int key_task_permission(co
 
 }
 
-extern struct key *lookup_user_key(struct task_struct *context,
-				   key_serial_t id, int create, int partial,
-				   key_perm_t perm);
+extern struct key_ref *lookup_user_key(struct task_struct *context,
+				       key_serial_t id, int create, int partial,
+				       key_perm_t perm);
 
 extern long join_session_keyring(const char *name);
 
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/internal.h linux-2.6.14-rc1-mm1-keys/security/keys/internal.h
--- linux-2.6.14-rc1-mm1/security/keys/internal.h	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/internal.h	2005-09-21 14:59:27.000000000 +0100
@@ -71,26 +71,26 @@ extern void keyring_publish_name(struct 
 
 extern int __key_link(struct key *keyring, struct key *key);
 
-extern struct key *__keyring_search_one(struct key *keyring,
-					const struct key_type *type,
-					const char *description,
-					key_perm_t perm);
+extern struct key_ref *__keyring_search_one(struct key_ref *keyring,
+					    const struct key_type *type,
+					    const char *description,
+					    key_perm_t perm);
 
 extern struct key *keyring_search_instkey(struct key *keyring,
 					  key_serial_t target_id);
 
 typedef int (*key_match_func_t)(const struct key *, const void *);
 
-extern struct key *keyring_search_aux(struct key *keyring,
-				      struct task_struct *tsk,
-				      struct key_type *type,
-				      const void *description,
-				      key_match_func_t match);
-
-extern struct key *search_process_keyrings(struct key_type *type,
-					   const void *description,
-					   key_match_func_t match,
-					   struct task_struct *tsk);
+extern struct key_ref *keyring_search_aux(struct key_ref *keyring,
+					  struct task_struct *tsk,
+					  struct key_type *type,
+					  const void *description,
+					  key_match_func_t match);
+
+extern struct key_ref *search_process_keyrings(struct key_type *type,
+					       const void *description,
+					       key_match_func_t match,
+					       struct task_struct *tsk);
 
 extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
 
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/key.c linux-2.6.14-rc1-mm1-keys/security/keys/key.c
--- linux-2.6.14-rc1-mm1/security/keys/key.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/key.c	2005-09-21 13:47:47.000000000 +0100
@@ -693,14 +693,16 @@ void key_type_put(struct key_type *ktype
  * - the key has an incremented refcount
  * - we need to put the key if we get an error
  */
-static inline struct key *__key_update(struct key *key, const void *payload,
-				       size_t plen)
+static inline struct key_ref *__key_update(struct key_ref *key_ref,
+					   const void *payload,
+					   size_t plen)
 {
+	struct key *key = key_deref(key_ref);
 	int ret;
 
 	/* need write permission on the key to update it */
 	ret = -EACCES;
-	if (!key_permission(key, KEY_WRITE))
+	if (!key_permission(key_ref, KEY_WRITE))
 		goto error;
 
 	ret = -EEXIST;
@@ -719,12 +721,12 @@ static inline struct key *__key_update(s
 
 	if (ret < 0)
 		goto error;
- out:
-	return key;
+out:
+	return key_ref;
 
- error:
+error:
 	key_put(key);
-	key = ERR_PTR(ret);
+	key_ref = ERR_PTR(ret);
 	goto out;
 
 } /* end __key_update() */
@@ -734,52 +736,56 @@ static inline struct key *__key_update(s
  * search the specified keyring for a key of the same description; if one is
  * found, update it, otherwise add a new one
  */
-struct key *key_create_or_update(struct key *keyring,
-				 const char *type,
-				 const char *description,
-				 const void *payload,
-				 size_t plen,
-				 int not_in_quota)
+struct key_ref *key_create_or_update(struct key_ref *keyring_ref,
+				     const char *type,
+				     const char *description,
+				     const void *payload,
+				     size_t plen,
+				     int not_in_quota)
 {
 	struct key_type *ktype;
-	struct key *key = NULL;
+	struct key_ref *key_ref;
+	struct key *keyring, *key = NULL;
 	key_perm_t perm;
 	int ret;
 
-	key_check(keyring);
-
 	/* look up the key type to see if it's one of the registered kernel
 	 * types */
 	ktype = key_type_lookup(type);
 	if (IS_ERR(ktype)) {
-		key = ERR_PTR(-ENODEV);
+		key_ref = ERR_PTR(-ENODEV);
 		goto error;
 	}
 
-	ret = -EINVAL;
+	key_ref = ERR_PTR(-EINVAL);
 	if (!ktype->match || !ktype->instantiate)
 		goto error_2;
 
+	keyring = key_deref(keyring_ref);
+
+	key_check(keyring);
+
+	down_write(&keyring->sem);
+
+	/* if we're going to allocate a new key, we're going to have
+	 * to modify the keyring */
+	key_ref = ERR_PTR(-EACCES);
+	if (!key_permission(keyring_ref, KEY_WRITE))
+		goto error_3;
+
 	/* search for an existing key of the same type and description in the
 	 * destination keyring
 	 */
-	down_write(&keyring->sem);
-
-	key = __keyring_search_one(keyring, ktype, description, 0);
-	if (!IS_ERR(key))
+	key_ref = __keyring_search_one(keyring_ref, ktype, description, 0);
+	if (!IS_ERR(key_ref))
 		goto found_matching_key;
 
-	/* if we're going to allocate a new key, we're going to have to modify
-	 * the keyring */
-	ret = -EACCES;
-	if (!key_permission(keyring, KEY_WRITE))
-		goto error_3;
-
 	/* decide on the permissions we want */
-	perm = KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK;
+	perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK;
+	perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK;
 
 	if (ktype->read)
-		perm |= KEY_USR_READ;
+		perm |= KEY_POS_READ | KEY_USR_READ;
 
 	if (ktype == &key_type_keyring || ktype->update)
 		perm |= KEY_USR_WRITE;
@@ -788,7 +794,7 @@ struct key *key_create_or_update(struct 
 	key = key_alloc(ktype, description, current->fsuid, current->fsgid,
 			perm, not_in_quota);
 	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+		key_ref = ERR_PTR(PTR_ERR(key));
 		goto error_3;
 	}
 
@@ -796,15 +802,18 @@ struct key *key_create_or_update(struct 
 	ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
 	if (ret < 0) {
 		key_put(key);
-		key = ERR_PTR(ret);
+		key_ref = ERR_PTR(ret);
+		goto error_3;
 	}
 
+	key_ref = key_mkref(key, is_key_possessed(keyring_ref));
+
  error_3:
 	up_write(&keyring->sem);
  error_2:
 	key_type_put(ktype);
  error:
-	return key;
+	return key_ref;
 
  found_matching_key:
 	/* we found a matching key, so we're going to try to update it
@@ -813,7 +822,7 @@ struct key *key_create_or_update(struct 
 	up_write(&keyring->sem);
 	key_type_put(ktype);
 
-	key = __key_update(key, payload, plen);
+	key_ref = __key_update(key_ref, payload, plen);
 	goto error;
 
 } /* end key_create_or_update() */
@@ -824,15 +833,16 @@ EXPORT_SYMBOL(key_create_or_update);
 /*
  * update a key
  */
-int key_update(struct key *key, const void *payload, size_t plen)
+int key_update(struct key_ref *key_ref, const void *payload, size_t plen)
 {
+	struct key *key = key_deref(key_ref);
 	int ret;
 
 	key_check(key);
 
 	/* the key must be writable */
 	ret = -EACCES;
-	if (!key_permission(key, KEY_WRITE))
+	if (!key_permission(key_ref, KEY_WRITE))
 		goto error;
 
 	/* attempt to update it if supported */
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/keyctl.c linux-2.6.14-rc1-mm1-keys/security/keys/keyctl.c
--- linux-2.6.14-rc1-mm1/security/keys/keyctl.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/keyctl.c	2005-09-21 13:44:18.000000000 +0100
@@ -34,7 +34,7 @@ asmlinkage long sys_add_key(const char _
 			    size_t plen,
 			    key_serial_t ringid)
 {
-	struct key *keyring, *key;
+	struct key_ref *keyring, *key;
 	char type[32], *description;
 	void *payload;
 	long dlen, ret;
@@ -97,14 +97,14 @@ asmlinkage long sys_add_key(const char _
 	key = key_create_or_update(keyring, type, description,
 				   payload, plen, 0);
 	if (!IS_ERR(key)) {
-		ret = key->serial;
-		key_put(key);
+		ret = key_deref(key)->serial;
+		key_put(key_deref(key));
 	}
 	else {
 		ret = PTR_ERR(key);
 	}
 
-	key_put(keyring);
+	key_put(key_deref(keyring));
  error3:
 	kfree(payload);
  error2:
@@ -131,7 +131,8 @@ asmlinkage long sys_request_key(const ch
 				key_serial_t destringid)
 {
 	struct key_type *ktype;
-	struct key *key, *dest;
+	struct key_ref *dest;
+	struct key *key;
 	char type[32], *description, *callout_info;
 	long dlen, ret;
 
@@ -204,7 +205,8 @@ asmlinkage long sys_request_key(const ch
 	}
 
 	/* do the search */
-	key = request_key_and_link(ktype, description, callout_info, dest);
+	key = request_key_and_link(ktype, description, callout_info,
+				   key_deref(dest));
 	if (IS_ERR(key)) {
 		ret = PTR_ERR(key);
 		goto error5;
@@ -216,7 +218,7 @@ asmlinkage long sys_request_key(const ch
  error5:
 	key_type_put(ktype);
  error4:
-	key_put(dest);
+	key_put(key_deref(dest));
  error3:
 	kfree(callout_info);
  error2:
@@ -234,7 +236,7 @@ asmlinkage long sys_request_key(const ch
  */
 long keyctl_get_keyring_ID(key_serial_t id, int create)
 {
-	struct key *key;
+	struct key_ref *key;
 	long ret;
 
 	key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
@@ -243,8 +245,8 @@ long keyctl_get_keyring_ID(key_serial_t 
 		goto error;
 	}
 
-	ret = key->serial;
-	key_put(key);
+	ret = key_deref(key)->serial;
+	key_put(key_deref(key));
  error:
 	return ret;
 
@@ -302,7 +304,7 @@ long keyctl_update_key(key_serial_t id,
 		       const void __user *_payload,
 		       size_t plen)
 {
-	struct key *key;
+	struct key_ref *key;
 	void *payload;
 	long ret;
 
@@ -333,7 +335,7 @@ long keyctl_update_key(key_serial_t id,
 	/* update the key */
 	ret = key_update(key, payload, plen);
 
-	key_put(key);
+	key_put(key_deref(key));
  error2:
 	kfree(payload);
  error:
@@ -349,7 +351,7 @@ long keyctl_update_key(key_serial_t id,
  */
 long keyctl_revoke_key(key_serial_t id)
 {
-	struct key *key;
+	struct key_ref *key;
 	long ret;
 
 	key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
@@ -358,10 +360,10 @@ long keyctl_revoke_key(key_serial_t id)
 		goto error;
 	}
 
-	key_revoke(key);
+	key_revoke(key_deref(key));
 	ret = 0;
 
-	key_put(key);
+	key_put(key_deref(key));
  error:
 	return ret;
 
@@ -375,7 +377,7 @@ long keyctl_revoke_key(key_serial_t id)
  */
 long keyctl_keyring_clear(key_serial_t ringid)
 {
-	struct key *keyring;
+	struct key_ref *keyring;
 	long ret;
 
 	keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
@@ -384,9 +386,9 @@ long keyctl_keyring_clear(key_serial_t r
 		goto error;
 	}
 
-	ret = keyring_clear(keyring);
+	ret = keyring_clear(key_deref(keyring));
 
-	key_put(keyring);
+	key_put(key_deref(keyring));
  error:
 	return ret;
 
@@ -401,7 +403,7 @@ long keyctl_keyring_clear(key_serial_t r
  */
 long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
 {
-	struct key *keyring, *key;
+	struct key_ref *keyring, *key;
 	long ret;
 
 	keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
@@ -416,11 +418,11 @@ long keyctl_keyring_link(key_serial_t id
 		goto error2;
 	}
 
-	ret = key_link(keyring, key);
+	ret = key_link(key_deref(keyring), key_deref(key));
 
-	key_put(key);
+	key_put(key_deref(key));
  error2:
-	key_put(keyring);
+	key_put(key_deref(keyring));
  error:
 	return ret;
 
@@ -435,7 +437,7 @@ long keyctl_keyring_link(key_serial_t id
  */
 long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
 {
-	struct key *keyring, *key;
+	struct key_ref *keyring, *key;
 	long ret;
 
 	keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
@@ -450,11 +452,11 @@ long keyctl_keyring_unlink(key_serial_t 
 		goto error2;
 	}
 
-	ret = key_unlink(keyring, key);
+	ret = key_unlink(key_deref(keyring), key_deref(key));
 
-	key_put(key);
+	key_put(key_deref(key));
  error2:
-	key_put(keyring);
+	key_put(key_deref(keyring));
  error:
 	return ret;
 
@@ -475,7 +477,8 @@ long keyctl_describe_key(key_serial_t ke
 			 char __user *buffer,
 			 size_t buflen)
 {
-	struct key *key, *instkey;
+	struct key_ref *key;
+	struct key *instkey;
 	char *tmpbuf;
 	long ret;
 
@@ -505,12 +508,12 @@ okay:
 		goto error2;
 
 	ret = snprintf(tmpbuf, PAGE_SIZE - 1,
-		       "%s;%d;%d;%06x;%s",
-		       key->type->name,
-		       key->uid,
-		       key->gid,
-		       key->perm,
-		       key->description ? key->description :""
+		       "%s;%d;%d;%08x;%s",
+		       key_deref(key)->type->name,
+		       key_deref(key)->uid,
+		       key_deref(key)->gid,
+		       key_deref(key)->perm,
+		       key_deref(key)->description ? key_deref(key)->description : ""
 		       );
 
 	/* include a NUL char at the end of the data */
@@ -530,7 +533,7 @@ okay:
 
 	kfree(tmpbuf);
  error2:
-	key_put(key);
+	key_put(key_deref(key));
  error:
 	return ret;
 
@@ -552,7 +555,7 @@ long keyctl_keyring_search(key_serial_t 
 			   key_serial_t destringid)
 {
 	struct key_type *ktype;
-	struct key *keyring, *key, *dest;
+	struct key_ref *keyring, *key, *dest;
 	char type[32], *description;
 	long dlen, ret;
 
@@ -621,21 +624,21 @@ long keyctl_keyring_search(key_serial_t 
 		if (!key_permission(key, KEY_LINK))
 			goto error6;
 
-		ret = key_link(dest, key);
+		ret = key_link(key_deref(dest), key_deref(key));
 		if (ret < 0)
 			goto error6;
 	}
 
-	ret = key->serial;
+	ret = key_deref(key)->serial;
 
  error6:
-	key_put(key);
+	key_put(key_deref(key));
  error5:
 	key_type_put(ktype);
  error4:
-	key_put(dest);
+	key_put(key_deref(dest));
  error3:
-	key_put(keyring);
+	key_put(key_deref(keyring));
  error2:
 	kfree(description);
  error:
@@ -645,16 +648,6 @@ long keyctl_keyring_search(key_serial_t 
 
 /*****************************************************************************/
 /*
- * see if the key we're looking at is the target key
- */
-static int keyctl_read_key_same(const struct key *key, const void *target)
-{
-	return key == target;
-
-} /* end keyctl_read_key_same() */
-
-/*****************************************************************************/
-/*
  * read a user key's payload
  * - the keyring must be readable or the key must be searchable from the
  *   process's keyrings
@@ -665,38 +658,34 @@ static int keyctl_read_key_same(const st
  */
 long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
 {
-	struct key *key, *skey;
+	struct key_ref *key_ref;
+	struct key *key;
 	long ret;
 
 	/* find the key first */
-	key = lookup_user_key(NULL, keyid, 0, 0, 0);
-	if (!IS_ERR(key)) {
-		/* see if we can read it directly */
-		if (key_permission(key, KEY_READ))
-			goto can_read_key;
-
-		/* we can't; see if it's searchable from this process's
-		 * keyrings
-		 * - we automatically take account of the fact that it may be
-		 *   dangling off an instantiation key
-		 */
-		skey = search_process_keyrings(key->type, key,
-					       keyctl_read_key_same, current);
-		if (!IS_ERR(skey))
-			goto can_read_key2;
+	key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);
+	if (IS_ERR(key_ref)) {
+		ret = -ENOKEY;
+		goto error;
+	}
 
-		ret = PTR_ERR(skey);
-		if (ret == -EAGAIN)
-			ret = -EACCES;
+	key = key_deref(key_ref);
+
+	/* see if we can read it directly */
+	if (key_permission(key_ref, KEY_READ))
+		goto can_read_key;
+
+	/* we can't; see if it's searchable from this process's
+	 * keyrings
+	 * - we automatically take account of the fact that it may be
+	 *   dangling off an instantiation key
+	 */
+	if (!is_key_possessed(key_ref)) {
+		ret = -EACCES;
 		goto error2;
 	}
 
-	ret = -ENOKEY;
-	goto error;
-
 	/* the key is probably readable - now try to read it */
- can_read_key2:
-	key_put(skey);
  can_read_key:
 	ret = key_validate(key);
 	if (ret == 0) {
@@ -726,6 +715,7 @@ long keyctl_read_key(key_serial_t keyid,
  */
 long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
 {
+	struct key_ref *key_ref;
 	struct key *key;
 	long ret;
 
@@ -733,12 +723,14 @@ long keyctl_chown_key(key_serial_t id, u
 	if (uid == (uid_t) -1 && gid == (gid_t) -1)
 		goto error;
 
-	key = lookup_user_key(NULL, id, 1, 1, 0);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 1, 1, 0);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
+	key = key_deref(key_ref);
+
 	/* make the changes with the locks held to prevent chown/chown races */
 	ret = -EACCES;
 	down_write(&key->sem);
@@ -783,19 +775,22 @@ long keyctl_chown_key(key_serial_t id, u
  */
 long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
 {
+	struct key_ref *key_ref;
 	struct key *key;
 	long ret;
 
 	ret = -EINVAL;
-	if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
+	if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
 		goto error;
 
-	key = lookup_user_key(NULL, id, 1, 1, 0);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 1, 1, 0);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
+	key = key_deref(key_ref);
+
 	/* make the changes with the locks held to prevent chown/chmod races */
 	ret = -EACCES;
 	down_write(&key->sem);
@@ -824,7 +819,8 @@ long keyctl_instantiate_key(key_serial_t
 			    key_serial_t ringid)
 {
 	struct request_key_auth *rka;
-	struct key *instkey, *keyring;
+	struct key_ref *keyring;
+	struct key *instkey;
 	void *payload;
 	long ret;
 
@@ -869,9 +865,9 @@ long keyctl_instantiate_key(key_serial_t
 
 	/* instantiate the key and link it into a keyring */
 	ret = key_instantiate_and_link(rka->target_key, payload, plen,
-				       keyring, instkey);
+				       key_deref(keyring), instkey);
 
-	key_put(keyring);
+	key_put(key_deref(keyring));
  error3:
 	key_put(instkey);
  error2:
@@ -889,7 +885,8 @@ long keyctl_instantiate_key(key_serial_t
 long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
 {
 	struct request_key_auth *rka;
-	struct key *instkey, *keyring;
+	struct key_ref *keyring;
+	struct key *instkey;
 	long ret;
 
 	/* find the instantiation authorisation key */
@@ -913,9 +910,10 @@ long keyctl_negate_key(key_serial_t id, 
 	}
 
 	/* instantiate the key and link it into a keyring */
-	ret = key_negate_and_link(rka->target_key, timeout, keyring, instkey);
+	ret = key_negate_and_link(rka->target_key, timeout, key_deref(keyring),
+				  instkey);
 
-	key_put(keyring);
+	key_put(key_deref(keyring));
  error2:
 	key_put(instkey);
  error:
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/keyring.c linux-2.6.14-rc1-mm1-keys/security/keys/keyring.c
--- linux-2.6.14-rc1-mm1/security/keys/keyring.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/keyring.c	2005-09-21 14:34:02.000000000 +0100
@@ -309,7 +309,7 @@ struct key *keyring_alloc(const char *de
 	int ret;
 
 	keyring = key_alloc(&key_type_keyring, description,
-			    uid, gid, KEY_USR_ALL, not_in_quota);
+			    uid, gid, KEY_POS_ALL | KEY_USR_ALL, not_in_quota);
 
 	if (!IS_ERR(keyring)) {
 		ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
@@ -333,12 +333,13 @@ struct key *keyring_alloc(const char *de
  * - we rely on RCU to prevent the keyring lists from disappearing on us
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we only found negative matching keys
+ * - we propagate the possession attribute from the keyring ref to the key ref
  */
-struct key *keyring_search_aux(struct key *keyring,
-			       struct task_struct *context,
-			       struct key_type *type,
-			       const void *description,
-			       key_match_func_t match)
+struct key_ref *keyring_search_aux(struct key_ref *keyring_ref,
+				   struct task_struct *context,
+				   struct key_type *type,
+				   const void *description,
+				   key_match_func_t match)
 {
 	struct {
 		struct keyring_list *keylist;
@@ -347,29 +348,33 @@ struct key *keyring_search_aux(struct ke
 
 	struct keyring_list *keylist;
 	struct timespec now;
-	struct key *key;
+	struct key_ref *key_ref;
+	unsigned long possessed;
+	struct key *keyring, *key;
 	long err;
 	int sp, kix;
 
+	keyring = key_deref(keyring_ref);
+	possessed = is_key_possessed(keyring_ref);
 	key_check(keyring);
 
-	rcu_read_lock();
-
 	/* top keyring must have search permission to begin the search */
-	key = ERR_PTR(-EACCES);
-	if (!key_task_permission(keyring, context, KEY_SEARCH))
+	key_ref = ERR_PTR(-EACCES);
+	if (!key_task_permission(keyring_ref, context, KEY_SEARCH))
 		goto error;
 
-	key = ERR_PTR(-ENOTDIR);
+	key_ref = ERR_PTR(-ENOTDIR);
 	if (keyring->type != &key_type_keyring)
 		goto error;
 
+	rcu_read_lock();
+
 	now = current_kernel_time();
 	err = -EAGAIN;
 	sp = 0;
 
 	/* start processing a new keyring */
- descend:
+descend:
 	if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
 		goto not_this_keyring;
 
@@ -397,7 +402,8 @@ struct key *keyring_search_aux(struct ke
 			continue;
 
 		/* key must have search permissions */
-		if (!key_task_permission(key, context, KEY_SEARCH))
+		if (!key_task_permission(key_mkref(key, possessed),
+					 context, KEY_SEARCH))
 			continue;
 
 		/* we set a different error code if we find a negative key */
@@ -411,7 +417,7 @@ struct key *keyring_search_aux(struct ke
 
 	/* search through the keyrings nested in this one */
 	kix = 0;
- ascend:
+ascend:
 	for (; kix < keylist->nkeys; kix++) {
 		key = keylist->keys[kix];
 		if (key->type != &key_type_keyring)
@@ -423,7 +429,8 @@ struct key *keyring_search_aux(struct ke
 		if (sp >= KEYRING_SEARCH_MAX_DEPTH)
 			continue;
 
-		if (!key_task_permission(key, context, KEY_SEARCH))
+		if (!key_task_permission(key_mkref(key, possessed),
+					 context, KEY_SEARCH))
 			continue;
 
 		/* stack the current position */
@@ -438,7 +445,7 @@ struct key *keyring_search_aux(struct ke
 
 	/* the keyring we're looking at was disqualified or didn't contain a
 	 * matching key */
- not_this_keyring:
+not_this_keyring:
 	if (sp > 0) {
 		/* resume the processing of a keyring higher up in the tree */
 		sp--;
@@ -447,16 +454,18 @@ struct key *keyring_search_aux(struct ke
 		goto ascend;
 	}
 
-	key = ERR_PTR(err);
-	goto error;
+	key_ref = ERR_PTR(err);
+	goto error_2;
 
 	/* we found a viable match */
- found:
+found:
 	atomic_inc(&key->usage);
 	key_check(key);
- error:
+	key_ref = key_mkref(key, possessed);
+error_2:
 	rcu_read_unlock();
-	return key;
+error:
+	return key_ref;
 
 } /* end keyring_search_aux() */
 
@@ -469,9 +478,9 @@ struct key *keyring_search_aux(struct ke
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we only found negative matching keys
  */
-struct key *keyring_search(struct key *keyring,
-			   struct key_type *type,
-			   const char *description)
+struct key_ref *keyring_search(struct key_ref *keyring,
+			       struct key_type *type,
+			       const char *description)
 {
 	if (!type->match)
 		return ERR_PTR(-ENOKEY);
@@ -488,15 +497,19 @@ EXPORT_SYMBOL(keyring_search);
  * search the given keyring only (no recursion)
  * - keyring must be locked by caller
  */
-struct key *__keyring_search_one(struct key *keyring,
-				 const struct key_type *ktype,
-				 const char *description,
-				 key_perm_t perm)
+struct key_ref *__keyring_search_one(struct key_ref *keyring_ref,
+				     const struct key_type *ktype,
+				     const char *description,
+				     key_perm_t perm)
 {
 	struct keyring_list *klist;
-	struct key *key;
+	unsigned long possessed;
+	struct key *keyring, *key;
 	int loop;
 
+	keyring = key_deref(keyring_ref);
+	possessed = is_key_possessed(keyring_ref);
+
 	rcu_read_lock();
 
 	klist = rcu_dereference(keyring->payload.subscriptions);
@@ -507,21 +520,20 @@ struct key *__keyring_search_one(struct 
 			if (key->type == ktype &&
 			    (!key->type->match ||
 			     key->type->match(key, description)) &&
-			    key_permission(key, perm) &&
+			    key_permission(key_mkref(key, possessed), perm) &&
 			    !test_bit(KEY_FLAG_REVOKED, &key->flags)
 			    )
 				goto found;
 		}
 	}
 
-	key = ERR_PTR(-ENOKEY);
-	goto error;
+	rcu_read_unlock();
+	return ERR_PTR(-ENOKEY);
 
  found:
 	atomic_inc(&key->usage);
- error:
 	rcu_read_unlock();
-	return key;
+	return key_mkref(key, possessed);
 
 } /* end __keyring_search_one() */
 
@@ -603,7 +615,7 @@ struct key *find_keyring_by_name(const c
 			if (strcmp(keyring->description, name) != 0)
 				continue;
 
-			if (!key_permission(keyring, KEY_SEARCH))
+			if (!key_permission(key_mkref(keyring, 0), KEY_SEARCH))
 				continue;
 
 			/* found a potential candidate, but we still need to
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/proc.c linux-2.6.14-rc1-mm1-keys/security/keys/proc.c
--- linux-2.6.14-rc1-mm1/security/keys/proc.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/proc.c	2005-09-21 13:35:36.000000000 +0100
@@ -167,7 +167,7 @@ static int proc_keys_show(struct seq_fil
 #define showflag(KEY, LETTER, FLAG) \
 	(test_bit(FLAG,	&(KEY)->flags) ? LETTER : '-')
 
-	seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %06x %5d %5d %-9.9s ",
+	seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ",
 		   key->serial,
 		   showflag(key, 'I', KEY_FLAG_INSTANTIATED),
 		   showflag(key, 'R', KEY_FLAG_REVOKED),
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/process_keys.c linux-2.6.14-rc1-mm1-keys/security/keys/process_keys.c
--- linux-2.6.14-rc1-mm1/security/keys/process_keys.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/process_keys.c	2005-09-21 13:45:22.000000000 +0100
@@ -39,7 +39,7 @@ struct key root_user_keyring = {
 	.type		= &key_type_keyring,
 	.user		= &root_key_user,
 	.sem		= __RWSEM_INITIALIZER(root_user_keyring.sem),
-	.perm		= KEY_USR_ALL,
+	.perm		= KEY_POS_ALL | KEY_USR_ALL,
 	.flags		= 1 << KEY_FLAG_INSTANTIATED,
 	.description	= "_uid.0",
 #ifdef KEY_DEBUGGING
@@ -54,7 +54,7 @@ struct key root_session_keyring = {
 	.type		= &key_type_keyring,
 	.user		= &root_key_user,
 	.sem		= __RWSEM_INITIALIZER(root_session_keyring.sem),
-	.perm		= KEY_USR_ALL,
+	.perm		= KEY_POS_ALL | KEY_USR_ALL,
 	.flags		= 1 << KEY_FLAG_INSTANTIATED,
 	.description	= "_uid_ses.0",
 #ifdef KEY_DEBUGGING
@@ -98,7 +98,7 @@ int alloc_uid_keyring(struct user_struct
 	user->session_keyring = session_keyring;
 	ret = 0;
 
- error:
+error:
 	return ret;
 
 } /* end alloc_uid_keyring() */
@@ -156,7 +156,7 @@ int install_thread_keyring(struct task_s
 	ret = 0;
 
 	key_put(old);
- error:
+error:
 	return ret;
 
 } /* end install_thread_keyring() */
@@ -193,7 +193,7 @@ int install_process_keyring(struct task_
 	}
 
 	ret = 0;
- error:
+error:
 	return ret;
 
 } /* end install_process_keyring() */
@@ -236,7 +236,7 @@ static int install_session_keyring(struc
 	/* we're using RCU on the pointer */
 	synchronize_rcu();
 	key_put(old);
- error:
+error:
 	return ret;
 
 } /* end install_session_keyring() */
@@ -376,13 +376,13 @@ void key_fsgid_changed(struct task_struc
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we found only negative matching keys
  */
-struct key *search_process_keyrings(struct key_type *type,
-				    const void *description,
-				    key_match_func_t match,
-				    struct task_struct *context)
+struct key_ref *search_process_keyrings(struct key_type *type,
+					const void *description,
+					key_match_func_t match,
+					struct task_struct *context)
 {
 	struct request_key_auth *rka;
-	struct key *key, *ret, *err, *instkey;
+	struct key_ref *key, *ret, *err, *instkey;
 
 	/* 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;
@@ -397,7 +397,7 @@ struct key *search_process_keyrings(stru
 
 	/* search the thread keyring first */
 	if (context->thread_keyring) {
-		key = keyring_search_aux(context->thread_keyring,
+		key = keyring_search_aux(key_mkref(context->thread_keyring, 1),
 					 context, type, description, match);
 		if (!IS_ERR(key))
 			goto found;
@@ -417,8 +417,9 @@ struct key *search_process_keyrings(stru
 
 	/* search the process keyring second */
 	if (context->signal->process_keyring) {
-		key = keyring_search_aux(context->signal->process_keyring,
-					 context, type, description, match);
+		key = keyring_search_aux(
+			key_mkref(context->signal->process_keyring, 1),
+			context, type, description, match);
 		if (!IS_ERR(key))
 			goto found;
 
@@ -439,7 +440,7 @@ struct key *search_process_keyrings(stru
 	if (context->signal->session_keyring) {
 		rcu_read_lock();
 		key = keyring_search_aux(
-			rcu_dereference(context->signal->session_keyring),
+			key_mkref(rcu_dereference(context->signal->session_keyring), 1),
 			context, type, description, match);
 		rcu_read_unlock();
 
@@ -466,18 +467,18 @@ struct key *search_process_keyrings(stru
 
 		rcu_read_lock();
 		instkey = __keyring_search_one(
-			rcu_dereference(context->signal->session_keyring),
+			key_mkref(rcu_dereference(context->signal->session_keyring), 1),
 			&key_type_request_key_auth, NULL, 0);
 		rcu_read_unlock();
 
 		if (IS_ERR(instkey))
 			goto no_key;
 
-		rka = instkey->payload.data;
+		rka = key_deref(instkey)->payload.data;
 
 		key = search_process_keyrings(type, description, match,
 					      rka->context);
-		key_put(instkey);
+		key_put(key_deref(instkey));
 
 		if (!IS_ERR(key))
 			goto found;
@@ -496,8 +497,9 @@ struct key *search_process_keyrings(stru
 	}
 	/* or search the user-session keyring */
 	else {
-		key = keyring_search_aux(context->user->session_keyring,
-					 context, type, description, match);
+		key = keyring_search_aux(
+			key_mkref(context->user->session_keyring, 1),
+			context, type, description, match);
 		if (!IS_ERR(key))
 			goto found;
 
@@ -526,20 +528,31 @@ found:
 
 /*****************************************************************************/
 /*
+ * see if the key we're looking at is the target key
+ */
+static int lookup_user_key_possessed(const struct key *key, const void *target)
+{
+	return key == target;
+
+} /* end lookup_user_key_possessed() */
+
+/*****************************************************************************/
+/*
  * lookup a key given a key ID from userspace with a given permissions mask
  * - don't create special keyrings unless so requested
  * - partially constructed keys aren't found unless requested
  */
-struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
-			    int create, int partial, key_perm_t perm)
+struct key_ref *lookup_user_key(struct task_struct *context, key_serial_t id,
+				int create, int partial, key_perm_t perm)
 {
+	struct key_ref *key_ref, *skey;
 	struct key *key;
 	int ret;
 
 	if (!context)
 		context = current;
 
-	key = ERR_PTR(-ENOKEY);
+	key_ref = ERR_PTR(-ENOKEY);
 
 	switch (id) {
 	case KEY_SPEC_THREAD_KEYRING:
@@ -556,6 +569,7 @@ struct key *lookup_user_key(struct task_
 
 		key = context->thread_keyring;
 		atomic_inc(&key->usage);
+		key_ref = key_mkref(key, 1);
 		break;
 
 	case KEY_SPEC_PROCESS_KEYRING:
@@ -572,6 +586,7 @@ struct key *lookup_user_key(struct task_
 
 		key = context->signal->process_keyring;
 		atomic_inc(&key->usage);
+		key_ref = key_mkref(key, 1);
 		break;
 
 	case KEY_SPEC_SESSION_KEYRING:
@@ -579,7 +594,7 @@ struct key *lookup_user_key(struct task_
 			/* always install a session keyring upon access if one
 			 * doesn't exist yet */
 			ret = install_session_keyring(
-			       context, context->user->session_keyring);
+				context, context->user->session_keyring);
 			if (ret < 0)
 				goto error;
 		}
@@ -588,16 +603,19 @@ struct key *lookup_user_key(struct task_
 		key = rcu_dereference(context->signal->session_keyring);
 		atomic_inc(&key->usage);
 		rcu_read_unlock();
+		key_ref = key_mkref(key, 1);
 		break;
 
 	case KEY_SPEC_USER_KEYRING:
 		key = context->user->uid_keyring;
 		atomic_inc(&key->usage);
+		key_ref = key_mkref(key, 1);
 		break;
 
 	case KEY_SPEC_USER_SESSION_KEYRING:
 		key = context->user->session_keyring;
 		atomic_inc(&key->usage);
+		key_ref = key_mkref(key, 1);
 		break;
 
 	case KEY_SPEC_GROUP_KEYRING:
@@ -606,13 +624,28 @@ struct key *lookup_user_key(struct task_
 		goto error;
 
 	default:
-		key = ERR_PTR(-EINVAL);
+		key_ref = ERR_PTR(-EINVAL);
 		if (id < 1)
 			goto error;
 
 		key = key_lookup(id);
-		if (IS_ERR(key))
+		if (IS_ERR(key)) {
+			key_ref = ERR_PTR(PTR_ERR(key));
 			goto error;
+		}
+
+		key_ref = key_mkref(key, 0);
+
+		/* check to see if we possess the key */
+		skey = search_process_keyrings(key->type, key,
+					       lookup_user_key_possessed,
+					       current);
+
+		if (!IS_ERR(skey)) {
+			key_put(key);
+			key_ref = skey;
+		}
+
 		break;
 	}
 
@@ -630,15 +663,15 @@ struct key *lookup_user_key(struct task_
 	/* check the permissions */
 	ret = -EACCES;
 
-	if (!key_task_permission(key, context, perm))
+	if (!key_task_permission(key_ref, context, perm))
 		goto invalid_key;
 
- error:
-	return key;
+error:
+	return key_ref;
 
- invalid_key:
-	key_put(key);
-	key = ERR_PTR(ret);
+invalid_key:
+	key_put(key_deref(key_ref));
+	key_ref = ERR_PTR(ret);
 	goto error;
 
 } /* end lookup_user_key() */
@@ -694,9 +727,9 @@ long join_session_keyring(const char *na
 	ret = keyring->serial;
 	key_put(keyring);
 
- error2:
+error2:
 	up(&key_session_sem);
- error:
+error:
 	return ret;
 
 } /* end join_session_keyring() */
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/request_key_auth.c linux-2.6.14-rc1-mm1-keys/security/keys/request_key_auth.c
--- linux-2.6.14-rc1-mm1/security/keys/request_key_auth.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/request_key_auth.c	2005-09-21 13:48:24.000000000 +0100
@@ -126,7 +126,7 @@ struct key *request_key_auth_new(struct 
 
 	rkakey = key_alloc(&key_type_request_key_auth, desc,
 			   current->fsuid, current->fsgid,
-			   KEY_USR_VIEW, 1);
+			   KEY_POS_VIEW | KEY_USR_VIEW, 1);
 	if (IS_ERR(rkakey)) {
 		key_put(keyring);
 		kleave("= %ld", PTR_ERR(rkakey));
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/request_key.c linux-2.6.14-rc1-mm1-keys/security/keys/request_key.c
--- linux-2.6.14-rc1-mm1/security/keys/request_key.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/request_key.c	2005-09-21 15:22:05.000000000 +0100
@@ -129,7 +129,7 @@ static struct key *__request_key_constru
 
 	/* create a key and add it to the queue */
 	key = key_alloc(type, description,
-			current->fsuid, current->fsgid, KEY_USR_ALL, 0);
+			current->fsuid, current->fsgid, KEY_POS_ALL, 0);
 	if (IS_ERR(key))
 		goto alloc_failed;
 
@@ -364,15 +364,25 @@ struct key *request_key_and_link(struct 
 				 struct key *dest_keyring)
 {
 	struct key_user *user;
+	struct key_ref *key_ref;
 	struct key *key;
 
 	kenter("%s,%s,%s,%p",
 	       type->name, description, callout_info, dest_keyring);
 
 	/* search all the process keyrings for a key */
-	key = search_process_keyrings(type, description, type->match, current);
+	key_ref = search_process_keyrings(type, description, type->match,
+					  current);
 
-	if (PTR_ERR(key) == -EAGAIN) {
+	kdebug("search 1: %p", key_ref);
+
+	if (!IS_ERR(key_ref)) {
+		key = key_deref(key_ref);
+	}
+	else if (PTR_ERR(key_ref) != -EAGAIN) {
+		key = ERR_PTR(PTR_ERR(key_ref));
+	}
+	else  {
 		/* the search failed, but the keyrings were searchable, so we
 		 * should consult userspace if we can */
 		key = ERR_PTR(-ENOKEY);
@@ -384,7 +394,7 @@ struct key *request_key_and_link(struct 
 		if (!user)
 			goto nomem;
 
-		do {
+		for (;;) {
 			if (signal_pending(current))
 				goto interrupted;
 
@@ -397,10 +407,20 @@ struct key *request_key_and_link(struct 
 
 			/* someone else made the key we want, so we need to
 			 * search again as it might now be available to us */
-			key = search_process_keyrings(type, description,
-						      type->match, current);
-
-		} while (PTR_ERR(key) == -EAGAIN);
+			key_ref = search_process_keyrings(type, description,
+							  type->match,
+							  current);
+
+			kdebug("search 2: %p", key_ref);
+
+			if (PTR_ERR(key_ref) != -EAGAIN) {
+				if (IS_ERR(key_ref))
+					key = key_deref(key_ref);
+				else
+					key = ERR_PTR(PTR_ERR(key_ref));
+				break;
+			}
+		}
 
 		key_user_put(user);
 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Keys: Add possessor permissions to keys
  2005-09-21 14:48 ` [PATCH] Keys: Add possessor permissions to keys David Howells
@ 2005-09-21 15:05   ` Linus Torvalds
  2005-09-21 15:44   ` David Howells
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 14+ messages in thread
From: Linus Torvalds @ 2005-09-21 15:05 UTC (permalink / raw)
  To: David Howells; +Cc: akpm, keyrings, linux-kernel



On Wed, 21 Sep 2005, David Howells wrote:
> 
> The attached patch adds extra permission grants to keys for the possessor of a
> key in addition to the owner, group and other permissions bits. This makes
> SUID binaries easier to support without going as far as labelling keys and key
> targets using the LSM facilities.

Ok, maybe I'm just strange, but when I see code like

	if (is_key_possessed(keyref)) {

I'm inevitably mentally going "Linda Blair! It is spewing pea-soup and
rotating its head!"

Maybe not the best of naming practices..

		Linus

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Keys: Add possessor permissions to keys
  2005-09-21 14:48 ` [PATCH] Keys: Add possessor permissions to keys David Howells
  2005-09-21 15:05   ` Linus Torvalds
@ 2005-09-21 15:44   ` David Howells
  2005-09-21 17:15   ` Andrew Morton
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 14+ messages in thread
From: David Howells @ 2005-09-21 15:44 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: David Howells, akpm, keyrings, linux-kernel

Linus Torvalds <torvalds@osdl.org> wrote:

> Ok, maybe I'm just strange, but when I see code like
> 
> 	if (is_key_possessed(keyref)) {
> 
> I'm inevitably mentally going "Linda Blair! It is spewing pea-soup and
> rotating its head!"
> 
> Maybe not the best of naming practices..

Or maybe not the best of mental or film watching practices? :-)

How about if I call it is_key_retained() instead?

Of course, I now prefer the name is_key_possessed() if only to frighten other
kernel developers...

David

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Keys: Add possessor permissions to keys
  2005-09-21 14:48 ` [PATCH] Keys: Add possessor permissions to keys David Howells
  2005-09-21 15:05   ` Linus Torvalds
  2005-09-21 15:44   ` David Howells
@ 2005-09-21 17:15   ` Andrew Morton
  2005-09-21 17:47     ` Trond Myklebust
  2005-09-21 18:36     ` David Howells
  2005-09-21 18:29   ` David Howells
  2005-09-21 19:23   ` James Morris
  4 siblings, 2 replies; 14+ messages in thread
From: Andrew Morton @ 2005-09-21 17:15 UTC (permalink / raw)
  To: David Howells; +Cc: torvalds, keyrings, linux-kernel

David Howells <dhowells@redhat.com> wrote:
>
> 
> The attached patch adds extra permission grants to keys for the possessor of a
> key in addition to the owner, group and other permissions bits. This makes
> SUID binaries easier to support without going as far as labelling keys and key
> targets using the LSM facilities.
> 
> This patch adds a second "pointer type" to key structures (struct key_ref *)
> that can have the bottom bit of the address set to indicate the possession of
> a key. This is propagated through searches from the keyring to the discovered
> key. It has been made a separate type so that the compiler can spot attempts
> to dereference a potentially incorrect pointer.

The above bit needs to be captured in a code comment.  Because:

> ...
>  /*
> + * key reference with possession flag handling
> + */
> +static inline struct key_ref *key_mkref(const struct key *key, unsigned long possession)
> +{
> +	return (struct key_ref *) ((unsigned long) key | possession);
> +}

Is hair-raising and makes people want to come after you with a stick ;)

(And an 80-col xterm)

ugh, I see.  `struct key_ref' doesn't actually exist anywhere.  The code
only ever deals with pointers to this non-existent structure and they are
munged `struct key *'s.

Did this _have_ to happen?

> +	}
> +	else if (key->uid == context->fsuid) {

Documentation/CodingStyle?

> +		       "%s;%d;%d;%08x;%s",
> +		       key_deref(key)->type->name,
> +		       key_deref(key)->uid,
> +		       key_deref(key)->gid,
> +		       key_deref(key)->perm,
> +		       key_deref(key)->description ? key_deref(key)->description : ""
>  		       );

This doesn't actually make things clear.

> +			if (PTR_ERR(key_ref) != -EAGAIN) {
> +				if (IS_ERR(key_ref))
> +					key = key_deref(key_ref);
> +				else
> +					key = ERR_PTR(PTR_ERR(key_ref));
> +				break;
> +			}
> +		}

That's getting a bit intimate with how IS_ERR and PTR_ERR are implemented
but I guess we're unlikely to change that.

This all seems quite inappropriate to -rc2?

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Keys: Add possessor permissions to keys
  2005-09-21 17:15   ` Andrew Morton
@ 2005-09-21 17:47     ` Trond Myklebust
  2005-09-21 18:36     ` David Howells
  1 sibling, 0 replies; 14+ messages in thread
From: Trond Myklebust @ 2005-09-21 17:47 UTC (permalink / raw)
  To: Andrew Morton; +Cc: David Howells, torvalds, keyrings, linux-kernel

on den 21.09.2005 Klokka 10:15 (-0700) skreiv Andrew Morton:

> > +			if (PTR_ERR(key_ref) != -EAGAIN) {
> > +				if (IS_ERR(key_ref))
> > +					key = key_deref(key_ref);
> > +				else
> > +					key = ERR_PTR(PTR_ERR(key_ref));
> > +				break;
> > +			}
> > +		}
> 
> That's getting a bit intimate with how IS_ERR and PTR_ERR are implemented
> but I guess we're unlikely to change that.

Shouldn't that test for IS_ERR(key_ref) be inverted?

Cheers,
  Trond


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Keys: Add possessor permissions to keys
  2005-09-21 14:48 ` [PATCH] Keys: Add possessor permissions to keys David Howells
                     ` (2 preceding siblings ...)
  2005-09-21 17:15   ` Andrew Morton
@ 2005-09-21 18:29   ` David Howells
  2005-09-21 18:45     ` Andrew Morton
  2005-10-03  4:43     ` [Keyrings] " Kyle Moffett
  2005-09-21 19:23   ` James Morris
  4 siblings, 2 replies; 14+ messages in thread
From: David Howells @ 2005-09-21 18:29 UTC (permalink / raw)
  To: Andrew Morton; +Cc: David Howells, torvalds, keyrings, linux-kernel

Andrew Morton <akpm@osdl.org> wrote:

> The above bit needs to be captured in a code comment.  Because:

Okay.

> Is hair-raising and makes people want to come after you with a stick ;)

If people get upset by this sort of thing, they shouldn't be doing kernel
development.

> ugh, I see.  `struct key_ref' doesn't actually exist anywhere.  The code
> only ever deals with pointers to this non-existent structure and they are
> munged `struct key *'s.
> 
> Did this _have_ to happen?

I want to make sure that the key-pointer-with-attribute is not dereferenced
accidentally (the attribute displaces the pointer by 1).

I can see several ways of doing what I wanted to do:

 (1) I could pass extra arguments around to carry the attribute, but that's
     starting to get unwieldy for functions that take pointers to three
     keys.

 (2) Define a reference structure, such as this:

	struct key_ref {
		struct key *key;
		int possess;
	};

     Or this (with the attribute folded into the pointer):

	struct key_ref {
		struct key *possessed_key;
	};

     This could be passed directly as argument and return values:

	struct key_ref keyring_search(struct key_ref keyring,
				      struct key_type *type,
				      const char *description);

     Which would give the compiler lots of joy, or it could be done like this:

	int keyring_search(struct key_ref *keyring,
			   struct key_type *type,
			   const char *description);
			   struct key_ref *_key);

     Which would require extra stack space or kmalloc memory and memory loads.

 (3) Key handles (which I've been asked for before).

     This involves detaching the permissions and suchlike from the key into a
     "handle" which can then be cloned. A temporary handle could then be used
     to hold the possession attribute and the other permissions at the time of
     the access.

     The downside of this is that it's quite a big change. It also makes
     joining session keyrings way more "interesting". It does have some nice
     features though.

 (4) Attach attribute to key pointer (which is what I've done).

     This is slightly tricky in that it involves altering the pointer to carry
     extra information; but on the other hand, the information can be
     extracted or discarded with a single AND instruction.

     I don't have to pass extra arguments around, though it may still use
     extra stack space for the extra automatic variables, depending on whether
     the compiler is clever enough to spot it can regenerate the real pointer
     by AND-ing again with the reference pointer.

Passing the attribute in the bottom bit of the pointer (option 4) seems to be
the best method of doing it. I started implementing option 1 first, but that
wasn't very pleasant.

> This doesn't actually make things clear.

Okay... I'll rethink that bit. "key" there should really be "key_ref" to make
the point.

> > +			if (PTR_ERR(key_ref) != -EAGAIN) {
> > +				if (IS_ERR(key_ref))
> > +					key = key_deref(key_ref);
> > +				else
> > +					key = ERR_PTR(PTR_ERR(key_ref));
> > +				break;
> > +			}
> > +		}
> 
> That's getting a bit intimate with how IS_ERR and PTR_ERR are implemented
> but I guess we're unlikely to change that.

You're referring to the ordering of the first two lines? I could, and probably
should, reorder them. It's also wrong: there should be a ! before the IS_ERR.

I've changed this to:

			if (!IS_ERR(key_ref)) {
				key = key_deref(key_ref);
				break;
			}

			if (PTR_ERR(key_ref) != -EAGAIN) {
				key = ERR_PTR(PTR_ERR(key_ref));
				break;
			}

> This all seems quite inappropriate to -rc2?

Which -rc2? If it's 2.6.14-rc2 you're referring to, then yes - that's already
released.

David

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH] Keys: Add possessor permissions to keys  [try #2]
       [not found] <5378.1127211442@warthog.cambridge.redhat.com>
  2005-09-21 14:48 ` [PATCH] Keys: Add possessor permissions to keys David Howells
@ 2005-09-21 18:33 ` David Howells
  2005-09-28 16:03 ` [PATCH] Keys: Add possessor permissions to keys [try #3] David Howells
  2 siblings, 0 replies; 14+ messages in thread
From: David Howells @ 2005-09-21 18:33 UTC (permalink / raw)
  To: torvalds, akpm; +Cc: keyrings, linux-kernel


The attached patch adds extra permission grants to keys for the possessor of a
key in addition to the owner, group and other permissions bits. This makes
SUID binaries easier to support without going as far as labelling keys and key
targets using the LSM facilities.

This patch adds a second "pointer type" to key structures (struct key_ref *)
that can have the bottom bit of the address set to indicate the possession of
a key. This is propagated through searches from the keyring to the discovered
key. It has been made a separate type so that the compiler can spot attempts
to dereference a potentially incorrect pointer.

The "possession" attribute can't be attached to a key structure directly as
it's not an intrinsic property of a key.

Pointers to keys have been replaced with struct key_ref *'s wherever
possession information needs to be passed through.

This does assume that the bottom bit of the pointer will always be zero on
return from kmem_cache_alloc().

Signed-Off-By: David Howells <dhowells@redhat.com>
---
warthog>diffstat -p1 keys-possess-2614rc1mm1-2.diff 
 Documentation/keys.txt           |   64 ++++++--
 include/linux/key-ui.h           |   28 ++-
 include/linux/key.h              |   70 +++++++--
 security/keys/internal.h         |   28 +--
 security/keys/key.c              |   82 ++++++----
 security/keys/keyctl.c           |  299 +++++++++++++++++++--------------------
 security/keys/keyring.c          |   84 ++++++----
 security/keys/proc.c             |    2 
 security/keys/process_keys.c     |  101 ++++++++-----
 security/keys/request_key.c      |   36 +++-
 security/keys/request_key_auth.c |    2 
 11 files changed, 478 insertions(+), 318 deletions(-)

diff -uNrp linux-2.6.14-rc1-mm1/Documentation/keys.txt linux-2.6.14-rc1-mm1-keys/Documentation/keys.txt
--- linux-2.6.14-rc1-mm1/Documentation/keys.txt	2005-08-30 13:56:09.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/Documentation/keys.txt	2005-09-21 15:19:22.000000000 +0100
@@ -195,8 +195,8 @@ KEY ACCESS PERMISSIONS
 ======================
 
 Keys have an owner user ID, a group access ID, and a permissions mask. The mask
-has up to eight bits each for user, group and other access. Only five of each
-set of eight bits are defined. These permissions granted are:
+has up to eight bits each for possessor, user, group and other access. Only
+five of each set of eight bits are defined. These permissions granted are:
 
  (*) View
 
@@ -241,16 +241,16 @@ about the status of the key service:
      type, description and permissions. The payload of the key is not available
      this way:
 
-	SERIAL   FLAGS  USAGE EXPY PERM   UID   GID   TYPE      DESCRIPTION: SUMMARY
-	00000001 I-----    39 perm 1f0000     0     0 keyring   _uid_ses.0: 1/4
-	00000002 I-----     2 perm 1f0000     0     0 keyring   _uid.0: empty
-	00000007 I-----     1 perm 1f0000     0     0 keyring   _pid.1: empty
-	0000018d I-----     1 perm 1f0000     0     0 keyring   _pid.412: empty
-	000004d2 I--Q--     1 perm 1f0000    32    -1 keyring   _uid.32: 1/4
-	000004d3 I--Q--     3 perm 1f0000    32    -1 keyring   _uid_ses.32: empty
-	00000892 I--QU-     1 perm 1f0000     0     0 user      metal:copper: 0
-	00000893 I--Q-N     1  35s 1f0000     0     0 user      metal:silver: 0
-	00000894 I--Q--     1  10h 1f0000     0     0 user      metal:gold: 0
+	SERIAL   FLAGS  USAGE EXPY PERM     UID   GID   TYPE      DESCRIPTION: SUMMARY
+	00000001 I-----    39 perm 1f1f0000     0     0 keyring   _uid_ses.0: 1/4
+	00000002 I-----     2 perm 1f1f0000     0     0 keyring   _uid.0: empty
+	00000007 I-----     1 perm 1f1f0000     0     0 keyring   _pid.1: empty
+	0000018d I-----     1 perm 1f1f0000     0     0 keyring   _pid.412: empty
+	000004d2 I--Q--     1 perm 1f1f0000    32    -1 keyring   _uid.32: 1/4
+	000004d3 I--Q--     3 perm 1f1f0000    32    -1 keyring   _uid_ses.32: empty
+	00000892 I--QU-     1 perm 1f000000     0     0 user      metal:copper: 0
+	00000893 I--Q-N     1  35s 1f1f0000     0     0 user      metal:silver: 0
+	00000894 I--Q--     1  10h 001f0000     0     0 user      metal:gold: 0
 
      The flags are:
 
@@ -637,6 +637,34 @@ call, and the key released upon close. H
 two different users opening the same file is left to the filesystem author to
 solve.
 
+Note that there are two different types of pointers to keys that may be
+encountered:
+
+ (*) struct key *
+
+     This simply points to the key structure itself. Key structures will be at
+     least four-byte aligned.
+
+ (*) struct key_ref *
+
+     This is equivalent to a struct key *, but the least significant bit is set
+     if the caller "possesses" the key. By "possession" it is meant that the
+     calling processes has a searchable link to the key from one of its
+     keyrings. Their are three functions for dealing with these:
+
+	struct key_ref *key_mkref(const struct key *key,
+				  unsigned long possession);
+
+	struct key *key_deref(const struct key_ref *key_ref);
+
+	unsigned long is_key_possessed(const struct key_ref *key_ref);
+
+     The first function constructs a key reference from a key pointer and
+     possession information (which must be 0 or 1 and no other value).
+
+     The second function retrieves the key pointer and the third retrieves the
+     possession flag).
+
 When accessing a key's payload contents, certain precautions must be taken to
 prevent access vs modification races. See the section "Notes on accessing
 payload contents" for more information.
@@ -689,14 +717,18 @@ payload contents" for more information.
 
 (*) If a keyring was found in the search, this can be further searched by:
 
-	struct key *keyring_search(struct key *keyring,
-				   const struct key_type *type,
-				   const char *description)
+	struct key_ref *keyring_search(struct key_ref *keyring,
+				       const struct key_type *type,
+				       const char *description)
 
     This searches the keyring tree specified for a matching key. Error ENOKEY
     is returned upon failure. If successful, the returned key will need to be
     released.
 
+    The possession attribute from the keyring reference pointer is used to
+    control access through the permissions mask and is propagated to the
+    returned key reference pointer if successful.
+
 
 (*) To check the validity of a key, this function can be called:
 
@@ -732,7 +764,7 @@ More complex payload contents must be al
 key->payload.data. One of the following ways must be selected to access the
 data:
 
- (1) Unmodifyable key type.
+ (1) Unmodifiable key type.
 
      If the key type does not have a modify method, then the key's payload can
      be accessed without any form of locking, provided that it's known to be
diff -uNrp linux-2.6.14-rc1-mm1/include/linux/key.h linux-2.6.14-rc1-mm1-keys/include/linux/key.h
--- linux-2.6.14-rc1-mm1/include/linux/key.h	2005-08-30 13:56:36.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/include/linux/key.h	2005-09-21 18:53:03.000000000 +0100
@@ -30,16 +30,24 @@ typedef int32_t key_serial_t;
 typedef uint32_t key_perm_t;
 
 struct key;
+struct key_ref;		/* pointer to a key with a possession flag */
 
 #ifdef CONFIG_KEYS
 
 #undef KEY_DEBUGGING
 
-#define KEY_USR_VIEW	0x00010000	/* user can view a key's attributes */
-#define KEY_USR_READ	0x00020000	/* user can read key payload / view keyring */
-#define KEY_USR_WRITE	0x00040000	/* user can update key payload / add link to keyring */
-#define KEY_USR_SEARCH	0x00080000	/* user can find a key in search / search a keyring */
-#define KEY_USR_LINK	0x00100000	/* user can create a link to a key/keyring */
+#define KEY_POS_VIEW	0x01000000	/* possessor can view a key's attributes */
+#define KEY_POS_READ	0x02000000	/* possessor can read key payload / view keyring */
+#define KEY_POS_WRITE	0x04000000	/* possessor can update key payload / add link to keyring */
+#define KEY_POS_SEARCH	0x08000000	/* possessor can find a key in search / search a keyring */
+#define KEY_POS_LINK	0x10000000	/* possessor can create a link to a key/keyring */
+#define KEY_POS_ALL	0x1f000000
+
+#define KEY_USR_VIEW	0x00010000	/* user permissions... */
+#define KEY_USR_READ	0x00020000
+#define KEY_USR_WRITE	0x00040000
+#define KEY_USR_SEARCH	0x00080000
+#define KEY_USR_LINK	0x00100000
 #define KEY_USR_ALL	0x001f0000
 
 #define KEY_GRP_VIEW	0x00000100	/* group permissions... */
@@ -221,14 +229,14 @@ extern struct key *request_key(struct ke
 
 extern int key_validate(struct key *key);
 
-extern struct key *key_create_or_update(struct key *keyring,
-					const char *type,
-					const char *description,
-					const void *payload,
-					size_t plen,
-					int not_in_quota);
+extern struct key_ref *key_create_or_update(struct key_ref *keyring,
+					    const char *type,
+					    const char *description,
+					    const void *payload,
+					    size_t plen,
+					    int not_in_quota);
 
-extern int key_update(struct key *key,
+extern int key_update(struct key_ref *key,
 		      const void *payload,
 		      size_t plen);
 
@@ -243,9 +251,9 @@ extern struct key *keyring_alloc(const c
 
 extern int keyring_clear(struct key *keyring);
 
-extern struct key *keyring_search(struct key *keyring,
-				  struct key_type *type,
-				  const char *description);
+extern struct key_ref *keyring_search(struct key_ref *keyring,
+				      struct key_type *type,
+				      const char *description);
 
 extern int keyring_add_key(struct key *keyring,
 			   struct key *key);
@@ -257,6 +265,35 @@ extern void keyring_replace_payload(stru
 #define key_serial(key) ((key) ? (key)->serial : 0)
 
 /*
+ * key reference with possession attribute handling
+ *
+ * NOTE! struct key_ref is not actually defined. This is because we abuse the
+ * bottom bit of the reference pointer to carry a flag to indicate whether the
+ * calling process possesses that key in one of its keyrings.
+ *
+ * the struct key_ref * has been made a separate type so that the compiler can
+ * reject attempts to dereference it without proper conversion.
+ *
+ * the following three functions are used to assemble and disassemble
+ * references
+ */
+static inline struct key_ref *key_mkref(const struct key *key,
+					unsigned long possession)
+{
+	return (struct key_ref *) ((unsigned long) key | possession);
+}
+
+static inline struct key *key_deref(const struct key_ref *key)
+{
+	return (struct key *) ((unsigned long) key & ~1UL);
+}
+
+static inline unsigned long is_key_possessed(const struct key_ref *key)
+{
+	return (unsigned long) key & 1UL;
+}
+
+/*
  * the userspace interface
  */
 extern struct key root_user_keyring, root_session_keyring;
@@ -285,6 +322,9 @@ extern void key_init(void);
 #define key_serial(k)			0
 #define key_get(k) 			({ NULL; })
 #define key_put(k)			do { } while(0)
+#define key_mkref(k)			({ NULL; })
+#define key_deref(k)			({ NULL; })
+#define is_key_possessed(k)		0
 #define alloc_uid_keyring(u)		0
 #define switch_uid_keyring(u)		do { } while(0)
 #define __install_session_keyring(t, k)	({ NULL; })
diff -uNrp linux-2.6.14-rc1-mm1/include/linux/key-ui.h linux-2.6.14-rc1-mm1-keys/include/linux/key-ui.h
--- linux-2.6.14-rc1-mm1/include/linux/key-ui.h	2005-08-30 13:56:36.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/include/linux/key-ui.h	2005-09-21 12:00:23.000000000 +0100
@@ -42,11 +42,14 @@ struct keyring_list {
 /*
  * check to see whether permission is granted to use a key in the desired way
  */
-static inline int key_permission(const struct key *key, key_perm_t perm)
+static inline int key_permission(const struct key_ref *key_ref, key_perm_t perm)
 {
+	struct key *key = key_deref(key_ref);
 	key_perm_t kperm;
 
-	if (key->uid == current->fsuid)
+	if (is_key_possessed(key_ref))
+		kperm = key->perm >> 24;
+	else if (key->uid == current->fsuid)
 		kperm = key->perm >> 16;
 	else if (key->gid != -1 &&
 		 key->perm & KEY_GRP_ALL &&
@@ -65,11 +68,14 @@ static inline int key_permission(const s
  * check to see whether permission is granted to use a key in at least one of
  * the desired ways
  */
-static inline int key_any_permission(const struct key *key, key_perm_t perm)
+static inline int key_any_permission(const struct key_ref *key_ref, key_perm_t perm)
 {
+	struct key *key = key_deref(key_ref);
 	key_perm_t kperm;
 
-	if (key->uid == current->fsuid)
+	if (is_key_possessed(key_ref))
+		kperm = key->perm >> 24;
+	else if (key->uid == current->fsuid)
 		kperm = key->perm >> 16;
 	else if (key->gid != -1 &&
 		 key->perm & KEY_GRP_ALL &&
@@ -94,13 +100,17 @@ static inline int key_task_groups_search
 	return ret;
 }
 
-static inline int key_task_permission(const struct key *key,
+static inline int key_task_permission(const struct key_ref *key_ref,
 				      struct task_struct *context,
 				      key_perm_t perm)
 {
+	struct key *key = key_deref(key_ref);
 	key_perm_t kperm;
 
-	if (key->uid == context->fsuid) {
+	if (is_key_possessed(key_ref)) {
+		kperm = key->perm >> 24;
+	}
+	else if (key->uid == context->fsuid) {
 		kperm = key->perm >> 16;
 	}
 	else if (key->gid != -1 &&
@@ -121,9 +131,9 @@ static inline int key_task_permission(co
 
 }
 
-extern struct key *lookup_user_key(struct task_struct *context,
-				   key_serial_t id, int create, int partial,
-				   key_perm_t perm);
+extern struct key_ref *lookup_user_key(struct task_struct *context,
+				       key_serial_t id, int create, int partial,
+				       key_perm_t perm);
 
 extern long join_session_keyring(const char *name);
 
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/internal.h linux-2.6.14-rc1-mm1-keys/security/keys/internal.h
--- linux-2.6.14-rc1-mm1/security/keys/internal.h	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/internal.h	2005-09-21 14:59:27.000000000 +0100
@@ -71,26 +71,26 @@ extern void keyring_publish_name(struct 
 
 extern int __key_link(struct key *keyring, struct key *key);
 
-extern struct key *__keyring_search_one(struct key *keyring,
-					const struct key_type *type,
-					const char *description,
-					key_perm_t perm);
+extern struct key_ref *__keyring_search_one(struct key_ref *keyring,
+					    const struct key_type *type,
+					    const char *description,
+					    key_perm_t perm);
 
 extern struct key *keyring_search_instkey(struct key *keyring,
 					  key_serial_t target_id);
 
 typedef int (*key_match_func_t)(const struct key *, const void *);
 
-extern struct key *keyring_search_aux(struct key *keyring,
-				      struct task_struct *tsk,
-				      struct key_type *type,
-				      const void *description,
-				      key_match_func_t match);
-
-extern struct key *search_process_keyrings(struct key_type *type,
-					   const void *description,
-					   key_match_func_t match,
-					   struct task_struct *tsk);
+extern struct key_ref *keyring_search_aux(struct key_ref *keyring,
+					  struct task_struct *tsk,
+					  struct key_type *type,
+					  const void *description,
+					  key_match_func_t match);
+
+extern struct key_ref *search_process_keyrings(struct key_type *type,
+					       const void *description,
+					       key_match_func_t match,
+					       struct task_struct *tsk);
 
 extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
 
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/key.c linux-2.6.14-rc1-mm1-keys/security/keys/key.c
--- linux-2.6.14-rc1-mm1/security/keys/key.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/key.c	2005-09-21 13:47:47.000000000 +0100
@@ -693,14 +693,16 @@ void key_type_put(struct key_type *ktype
  * - the key has an incremented refcount
  * - we need to put the key if we get an error
  */
-static inline struct key *__key_update(struct key *key, const void *payload,
-				       size_t plen)
+static inline struct key_ref *__key_update(struct key_ref *key_ref,
+					   const void *payload,
+					   size_t plen)
 {
+	struct key *key = key_deref(key_ref);
 	int ret;
 
 	/* need write permission on the key to update it */
 	ret = -EACCES;
-	if (!key_permission(key, KEY_WRITE))
+	if (!key_permission(key_ref, KEY_WRITE))
 		goto error;
 
 	ret = -EEXIST;
@@ -719,12 +721,12 @@ static inline struct key *__key_update(s
 
 	if (ret < 0)
 		goto error;
- out:
-	return key;
+out:
+	return key_ref;
 
- error:
+error:
 	key_put(key);
-	key = ERR_PTR(ret);
+	key_ref = ERR_PTR(ret);
 	goto out;
 
 } /* end __key_update() */
@@ -734,52 +736,56 @@ static inline struct key *__key_update(s
  * search the specified keyring for a key of the same description; if one is
  * found, update it, otherwise add a new one
  */
-struct key *key_create_or_update(struct key *keyring,
-				 const char *type,
-				 const char *description,
-				 const void *payload,
-				 size_t plen,
-				 int not_in_quota)
+struct key_ref *key_create_or_update(struct key_ref *keyring_ref,
+				     const char *type,
+				     const char *description,
+				     const void *payload,
+				     size_t plen,
+				     int not_in_quota)
 {
 	struct key_type *ktype;
-	struct key *key = NULL;
+	struct key_ref *key_ref;
+	struct key *keyring, *key = NULL;
 	key_perm_t perm;
 	int ret;
 
-	key_check(keyring);
-
 	/* look up the key type to see if it's one of the registered kernel
 	 * types */
 	ktype = key_type_lookup(type);
 	if (IS_ERR(ktype)) {
-		key = ERR_PTR(-ENODEV);
+		key_ref = ERR_PTR(-ENODEV);
 		goto error;
 	}
 
-	ret = -EINVAL;
+	key_ref = ERR_PTR(-EINVAL);
 	if (!ktype->match || !ktype->instantiate)
 		goto error_2;
 
+	keyring = key_deref(keyring_ref);
+
+	key_check(keyring);
+
+	down_write(&keyring->sem);
+
+	/* if we're going to allocate a new key, we're going to have
+	 * to modify the keyring */
+	key_ref = ERR_PTR(-EACCES);
+	if (!key_permission(keyring_ref, KEY_WRITE))
+		goto error_3;
+
 	/* search for an existing key of the same type and description in the
 	 * destination keyring
 	 */
-	down_write(&keyring->sem);
-
-	key = __keyring_search_one(keyring, ktype, description, 0);
-	if (!IS_ERR(key))
+	key_ref = __keyring_search_one(keyring_ref, ktype, description, 0);
+	if (!IS_ERR(key_ref))
 		goto found_matching_key;
 
-	/* if we're going to allocate a new key, we're going to have to modify
-	 * the keyring */
-	ret = -EACCES;
-	if (!key_permission(keyring, KEY_WRITE))
-		goto error_3;
-
 	/* decide on the permissions we want */
-	perm = KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK;
+	perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK;
+	perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK;
 
 	if (ktype->read)
-		perm |= KEY_USR_READ;
+		perm |= KEY_POS_READ | KEY_USR_READ;
 
 	if (ktype == &key_type_keyring || ktype->update)
 		perm |= KEY_USR_WRITE;
@@ -788,7 +794,7 @@ struct key *key_create_or_update(struct 
 	key = key_alloc(ktype, description, current->fsuid, current->fsgid,
 			perm, not_in_quota);
 	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+		key_ref = ERR_PTR(PTR_ERR(key));
 		goto error_3;
 	}
 
@@ -796,15 +802,18 @@ struct key *key_create_or_update(struct 
 	ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
 	if (ret < 0) {
 		key_put(key);
-		key = ERR_PTR(ret);
+		key_ref = ERR_PTR(ret);
+		goto error_3;
 	}
 
+	key_ref = key_mkref(key, is_key_possessed(keyring_ref));
+
  error_3:
 	up_write(&keyring->sem);
  error_2:
 	key_type_put(ktype);
  error:
-	return key;
+	return key_ref;
 
  found_matching_key:
 	/* we found a matching key, so we're going to try to update it
@@ -813,7 +822,7 @@ struct key *key_create_or_update(struct 
 	up_write(&keyring->sem);
 	key_type_put(ktype);
 
-	key = __key_update(key, payload, plen);
+	key_ref = __key_update(key_ref, payload, plen);
 	goto error;
 
 } /* end key_create_or_update() */
@@ -824,15 +833,16 @@ EXPORT_SYMBOL(key_create_or_update);
 /*
  * update a key
  */
-int key_update(struct key *key, const void *payload, size_t plen)
+int key_update(struct key_ref *key_ref, const void *payload, size_t plen)
 {
+	struct key *key = key_deref(key_ref);
 	int ret;
 
 	key_check(key);
 
 	/* the key must be writable */
 	ret = -EACCES;
-	if (!key_permission(key, KEY_WRITE))
+	if (!key_permission(key_ref, KEY_WRITE))
 		goto error;
 
 	/* attempt to update it if supported */
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/keyctl.c linux-2.6.14-rc1-mm1-keys/security/keys/keyctl.c
--- linux-2.6.14-rc1-mm1/security/keys/keyctl.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/keyctl.c	2005-09-21 19:21:30.000000000 +0100
@@ -34,7 +34,7 @@ asmlinkage long sys_add_key(const char _
 			    size_t plen,
 			    key_serial_t ringid)
 {
-	struct key *keyring, *key;
+	struct key_ref *keyring_ref, *key_ref;
 	char type[32], *description;
 	void *payload;
 	long dlen, ret;
@@ -86,25 +86,25 @@ asmlinkage long sys_add_key(const char _
 	}
 
 	/* find the target keyring (which must be writable) */
-	keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
+	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+	if (IS_ERR(keyring_ref)) {
+		ret = PTR_ERR(keyring_ref);
 		goto error3;
 	}
 
 	/* create or update the requested key and add it to the target
 	 * keyring */
-	key = key_create_or_update(keyring, type, description,
-				   payload, plen, 0);
-	if (!IS_ERR(key)) {
-		ret = key->serial;
-		key_put(key);
+	key_ref = key_create_or_update(keyring_ref, type, description,
+				       payload, plen, 0);
+	if (!IS_ERR(key_ref)) {
+		ret = key_deref(key_ref)->serial;
+		key_put(key_deref(key_ref));
 	}
 	else {
-		ret = PTR_ERR(key);
+		ret = PTR_ERR(key_ref);
 	}
 
-	key_put(keyring);
+	key_put(key_deref(keyring_ref));
  error3:
 	kfree(payload);
  error2:
@@ -131,7 +131,8 @@ asmlinkage long sys_request_key(const ch
 				key_serial_t destringid)
 {
 	struct key_type *ktype;
-	struct key *key, *dest;
+	struct key_ref *dest_ref;
+	struct key *key;
 	char type[32], *description, *callout_info;
 	long dlen, ret;
 
@@ -187,11 +188,11 @@ asmlinkage long sys_request_key(const ch
 	}
 
 	/* get the destination keyring if specified */
-	dest = NULL;
+	dest_ref = NULL;
 	if (destringid) {
-		dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
-		if (IS_ERR(dest)) {
-			ret = PTR_ERR(dest);
+		dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+		if (IS_ERR(dest_ref)) {
+			ret = PTR_ERR(dest_ref);
 			goto error3;
 		}
 	}
@@ -204,7 +205,8 @@ asmlinkage long sys_request_key(const ch
 	}
 
 	/* do the search */
-	key = request_key_and_link(ktype, description, callout_info, dest);
+	key = request_key_and_link(ktype, description, callout_info,
+				   key_deref(dest_ref));
 	if (IS_ERR(key)) {
 		ret = PTR_ERR(key);
 		goto error5;
@@ -216,7 +218,7 @@ asmlinkage long sys_request_key(const ch
  error5:
 	key_type_put(ktype);
  error4:
-	key_put(dest);
+	key_put(key_deref(dest_ref));
  error3:
 	kfree(callout_info);
  error2:
@@ -234,17 +236,17 @@ asmlinkage long sys_request_key(const ch
  */
 long keyctl_get_keyring_ID(key_serial_t id, int create)
 {
-	struct key *key;
+	struct key_ref *key_ref;
 	long ret;
 
-	key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
-	ret = key->serial;
-	key_put(key);
+	ret = key_deref(key_ref)->serial;
+	key_put(key_deref(key_ref));
  error:
 	return ret;
 
@@ -302,7 +304,7 @@ long keyctl_update_key(key_serial_t id,
 		       const void __user *_payload,
 		       size_t plen)
 {
-	struct key *key;
+	struct key_ref *key_ref;
 	void *payload;
 	long ret;
 
@@ -324,16 +326,16 @@ long keyctl_update_key(key_serial_t id,
 	}
 
 	/* find the target key (which must be writable) */
-	key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error2;
 	}
 
 	/* update the key */
-	ret = key_update(key, payload, plen);
+	ret = key_update(key_ref, payload, plen);
 
-	key_put(key);
+	key_put(key_deref(key_ref));
  error2:
 	kfree(payload);
  error:
@@ -349,19 +351,19 @@ long keyctl_update_key(key_serial_t id,
  */
 long keyctl_revoke_key(key_serial_t id)
 {
-	struct key *key;
+	struct key_ref *key_ref;
 	long ret;
 
-	key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
-	key_revoke(key);
+	key_revoke(key_deref(key_ref));
 	ret = 0;
 
-	key_put(key);
+	key_put(key_deref(key_ref));
  error:
 	return ret;
 
@@ -375,18 +377,18 @@ long keyctl_revoke_key(key_serial_t id)
  */
 long keyctl_keyring_clear(key_serial_t ringid)
 {
-	struct key *keyring;
+	struct key_ref *keyring_ref;
 	long ret;
 
-	keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
+	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+	if (IS_ERR(keyring_ref)) {
+		ret = PTR_ERR(keyring_ref);
 		goto error;
 	}
 
-	ret = keyring_clear(keyring);
+	ret = keyring_clear(key_deref(keyring_ref));
 
-	key_put(keyring);
+	key_put(key_deref(keyring_ref));
  error:
 	return ret;
 
@@ -401,26 +403,26 @@ long keyctl_keyring_clear(key_serial_t r
  */
 long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
 {
-	struct key *keyring, *key;
+	struct key_ref *keyring_ref, *key_ref;
 	long ret;
 
-	keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
+	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+	if (IS_ERR(keyring_ref)) {
+		ret = PTR_ERR(keyring_ref);
 		goto error;
 	}
 
-	key = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error2;
 	}
 
-	ret = key_link(keyring, key);
+	ret = key_link(key_deref(keyring_ref), key_deref(key_ref));
 
-	key_put(key);
+	key_put(key_deref(key_ref));
  error2:
-	key_put(keyring);
+	key_put(key_deref(keyring_ref));
  error:
 	return ret;
 
@@ -435,26 +437,26 @@ long keyctl_keyring_link(key_serial_t id
  */
 long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
 {
-	struct key *keyring, *key;
+	struct key_ref *keyring_ref, *key_ref;
 	long ret;
 
-	keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
+	keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
+	if (IS_ERR(keyring_ref)) {
+		ret = PTR_ERR(keyring_ref);
 		goto error;
 	}
 
-	key = lookup_user_key(NULL, id, 0, 0, 0);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 0, 0, 0);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error2;
 	}
 
-	ret = key_unlink(keyring, key);
+	ret = key_unlink(key_deref(keyring_ref), key_deref(key_ref));
 
-	key_put(key);
+	key_put(key_deref(key_ref));
  error2:
-	key_put(keyring);
+	key_put(key_deref(keyring_ref));
  error:
 	return ret;
 
@@ -475,25 +477,27 @@ long keyctl_describe_key(key_serial_t ke
 			 char __user *buffer,
 			 size_t buflen)
 {
+	struct key_ref *key_ref;
 	struct key *key, *instkey;
 	char *tmpbuf;
 	long ret;
 
-	key = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
-	if (IS_ERR(key)) {
+	key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
+	if (IS_ERR(key_ref)) {
 		/* viewing a key under construction is permitted if we have the
 		 * authorisation token handy */
-		if (PTR_ERR(key) == -EACCES) {
+		if (PTR_ERR(key_ref) == -EACCES) {
 			instkey = key_get_instantiation_authkey(keyid);
 			if (!IS_ERR(instkey)) {
 				key_put(instkey);
-				key = lookup_user_key(NULL, keyid, 0, 1, 0);
-				if (!IS_ERR(key))
+				key_ref = lookup_user_key(NULL, keyid,
+							  0, 1, 0);
+				if (!IS_ERR(key_ref))
 					goto okay;
 			}
 		}
 
-		ret = PTR_ERR(key);
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
@@ -504,13 +508,16 @@ okay:
 	if (!tmpbuf)
 		goto error2;
 
+	key = key_deref(key_ref);
+
 	ret = snprintf(tmpbuf, PAGE_SIZE - 1,
-		       "%s;%d;%d;%06x;%s",
-		       key->type->name,
-		       key->uid,
-		       key->gid,
-		       key->perm,
-		       key->description ? key->description :""
+		       "%s;%d;%d;%08x;%s",
+		       key_deref(key_ref)->type->name,
+		       key_deref(key_ref)->uid,
+		       key_deref(key_ref)->gid,
+		       key_deref(key_ref)->perm,
+		       key_deref(key_ref)->description ?
+		       key_deref(key_ref)->description : ""
 		       );
 
 	/* include a NUL char at the end of the data */
@@ -530,7 +537,7 @@ okay:
 
 	kfree(tmpbuf);
  error2:
-	key_put(key);
+	key_put(key_deref(key_ref));
  error:
 	return ret;
 
@@ -552,7 +559,7 @@ long keyctl_keyring_search(key_serial_t 
 			   key_serial_t destringid)
 {
 	struct key_type *ktype;
-	struct key *keyring, *key, *dest;
+	struct key_ref *keyring_ref, *key_ref, *dest_ref;
 	char type[32], *description;
 	long dlen, ret;
 
@@ -581,18 +588,18 @@ long keyctl_keyring_search(key_serial_t 
 		goto error2;
 
 	/* get the keyring at which to begin the search */
-	keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
+	keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
+	if (IS_ERR(keyring_ref)) {
+		ret = PTR_ERR(keyring_ref);
 		goto error2;
 	}
 
 	/* get the destination keyring if specified */
-	dest = NULL;
+	dest_ref = NULL;
 	if (destringid) {
-		dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
-		if (IS_ERR(dest)) {
-			ret = PTR_ERR(dest);
+		dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+		if (IS_ERR(dest_ref)) {
+			ret = PTR_ERR(dest_ref);
 			goto error3;
 		}
 	}
@@ -605,9 +612,9 @@ long keyctl_keyring_search(key_serial_t 
 	}
 
 	/* do the search */
-	key = keyring_search(keyring, ktype, description);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = keyring_search(keyring_ref, ktype, description);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 
 		/* treat lack or presence of a negative key the same */
 		if (ret == -EAGAIN)
@@ -616,26 +623,26 @@ long keyctl_keyring_search(key_serial_t 
 	}
 
 	/* link the resulting key to the destination keyring if we can */
-	if (dest) {
+	if (dest_ref) {
 		ret = -EACCES;
-		if (!key_permission(key, KEY_LINK))
+		if (!key_permission(key_ref, KEY_LINK))
 			goto error6;
 
-		ret = key_link(dest, key);
+		ret = key_link(key_deref(dest_ref), key_deref(key_ref));
 		if (ret < 0)
 			goto error6;
 	}
 
-	ret = key->serial;
+	ret = key_deref(key_ref)->serial;
 
  error6:
-	key_put(key);
+	key_put(key_deref(key_ref));
  error5:
 	key_type_put(ktype);
  error4:
-	key_put(dest);
+	key_put(key_deref(dest_ref));
  error3:
-	key_put(keyring);
+	key_put(key_deref(keyring_ref));
  error2:
 	kfree(description);
  error:
@@ -645,16 +652,6 @@ long keyctl_keyring_search(key_serial_t 
 
 /*****************************************************************************/
 /*
- * see if the key we're looking at is the target key
- */
-static int keyctl_read_key_same(const struct key *key, const void *target)
-{
-	return key == target;
-
-} /* end keyctl_read_key_same() */
-
-/*****************************************************************************/
-/*
  * read a user key's payload
  * - the keyring must be readable or the key must be searchable from the
  *   process's keyrings
@@ -665,38 +662,33 @@ static int keyctl_read_key_same(const st
  */
 long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
 {
-	struct key *key, *skey;
+	struct key_ref *key_ref;
+	struct key *key;
 	long ret;
 
 	/* find the key first */
-	key = lookup_user_key(NULL, keyid, 0, 0, 0);
-	if (!IS_ERR(key)) {
-		/* see if we can read it directly */
-		if (key_permission(key, KEY_READ))
-			goto can_read_key;
-
-		/* we can't; see if it's searchable from this process's
-		 * keyrings
-		 * - we automatically take account of the fact that it may be
-		 *   dangling off an instantiation key
-		 */
-		skey = search_process_keyrings(key->type, key,
-					       keyctl_read_key_same, current);
-		if (!IS_ERR(skey))
-			goto can_read_key2;
+	key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);
+	if (IS_ERR(key_ref)) {
+		ret = -ENOKEY;
+		goto error;
+	}
 
-		ret = PTR_ERR(skey);
-		if (ret == -EAGAIN)
-			ret = -EACCES;
+	key = key_deref(key_ref);
+
+	/* see if we can read it directly */
+	if (key_permission(key_ref, KEY_READ))
+		goto can_read_key;
+
+	/* we can't; see if it's searchable from this process's keyrings
+	 * - we automatically take account of the fact that it may be
+	 *   dangling off an instantiation key
+	 */
+	if (!is_key_possessed(key_ref)) {
+		ret = -EACCES;
 		goto error2;
 	}
 
-	ret = -ENOKEY;
-	goto error;
-
 	/* the key is probably readable - now try to read it */
- can_read_key2:
-	key_put(skey);
  can_read_key:
 	ret = key_validate(key);
 	if (ret == 0) {
@@ -726,6 +718,7 @@ long keyctl_read_key(key_serial_t keyid,
  */
 long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
 {
+	struct key_ref *key_ref;
 	struct key *key;
 	long ret;
 
@@ -733,12 +726,14 @@ long keyctl_chown_key(key_serial_t id, u
 	if (uid == (uid_t) -1 && gid == (gid_t) -1)
 		goto error;
 
-	key = lookup_user_key(NULL, id, 1, 1, 0);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 1, 1, 0);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
+	key = key_deref(key_ref);
+
 	/* make the changes with the locks held to prevent chown/chown races */
 	ret = -EACCES;
 	down_write(&key->sem);
@@ -783,19 +778,22 @@ long keyctl_chown_key(key_serial_t id, u
  */
 long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
 {
+	struct key_ref *key_ref;
 	struct key *key;
 	long ret;
 
 	ret = -EINVAL;
-	if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
+	if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
 		goto error;
 
-	key = lookup_user_key(NULL, id, 1, 1, 0);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 1, 1, 0);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
+	key = key_deref(key_ref);
+
 	/* make the changes with the locks held to prevent chown/chmod races */
 	ret = -EACCES;
 	down_write(&key->sem);
@@ -824,7 +822,8 @@ long keyctl_instantiate_key(key_serial_t
 			    key_serial_t ringid)
 {
 	struct request_key_auth *rka;
-	struct key *instkey, *keyring;
+	struct key_ref *keyring_ref;
+	struct key *instkey;
 	void *payload;
 	long ret;
 
@@ -857,21 +856,21 @@ long keyctl_instantiate_key(key_serial_t
 
 	/* find the destination keyring amongst those belonging to the
 	 * requesting task */
-	keyring = NULL;
+	keyring_ref = NULL;
 	if (ringid) {
-		keyring = lookup_user_key(rka->context, ringid, 1, 0,
-					  KEY_WRITE);
-		if (IS_ERR(keyring)) {
-			ret = PTR_ERR(keyring);
+		keyring_ref = lookup_user_key(rka->context, ringid, 1, 0,
+					      KEY_WRITE);
+		if (IS_ERR(keyring_ref)) {
+			ret = PTR_ERR(keyring_ref);
 			goto error3;
 		}
 	}
 
 	/* instantiate the key and link it into a keyring */
 	ret = key_instantiate_and_link(rka->target_key, payload, plen,
-				       keyring, instkey);
+				       key_deref(keyring_ref), instkey);
 
-	key_put(keyring);
+	key_put(key_deref(keyring_ref));
  error3:
 	key_put(instkey);
  error2:
@@ -889,7 +888,8 @@ long keyctl_instantiate_key(key_serial_t
 long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
 {
 	struct request_key_auth *rka;
-	struct key *instkey, *keyring;
+	struct key_ref *keyring_ref;
+	struct key *instkey;
 	long ret;
 
 	/* find the instantiation authorisation key */
@@ -903,19 +903,20 @@ long keyctl_negate_key(key_serial_t id, 
 
 	/* find the destination keyring if present (which must also be
 	 * writable) */
-	keyring = NULL;
+	keyring_ref = NULL;
 	if (ringid) {
-		keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-		if (IS_ERR(keyring)) {
-			ret = PTR_ERR(keyring);
+		keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+		if (IS_ERR(keyring_ref)) {
+			ret = PTR_ERR(keyring_ref);
 			goto error2;
 		}
 	}
 
 	/* instantiate the key and link it into a keyring */
-	ret = key_negate_and_link(rka->target_key, timeout, keyring, instkey);
+	ret = key_negate_and_link(rka->target_key, timeout,
+				  key_deref(keyring_ref), instkey);
 
-	key_put(keyring);
+	key_put(key_deref(keyring_ref));
  error2:
 	key_put(instkey);
  error:
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/keyring.c linux-2.6.14-rc1-mm1-keys/security/keys/keyring.c
--- linux-2.6.14-rc1-mm1/security/keys/keyring.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/keyring.c	2005-09-21 14:34:02.000000000 +0100
@@ -309,7 +309,7 @@ struct key *keyring_alloc(const char *de
 	int ret;
 
 	keyring = key_alloc(&key_type_keyring, description,
-			    uid, gid, KEY_USR_ALL, not_in_quota);
+			    uid, gid, KEY_POS_ALL | KEY_USR_ALL, not_in_quota);
 
 	if (!IS_ERR(keyring)) {
 		ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
@@ -333,12 +333,13 @@ struct key *keyring_alloc(const char *de
  * - we rely on RCU to prevent the keyring lists from disappearing on us
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we only found negative matching keys
+ * - we propagate the possession attribute from the keyring ref to the key ref
  */
-struct key *keyring_search_aux(struct key *keyring,
-			       struct task_struct *context,
-			       struct key_type *type,
-			       const void *description,
-			       key_match_func_t match)
+struct key_ref *keyring_search_aux(struct key_ref *keyring_ref,
+				   struct task_struct *context,
+				   struct key_type *type,
+				   const void *description,
+				   key_match_func_t match)
 {
 	struct {
 		struct keyring_list *keylist;
@@ -347,29 +348,33 @@ struct key *keyring_search_aux(struct ke
 
 	struct keyring_list *keylist;
 	struct timespec now;
-	struct key *key;
+	struct key_ref *key_ref;
+	unsigned long possessed;
+	struct key *keyring, *key;
 	long err;
 	int sp, kix;
 
+	keyring = key_deref(keyring_ref);
+	possessed = is_key_possessed(keyring_ref);
 	key_check(keyring);
 
-	rcu_read_lock();
-
 	/* top keyring must have search permission to begin the search */
-	key = ERR_PTR(-EACCES);
-	if (!key_task_permission(keyring, context, KEY_SEARCH))
+	key_ref = ERR_PTR(-EACCES);
+	if (!key_task_permission(keyring_ref, context, KEY_SEARCH))
 		goto error;
 
-	key = ERR_PTR(-ENOTDIR);
+	key_ref = ERR_PTR(-ENOTDIR);
 	if (keyring->type != &key_type_keyring)
 		goto error;
 
+	rcu_read_lock();
+
 	now = current_kernel_time();
 	err = -EAGAIN;
 	sp = 0;
 
 	/* start processing a new keyring */
- descend:
+descend:
 	if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
 		goto not_this_keyring;
 
@@ -397,7 +402,8 @@ struct key *keyring_search_aux(struct ke
 			continue;
 
 		/* key must have search permissions */
-		if (!key_task_permission(key, context, KEY_SEARCH))
+		if (!key_task_permission(key_mkref(key, possessed),
+					 context, KEY_SEARCH))
 			continue;
 
 		/* we set a different error code if we find a negative key */
@@ -411,7 +417,7 @@ struct key *keyring_search_aux(struct ke
 
 	/* search through the keyrings nested in this one */
 	kix = 0;
- ascend:
+ascend:
 	for (; kix < keylist->nkeys; kix++) {
 		key = keylist->keys[kix];
 		if (key->type != &key_type_keyring)
@@ -423,7 +429,8 @@ struct key *keyring_search_aux(struct ke
 		if (sp >= KEYRING_SEARCH_MAX_DEPTH)
 			continue;
 
-		if (!key_task_permission(key, context, KEY_SEARCH))
+		if (!key_task_permission(key_mkref(key, possessed),
+					 context, KEY_SEARCH))
 			continue;
 
 		/* stack the current position */
@@ -438,7 +445,7 @@ struct key *keyring_search_aux(struct ke
 
 	/* the keyring we're looking at was disqualified or didn't contain a
 	 * matching key */
- not_this_keyring:
+not_this_keyring:
 	if (sp > 0) {
 		/* resume the processing of a keyring higher up in the tree */
 		sp--;
@@ -447,16 +454,18 @@ struct key *keyring_search_aux(struct ke
 		goto ascend;
 	}
 
-	key = ERR_PTR(err);
-	goto error;
+	key_ref = ERR_PTR(err);
+	goto error_2;
 
 	/* we found a viable match */
- found:
+found:
 	atomic_inc(&key->usage);
 	key_check(key);
- error:
+	key_ref = key_mkref(key, possessed);
+error_2:
 	rcu_read_unlock();
-	return key;
+error:
+	return key_ref;
 
 } /* end keyring_search_aux() */
 
@@ -469,9 +478,9 @@ struct key *keyring_search_aux(struct ke
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we only found negative matching keys
  */
-struct key *keyring_search(struct key *keyring,
-			   struct key_type *type,
-			   const char *description)
+struct key_ref *keyring_search(struct key_ref *keyring,
+			       struct key_type *type,
+			       const char *description)
 {
 	if (!type->match)
 		return ERR_PTR(-ENOKEY);
@@ -488,15 +497,19 @@ EXPORT_SYMBOL(keyring_search);
  * search the given keyring only (no recursion)
  * - keyring must be locked by caller
  */
-struct key *__keyring_search_one(struct key *keyring,
-				 const struct key_type *ktype,
-				 const char *description,
-				 key_perm_t perm)
+struct key_ref *__keyring_search_one(struct key_ref *keyring_ref,
+				     const struct key_type *ktype,
+				     const char *description,
+				     key_perm_t perm)
 {
 	struct keyring_list *klist;
-	struct key *key;
+	unsigned long possessed;
+	struct key *keyring, *key;
 	int loop;
 
+	keyring = key_deref(keyring_ref);
+	possessed = is_key_possessed(keyring_ref);
+
 	rcu_read_lock();
 
 	klist = rcu_dereference(keyring->payload.subscriptions);
@@ -507,21 +520,20 @@ struct key *__keyring_search_one(struct 
 			if (key->type == ktype &&
 			    (!key->type->match ||
 			     key->type->match(key, description)) &&
-			    key_permission(key, perm) &&
+			    key_permission(key_mkref(key, possessed), perm) &&
 			    !test_bit(KEY_FLAG_REVOKED, &key->flags)
 			    )
 				goto found;
 		}
 	}
 
-	key = ERR_PTR(-ENOKEY);
-	goto error;
+	rcu_read_unlock();
+	return ERR_PTR(-ENOKEY);
 
  found:
 	atomic_inc(&key->usage);
- error:
 	rcu_read_unlock();
-	return key;
+	return key_mkref(key, possessed);
 
 } /* end __keyring_search_one() */
 
@@ -603,7 +615,7 @@ struct key *find_keyring_by_name(const c
 			if (strcmp(keyring->description, name) != 0)
 				continue;
 
-			if (!key_permission(keyring, KEY_SEARCH))
+			if (!key_permission(key_mkref(keyring, 0), KEY_SEARCH))
 				continue;
 
 			/* found a potential candidate, but we still need to
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/proc.c linux-2.6.14-rc1-mm1-keys/security/keys/proc.c
--- linux-2.6.14-rc1-mm1/security/keys/proc.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/proc.c	2005-09-21 13:35:36.000000000 +0100
@@ -167,7 +167,7 @@ static int proc_keys_show(struct seq_fil
 #define showflag(KEY, LETTER, FLAG) \
 	(test_bit(FLAG,	&(KEY)->flags) ? LETTER : '-')
 
-	seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %06x %5d %5d %-9.9s ",
+	seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ",
 		   key->serial,
 		   showflag(key, 'I', KEY_FLAG_INSTANTIATED),
 		   showflag(key, 'R', KEY_FLAG_REVOKED),
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/process_keys.c linux-2.6.14-rc1-mm1-keys/security/keys/process_keys.c
--- linux-2.6.14-rc1-mm1/security/keys/process_keys.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/process_keys.c	2005-09-21 13:45:22.000000000 +0100
@@ -39,7 +39,7 @@ struct key root_user_keyring = {
 	.type		= &key_type_keyring,
 	.user		= &root_key_user,
 	.sem		= __RWSEM_INITIALIZER(root_user_keyring.sem),
-	.perm		= KEY_USR_ALL,
+	.perm		= KEY_POS_ALL | KEY_USR_ALL,
 	.flags		= 1 << KEY_FLAG_INSTANTIATED,
 	.description	= "_uid.0",
 #ifdef KEY_DEBUGGING
@@ -54,7 +54,7 @@ struct key root_session_keyring = {
 	.type		= &key_type_keyring,
 	.user		= &root_key_user,
 	.sem		= __RWSEM_INITIALIZER(root_session_keyring.sem),
-	.perm		= KEY_USR_ALL,
+	.perm		= KEY_POS_ALL | KEY_USR_ALL,
 	.flags		= 1 << KEY_FLAG_INSTANTIATED,
 	.description	= "_uid_ses.0",
 #ifdef KEY_DEBUGGING
@@ -98,7 +98,7 @@ int alloc_uid_keyring(struct user_struct
 	user->session_keyring = session_keyring;
 	ret = 0;
 
- error:
+error:
 	return ret;
 
 } /* end alloc_uid_keyring() */
@@ -156,7 +156,7 @@ int install_thread_keyring(struct task_s
 	ret = 0;
 
 	key_put(old);
- error:
+error:
 	return ret;
 
 } /* end install_thread_keyring() */
@@ -193,7 +193,7 @@ int install_process_keyring(struct task_
 	}
 
 	ret = 0;
- error:
+error:
 	return ret;
 
 } /* end install_process_keyring() */
@@ -236,7 +236,7 @@ static int install_session_keyring(struc
 	/* we're using RCU on the pointer */
 	synchronize_rcu();
 	key_put(old);
- error:
+error:
 	return ret;
 
 } /* end install_session_keyring() */
@@ -376,13 +376,13 @@ void key_fsgid_changed(struct task_struc
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we found only negative matching keys
  */
-struct key *search_process_keyrings(struct key_type *type,
-				    const void *description,
-				    key_match_func_t match,
-				    struct task_struct *context)
+struct key_ref *search_process_keyrings(struct key_type *type,
+					const void *description,
+					key_match_func_t match,
+					struct task_struct *context)
 {
 	struct request_key_auth *rka;
-	struct key *key, *ret, *err, *instkey;
+	struct key_ref *key, *ret, *err, *instkey;
 
 	/* 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;
@@ -397,7 +397,7 @@ struct key *search_process_keyrings(stru
 
 	/* search the thread keyring first */
 	if (context->thread_keyring) {
-		key = keyring_search_aux(context->thread_keyring,
+		key = keyring_search_aux(key_mkref(context->thread_keyring, 1),
 					 context, type, description, match);
 		if (!IS_ERR(key))
 			goto found;
@@ -417,8 +417,9 @@ struct key *search_process_keyrings(stru
 
 	/* search the process keyring second */
 	if (context->signal->process_keyring) {
-		key = keyring_search_aux(context->signal->process_keyring,
-					 context, type, description, match);
+		key = keyring_search_aux(
+			key_mkref(context->signal->process_keyring, 1),
+			context, type, description, match);
 		if (!IS_ERR(key))
 			goto found;
 
@@ -439,7 +440,7 @@ struct key *search_process_keyrings(stru
 	if (context->signal->session_keyring) {
 		rcu_read_lock();
 		key = keyring_search_aux(
-			rcu_dereference(context->signal->session_keyring),
+			key_mkref(rcu_dereference(context->signal->session_keyring), 1),
 			context, type, description, match);
 		rcu_read_unlock();
 
@@ -466,18 +467,18 @@ struct key *search_process_keyrings(stru
 
 		rcu_read_lock();
 		instkey = __keyring_search_one(
-			rcu_dereference(context->signal->session_keyring),
+			key_mkref(rcu_dereference(context->signal->session_keyring), 1),
 			&key_type_request_key_auth, NULL, 0);
 		rcu_read_unlock();
 
 		if (IS_ERR(instkey))
 			goto no_key;
 
-		rka = instkey->payload.data;
+		rka = key_deref(instkey)->payload.data;
 
 		key = search_process_keyrings(type, description, match,
 					      rka->context);
-		key_put(instkey);
+		key_put(key_deref(instkey));
 
 		if (!IS_ERR(key))
 			goto found;
@@ -496,8 +497,9 @@ struct key *search_process_keyrings(stru
 	}
 	/* or search the user-session keyring */
 	else {
-		key = keyring_search_aux(context->user->session_keyring,
-					 context, type, description, match);
+		key = keyring_search_aux(
+			key_mkref(context->user->session_keyring, 1),
+			context, type, description, match);
 		if (!IS_ERR(key))
 			goto found;
 
@@ -526,20 +528,31 @@ found:
 
 /*****************************************************************************/
 /*
+ * see if the key we're looking at is the target key
+ */
+static int lookup_user_key_possessed(const struct key *key, const void *target)
+{
+	return key == target;
+
+} /* end lookup_user_key_possessed() */
+
+/*****************************************************************************/
+/*
  * lookup a key given a key ID from userspace with a given permissions mask
  * - don't create special keyrings unless so requested
  * - partially constructed keys aren't found unless requested
  */
-struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
-			    int create, int partial, key_perm_t perm)
+struct key_ref *lookup_user_key(struct task_struct *context, key_serial_t id,
+				int create, int partial, key_perm_t perm)
 {
+	struct key_ref *key_ref, *skey;
 	struct key *key;
 	int ret;
 
 	if (!context)
 		context = current;
 
-	key = ERR_PTR(-ENOKEY);
+	key_ref = ERR_PTR(-ENOKEY);
 
 	switch (id) {
 	case KEY_SPEC_THREAD_KEYRING:
@@ -556,6 +569,7 @@ struct key *lookup_user_key(struct task_
 
 		key = context->thread_keyring;
 		atomic_inc(&key->usage);
+		key_ref = key_mkref(key, 1);
 		break;
 
 	case KEY_SPEC_PROCESS_KEYRING:
@@ -572,6 +586,7 @@ struct key *lookup_user_key(struct task_
 
 		key = context->signal->process_keyring;
 		atomic_inc(&key->usage);
+		key_ref = key_mkref(key, 1);
 		break;
 
 	case KEY_SPEC_SESSION_KEYRING:
@@ -579,7 +594,7 @@ struct key *lookup_user_key(struct task_
 			/* always install a session keyring upon access if one
 			 * doesn't exist yet */
 			ret = install_session_keyring(
-			       context, context->user->session_keyring);
+				context, context->user->session_keyring);
 			if (ret < 0)
 				goto error;
 		}
@@ -588,16 +603,19 @@ struct key *lookup_user_key(struct task_
 		key = rcu_dereference(context->signal->session_keyring);
 		atomic_inc(&key->usage);
 		rcu_read_unlock();
+		key_ref = key_mkref(key, 1);
 		break;
 
 	case KEY_SPEC_USER_KEYRING:
 		key = context->user->uid_keyring;
 		atomic_inc(&key->usage);
+		key_ref = key_mkref(key, 1);
 		break;
 
 	case KEY_SPEC_USER_SESSION_KEYRING:
 		key = context->user->session_keyring;
 		atomic_inc(&key->usage);
+		key_ref = key_mkref(key, 1);
 		break;
 
 	case KEY_SPEC_GROUP_KEYRING:
@@ -606,13 +624,28 @@ struct key *lookup_user_key(struct task_
 		goto error;
 
 	default:
-		key = ERR_PTR(-EINVAL);
+		key_ref = ERR_PTR(-EINVAL);
 		if (id < 1)
 			goto error;
 
 		key = key_lookup(id);
-		if (IS_ERR(key))
+		if (IS_ERR(key)) {
+			key_ref = ERR_PTR(PTR_ERR(key));
 			goto error;
+		}
+
+		key_ref = key_mkref(key, 0);
+
+		/* check to see if we possess the key */
+		skey = search_process_keyrings(key->type, key,
+					       lookup_user_key_possessed,
+					       current);
+
+		if (!IS_ERR(skey)) {
+			key_put(key);
+			key_ref = skey;
+		}
+
 		break;
 	}
 
@@ -630,15 +663,15 @@ struct key *lookup_user_key(struct task_
 	/* check the permissions */
 	ret = -EACCES;
 
-	if (!key_task_permission(key, context, perm))
+	if (!key_task_permission(key_ref, context, perm))
 		goto invalid_key;
 
- error:
-	return key;
+error:
+	return key_ref;
 
- invalid_key:
-	key_put(key);
-	key = ERR_PTR(ret);
+invalid_key:
+	key_put(key_deref(key_ref));
+	key_ref = ERR_PTR(ret);
 	goto error;
 
 } /* end lookup_user_key() */
@@ -694,9 +727,9 @@ long join_session_keyring(const char *na
 	ret = keyring->serial;
 	key_put(keyring);
 
- error2:
+error2:
 	up(&key_session_sem);
- error:
+error:
 	return ret;
 
 } /* end join_session_keyring() */
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/request_key_auth.c linux-2.6.14-rc1-mm1-keys/security/keys/request_key_auth.c
--- linux-2.6.14-rc1-mm1/security/keys/request_key_auth.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/request_key_auth.c	2005-09-21 13:48:24.000000000 +0100
@@ -126,7 +126,7 @@ struct key *request_key_auth_new(struct 
 
 	rkakey = key_alloc(&key_type_request_key_auth, desc,
 			   current->fsuid, current->fsgid,
-			   KEY_USR_VIEW, 1);
+			   KEY_POS_VIEW | KEY_USR_VIEW, 1);
 	if (IS_ERR(rkakey)) {
 		key_put(keyring);
 		kleave("= %ld", PTR_ERR(rkakey));
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/request_key.c linux-2.6.14-rc1-mm1-keys/security/keys/request_key.c
--- linux-2.6.14-rc1-mm1/security/keys/request_key.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/request_key.c	2005-09-21 18:43:03.000000000 +0100
@@ -129,7 +129,7 @@ static struct key *__request_key_constru
 
 	/* create a key and add it to the queue */
 	key = key_alloc(type, description,
-			current->fsuid, current->fsgid, KEY_USR_ALL, 0);
+			current->fsuid, current->fsgid, KEY_POS_ALL, 0);
 	if (IS_ERR(key))
 		goto alloc_failed;
 
@@ -364,15 +364,25 @@ struct key *request_key_and_link(struct 
 				 struct key *dest_keyring)
 {
 	struct key_user *user;
+	struct key_ref *key_ref;
 	struct key *key;
 
 	kenter("%s,%s,%s,%p",
 	       type->name, description, callout_info, dest_keyring);
 
 	/* search all the process keyrings for a key */
-	key = search_process_keyrings(type, description, type->match, current);
+	key_ref = search_process_keyrings(type, description, type->match,
+					  current);
 
-	if (PTR_ERR(key) == -EAGAIN) {
+	kdebug("search 1: %p", key_ref);
+
+	if (!IS_ERR(key_ref)) {
+		key = key_deref(key_ref);
+	}
+	else if (PTR_ERR(key_ref) != -EAGAIN) {
+		key = ERR_PTR(PTR_ERR(key_ref));
+	}
+	else  {
 		/* the search failed, but the keyrings were searchable, so we
 		 * should consult userspace if we can */
 		key = ERR_PTR(-ENOKEY);
@@ -384,7 +394,7 @@ struct key *request_key_and_link(struct 
 		if (!user)
 			goto nomem;
 
-		do {
+		for (;;) {
 			if (signal_pending(current))
 				goto interrupted;
 
@@ -397,10 +407,22 @@ struct key *request_key_and_link(struct 
 
 			/* someone else made the key we want, so we need to
 			 * search again as it might now be available to us */
-			key = search_process_keyrings(type, description,
-						      type->match, current);
+			key_ref = search_process_keyrings(type, description,
+							  type->match,
+							  current);
+
+			kdebug("search 2: %p", key_ref);
 
-		} while (PTR_ERR(key) == -EAGAIN);
+			if (!IS_ERR(key_ref)) {
+				key = key_deref(key_ref);
+				break;
+			}
+
+			if (PTR_ERR(key_ref) != -EAGAIN) {
+				key = ERR_PTR(PTR_ERR(key_ref));
+				break;
+			}
+		}
 
 		key_user_put(user);
 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Keys: Add possessor permissions to keys
  2005-09-21 17:15   ` Andrew Morton
  2005-09-21 17:47     ` Trond Myklebust
@ 2005-09-21 18:36     ` David Howells
  1 sibling, 0 replies; 14+ messages in thread
From: David Howells @ 2005-09-21 18:36 UTC (permalink / raw)
  To: Trond Myklebust
  Cc: Andrew Morton, David Howells, torvalds, keyrings, linux-kernel

Trond Myklebust <trond.myklebust@fys.uio.no> wrote:

> 
> Shouldn't that test for IS_ERR(key_ref) be inverted?

Yes, and it should come first.

David

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Keys: Add possessor permissions to keys
  2005-09-21 18:29   ` David Howells
@ 2005-09-21 18:45     ` Andrew Morton
  2005-09-21 18:56       ` Linus Torvalds
  2005-09-22 10:00       ` David Howells
  2005-10-03  4:43     ` [Keyrings] " Kyle Moffett
  1 sibling, 2 replies; 14+ messages in thread
From: Andrew Morton @ 2005-09-21 18:45 UTC (permalink / raw)
  To: David Howells; +Cc: dhowells, torvalds, keyrings, linux-kernel

David Howells <dhowells@redhat.com> wrote:
>
> Andrew Morton <akpm@osdl.org> wrote:
> 
> > The above bit needs to be captured in a code comment.  Because:
> 
> Okay.
> 
> > Is hair-raising and makes people want to come after you with a stick ;)
> 
> If people get upset by this sort of thing, they shouldn't be doing kernel
> development.

hrmph.  Of course it's a reasonable trick from a performance and
convenience and resource consumption POV.  But it's a new idiom and the
threshold for new idioms is non-zero.  We use it in struct page, but struct
page is special.

It does need really obvious commenting.  Pity the poor person who spends
ten miniutes trying to find the definition of struct key_ref.

> ...
> > > +			if (PTR_ERR(key_ref) != -EAGAIN) {
> > > +				if (IS_ERR(key_ref))
> > > +					key = key_deref(key_ref);
> > > +				else
> > > +					key = ERR_PTR(PTR_ERR(key_ref));
> > > +				break;
> > > +			}
> > > +		}
> > 
> > That's getting a bit intimate with how IS_ERR and PTR_ERR are implemented
> > but I guess we're unlikely to change that.
> 
> You're referring to the ordering of the first two lines? I could, and probably
> should, reorder them.

Yup.  Logically we shouldn't use PTR_ERR unless IS_ERR is known to be true.
Yes, it works and yes, it'll surely continue to work.  But.

> It's also wrong: there should be a ! before the IS_ERR.
> 
> I've changed this to:
> 
> 			if (!IS_ERR(key_ref)) {
> 				key = key_deref(key_ref);
> 				break;
> 			}
> 
> 			if (PTR_ERR(key_ref) != -EAGAIN) {
> 				key = ERR_PTR(PTR_ERR(key_ref));
> 				break;
> 			}

OK.

> > This all seems quite inappropriate to -rc2?
> 
> Which -rc2? If it's 2.6.14-rc2 you're referring to, then yes - that's already
> released.

It doesn't fix any bugs (does it?).  Hence according to the shiny new rules
this work is 2.6.15 material.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Keys: Add possessor permissions to keys
  2005-09-21 18:45     ` Andrew Morton
@ 2005-09-21 18:56       ` Linus Torvalds
  2005-09-22 10:00       ` David Howells
  1 sibling, 0 replies; 14+ messages in thread
From: Linus Torvalds @ 2005-09-21 18:56 UTC (permalink / raw)
  To: Andrew Morton; +Cc: David Howells, keyrings, linux-kernel



On Wed, 21 Sep 2005, Andrew Morton wrote:
> 
> hrmph.  Of course it's a reasonable trick from a performance and
> convenience and resource consumption POV.  But it's a new idiom and the
> threshold for new idioms is non-zero.  We use it in struct page, but struct
> page is special.

Hmm.. I don't feel it is that new, but maybe that's because I've used that 
trick in other places. I think it's pretty common in a "type-safe C" way, 
and it should probably be encouraged. A unique pointer type for special 
usages, that you can't dereference even by mistake..

But adding a few comments might certainly be worth it. If only to teach 
others the trick.

		Linus

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Keys: Add possessor permissions to keys
  2005-09-21 14:48 ` [PATCH] Keys: Add possessor permissions to keys David Howells
                     ` (3 preceding siblings ...)
  2005-09-21 18:29   ` David Howells
@ 2005-09-21 19:23   ` James Morris
  4 siblings, 0 replies; 14+ messages in thread
From: James Morris @ 2005-09-21 19:23 UTC (permalink / raw)
  To: David Howells; +Cc: torvalds, akpm, keyrings, linux-kernel

On Wed, 21 Sep 2005, David Howells wrote:


> +	if (is_key_possessed(key_ref)) {
> +		kperm = key->perm >> 24;
> +	}
> +	else if (key->uid == context->fsuid) {
>  		kperm = key->perm >> 16;

Can you use macros for these magic numbers?


- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] Keys: Add possessor permissions to keys
  2005-09-21 18:45     ` Andrew Morton
  2005-09-21 18:56       ` Linus Torvalds
@ 2005-09-22 10:00       ` David Howells
  1 sibling, 0 replies; 14+ messages in thread
From: David Howells @ 2005-09-22 10:00 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Andrew Morton, David Howells, keyrings, linux-kernel

Linus Torvalds <torvalds@osdl.org> wrote:

> > hrmph.  Of course it's a reasonable trick from a performance and
> > convenience and resource consumption POV.  But it's a new idiom and the
> > threshold for new idioms is non-zero.  We use it in struct page, but struct
> > page is special.
> 
> Hmm.. I don't feel it is that new, but maybe that's because I've used that 
> trick in other places. I think it's pretty common in a "type-safe C" way, 
> and it should probably be encouraged. A unique pointer type for special 
> usages, that you can't dereference even by mistake..

It's something that C isn't particularly good at. C++ is better at this as you
can define a class and overload the -> operator and the unary * operator if
you're feeling particularly evil or adventurous. But C it is...

> But adding a few comments might certainly be worth it. If only to teach 
> others the trick.

Maybe there should be some naming convention for quasi-pointers like this? I
could typedef it, for instance, and hang comments appropriate to its nature of
the typedef. Perhaps:

	typedef struct __key_ref_with_possession_attribute *key_ref;

And then give its accessor functions capital letters to make them stand out,
though that might give the false impression that they're actually preprocessor
macros.

Or perhaps I should rename two of the functions:

	key_mkref() -> construct_key_ref()
	key_deref() -> convert_key_ref_to_ptr() or extract_key_ptr()

Would that serve in lieu of commenting every time I use these things?

David

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH] Keys: Add possessor permissions to keys [try #3]
       [not found] <5378.1127211442@warthog.cambridge.redhat.com>
  2005-09-21 14:48 ` [PATCH] Keys: Add possessor permissions to keys David Howells
  2005-09-21 18:33 ` [PATCH] Keys: Add possessor permissions to keys [try #2] David Howells
@ 2005-09-28 16:03 ` David Howells
  2 siblings, 0 replies; 14+ messages in thread
From: David Howells @ 2005-09-28 16:03 UTC (permalink / raw)
  To: torvalds, akpm; +Cc: keyrings, linux-kernel


The attached patch adds extra permission grants to keys for the possessor of a
key in addition to the owner, group and other permissions bits. This makes
SUID binaries easier to support without going as far as labelling keys and key
targets using the LSM facilities.

This patch adds a second "pointer type" to key structures (struct key_ref *)
that can have the bottom bit of the address set to indicate the possession of
a key. This is propagated through searches from the keyring to the discovered
key. It has been made a separate type so that the compiler can spot attempts
to dereference a potentially incorrect pointer.

The "possession" attribute can't be attached to a key structure directly as
it's not an intrinsic property of a key.

Pointers to keys have been replaced with struct key_ref *'s wherever
possession information needs to be passed through.

This does assume that the bottom bit of the pointer will always be zero on
return from kmem_cache_alloc().

The key reference type has been made into a typedef so that at least it can be
located in the sources, even though it's basically a pointer to an undefined
type. I've also renamed the accessor functions to be more useful, and all
reference variables should now end in "_ref".

Signed-Off-By: David Howells <dhowells@redhat.com>
---
warthog>diffstat -p1 keys-possess-2614rc1mm1-3.diff 
 Documentation/keys.txt           |   74 +++++++--
 include/linux/key-ui.h           |   28 ++-
 include/linux/key.h              |   78 ++++++++--
 security/keys/internal.h         |   28 +--
 security/keys/key.c              |   81 +++++-----
 security/keys/keyctl.c           |  299 +++++++++++++++++++--------------------
 security/keys/keyring.c          |   86 ++++++-----
 security/keys/proc.c             |    2 
 security/keys/process_keys.c     |  164 +++++++++++++--------
 security/keys/request_key.c      |   36 +++-
 security/keys/request_key_auth.c |    2 
 11 files changed, 528 insertions(+), 350 deletions(-)

diff -uNrp linux-2.6.14-rc1-mm1/Documentation/keys.txt linux-2.6.14-rc1-mm1-keys/Documentation/keys.txt
--- linux-2.6.14-rc1-mm1/Documentation/keys.txt	2005-08-30 13:56:09.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/Documentation/keys.txt	2005-09-28 16:49:38.000000000 +0100
@@ -195,8 +195,8 @@ KEY ACCESS PERMISSIONS
 ======================
 
 Keys have an owner user ID, a group access ID, and a permissions mask. The mask
-has up to eight bits each for user, group and other access. Only five of each
-set of eight bits are defined. These permissions granted are:
+has up to eight bits each for possessor, user, group and other access. Only
+five of each set of eight bits are defined. These permissions granted are:
 
  (*) View
 
@@ -241,16 +241,16 @@ about the status of the key service:
      type, description and permissions. The payload of the key is not available
      this way:
 
-	SERIAL   FLAGS  USAGE EXPY PERM   UID   GID   TYPE      DESCRIPTION: SUMMARY
-	00000001 I-----    39 perm 1f0000     0     0 keyring   _uid_ses.0: 1/4
-	00000002 I-----     2 perm 1f0000     0     0 keyring   _uid.0: empty
-	00000007 I-----     1 perm 1f0000     0     0 keyring   _pid.1: empty
-	0000018d I-----     1 perm 1f0000     0     0 keyring   _pid.412: empty
-	000004d2 I--Q--     1 perm 1f0000    32    -1 keyring   _uid.32: 1/4
-	000004d3 I--Q--     3 perm 1f0000    32    -1 keyring   _uid_ses.32: empty
-	00000892 I--QU-     1 perm 1f0000     0     0 user      metal:copper: 0
-	00000893 I--Q-N     1  35s 1f0000     0     0 user      metal:silver: 0
-	00000894 I--Q--     1  10h 1f0000     0     0 user      metal:gold: 0
+	SERIAL   FLAGS  USAGE EXPY PERM     UID   GID   TYPE      DESCRIPTION: SUMMARY
+	00000001 I-----    39 perm 1f1f0000     0     0 keyring   _uid_ses.0: 1/4
+	00000002 I-----     2 perm 1f1f0000     0     0 keyring   _uid.0: empty
+	00000007 I-----     1 perm 1f1f0000     0     0 keyring   _pid.1: empty
+	0000018d I-----     1 perm 1f1f0000     0     0 keyring   _pid.412: empty
+	000004d2 I--Q--     1 perm 1f1f0000    32    -1 keyring   _uid.32: 1/4
+	000004d3 I--Q--     3 perm 1f1f0000    32    -1 keyring   _uid_ses.32: empty
+	00000892 I--QU-     1 perm 1f000000     0     0 user      metal:copper: 0
+	00000893 I--Q-N     1  35s 1f1f0000     0     0 user      metal:silver: 0
+	00000894 I--Q--     1  10h 001f0000     0     0 user      metal:gold: 0
 
      The flags are:
 
@@ -637,6 +637,34 @@ call, and the key released upon close. H
 two different users opening the same file is left to the filesystem author to
 solve.
 
+Note that there are two different types of pointers to keys that may be
+encountered:
+
+ (*) struct key *
+
+     This simply points to the key structure itself. Key structures will be at
+     least four-byte aligned.
+
+ (*) key_ref_t
+
+     This is equivalent to a struct key *, but the least significant bit is set
+     if the caller "possesses" the key. By "possession" it is meant that the
+     calling processes has a searchable link to the key from one of its
+     keyrings. There are three functions for dealing with these:
+
+	key_ref_t make_key_ref(const struct key *key,
+			       unsigned long possession);
+
+	struct key *key_ref_to_ptr(const key_ref_t key_ref);
+
+	unsigned long is_key_possessed(const key_ref_t key_ref);
+
+     The first function constructs a key reference from a key pointer and
+     possession information (which must be 0 or 1 and not any other value).
+
+     The second function retrieves the key pointer from a reference and the
+     third retrieves the possession flag.
+
 When accessing a key's payload contents, certain precautions must be taken to
 prevent access vs modification races. See the section "Notes on accessing
 payload contents" for more information.
@@ -665,7 +693,11 @@ payload contents" for more information.
 
 	void key_put(struct key *key);
 
-    This can be called from interrupt context. If CONFIG_KEYS is not set then
+    Or:
+
+	void key_ref_put(key_ref_t key_ref);
+
+    These can be called from interrupt context. If CONFIG_KEYS is not set then
     the argument will not be parsed.
 
 
@@ -689,13 +721,17 @@ payload contents" for more information.
 
 (*) If a keyring was found in the search, this can be further searched by:
 
-	struct key *keyring_search(struct key *keyring,
-				   const struct key_type *type,
-				   const char *description)
+	key_ref_t keyring_search(key_ref_t keyring_ref,
+				 const struct key_type *type,
+				 const char *description)
 
     This searches the keyring tree specified for a matching key. Error ENOKEY
-    is returned upon failure. If successful, the returned key will need to be
-    released.
+    is returned upon failure (use IS_ERR/PTR_ERR to determine). If successful,
+    the returned key will need to be released.
+
+    The possession attribute from the keyring reference is used to control
+    access through the permissions mask and is propagated to the returned key
+    reference pointer if successful.
 
 
 (*) To check the validity of a key, this function can be called:
@@ -732,7 +768,7 @@ More complex payload contents must be al
 key->payload.data. One of the following ways must be selected to access the
 data:
 
- (1) Unmodifyable key type.
+ (1) Unmodifiable key type.
 
      If the key type does not have a modify method, then the key's payload can
      be accessed without any form of locking, provided that it's known to be
diff -uNrp linux-2.6.14-rc1-mm1/include/linux/key.h linux-2.6.14-rc1-mm1-keys/include/linux/key.h
--- linux-2.6.14-rc1-mm1/include/linux/key.h	2005-08-30 13:56:36.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/include/linux/key.h	2005-09-28 16:55:52.000000000 +0100
@@ -35,11 +35,18 @@ struct key;
 
 #undef KEY_DEBUGGING
 
-#define KEY_USR_VIEW	0x00010000	/* user can view a key's attributes */
-#define KEY_USR_READ	0x00020000	/* user can read key payload / view keyring */
-#define KEY_USR_WRITE	0x00040000	/* user can update key payload / add link to keyring */
-#define KEY_USR_SEARCH	0x00080000	/* user can find a key in search / search a keyring */
-#define KEY_USR_LINK	0x00100000	/* user can create a link to a key/keyring */
+#define KEY_POS_VIEW	0x01000000	/* possessor can view a key's attributes */
+#define KEY_POS_READ	0x02000000	/* possessor can read key payload / view keyring */
+#define KEY_POS_WRITE	0x04000000	/* possessor can update key payload / add link to keyring */
+#define KEY_POS_SEARCH	0x08000000	/* possessor can find a key in search / search a keyring */
+#define KEY_POS_LINK	0x10000000	/* possessor can create a link to a key/keyring */
+#define KEY_POS_ALL	0x1f000000
+
+#define KEY_USR_VIEW	0x00010000	/* user permissions... */
+#define KEY_USR_READ	0x00020000
+#define KEY_USR_WRITE	0x00040000
+#define KEY_USR_SEARCH	0x00080000
+#define KEY_USR_LINK	0x00100000
 #define KEY_USR_ALL	0x001f0000
 
 #define KEY_GRP_VIEW	0x00000100	/* group permissions... */
@@ -67,6 +74,38 @@ struct keyring_name;
 
 /*****************************************************************************/
 /*
+ * key reference with possession attribute handling
+ *
+ * NOTE! key_ref_t is a typedef'd pointer to a type that is not actually
+ * defined. This is because we abuse the bottom bit of the reference to carry a
+ * flag to indicate whether the calling process possesses that key in one of
+ * its keyrings.
+ *
+ * the key_ref_t has been made a separate type so that the compiler can reject
+ * attempts to dereference it without proper conversion.
+ *
+ * the three functions are used to assemble and disassemble references
+ */
+typedef struct __key_reference_with_attributes *key_ref_t;
+
+static inline key_ref_t make_key_ref(const struct key *key,
+				     unsigned long possession)
+{
+	return (key_ref_t) ((unsigned long) key | possession);
+}
+
+static inline struct key *key_ref_to_ptr(const key_ref_t key_ref)
+{
+	return (struct key *) ((unsigned long) key_ref & ~1UL);
+}
+
+static inline unsigned long is_key_possessed(const key_ref_t key_ref)
+{
+	return (unsigned long) key_ref & 1UL;
+}
+
+/*****************************************************************************/
+/*
  * authentication token / access credential / keyring
  * - types of key include:
  *   - keyrings
@@ -215,20 +254,25 @@ static inline struct key *key_get(struct
 	return key;
 }
 
+static inline void key_ref_put(key_ref_t key_ref)
+{
+	key_put(key_ref_to_ptr(key_ref));
+}
+
 extern struct key *request_key(struct key_type *type,
 			       const char *description,
 			       const char *callout_info);
 
 extern int key_validate(struct key *key);
 
-extern struct key *key_create_or_update(struct key *keyring,
-					const char *type,
-					const char *description,
-					const void *payload,
-					size_t plen,
-					int not_in_quota);
+extern key_ref_t key_create_or_update(key_ref_t keyring,
+				      const char *type,
+				      const char *description,
+				      const void *payload,
+				      size_t plen,
+				      int not_in_quota);
 
-extern int key_update(struct key *key,
+extern int key_update(key_ref_t key,
 		      const void *payload,
 		      size_t plen);
 
@@ -243,9 +287,9 @@ extern struct key *keyring_alloc(const c
 
 extern int keyring_clear(struct key *keyring);
 
-extern struct key *keyring_search(struct key *keyring,
-				  struct key_type *type,
-				  const char *description);
+extern key_ref_t keyring_search(key_ref_t keyring,
+				struct key_type *type,
+				const char *description);
 
 extern int keyring_add_key(struct key *keyring,
 			   struct key *key);
@@ -285,6 +329,10 @@ extern void key_init(void);
 #define key_serial(k)			0
 #define key_get(k) 			({ NULL; })
 #define key_put(k)			do { } while(0)
+#define key_ref_put(k)			do { } while(0)
+#define make_key_ref(k)			({ NULL; })
+#define key_ref_to_ptr(k)		({ NULL; })
+#define is_key_possessed(k)		0
 #define alloc_uid_keyring(u)		0
 #define switch_uid_keyring(u)		do { } while(0)
 #define __install_session_keyring(t, k)	({ NULL; })
diff -uNrp linux-2.6.14-rc1-mm1/include/linux/key-ui.h linux-2.6.14-rc1-mm1-keys/include/linux/key-ui.h
--- linux-2.6.14-rc1-mm1/include/linux/key-ui.h	2005-08-30 13:56:36.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/include/linux/key-ui.h	2005-09-28 15:27:09.000000000 +0100
@@ -42,11 +42,14 @@ struct keyring_list {
 /*
  * check to see whether permission is granted to use a key in the desired way
  */
-static inline int key_permission(const struct key *key, key_perm_t perm)
+static inline int key_permission(const key_ref_t key_ref, key_perm_t perm)
 {
+	struct key *key = key_ref_to_ptr(key_ref);
 	key_perm_t kperm;
 
-	if (key->uid == current->fsuid)
+	if (is_key_possessed(key_ref))
+		kperm = key->perm >> 24;
+	else if (key->uid == current->fsuid)
 		kperm = key->perm >> 16;
 	else if (key->gid != -1 &&
 		 key->perm & KEY_GRP_ALL &&
@@ -65,11 +68,14 @@ static inline int key_permission(const s
  * check to see whether permission is granted to use a key in at least one of
  * the desired ways
  */
-static inline int key_any_permission(const struct key *key, key_perm_t perm)
+static inline int key_any_permission(const key_ref_t key_ref, key_perm_t perm)
 {
+	struct key *key = key_ref_to_ptr(key_ref);
 	key_perm_t kperm;
 
-	if (key->uid == current->fsuid)
+	if (is_key_possessed(key_ref))
+		kperm = key->perm >> 24;
+	else if (key->uid == current->fsuid)
 		kperm = key->perm >> 16;
 	else if (key->gid != -1 &&
 		 key->perm & KEY_GRP_ALL &&
@@ -94,13 +100,17 @@ static inline int key_task_groups_search
 	return ret;
 }
 
-static inline int key_task_permission(const struct key *key,
+static inline int key_task_permission(const key_ref_t key_ref,
 				      struct task_struct *context,
 				      key_perm_t perm)
 {
+	struct key *key = key_ref_to_ptr(key_ref);
 	key_perm_t kperm;
 
-	if (key->uid == context->fsuid) {
+	if (is_key_possessed(key_ref)) {
+		kperm = key->perm >> 24;
+	}
+	else if (key->uid == context->fsuid) {
 		kperm = key->perm >> 16;
 	}
 	else if (key->gid != -1 &&
@@ -121,9 +131,9 @@ static inline int key_task_permission(co
 
 }
 
-extern struct key *lookup_user_key(struct task_struct *context,
-				   key_serial_t id, int create, int partial,
-				   key_perm_t perm);
+extern key_ref_t lookup_user_key(struct task_struct *context,
+				 key_serial_t id, int create, int partial,
+				 key_perm_t perm);
 
 extern long join_session_keyring(const char *name);
 
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/internal.h linux-2.6.14-rc1-mm1-keys/security/keys/internal.h
--- linux-2.6.14-rc1-mm1/security/keys/internal.h	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/internal.h	2005-09-28 15:29:05.000000000 +0100
@@ -71,26 +71,26 @@ extern void keyring_publish_name(struct 
 
 extern int __key_link(struct key *keyring, struct key *key);
 
-extern struct key *__keyring_search_one(struct key *keyring,
-					const struct key_type *type,
-					const char *description,
-					key_perm_t perm);
+extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
+				      const struct key_type *type,
+				      const char *description,
+				      key_perm_t perm);
 
 extern struct key *keyring_search_instkey(struct key *keyring,
 					  key_serial_t target_id);
 
 typedef int (*key_match_func_t)(const struct key *, const void *);
 
-extern struct key *keyring_search_aux(struct key *keyring,
-				      struct task_struct *tsk,
-				      struct key_type *type,
-				      const void *description,
-				      key_match_func_t match);
-
-extern struct key *search_process_keyrings(struct key_type *type,
-					   const void *description,
-					   key_match_func_t match,
-					   struct task_struct *tsk);
+extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
+				    struct task_struct *tsk,
+				    struct key_type *type,
+				    const void *description,
+				    key_match_func_t match);
+
+extern key_ref_t search_process_keyrings(struct key_type *type,
+					 const void *description,
+					 key_match_func_t match,
+					 struct task_struct *tsk);
 
 extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
 
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/key.c linux-2.6.14-rc1-mm1-keys/security/keys/key.c
--- linux-2.6.14-rc1-mm1/security/keys/key.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/key.c	2005-09-28 15:29:21.000000000 +0100
@@ -693,14 +693,15 @@ void key_type_put(struct key_type *ktype
  * - the key has an incremented refcount
  * - we need to put the key if we get an error
  */
-static inline struct key *__key_update(struct key *key, const void *payload,
-				       size_t plen)
+static inline key_ref_t __key_update(key_ref_t key_ref,
+				     const void *payload, size_t plen)
 {
+	struct key *key = key_ref_to_ptr(key_ref);
 	int ret;
 
 	/* need write permission on the key to update it */
 	ret = -EACCES;
-	if (!key_permission(key, KEY_WRITE))
+	if (!key_permission(key_ref, KEY_WRITE))
 		goto error;
 
 	ret = -EEXIST;
@@ -719,12 +720,12 @@ static inline struct key *__key_update(s
 
 	if (ret < 0)
 		goto error;
- out:
-	return key;
+out:
+	return key_ref;
 
- error:
+error:
 	key_put(key);
-	key = ERR_PTR(ret);
+	key_ref = ERR_PTR(ret);
 	goto out;
 
 } /* end __key_update() */
@@ -734,52 +735,56 @@ static inline struct key *__key_update(s
  * search the specified keyring for a key of the same description; if one is
  * found, update it, otherwise add a new one
  */
-struct key *key_create_or_update(struct key *keyring,
-				 const char *type,
-				 const char *description,
-				 const void *payload,
-				 size_t plen,
-				 int not_in_quota)
+key_ref_t key_create_or_update(key_ref_t keyring_ref,
+			       const char *type,
+			       const char *description,
+			       const void *payload,
+			       size_t plen,
+			       int not_in_quota)
 {
 	struct key_type *ktype;
-	struct key *key = NULL;
+	struct key *keyring, *key = NULL;
 	key_perm_t perm;
+	key_ref_t key_ref;
 	int ret;
 
-	key_check(keyring);
-
 	/* look up the key type to see if it's one of the registered kernel
 	 * types */
 	ktype = key_type_lookup(type);
 	if (IS_ERR(ktype)) {
-		key = ERR_PTR(-ENODEV);
+		key_ref = ERR_PTR(-ENODEV);
 		goto error;
 	}
 
-	ret = -EINVAL;
+	key_ref = ERR_PTR(-EINVAL);
 	if (!ktype->match || !ktype->instantiate)
 		goto error_2;
 
+	keyring = key_ref_to_ptr(keyring_ref);
+
+	key_check(keyring);
+
+	down_write(&keyring->sem);
+
+	/* if we're going to allocate a new key, we're going to have
+	 * to modify the keyring */
+	key_ref = ERR_PTR(-EACCES);
+	if (!key_permission(keyring_ref, KEY_WRITE))
+		goto error_3;
+
 	/* search for an existing key of the same type and description in the
 	 * destination keyring
 	 */
-	down_write(&keyring->sem);
-
-	key = __keyring_search_one(keyring, ktype, description, 0);
-	if (!IS_ERR(key))
+	key_ref = __keyring_search_one(keyring_ref, ktype, description, 0);
+	if (!IS_ERR(key_ref))
 		goto found_matching_key;
 
-	/* if we're going to allocate a new key, we're going to have to modify
-	 * the keyring */
-	ret = -EACCES;
-	if (!key_permission(keyring, KEY_WRITE))
-		goto error_3;
-
 	/* decide on the permissions we want */
-	perm = KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK;
+	perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK;
+	perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK;
 
 	if (ktype->read)
-		perm |= KEY_USR_READ;
+		perm |= KEY_POS_READ | KEY_USR_READ;
 
 	if (ktype == &key_type_keyring || ktype->update)
 		perm |= KEY_USR_WRITE;
@@ -788,7 +793,7 @@ struct key *key_create_or_update(struct 
 	key = key_alloc(ktype, description, current->fsuid, current->fsgid,
 			perm, not_in_quota);
 	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+		key_ref = ERR_PTR(PTR_ERR(key));
 		goto error_3;
 	}
 
@@ -796,15 +801,18 @@ struct key *key_create_or_update(struct 
 	ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
 	if (ret < 0) {
 		key_put(key);
-		key = ERR_PTR(ret);
+		key_ref = ERR_PTR(ret);
+		goto error_3;
 	}
 
+	key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
+
  error_3:
 	up_write(&keyring->sem);
  error_2:
 	key_type_put(ktype);
  error:
-	return key;
+	return key_ref;
 
  found_matching_key:
 	/* we found a matching key, so we're going to try to update it
@@ -813,7 +821,7 @@ struct key *key_create_or_update(struct 
 	up_write(&keyring->sem);
 	key_type_put(ktype);
 
-	key = __key_update(key, payload, plen);
+	key_ref = __key_update(key_ref, payload, plen);
 	goto error;
 
 } /* end key_create_or_update() */
@@ -824,15 +832,16 @@ EXPORT_SYMBOL(key_create_or_update);
 /*
  * update a key
  */
-int key_update(struct key *key, const void *payload, size_t plen)
+int key_update(key_ref_t key_ref, const void *payload, size_t plen)
 {
+	struct key *key = key_ref_to_ptr(key_ref);
 	int ret;
 
 	key_check(key);
 
 	/* the key must be writable */
 	ret = -EACCES;
-	if (!key_permission(key, KEY_WRITE))
+	if (!key_permission(key_ref, KEY_WRITE))
 		goto error;
 
 	/* attempt to update it if supported */
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/keyctl.c linux-2.6.14-rc1-mm1-keys/security/keys/keyctl.c
--- linux-2.6.14-rc1-mm1/security/keys/keyctl.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/keyctl.c	2005-09-28 16:29:44.000000000 +0100
@@ -34,7 +34,7 @@ asmlinkage long sys_add_key(const char _
 			    size_t plen,
 			    key_serial_t ringid)
 {
-	struct key *keyring, *key;
+	key_ref_t keyring_ref, key_ref;
 	char type[32], *description;
 	void *payload;
 	long dlen, ret;
@@ -86,25 +86,25 @@ asmlinkage long sys_add_key(const char _
 	}
 
 	/* find the target keyring (which must be writable) */
-	keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
+	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+	if (IS_ERR(keyring_ref)) {
+		ret = PTR_ERR(keyring_ref);
 		goto error3;
 	}
 
 	/* create or update the requested key and add it to the target
 	 * keyring */
-	key = key_create_or_update(keyring, type, description,
-				   payload, plen, 0);
-	if (!IS_ERR(key)) {
-		ret = key->serial;
-		key_put(key);
+	key_ref = key_create_or_update(keyring_ref, type, description,
+				       payload, plen, 0);
+	if (!IS_ERR(key_ref)) {
+		ret = key_ref_to_ptr(key_ref)->serial;
+		key_ref_put(key_ref);
 	}
 	else {
-		ret = PTR_ERR(key);
+		ret = PTR_ERR(key_ref);
 	}
 
-	key_put(keyring);
+	key_ref_put(keyring_ref);
  error3:
 	kfree(payload);
  error2:
@@ -131,7 +131,8 @@ asmlinkage long sys_request_key(const ch
 				key_serial_t destringid)
 {
 	struct key_type *ktype;
-	struct key *key, *dest;
+	struct key *key;
+	key_ref_t dest_ref;
 	char type[32], *description, *callout_info;
 	long dlen, ret;
 
@@ -187,11 +188,11 @@ asmlinkage long sys_request_key(const ch
 	}
 
 	/* get the destination keyring if specified */
-	dest = NULL;
+	dest_ref = NULL;
 	if (destringid) {
-		dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
-		if (IS_ERR(dest)) {
-			ret = PTR_ERR(dest);
+		dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+		if (IS_ERR(dest_ref)) {
+			ret = PTR_ERR(dest_ref);
 			goto error3;
 		}
 	}
@@ -204,7 +205,8 @@ asmlinkage long sys_request_key(const ch
 	}
 
 	/* do the search */
-	key = request_key_and_link(ktype, description, callout_info, dest);
+	key = request_key_and_link(ktype, description, callout_info,
+				   key_ref_to_ptr(dest_ref));
 	if (IS_ERR(key)) {
 		ret = PTR_ERR(key);
 		goto error5;
@@ -216,7 +218,7 @@ asmlinkage long sys_request_key(const ch
  error5:
 	key_type_put(ktype);
  error4:
-	key_put(dest);
+	key_ref_put(dest_ref);
  error3:
 	kfree(callout_info);
  error2:
@@ -234,17 +236,17 @@ asmlinkage long sys_request_key(const ch
  */
 long keyctl_get_keyring_ID(key_serial_t id, int create)
 {
-	struct key *key;
+	key_ref_t key_ref;
 	long ret;
 
-	key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
-	ret = key->serial;
-	key_put(key);
+	ret = key_ref_to_ptr(key_ref)->serial;
+	key_ref_put(key_ref);
  error:
 	return ret;
 
@@ -302,7 +304,7 @@ long keyctl_update_key(key_serial_t id,
 		       const void __user *_payload,
 		       size_t plen)
 {
-	struct key *key;
+	key_ref_t key_ref;
 	void *payload;
 	long ret;
 
@@ -324,16 +326,16 @@ long keyctl_update_key(key_serial_t id,
 	}
 
 	/* find the target key (which must be writable) */
-	key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error2;
 	}
 
 	/* update the key */
-	ret = key_update(key, payload, plen);
+	ret = key_update(key_ref, payload, plen);
 
-	key_put(key);
+	key_ref_put(key_ref);
  error2:
 	kfree(payload);
  error:
@@ -349,19 +351,19 @@ long keyctl_update_key(key_serial_t id,
  */
 long keyctl_revoke_key(key_serial_t id)
 {
-	struct key *key;
+	key_ref_t key_ref;
 	long ret;
 
-	key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
-	key_revoke(key);
+	key_revoke(key_ref_to_ptr(key_ref));
 	ret = 0;
 
-	key_put(key);
+	key_ref_put(key_ref);
  error:
 	return ret;
 
@@ -375,18 +377,18 @@ long keyctl_revoke_key(key_serial_t id)
  */
 long keyctl_keyring_clear(key_serial_t ringid)
 {
-	struct key *keyring;
+	key_ref_t keyring_ref;
 	long ret;
 
-	keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
+	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+	if (IS_ERR(keyring_ref)) {
+		ret = PTR_ERR(keyring_ref);
 		goto error;
 	}
 
-	ret = keyring_clear(keyring);
+	ret = keyring_clear(key_ref_to_ptr(keyring_ref));
 
-	key_put(keyring);
+	key_ref_put(keyring_ref);
  error:
 	return ret;
 
@@ -401,26 +403,26 @@ long keyctl_keyring_clear(key_serial_t r
  */
 long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
 {
-	struct key *keyring, *key;
+	key_ref_t keyring_ref, key_ref;
 	long ret;
 
-	keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
+	keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+	if (IS_ERR(keyring_ref)) {
+		ret = PTR_ERR(keyring_ref);
 		goto error;
 	}
 
-	key = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error2;
 	}
 
-	ret = key_link(keyring, key);
+	ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
 
-	key_put(key);
+	key_ref_put(key_ref);
  error2:
-	key_put(keyring);
+	key_ref_put(keyring_ref);
  error:
 	return ret;
 
@@ -435,26 +437,26 @@ long keyctl_keyring_link(key_serial_t id
  */
 long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
 {
-	struct key *keyring, *key;
+	key_ref_t keyring_ref, key_ref;
 	long ret;
 
-	keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
+	keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
+	if (IS_ERR(keyring_ref)) {
+		ret = PTR_ERR(keyring_ref);
 		goto error;
 	}
 
-	key = lookup_user_key(NULL, id, 0, 0, 0);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 0, 0, 0);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error2;
 	}
 
-	ret = key_unlink(keyring, key);
+	ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
 
-	key_put(key);
+	key_ref_put(key_ref);
  error2:
-	key_put(keyring);
+	key_ref_put(keyring_ref);
  error:
 	return ret;
 
@@ -476,24 +478,26 @@ long keyctl_describe_key(key_serial_t ke
 			 size_t buflen)
 {
 	struct key *key, *instkey;
+	key_ref_t key_ref;
 	char *tmpbuf;
 	long ret;
 
-	key = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
-	if (IS_ERR(key)) {
+	key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
+	if (IS_ERR(key_ref)) {
 		/* viewing a key under construction is permitted if we have the
 		 * authorisation token handy */
-		if (PTR_ERR(key) == -EACCES) {
+		if (PTR_ERR(key_ref) == -EACCES) {
 			instkey = key_get_instantiation_authkey(keyid);
 			if (!IS_ERR(instkey)) {
 				key_put(instkey);
-				key = lookup_user_key(NULL, keyid, 0, 1, 0);
-				if (!IS_ERR(key))
+				key_ref = lookup_user_key(NULL, keyid,
+							  0, 1, 0);
+				if (!IS_ERR(key_ref))
 					goto okay;
 			}
 		}
 
-		ret = PTR_ERR(key);
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
@@ -504,13 +508,16 @@ okay:
 	if (!tmpbuf)
 		goto error2;
 
+	key = key_ref_to_ptr(key_ref);
+
 	ret = snprintf(tmpbuf, PAGE_SIZE - 1,
-		       "%s;%d;%d;%06x;%s",
-		       key->type->name,
-		       key->uid,
-		       key->gid,
-		       key->perm,
-		       key->description ? key->description :""
+		       "%s;%d;%d;%08x;%s",
+		       key_ref_to_ptr(key_ref)->type->name,
+		       key_ref_to_ptr(key_ref)->uid,
+		       key_ref_to_ptr(key_ref)->gid,
+		       key_ref_to_ptr(key_ref)->perm,
+		       key_ref_to_ptr(key_ref)->description ?
+		       key_ref_to_ptr(key_ref)->description : ""
 		       );
 
 	/* include a NUL char at the end of the data */
@@ -530,7 +537,7 @@ okay:
 
 	kfree(tmpbuf);
  error2:
-	key_put(key);
+	key_ref_put(key_ref);
  error:
 	return ret;
 
@@ -552,7 +559,7 @@ long keyctl_keyring_search(key_serial_t 
 			   key_serial_t destringid)
 {
 	struct key_type *ktype;
-	struct key *keyring, *key, *dest;
+	key_ref_t keyring_ref, key_ref, dest_ref;
 	char type[32], *description;
 	long dlen, ret;
 
@@ -581,18 +588,18 @@ long keyctl_keyring_search(key_serial_t 
 		goto error2;
 
 	/* get the keyring at which to begin the search */
-	keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
-	if (IS_ERR(keyring)) {
-		ret = PTR_ERR(keyring);
+	keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
+	if (IS_ERR(keyring_ref)) {
+		ret = PTR_ERR(keyring_ref);
 		goto error2;
 	}
 
 	/* get the destination keyring if specified */
-	dest = NULL;
+	dest_ref = NULL;
 	if (destringid) {
-		dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
-		if (IS_ERR(dest)) {
-			ret = PTR_ERR(dest);
+		dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+		if (IS_ERR(dest_ref)) {
+			ret = PTR_ERR(dest_ref);
 			goto error3;
 		}
 	}
@@ -605,9 +612,9 @@ long keyctl_keyring_search(key_serial_t 
 	}
 
 	/* do the search */
-	key = keyring_search(keyring, ktype, description);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = keyring_search(keyring_ref, ktype, description);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 
 		/* treat lack or presence of a negative key the same */
 		if (ret == -EAGAIN)
@@ -616,26 +623,26 @@ long keyctl_keyring_search(key_serial_t 
 	}
 
 	/* link the resulting key to the destination keyring if we can */
-	if (dest) {
+	if (dest_ref) {
 		ret = -EACCES;
-		if (!key_permission(key, KEY_LINK))
+		if (!key_permission(key_ref, KEY_LINK))
 			goto error6;
 
-		ret = key_link(dest, key);
+		ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref));
 		if (ret < 0)
 			goto error6;
 	}
 
-	ret = key->serial;
+	ret = key_ref_to_ptr(key_ref)->serial;
 
  error6:
-	key_put(key);
+	key_ref_put(key_ref);
  error5:
 	key_type_put(ktype);
  error4:
-	key_put(dest);
+	key_ref_put(dest_ref);
  error3:
-	key_put(keyring);
+	key_ref_put(keyring_ref);
  error2:
 	kfree(description);
  error:
@@ -645,16 +652,6 @@ long keyctl_keyring_search(key_serial_t 
 
 /*****************************************************************************/
 /*
- * see if the key we're looking at is the target key
- */
-static int keyctl_read_key_same(const struct key *key, const void *target)
-{
-	return key == target;
-
-} /* end keyctl_read_key_same() */
-
-/*****************************************************************************/
-/*
  * read a user key's payload
  * - the keyring must be readable or the key must be searchable from the
  *   process's keyrings
@@ -665,38 +662,33 @@ static int keyctl_read_key_same(const st
  */
 long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
 {
-	struct key *key, *skey;
+	struct key *key;
+	key_ref_t key_ref;
 	long ret;
 
 	/* find the key first */
-	key = lookup_user_key(NULL, keyid, 0, 0, 0);
-	if (!IS_ERR(key)) {
-		/* see if we can read it directly */
-		if (key_permission(key, KEY_READ))
-			goto can_read_key;
-
-		/* we can't; see if it's searchable from this process's
-		 * keyrings
-		 * - we automatically take account of the fact that it may be
-		 *   dangling off an instantiation key
-		 */
-		skey = search_process_keyrings(key->type, key,
-					       keyctl_read_key_same, current);
-		if (!IS_ERR(skey))
-			goto can_read_key2;
+	key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);
+	if (IS_ERR(key_ref)) {
+		ret = -ENOKEY;
+		goto error;
+	}
 
-		ret = PTR_ERR(skey);
-		if (ret == -EAGAIN)
-			ret = -EACCES;
+	key = key_ref_to_ptr(key_ref);
+
+	/* see if we can read it directly */
+	if (key_permission(key_ref, KEY_READ))
+		goto can_read_key;
+
+	/* we can't; see if it's searchable from this process's keyrings
+	 * - we automatically take account of the fact that it may be
+	 *   dangling off an instantiation key
+	 */
+	if (!is_key_possessed(key_ref)) {
+		ret = -EACCES;
 		goto error2;
 	}
 
-	ret = -ENOKEY;
-	goto error;
-
 	/* the key is probably readable - now try to read it */
- can_read_key2:
-	key_put(skey);
  can_read_key:
 	ret = key_validate(key);
 	if (ret == 0) {
@@ -727,18 +719,21 @@ long keyctl_read_key(key_serial_t keyid,
 long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
 {
 	struct key *key;
+	key_ref_t key_ref;
 	long ret;
 
 	ret = 0;
 	if (uid == (uid_t) -1 && gid == (gid_t) -1)
 		goto error;
 
-	key = lookup_user_key(NULL, id, 1, 1, 0);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 1, 1, 0);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
+	key = key_ref_to_ptr(key_ref);
+
 	/* make the changes with the locks held to prevent chown/chown races */
 	ret = -EACCES;
 	down_write(&key->sem);
@@ -784,18 +779,21 @@ long keyctl_chown_key(key_serial_t id, u
 long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
 {
 	struct key *key;
+	key_ref_t key_ref;
 	long ret;
 
 	ret = -EINVAL;
-	if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
+	if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
 		goto error;
 
-	key = lookup_user_key(NULL, id, 1, 1, 0);
-	if (IS_ERR(key)) {
-		ret = PTR_ERR(key);
+	key_ref = lookup_user_key(NULL, id, 1, 1, 0);
+	if (IS_ERR(key_ref)) {
+		ret = PTR_ERR(key_ref);
 		goto error;
 	}
 
+	key = key_ref_to_ptr(key_ref);
+
 	/* make the changes with the locks held to prevent chown/chmod races */
 	ret = -EACCES;
 	down_write(&key->sem);
@@ -824,7 +822,8 @@ long keyctl_instantiate_key(key_serial_t
 			    key_serial_t ringid)
 {
 	struct request_key_auth *rka;
-	struct key *instkey, *keyring;
+	struct key *instkey;
+	key_ref_t keyring_ref;
 	void *payload;
 	long ret;
 
@@ -857,21 +856,21 @@ long keyctl_instantiate_key(key_serial_t
 
 	/* find the destination keyring amongst those belonging to the
 	 * requesting task */
-	keyring = NULL;
+	keyring_ref = NULL;
 	if (ringid) {
-		keyring = lookup_user_key(rka->context, ringid, 1, 0,
-					  KEY_WRITE);
-		if (IS_ERR(keyring)) {
-			ret = PTR_ERR(keyring);
+		keyring_ref = lookup_user_key(rka->context, ringid, 1, 0,
+					      KEY_WRITE);
+		if (IS_ERR(keyring_ref)) {
+			ret = PTR_ERR(keyring_ref);
 			goto error3;
 		}
 	}
 
 	/* instantiate the key and link it into a keyring */
 	ret = key_instantiate_and_link(rka->target_key, payload, plen,
-				       keyring, instkey);
+				       key_ref_to_ptr(keyring_ref), instkey);
 
-	key_put(keyring);
+	key_ref_put(keyring_ref);
  error3:
 	key_put(instkey);
  error2:
@@ -889,7 +888,8 @@ long keyctl_instantiate_key(key_serial_t
 long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
 {
 	struct request_key_auth *rka;
-	struct key *instkey, *keyring;
+	struct key *instkey;
+	key_ref_t keyring_ref;
 	long ret;
 
 	/* find the instantiation authorisation key */
@@ -903,19 +903,20 @@ long keyctl_negate_key(key_serial_t id, 
 
 	/* find the destination keyring if present (which must also be
 	 * writable) */
-	keyring = NULL;
+	keyring_ref = NULL;
 	if (ringid) {
-		keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-		if (IS_ERR(keyring)) {
-			ret = PTR_ERR(keyring);
+		keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+		if (IS_ERR(keyring_ref)) {
+			ret = PTR_ERR(keyring_ref);
 			goto error2;
 		}
 	}
 
 	/* instantiate the key and link it into a keyring */
-	ret = key_negate_and_link(rka->target_key, timeout, keyring, instkey);
+	ret = key_negate_and_link(rka->target_key, timeout,
+				  key_ref_to_ptr(keyring_ref), instkey);
 
-	key_put(keyring);
+	key_ref_put(keyring_ref);
  error2:
 	key_put(instkey);
  error:
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/keyring.c linux-2.6.14-rc1-mm1-keys/security/keys/keyring.c
--- linux-2.6.14-rc1-mm1/security/keys/keyring.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/keyring.c	2005-09-28 15:32:08.000000000 +0100
@@ -309,7 +309,7 @@ struct key *keyring_alloc(const char *de
 	int ret;
 
 	keyring = key_alloc(&key_type_keyring, description,
-			    uid, gid, KEY_USR_ALL, not_in_quota);
+			    uid, gid, KEY_POS_ALL | KEY_USR_ALL, not_in_quota);
 
 	if (!IS_ERR(keyring)) {
 		ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
@@ -333,12 +333,13 @@ struct key *keyring_alloc(const char *de
  * - we rely on RCU to prevent the keyring lists from disappearing on us
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we only found negative matching keys
+ * - we propagate the possession attribute from the keyring ref to the key ref
  */
-struct key *keyring_search_aux(struct key *keyring,
-			       struct task_struct *context,
-			       struct key_type *type,
-			       const void *description,
-			       key_match_func_t match)
+key_ref_t keyring_search_aux(key_ref_t keyring_ref,
+			     struct task_struct *context,
+			     struct key_type *type,
+			     const void *description,
+			     key_match_func_t match)
 {
 	struct {
 		struct keyring_list *keylist;
@@ -347,29 +348,33 @@ struct key *keyring_search_aux(struct ke
 
 	struct keyring_list *keylist;
 	struct timespec now;
-	struct key *key;
+	unsigned long possessed;
+	struct key *keyring, *key;
+	key_ref_t key_ref;
 	long err;
 	int sp, kix;
 
+	keyring = key_ref_to_ptr(keyring_ref);
+	possessed = is_key_possessed(keyring_ref);
 	key_check(keyring);
 
-	rcu_read_lock();
-
 	/* top keyring must have search permission to begin the search */
-	key = ERR_PTR(-EACCES);
-	if (!key_task_permission(keyring, context, KEY_SEARCH))
+	key_ref = ERR_PTR(-EACCES);
+	if (!key_task_permission(keyring_ref, context, KEY_SEARCH))
 		goto error;
 
-	key = ERR_PTR(-ENOTDIR);
+	key_ref = ERR_PTR(-ENOTDIR);
 	if (keyring->type != &key_type_keyring)
 		goto error;
 
+	rcu_read_lock();
+
 	now = current_kernel_time();
 	err = -EAGAIN;
 	sp = 0;
 
 	/* start processing a new keyring */
- descend:
+descend:
 	if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
 		goto not_this_keyring;
 
@@ -397,7 +402,8 @@ struct key *keyring_search_aux(struct ke
 			continue;
 
 		/* key must have search permissions */
-		if (!key_task_permission(key, context, KEY_SEARCH))
+		if (!key_task_permission(make_key_ref(key, possessed),
+					 context, KEY_SEARCH))
 			continue;
 
 		/* we set a different error code if we find a negative key */
@@ -411,7 +417,7 @@ struct key *keyring_search_aux(struct ke
 
 	/* search through the keyrings nested in this one */
 	kix = 0;
- ascend:
+ascend:
 	for (; kix < keylist->nkeys; kix++) {
 		key = keylist->keys[kix];
 		if (key->type != &key_type_keyring)
@@ -423,7 +429,8 @@ struct key *keyring_search_aux(struct ke
 		if (sp >= KEYRING_SEARCH_MAX_DEPTH)
 			continue;
 
-		if (!key_task_permission(key, context, KEY_SEARCH))
+		if (!key_task_permission(make_key_ref(key, possessed),
+					 context, KEY_SEARCH))
 			continue;
 
 		/* stack the current position */
@@ -438,7 +445,7 @@ struct key *keyring_search_aux(struct ke
 
 	/* the keyring we're looking at was disqualified or didn't contain a
 	 * matching key */
- not_this_keyring:
+not_this_keyring:
 	if (sp > 0) {
 		/* resume the processing of a keyring higher up in the tree */
 		sp--;
@@ -447,16 +454,18 @@ struct key *keyring_search_aux(struct ke
 		goto ascend;
 	}
 
-	key = ERR_PTR(err);
-	goto error;
+	key_ref = ERR_PTR(err);
+	goto error_2;
 
 	/* we found a viable match */
- found:
+found:
 	atomic_inc(&key->usage);
 	key_check(key);
- error:
+	key_ref = make_key_ref(key, possessed);
+error_2:
 	rcu_read_unlock();
-	return key;
+error:
+	return key_ref;
 
 } /* end keyring_search_aux() */
 
@@ -469,9 +478,9 @@ struct key *keyring_search_aux(struct ke
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we only found negative matching keys
  */
-struct key *keyring_search(struct key *keyring,
-			   struct key_type *type,
-			   const char *description)
+key_ref_t keyring_search(key_ref_t keyring,
+			 struct key_type *type,
+			 const char *description)
 {
 	if (!type->match)
 		return ERR_PTR(-ENOKEY);
@@ -488,15 +497,19 @@ EXPORT_SYMBOL(keyring_search);
  * search the given keyring only (no recursion)
  * - keyring must be locked by caller
  */
-struct key *__keyring_search_one(struct key *keyring,
-				 const struct key_type *ktype,
-				 const char *description,
-				 key_perm_t perm)
+key_ref_t __keyring_search_one(key_ref_t keyring_ref,
+			       const struct key_type *ktype,
+			       const char *description,
+			       key_perm_t perm)
 {
 	struct keyring_list *klist;
-	struct key *key;
+	unsigned long possessed;
+	struct key *keyring, *key;
 	int loop;
 
+	keyring = key_ref_to_ptr(keyring_ref);
+	possessed = is_key_possessed(keyring_ref);
+
 	rcu_read_lock();
 
 	klist = rcu_dereference(keyring->payload.subscriptions);
@@ -507,21 +520,21 @@ struct key *__keyring_search_one(struct 
 			if (key->type == ktype &&
 			    (!key->type->match ||
 			     key->type->match(key, description)) &&
-			    key_permission(key, perm) &&
+			    key_permission(make_key_ref(key, possessed),
+					   perm) &&
 			    !test_bit(KEY_FLAG_REVOKED, &key->flags)
 			    )
 				goto found;
 		}
 	}
 
-	key = ERR_PTR(-ENOKEY);
-	goto error;
+	rcu_read_unlock();
+	return ERR_PTR(-ENOKEY);
 
  found:
 	atomic_inc(&key->usage);
- error:
 	rcu_read_unlock();
-	return key;
+	return make_key_ref(key, possessed);
 
 } /* end __keyring_search_one() */
 
@@ -603,7 +616,8 @@ struct key *find_keyring_by_name(const c
 			if (strcmp(keyring->description, name) != 0)
 				continue;
 
-			if (!key_permission(keyring, KEY_SEARCH))
+			if (!key_permission(make_key_ref(keyring, 0),
+					    KEY_SEARCH))
 				continue;
 
 			/* found a potential candidate, but we still need to
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/proc.c linux-2.6.14-rc1-mm1-keys/security/keys/proc.c
--- linux-2.6.14-rc1-mm1/security/keys/proc.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/proc.c	2005-09-21 13:35:36.000000000 +0100
@@ -167,7 +167,7 @@ static int proc_keys_show(struct seq_fil
 #define showflag(KEY, LETTER, FLAG) \
 	(test_bit(FLAG,	&(KEY)->flags) ? LETTER : '-')
 
-	seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %06x %5d %5d %-9.9s ",
+	seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ",
 		   key->serial,
 		   showflag(key, 'I', KEY_FLAG_INSTANTIATED),
 		   showflag(key, 'R', KEY_FLAG_REVOKED),
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/process_keys.c linux-2.6.14-rc1-mm1-keys/security/keys/process_keys.c
--- linux-2.6.14-rc1-mm1/security/keys/process_keys.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/process_keys.c	2005-09-28 16:30:34.000000000 +0100
@@ -39,7 +39,7 @@ struct key root_user_keyring = {
 	.type		= &key_type_keyring,
 	.user		= &root_key_user,
 	.sem		= __RWSEM_INITIALIZER(root_user_keyring.sem),
-	.perm		= KEY_USR_ALL,
+	.perm		= KEY_POS_ALL | KEY_USR_ALL,
 	.flags		= 1 << KEY_FLAG_INSTANTIATED,
 	.description	= "_uid.0",
 #ifdef KEY_DEBUGGING
@@ -54,7 +54,7 @@ struct key root_session_keyring = {
 	.type		= &key_type_keyring,
 	.user		= &root_key_user,
 	.sem		= __RWSEM_INITIALIZER(root_session_keyring.sem),
-	.perm		= KEY_USR_ALL,
+	.perm		= KEY_POS_ALL | KEY_USR_ALL,
 	.flags		= 1 << KEY_FLAG_INSTANTIATED,
 	.description	= "_uid_ses.0",
 #ifdef KEY_DEBUGGING
@@ -98,7 +98,7 @@ int alloc_uid_keyring(struct user_struct
 	user->session_keyring = session_keyring;
 	ret = 0;
 
- error:
+error:
 	return ret;
 
 } /* end alloc_uid_keyring() */
@@ -156,7 +156,7 @@ int install_thread_keyring(struct task_s
 	ret = 0;
 
 	key_put(old);
- error:
+error:
 	return ret;
 
 } /* end install_thread_keyring() */
@@ -193,7 +193,7 @@ int install_process_keyring(struct task_
 	}
 
 	ret = 0;
- error:
+error:
 	return ret;
 
 } /* end install_process_keyring() */
@@ -236,7 +236,7 @@ static int install_session_keyring(struc
 	/* we're using RCU on the pointer */
 	synchronize_rcu();
 	key_put(old);
- error:
+error:
 	return ret;
 
 } /* end install_session_keyring() */
@@ -376,13 +376,13 @@ void key_fsgid_changed(struct task_struc
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we found only negative matching keys
  */
-struct key *search_process_keyrings(struct key_type *type,
-				    const void *description,
-				    key_match_func_t match,
-				    struct task_struct *context)
+key_ref_t search_process_keyrings(struct key_type *type,
+				  const void *description,
+				  key_match_func_t match,
+				  struct task_struct *context)
 {
 	struct request_key_auth *rka;
-	struct key *key, *ret, *err, *instkey;
+	key_ref_t key_ref, ret, err, instkey_ref;
 
 	/* 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;
@@ -391,46 +391,48 @@ struct key *search_process_keyrings(stru
 	 *
 	 * in terms of priority: success > -ENOKEY > -EAGAIN > other error
 	 */
-	key = NULL;
+	key_ref = NULL;
 	ret = NULL;
 	err = ERR_PTR(-EAGAIN);
 
 	/* search the thread keyring first */
 	if (context->thread_keyring) {
-		key = keyring_search_aux(context->thread_keyring,
-					 context, type, description, match);
-		if (!IS_ERR(key))
+		key_ref = keyring_search_aux(
+			make_key_ref(context->thread_keyring, 1),
+			context, type, description, match);
+		if (!IS_ERR(key_ref))
 			goto found;
 
-		switch (PTR_ERR(key)) {
+		switch (PTR_ERR(key_ref)) {
 		case -EAGAIN: /* no key */
 			if (ret)
 				break;
 		case -ENOKEY: /* negative key */
-			ret = key;
+			ret = key_ref;
 			break;
 		default:
-			err = key;
+			err = key_ref;
 			break;
 		}
 	}
 
 	/* search the process keyring second */
 	if (context->signal->process_keyring) {
-		key = keyring_search_aux(context->signal->process_keyring,
-					 context, type, description, match);
-		if (!IS_ERR(key))
+		key_ref = keyring_search_aux(
+			make_key_ref(context->signal->process_keyring, 1),
+			context, type, description, match);
+		if (!IS_ERR(key_ref))
 			goto found;
 
-		switch (PTR_ERR(key)) {
+		switch (PTR_ERR(key_ref)) {
 		case -EAGAIN: /* no key */
 			if (ret)
 				break;
 		case -ENOKEY: /* negative key */
-			ret = key;
+			ret = key_ref;
 			break;
 		default:
-			err = key;
+			err = key_ref;
 			break;
 		}
 	}
@@ -438,23 +440,25 @@ struct key *search_process_keyrings(stru
 	/* search the session keyring */
 	if (context->signal->session_keyring) {
 		rcu_read_lock();
-		key = keyring_search_aux(
-			rcu_dereference(context->signal->session_keyring),
+		key_ref = keyring_search_aux(
+			make_key_ref(rcu_dereference(
+					     context->signal->session_keyring),
+				     1),
 			context, type, description, match);
 		rcu_read_unlock();
 
-		if (!IS_ERR(key))
+		if (!IS_ERR(key_ref))
 			goto found;
 
-		switch (PTR_ERR(key)) {
+		switch (PTR_ERR(key_ref)) {
 		case -EAGAIN: /* no key */
 			if (ret)
 				break;
 		case -ENOKEY: /* negative key */
-			ret = key;
+			ret = key_ref;
 			break;
 		default:
-			err = key;
+			err = key_ref;
 			break;
 		}
 
@@ -465,51 +469,54 @@ struct key *search_process_keyrings(stru
 			goto no_key;
 
 		rcu_read_lock();
-		instkey = __keyring_search_one(
-			rcu_dereference(context->signal->session_keyring),
+		instkey_ref = __keyring_search_one(
+			make_key_ref(rcu_dereference(
+					     context->signal->session_keyring),
+				     1),
 			&key_type_request_key_auth, NULL, 0);
 		rcu_read_unlock();
 
-		if (IS_ERR(instkey))
+		if (IS_ERR(instkey_ref))
 			goto no_key;
 
-		rka = instkey->payload.data;
+		rka = key_ref_to_ptr(instkey_ref)->payload.data;
 
-		key = search_process_keyrings(type, description, match,
-					      rka->context);
-		key_put(instkey);
+		key_ref = search_process_keyrings(type, description, match,
+						  rka->context);
+		key_ref_put(instkey_ref);
 
-		if (!IS_ERR(key))
+		if (!IS_ERR(key_ref))
 			goto found;
 
-		switch (PTR_ERR(key)) {
+		switch (PTR_ERR(key_ref)) {
 		case -EAGAIN: /* no key */
 			if (ret)
 				break;
 		case -ENOKEY: /* negative key */
-			ret = key;
+			ret = key_ref;
 			break;
 		default:
-			err = key;
+			err = key_ref;
 			break;
 		}
 	}
 	/* or search the user-session keyring */
 	else {
-		key = keyring_search_aux(context->user->session_keyring,
-					 context, type, description, match);
-		if (!IS_ERR(key))
+		key_ref = keyring_search_aux(
+			make_key_ref(context->user->session_keyring, 1),
+			context, type, description, match);
+		if (!IS_ERR(key_ref))
 			goto found;
 
-		switch (PTR_ERR(key)) {
+		switch (PTR_ERR(key_ref)) {
 		case -EAGAIN: /* no key */
 			if (ret)
 				break;
 		case -ENOKEY: /* negative key */
-			ret = key;
+			ret = key_ref;
 			break;
 		default:
-			err = key;
+			err = key_ref;
 			break;
 		}
 	}
@@ -517,29 +524,40 @@ struct key *search_process_keyrings(stru
 
 no_key:
 	/* no key - decide on the error we're going to go for */
-	key = ret ? ret : err;
+	key_ref = ret ? ret : err;
 
 found:
-	return key;
+	return key_ref;
 
 } /* end search_process_keyrings() */
 
 /*****************************************************************************/
 /*
+ * see if the key we're looking at is the target key
+ */
+static int lookup_user_key_possessed(const struct key *key, const void *target)
+{
+	return key == target;
+
+} /* end lookup_user_key_possessed() */
+
+/*****************************************************************************/
+/*
  * lookup a key given a key ID from userspace with a given permissions mask
  * - don't create special keyrings unless so requested
  * - partially constructed keys aren't found unless requested
  */
-struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
-			    int create, int partial, key_perm_t perm)
+key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id,
+			  int create, int partial, key_perm_t perm)
 {
+	key_ref_t key_ref, skey_ref;
 	struct key *key;
 	int ret;
 
 	if (!context)
 		context = current;
 
-	key = ERR_PTR(-ENOKEY);
+	key_ref = ERR_PTR(-ENOKEY);
 
 	switch (id) {
 	case KEY_SPEC_THREAD_KEYRING:
@@ -556,6 +574,7 @@ struct key *lookup_user_key(struct task_
 
 		key = context->thread_keyring;
 		atomic_inc(&key->usage);
+		key_ref = make_key_ref(key, 1);
 		break;
 
 	case KEY_SPEC_PROCESS_KEYRING:
@@ -572,6 +591,7 @@ struct key *lookup_user_key(struct task_
 
 		key = context->signal->process_keyring;
 		atomic_inc(&key->usage);
+		key_ref = make_key_ref(key, 1);
 		break;
 
 	case KEY_SPEC_SESSION_KEYRING:
@@ -579,7 +599,7 @@ struct key *lookup_user_key(struct task_
 			/* always install a session keyring upon access if one
 			 * doesn't exist yet */
 			ret = install_session_keyring(
-			       context, context->user->session_keyring);
+				context, context->user->session_keyring);
 			if (ret < 0)
 				goto error;
 		}
@@ -588,16 +608,19 @@ struct key *lookup_user_key(struct task_
 		key = rcu_dereference(context->signal->session_keyring);
 		atomic_inc(&key->usage);
 		rcu_read_unlock();
+		key_ref = make_key_ref(key, 1);
 		break;
 
 	case KEY_SPEC_USER_KEYRING:
 		key = context->user->uid_keyring;
 		atomic_inc(&key->usage);
+		key_ref = make_key_ref(key, 1);
 		break;
 
 	case KEY_SPEC_USER_SESSION_KEYRING:
 		key = context->user->session_keyring;
 		atomic_inc(&key->usage);
+		key_ref = make_key_ref(key, 1);
 		break;
 
 	case KEY_SPEC_GROUP_KEYRING:
@@ -606,13 +629,28 @@ struct key *lookup_user_key(struct task_
 		goto error;
 
 	default:
-		key = ERR_PTR(-EINVAL);
+		key_ref = ERR_PTR(-EINVAL);
 		if (id < 1)
 			goto error;
 
 		key = key_lookup(id);
-		if (IS_ERR(key))
+		if (IS_ERR(key)) {
+			key_ref = ERR_PTR(PTR_ERR(key));
 			goto error;
+		}
+
+		key_ref = make_key_ref(key, 0);
+
+		/* check to see if we possess the key */
+		skey_ref = search_process_keyrings(key->type, key,
+						   lookup_user_key_possessed,
+						   current);
+
+		if (!IS_ERR(skey_ref)) {
+			key_put(key);
+			key_ref = skey_ref;
+		}
+
 		break;
 	}
 
@@ -630,15 +668,15 @@ struct key *lookup_user_key(struct task_
 	/* check the permissions */
 	ret = -EACCES;
 
-	if (!key_task_permission(key, context, perm))
+	if (!key_task_permission(key_ref, context, perm))
 		goto invalid_key;
 
- error:
-	return key;
+error:
+	return key_ref;
 
- invalid_key:
-	key_put(key);
-	key = ERR_PTR(ret);
+invalid_key:
+	key_ref_put(key_ref);
+	key_ref = ERR_PTR(ret);
 	goto error;
 
 } /* end lookup_user_key() */
@@ -694,9 +732,9 @@ long join_session_keyring(const char *na
 	ret = keyring->serial;
 	key_put(keyring);
 
- error2:
+error2:
 	up(&key_session_sem);
- error:
+error:
 	return ret;
 
 } /* end join_session_keyring() */
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/request_key_auth.c linux-2.6.14-rc1-mm1-keys/security/keys/request_key_auth.c
--- linux-2.6.14-rc1-mm1/security/keys/request_key_auth.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/request_key_auth.c	2005-09-21 13:48:24.000000000 +0100
@@ -126,7 +126,7 @@ struct key *request_key_auth_new(struct 
 
 	rkakey = key_alloc(&key_type_request_key_auth, desc,
 			   current->fsuid, current->fsgid,
-			   KEY_USR_VIEW, 1);
+			   KEY_POS_VIEW | KEY_USR_VIEW, 1);
 	if (IS_ERR(rkakey)) {
 		key_put(keyring);
 		kleave("= %ld", PTR_ERR(rkakey));
diff -uNrp linux-2.6.14-rc1-mm1/security/keys/request_key.c linux-2.6.14-rc1-mm1-keys/security/keys/request_key.c
--- linux-2.6.14-rc1-mm1/security/keys/request_key.c	2005-08-30 13:56:44.000000000 +0100
+++ linux-2.6.14-rc1-mm1-keys/security/keys/request_key.c	2005-09-28 16:26:41.000000000 +0100
@@ -129,7 +129,7 @@ static struct key *__request_key_constru
 
 	/* create a key and add it to the queue */
 	key = key_alloc(type, description,
-			current->fsuid, current->fsgid, KEY_USR_ALL, 0);
+			current->fsuid, current->fsgid, KEY_POS_ALL, 0);
 	if (IS_ERR(key))
 		goto alloc_failed;
 
@@ -365,14 +365,24 @@ struct key *request_key_and_link(struct 
 {
 	struct key_user *user;
 	struct key *key;
+	key_ref_t key_ref;
 
 	kenter("%s,%s,%s,%p",
 	       type->name, description, callout_info, dest_keyring);
 
 	/* search all the process keyrings for a key */
-	key = search_process_keyrings(type, description, type->match, current);
+	key_ref = search_process_keyrings(type, description, type->match,
+					  current);
 
-	if (PTR_ERR(key) == -EAGAIN) {
+	kdebug("search 1: %p", key_ref);
+
+	if (!IS_ERR(key_ref)) {
+		key = key_ref_to_ptr(key_ref);
+	}
+	else if (PTR_ERR(key_ref) != -EAGAIN) {
+		key = ERR_PTR(PTR_ERR(key_ref));
+	}
+	else  {
 		/* the search failed, but the keyrings were searchable, so we
 		 * should consult userspace if we can */
 		key = ERR_PTR(-ENOKEY);
@@ -384,7 +394,7 @@ struct key *request_key_and_link(struct 
 		if (!user)
 			goto nomem;
 
-		do {
+		for (;;) {
 			if (signal_pending(current))
 				goto interrupted;
 
@@ -397,10 +407,22 @@ struct key *request_key_and_link(struct 
 
 			/* someone else made the key we want, so we need to
 			 * search again as it might now be available to us */
-			key = search_process_keyrings(type, description,
-						      type->match, current);
+			key_ref = search_process_keyrings(type, description,
+							  type->match,
+							  current);
+
+			kdebug("search 2: %p", key_ref);
 
-		} while (PTR_ERR(key) == -EAGAIN);
+			if (!IS_ERR(key_ref)) {
+				key = key_ref_to_ptr(key_ref);
+				break;
+			}
+
+			if (PTR_ERR(key_ref) != -EAGAIN) {
+				key = ERR_PTR(PTR_ERR(key_ref));
+				break;
+			}
+		}
 
 		key_user_put(user);
 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Keyrings] Re: [PATCH] Keys: Add possessor permissions to keys
  2005-09-21 18:29   ` David Howells
  2005-09-21 18:45     ` Andrew Morton
@ 2005-10-03  4:43     ` Kyle Moffett
  1 sibling, 0 replies; 14+ messages in thread
From: Kyle Moffett @ 2005-10-03  4:43 UTC (permalink / raw)
  To: David Howells; +Cc: Andrew Morton, torvalds, keyrings, linux-kernel

On Sep 21, 2005, at 14:29:54, David Howells wrote:
> (3) Key handles (which I've been asked for before).
>
> This involves detaching the permissions and suchlike from the key  
> into a "handle" which can then be cloned. A temporary handle could  
> then be used to hold the possession attribute and the other  
> permissions at the time of the access.
>
> The downside of this is that it's quite a big change. It also makes  
> joining session keyrings way more "interesting". It does have some  
> nice features though.

Are there any plans to implement this functionality in the near  
future?  It would complement the existing security model nicely by  
allowing a process to clone its key handle either explicitly (with  a  
keyctl call) or implicitly (by passing it over a file handle to  
another process), and then later revoke the cloned handle and all  
handles cloned from it with a single call, much as one can SIGKILL an  
entire process group with a single kill().  It seems that a key  
handle would be little more than a special sort of file handle  
attached to a key.  I'm curious what issues you've found with joining  
session keyrings.  I haven't thought about that part specifically,  
but it seems that perhaps there should be a set of "default"  
permissions and attributes that are associated with a new lookup-by- 
key-id handle.


Cheers,
Kyle Moffett

--
There are two ways of constructing a software design. One way is to  
make it so simple that there are obviously no deficiencies. And the  
other way is to make it so complicated that there are no obvious  
deficiencies.  The first method is far more difficult.
   -- C.A.R. Hoare



^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2005-10-03  4:44 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <5378.1127211442@warthog.cambridge.redhat.com>
2005-09-21 14:48 ` [PATCH] Keys: Add possessor permissions to keys David Howells
2005-09-21 15:05   ` Linus Torvalds
2005-09-21 15:44   ` David Howells
2005-09-21 17:15   ` Andrew Morton
2005-09-21 17:47     ` Trond Myklebust
2005-09-21 18:36     ` David Howells
2005-09-21 18:29   ` David Howells
2005-09-21 18:45     ` Andrew Morton
2005-09-21 18:56       ` Linus Torvalds
2005-09-22 10:00       ` David Howells
2005-10-03  4:43     ` [Keyrings] " Kyle Moffett
2005-09-21 19:23   ` James Morris
2005-09-21 18:33 ` [PATCH] Keys: Add possessor permissions to keys [try #2] David Howells
2005-09-28 16:03 ` [PATCH] Keys: Add possessor permissions to keys [try #3] David Howells

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).