diff mbox

net: sysctl_net_core: check SNDBUF and RCVBUF for min length

Message ID 1426073357-6211-1-git-send-email-alexey.kodanev@oracle.com
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Alexey Kodanev March 11, 2015, 11:29 a.m. UTC
sysctl has sysctl.net.core.rmem_*/wmem_* parameters which can be
set to incorrect values. Given that 'struct sk_buff' allocates from
rcvbuf, incorrectly set buffer length could result to memory
allocation failures. For example, set them as follows:

    # sysctl net.core.rmem_default=64
      net.core.wmem_default = 64
    # sysctl net.core.wmem_default=64
      net.core.wmem_default = 64
    # ping localhost -s 1024 -i 0 > /dev/null

This could result to the following failure:

skbuff: skb_over_panic: text:ffffffff81628db4 len:-32 put:-32
head:ffff88003a1cc200 data:ffff88003a1cc200 tail:0xffffffe0 end:0xc0 dev:<NULL>
kernel BUG at net/core/skbuff.c:102!
invalid opcode: 0000 [#1] SMP
...
task: ffff88003b7f5550 ti: ffff88003ae88000 task.ti: ffff88003ae88000
RIP: 0010:[<ffffffff8155fbd1>]  [<ffffffff8155fbd1>] skb_put+0xa1/0xb0
RSP: 0018:ffff88003ae8bc68  EFLAGS: 00010296
RAX: 000000000000008d RBX: 00000000ffffffe0 RCX: 0000000000000000
RDX: ffff88003fdcf598 RSI: ffff88003fdcd9c8 RDI: ffff88003fdcd9c8
RBP: ffff88003ae8bc88 R08: 0000000000000001 R09: 0000000000000000
R10: 0000000000000001 R11: 00000000000002b2 R12: 0000000000000000
R13: 0000000000000000 R14: ffff88003d3f7300 R15: ffff88000012a900
FS:  00007fa0e2b4a840(0000) GS:ffff88003fc00000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000d0f7e0 CR3: 000000003b8fb000 CR4: 00000000000006f0
Stack:
 ffff88003a1cc200 00000000ffffffe0 00000000000000c0 ffffffff818cab1d
 ffff88003ae8bd68 ffffffff81628db4 ffff88003ae8bd48 ffff88003b7f5550
 ffff880031a09408 ffff88003b7f5550 ffff88000012aa48 ffff88000012ab00
Call Trace:
 [<ffffffff81628db4>] unix_stream_sendmsg+0x2c4/0x470
 [<ffffffff81556f56>] sock_write_iter+0x146/0x160
 [<ffffffff811d9612>] new_sync_write+0x92/0xd0
 [<ffffffff811d9cd6>] vfs_write+0xd6/0x180
 [<ffffffff811da499>] SyS_write+0x59/0xd0
 [<ffffffff81651532>] system_call_fastpath+0x12/0x17
Code: 00 00 48 89 44 24 10 8b 87 c8 00 00 00 48 89 44 24 08 48 8b 87 d8 00
      00 00 48 c7 c7 30 db 91 81 48 89 04 24 31 c0 e8 4f a8 0e 00 <0f> 0b
      eb fe 66 66 2e 0f 1f 84 00 00 00 00 00 55 48 89 e5 48 83
RIP  [<ffffffff8155fbd1>] skb_put+0xa1/0xb0
RSP <ffff88003ae8bc68>
Kernel panic - not syncing: Fatal exception

Moreover, the possible minimum is 1, so we can get another kernel panic:
...
BUG: unable to handle kernel paging request at ffff88013caee5c0
IP: [<ffffffff815604cf>] __alloc_skb+0x12f/0x1f0
...

Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
---
 net/core/sysctl_net_core.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

Comments

Eric Dumazet March 11, 2015, 1:25 p.m. UTC | #1
On Wed, 2015-03-11 at 14:29 +0300, Alexey Kodanev wrote:
> sysctl has sysctl.net.core.rmem_*/wmem_* parameters which can be
> set to incorrect values. Given that 'struct sk_buff' allocates from
> rcvbuf, incorrectly set buffer length could result to memory
> allocation failures. For example, set them as follows:
> 
>     # sysctl net.core.rmem_default=64
>       net.core.wmem_default = 64
>     # sysctl net.core.wmem_default=64
>       net.core.wmem_default = 64
>     # ping localhost -s 1024 -i 0 > /dev/null
> 

Yeah, root users seem to act like monkeys these days ;)

Note the real bug is in unix_stream_sendmsg(), as it assumes
 sk_sndbuf > 130 :

	/* Keep two messages in the pipe so it schedules better */
	size = min_t(int, size, (sk->sk_sndbuf >> 1) - 64);

The 64 here seems to assume skb overhead of linux 0.1 on a hypothetical
16bit host ;)

I guess your fix is fine, but might break applications that were
expecting that sysctl net.core.wmem_default=512  would effectively limit
queue occupancy to one skb (without crashing unix_stream_sendmsg())

As commit eea86af6b1e18d6fa did not trigger bug reports, I think we
should get your patch, and eventually adjust SOCK_MIN_SNDBUF if required
later.

Note that we should also limit max value, because of possible arithmetic
overflows for sk->sk_wmem_alloc.

A max of (1U << 31) might be reasonable ?




--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller March 12, 2015, 1:25 a.m. UTC | #2
From: Alexey Kodanev <alexey.kodanev@oracle.com>
Date: Wed, 11 Mar 2015 14:29:17 +0300

> sysctl has sysctl.net.core.rmem_*/wmem_* parameters which can be
> set to incorrect values. Given that 'struct sk_buff' allocates from
> rcvbuf, incorrectly set buffer length could result to memory
> allocation failures. For example, set them as follows:
> 
>     # sysctl net.core.rmem_default=64
>       net.core.wmem_default = 64
>     # sysctl net.core.wmem_default=64
>       net.core.wmem_default = 64
>     # ping localhost -s 1024 -i 0 > /dev/null
> 
> This could result to the following failure:
 ...
> Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>

Applied, but someone needs to followup with fixes to AF_UNIX etc.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 4334248..8ce351f 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -25,6 +25,8 @@ 
 static int zero = 0;
 static int one = 1;
 static int ushort_max = USHRT_MAX;
+static int min_sndbuf = SOCK_MIN_SNDBUF;
+static int min_rcvbuf = SOCK_MIN_RCVBUF;
 
 static int net_msg_warn;	/* Unused, but still a sysctl */
 
@@ -237,7 +239,7 @@  static struct ctl_table net_core_table[] = {
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_minmax,
-		.extra1		= &one,
+		.extra1		= &min_sndbuf,
 	},
 	{
 		.procname	= "rmem_max",
@@ -245,7 +247,7 @@  static struct ctl_table net_core_table[] = {
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_minmax,
-		.extra1		= &one,
+		.extra1		= &min_rcvbuf,
 	},
 	{
 		.procname	= "wmem_default",
@@ -253,7 +255,7 @@  static struct ctl_table net_core_table[] = {
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_minmax,
-		.extra1		= &one,
+		.extra1		= &min_sndbuf,
 	},
 	{
 		.procname	= "rmem_default",
@@ -261,7 +263,7 @@  static struct ctl_table net_core_table[] = {
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_minmax,
-		.extra1		= &one,
+		.extra1		= &min_rcvbuf,
 	},
 	{
 		.procname	= "dev_weight",