[Devel] [PATCH RH9 04/30] keys, user: Fix high order allocation in user_instantiate() #PSBM-107794

Andrey Zhadchenko andrey.zhadchenko at virtuozzo.com
Tue Sep 28 21:48:55 MSK 2021


From: Andrey Ryabinin <aryabinin at virtuozzo.com>

Adding user key might trigger 4-order allocation which is unreliable
in case of fragmented memory:

 ------------[ cut here ]------------
 WARNING: CPU: 3 PID: 134927 at mm/page_alloc.c:3533 __alloc_pages_nodemask+0x1b1/0x600
 order 4 >= 3, gfp 0x40d0
 Kernel panic - not syncing: panic_on_warn set ...
 CPU: 3 PID: 134927 Comm: add_key01 ve: 0 Kdump: loaded Tainted: G           OE  ------------   3.10.0-1127.18.2.vz7.163.15 #1 163.15
 Hardware name: Virtuozzo KVM, BIOS 1.11.0-2.vz7.2 04/01/2014
 Call Trace:
  dump_stack+0x19/0x1b
  panic+0xe8/0x21f
  __warn+0xfa/0x100
  warn_slowpath_fmt+0x5f/0x80
  __alloc_pages_nodemask+0x1b1/0x600
  alloc_pages_current+0x98/0x110
  kmalloc_order+0x18/0x40
  kmalloc_order_trace+0x26/0xa0
  __kmalloc+0x281/0x2a0
  user_instantiate+0x47/0x90
  __key_instantiate_and_link+0x54/0x100
  key_create_or_update+0x398/0x490
  SyS_add_key+0x12c/0x220
  system_call_fastpath+0x25/0x2a

Use kvmalloc() to avoid potential -ENOMEM due to fragmentation.

https://jira.sw.ru/browse/PSBM-107794
Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>

(cherry picked from commit 499126f3b029a72e2883b386c94fe4fc94f32c91)
Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>

+++
keys,user: fix NULL-ptr dereference in user_destroy() #PSBM-108198

key->payload.data could be NULL

BUG: unable to handle kernel NULL pointer dereference at 0000000000000010
IP: user_destroy+0x13/0x30

Call Trace:
  key_gc_unused_keys.constprop.1+0xfd/0x110
  key_garbage_collector+0x1d7/0x390
  process_one_work+0x185/0x440
  worker_thread+0x126/0x3c0
  kthread+0xd1/0xe0
  ret_from_fork_nospec_begin+0x7/0x21

Add the necessary check to fix this.

https://jira.sw.ru/browse/PSBM-108198
Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>

mFixes: d77ff0bac744 ("keys, user: Fix high order allocation in user_instantiate()")
(cherry picked from commit a0e271fd8929312b1c5dab72fbc8bc336a296b45)
Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>

+++
keys,user: Fix NULL-ptr dereference in user_free_preparse() #PSBM-108291

user_free_preparse() can validly receive "prep" arg with NULL payload
(prep->payload.data[0]) => add a check for that.

key_create_or_update()
{
        ...
        if (index_key.type->preparse) {
                ret = index_key.type->preparse(&prep);
                // user_preparse(), kvmalloc(), prep->payload.data[0] filled
                ...
        }
        ...
        ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &edit);
        // it sets prep->payload.data[0] to NULL
        ...
error_free_prep:
        if (index_key.type->preparse)
                index_key.type->free_preparse(&prep);
                // user_free_preparse(), memset(prep->payload.data[0], ...)
		// crash here
        ...
}

key_create_or_update()
 __key_instantiate_and_link()
  key->type->instantiate() == generic_key_instantiate()
   prep->payload.data[0] = NULL;

mFixes: d77ff0bac744 ("keys, user: Fix high order allocation in user_instantiate()")
https://jira.sw.ru/browse/PSBM-108291

Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>

(cherry picked from vz8 commit 164392d23bad844e05064d22f6a9509ec4ceff40)
Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
---
 security/keys/user_defined.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 749e2a4..b06aace 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -5,6 +5,7 @@
  * Written by David Howells (dhowells at redhat.com)
  */
 
+#include <linux/mm.h>
 #include <linux/export.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -64,7 +65,7 @@ int user_preparse(struct key_preparsed_payload *prep)
 	if (datalen <= 0 || datalen > 32767 || !prep->data)
 		return -EINVAL;
 
-	upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
+	upayload = kvmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
 	if (!upayload)
 		return -ENOMEM;
 
@@ -82,7 +83,12 @@ int user_preparse(struct key_preparsed_payload *prep)
  */
 void user_free_preparse(struct key_preparsed_payload *prep)
 {
-	kfree_sensitive(prep->payload.data[0]);
+	struct user_key_payload *upayload = prep->payload.data[0];
+
+	if (upayload) {
+		memset(upayload, 0, sizeof(*upayload) + upayload->datalen);
+		kvfree(upayload);
+	}
 }
 EXPORT_SYMBOL_GPL(user_free_preparse);
 
@@ -91,7 +97,8 @@ static void user_free_payload_rcu(struct rcu_head *head)
 	struct user_key_payload *payload;
 
 	payload = container_of(head, struct user_key_payload, rcu);
-	kfree_sensitive(payload);
+	memset(payload, 0, sizeof(*payload) + payload->datalen);
+	kvfree(payload);
 }
 
 /*
@@ -147,7 +154,10 @@ void user_destroy(struct key *key)
 {
 	struct user_key_payload *upayload = key->payload.data[0];
 
-	kfree_sensitive(upayload);
+	if (upayload) {
+		memset(upayload, 0, sizeof(*upayload) + upayload->datalen);
+		kvfree(upayload);
+	}
 }
 
 EXPORT_SYMBOL_GPL(user_destroy);
-- 
1.8.3.1



More information about the Devel mailing list