Commit 0147fc058d11bd4009b126d09974d2c8f48fef15

Authored by Alexey Dobriyan
Committed by David S. Miller
1 parent 8475ef9fd1

tcp: restrict net.ipv4.tcp_adv_win_scale (#20312)

tcp_win_from_space() does the following:

      if (sysctl_tcp_adv_win_scale <= 0)
              return space >> (-sysctl_tcp_adv_win_scale);
      else
              return space - (space >> sysctl_tcp_adv_win_scale);

"space" is int.

As per C99 6.5.7 (3) shifting int for 32 or more bits is
undefined behaviour.

Indeed, if sysctl_tcp_adv_win_scale is exactly 32,
space >> 32 equals space and function returns 0.

Which means we busyloop in tcp_fixup_rcvbuf().

Restrict net.ipv4.tcp_adv_win_scale to [-31, 31].

Fix https://bugzilla.kernel.org/show_bug.cgi?id=20312

Steps to reproduce:

      echo 32 >/proc/sys/net/ipv4/tcp_adv_win_scale
      wget www.kernel.org
      [softlockup]

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 2 changed files with 6 additions and 1 deletions Side-by-side Diff

Documentation/networking/ip-sysctl.txt
... ... @@ -144,6 +144,7 @@
144 144 Count buffering overhead as bytes/2^tcp_adv_win_scale
145 145 (if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale),
146 146 if it is <= 0.
  147 + Possible values are [-31, 31], inclusive.
147 148 Default: 2
148 149  
149 150 tcp_allowed_congestion_control - STRING
net/ipv4/sysctl_net_ipv4.c
... ... @@ -26,6 +26,8 @@
26 26 static int tcp_retr1_max = 255;
27 27 static int ip_local_port_range_min[] = { 1, 1 };
28 28 static int ip_local_port_range_max[] = { 65535, 65535 };
  29 +static int tcp_adv_win_scale_min = -31;
  30 +static int tcp_adv_win_scale_max = 31;
29 31  
30 32 /* Update system visible IP port range */
31 33 static void set_local_port_range(int range[2])
... ... @@ -426,7 +428,9 @@
426 428 .data = &sysctl_tcp_adv_win_scale,
427 429 .maxlen = sizeof(int),
428 430 .mode = 0644,
429   - .proc_handler = proc_dointvec
  431 + .proc_handler = proc_dointvec_minmax,
  432 + .extra1 = &tcp_adv_win_scale_min,
  433 + .extra2 = &tcp_adv_win_scale_max,
430 434 },
431 435 {
432 436 .procname = "tcp_tw_reuse",