aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation/assoc_array.txt
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2013-12-02 06:24:18 -0500
committerDavid Howells <dhowells@redhat.com>2013-12-02 06:24:18 -0500
commit23fd78d76415729b338ff1802a0066b4a62f7fb8 (patch)
treeb832cd635e3e3fe8cca93de1a2e5bb165a968538 /Documentation/assoc_array.txt
parentd54e58b7f01552b0eb7d445f4b58de4499ad5ea6 (diff)
KEYS: Fix multiple key add into associative array
If sufficient keys (or keyrings) are added into a keyring such that a node in the associative array's tree overflows (each node has a capacity N, currently 16) and such that all N+1 keys have the same index key segment for that level of the tree (the level'th nibble of the index key), then assoc_array_insert() calls ops->diff_objects() to indicate at which bit position the two index keys vary. However, __key_link_begin() passes a NULL object to assoc_array_insert() with the intention of supplying the correct pointer later before we commit the change. This means that keyring_diff_objects() is given a NULL pointer as one of its arguments which it does not expect. This results in an oops like the attached. With the previous patch to fix the keyring hash function, this can be forced much more easily by creating a keyring and only adding keyrings to it. Add any other sort of key and a different insertion path is taken - all 16+1 objects must want to cluster in the same node slot. This can be tested by: r=`keyctl newring sandbox @s` for ((i=0; i<=16; i++)); do keyctl newring ring$i $r; done This should work fine, but oopses when the 17th keyring is added. Since ops->diff_objects() is always called with the first pointer pointing to the object to be inserted (ie. the NULL pointer), we can fix the problem by changing the to-be-inserted object pointer to point to the index key passed into assoc_array_insert() instead. Whilst we're at it, we also switch the arguments so that they are the same as for ->compare_object(). BUG: unable to handle kernel NULL pointer dereference at 0000000000000088 IP: [<ffffffff81191ee4>] hash_key_type_and_desc+0x18/0xb0 ... RIP: 0010:[<ffffffff81191ee4>] hash_key_type_and_desc+0x18/0xb0 ... Call Trace: [<ffffffff81191f9d>] keyring_diff_objects+0x21/0xd2 [<ffffffff811f09ef>] assoc_array_insert+0x3b6/0x908 [<ffffffff811929a7>] __key_link_begin+0x78/0xe5 [<ffffffff81191a2e>] key_create_or_update+0x17d/0x36a [<ffffffff81192e0a>] SyS_add_key+0x123/0x183 [<ffffffff81400ddb>] tracesys+0xdd/0xe2 Signed-off-by: David Howells <dhowells@redhat.com> Tested-by: Stephen Gallagher <sgallagh@redhat.com>
Diffstat (limited to 'Documentation/assoc_array.txt')
-rw-r--r--Documentation/assoc_array.txt6
1 files changed, 3 insertions, 3 deletions
diff --git a/Documentation/assoc_array.txt b/Documentation/assoc_array.txt
index f4faec0f66e4..2f2c6cdd73c0 100644
--- a/Documentation/assoc_array.txt
+++ b/Documentation/assoc_array.txt
@@ -164,10 +164,10 @@ This points to a number of methods, all of which need to be provided:
164 164
165 (4) Diff the index keys of two objects. 165 (4) Diff the index keys of two objects.
166 166
167 int (*diff_objects)(const void *a, const void *b); 167 int (*diff_objects)(const void *object, const void *index_key);
168 168
169 Return the bit position at which the index keys of two objects differ or 169 Return the bit position at which the index key of the specified object
170 -1 if they are the same. 170 differs from the given index key or -1 if they are the same.
171 171
172 172
173 (5) Free an object. 173 (5) Free an object.