[RHEL7,COMMIT] tun: Silence allocation failer if user asked for too big header

Submitted by Vasily Averin on Oct. 6, 2020, 8:19 a.m.

Details

Message ID 202010060819.0968JA2b002955@vz7build.vvs.sw.ru
State New
Series "tun: Silence allocation failer if user asked for too big header"
Headers show

Commit Message

Vasily Averin Oct. 6, 2020, 8:19 a.m.
The commit is pushed to "branch-rh7-3.10.0-1127.18.2.vz7.163.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1127.18.2.vz7.163.33
------>
commit 1e0ad3477bddaf5621b7cc620e6ed64e405ec8cd
Author: Andrey Ryabinin <aryabinin@virtuozzo.com>
Date:   Tue Oct 6 11:19:10 2020 +0300

    tun: Silence allocation failer if user asked for too big header
    
    Userspace may ask tun device to send packet with ridiculously
    big header and trigger this:
    
     ------------[ cut here ]------------
     WARNING: CPU: 1 PID: 15366 at mm/page_alloc.c:3548 __alloc_pages_nodemask+0x537/0x1200
     order 19 >= 11, gfp 0x2044d0
     Call Trace:
       dump_stack+0x19/0x1b
       __warn+0x17f/0x1c0
       warn_slowpath_fmt+0xad/0xe0
       __alloc_pages_nodemask+0x537/0x1200
       kmalloc_large_node+0x5f/0xd0
       __kmalloc_node_track_caller+0x425/0x630
       __kmalloc_reserve.isra.33+0x47/0xd0
       __alloc_skb+0xdd/0x5f0
       alloc_skb_with_frags+0x8f/0x540
       sock_alloc_send_pskb+0x5e5/0x940
       tun_get_user+0x38b/0x24a0 [tun]
       tun_chr_aio_write+0x13a/0x250 [tun]
       do_sync_readv_writev+0xdf/0x1c0
       do_readv_writev+0x1a5/0x850
       vfs_writev+0xba/0x190
       SyS_writev+0x17c/0x340
       system_call_fastpath+0x25/0x2a
    
    Just add __GFP_NOWARN and silently return -ENOMEM to fix this.
    
    https://jira.sw.ru/browse/PSBM-103639
    Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 drivers/net/tun.c  | 4 ++--
 include/net/sock.h | 7 +++++++
 net/core/sock.c    | 9 +++++++++
 3 files changed, 18 insertions(+), 2 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index e95a89b..c0879c6 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1142,8 +1142,8 @@  static struct sk_buff *tun_alloc_skb(struct tun_file *tfile,
 	if (prepad + len < PAGE_SIZE || !linear)
 		linear = len;
 
-	skb = sock_alloc_send_pskb(sk, prepad + linear, len - linear, noblock,
-				   &err, 0);
+	skb = sock_alloc_send_pskb_flags(sk, prepad + linear, len - linear, noblock,
+				&err, 0, __GFP_NOWARN);
 	if (!skb)
 		return ERR_PTR(err);
 
diff --git a/include/net/sock.h b/include/net/sock.h
index 4136d2c..1912d85 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1626,6 +1626,13 @@  extern struct sk_buff		*sock_alloc_send_pskb(struct sock *sk,
 						      int noblock,
 						      int *errcode,
 						      int max_page_order);
+extern struct sk_buff		*sock_alloc_send_pskb_flags(struct sock *sk,
+						      unsigned long header_len,
+						      unsigned long data_len,
+						      int noblock,
+						      int *errcode,
+						      int max_page_order,
+						      gfp_t extra_flags);
 extern void *sock_kmalloc(struct sock *sk, int size,
 			  gfp_t priority);
 extern void sock_kfree_s(struct sock *sk, void *mem, int size);
diff --git a/net/core/sock.c b/net/core/sock.c
index 508fc60..07ea42f 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1964,6 +1964,15 @@  struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
 }
 EXPORT_SYMBOL(sock_alloc_send_pskb);
 
+struct sk_buff *sock_alloc_send_pskb_flags(struct sock *sk, unsigned long header_len,
+				     unsigned long data_len, int noblock,
+				     int *errcode, int max_page_order, gfp_t extra_flags)
+{
+	return __sock_alloc_send_pskb(sk, header_len, data_len, noblock,
+				errcode, max_page_order, extra_flags);
+}
+EXPORT_SYMBOL(sock_alloc_send_pskb_flags);
+
 struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size,
 				    int noblock, int *errcode)
 {