[PATCH] Keys: Add possessor permissions to keys [try #3]
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>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/include/linux/key.h b/include/linux/key.h
index 970bbd9..f1efa01 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -35,11 +35,18 @@
#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 @@
/*****************************************************************************/
/*
+ * 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 @@
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 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 @@
#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; })