[RHEL8,COMMIT] keys, user: Fix high order allocation in user_instantiate() #PSBM-107794

Submitted by Konstantin Khorenko on Sept. 24, 2020, 1:43 p.m.

Details

Message ID 202009241343.08ODh1QY371426@finist-co8.sw.ru
State New
Series "keys, user: Fix high order allocation in user_instantiate()"
Headers show

Commit Message

Konstantin Khorenko Sept. 24, 2020, 1:43 p.m.
The commit is pushed to "branch-rh8-4.18.0-193.6.3.vz8.4.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh8-4.18.0-193.6.3.vz8.4.7
------>
commit d77ff0bac7444625507cf0419d57bd3d72972801
Author: Andrey Ryabinin <aryabinin@virtuozzo.com>
Date:   Tue Sep 15 11:55:26 2020 +0300

    keys, user: Fix high order allocation in user_instantiate() #PSBM-107794
    
    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@virtuozzo.com>
    
    (cherry picked from commit 499126f3b029a72e2883b386c94fe4fc94f32c91)
    Signed-off-by: Konstantin Khorenko <khorenko@virtuozzo.com>
---
 security/keys/user_defined.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

Patch hide | download patch | download mbox

diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 9f558bedba23..39add3cd78ef 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -9,6 +9,7 @@ 
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -68,7 +69,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;
 
@@ -86,7 +87,10 @@  EXPORT_SYMBOL_GPL(user_preparse);
  */
 void user_free_preparse(struct key_preparsed_payload *prep)
 {
-	kzfree(prep->payload.data[0]);
+	struct user_key_payload *upayload = prep->payload.data[0];
+
+	memset(upayload, 0, sizeof(*upayload) + upayload->datalen);
+	kvfree(upayload);
 }
 EXPORT_SYMBOL_GPL(user_free_preparse);
 
@@ -95,7 +99,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);
-	kzfree(payload);
+	memset(payload, 0, sizeof(*payload) + payload->datalen);
+	kvfree(payload);
 }
 
 /*
@@ -151,7 +156,8 @@  void user_destroy(struct key *key)
 {
 	struct user_key_payload *upayload = key->payload.data[0];
 
-	kzfree(upayload);
+	memset(upayload, 0, sizeof(*upayload) + upayload->datalen);
+	kvfree(upayload);
 }
 
 EXPORT_SYMBOL_GPL(user_destroy);