Commit 0b8336f5fc26f263821534d7a9a3633748692207

Authored by Sven Eckelmann
Committed by Antonio Quartulli
1 parent 77927b7d9d

batman-adv: Fix gw_bandwidth calculation on 32 bit systems

The TVLV for the gw_bandwidth stores everything as u32. But the
gw_bandwidth reads the signed long which limits the maximum value to
(2 ** 31 - 1) on systems with 4 byte long. Also the input value is always
converted from either Mibit/s or Kibit/s to 100Kibit/s. This reduces the
values even further when the user sets it via the default unit Kibit/s. It
may even cause an integer overflow and end up with a value the user never
intended.

Instead read the values as u64, check for possible overflows, do the unit
adjustments and then reduce the size to u32.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>

Showing 1 changed file with 42 additions and 7 deletions Side-by-side Diff

net/batman-adv/gateway_common.c
... ... @@ -22,6 +22,7 @@
22 22 #include <linux/errno.h>
23 23 #include <linux/byteorder/generic.h>
24 24 #include <linux/kernel.h>
  25 +#include <linux/math64.h>
25 26 #include <linux/netdevice.h>
26 27 #include <linux/stddef.h>
27 28 #include <linux/string.h>
... ... @@ -44,7 +45,7 @@
44 45 {
45 46 enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT;
46 47 char *slash_ptr, *tmp_ptr;
47   - long ldown, lup;
  48 + u64 ldown, lup;
48 49 int ret;
49 50  
50 51 slash_ptr = strchr(buff, '/');
... ... @@ -62,7 +63,7 @@
62 63 *tmp_ptr = '\0';
63 64 }
64 65  
65   - ret = kstrtol(buff, 10, &ldown);
  66 + ret = kstrtou64(buff, 10, &ldown);
66 67 if (ret) {
67 68 batadv_err(net_dev,
68 69 "Download speed of gateway mode invalid: %s\n",
69 70  
70 71  
... ... @@ -72,14 +73,31 @@
72 73  
73 74 switch (bw_unit_type) {
74 75 case BATADV_BW_UNIT_MBIT:
75   - *down = ldown * 10;
  76 + /* prevent overflow */
  77 + if (U64_MAX / 10 < ldown) {
  78 + batadv_err(net_dev,
  79 + "Download speed of gateway mode too large: %s\n",
  80 + buff);
  81 + return false;
  82 + }
  83 +
  84 + ldown *= 10;
76 85 break;
77 86 case BATADV_BW_UNIT_KBIT:
78 87 default:
79   - *down = ldown / 100;
  88 + ldown = div_u64(ldown, 100);
80 89 break;
81 90 }
82 91  
  92 + if (U32_MAX < ldown) {
  93 + batadv_err(net_dev,
  94 + "Download speed of gateway mode too large: %s\n",
  95 + buff);
  96 + return false;
  97 + }
  98 +
  99 + *down = ldown;
  100 +
83 101 /* we also got some upload info */
84 102 if (slash_ptr) {
85 103 bw_unit_type = BATADV_BW_UNIT_KBIT;
... ... @@ -95,7 +113,7 @@
95 113 *tmp_ptr = '\0';
96 114 }
97 115  
98   - ret = kstrtol(slash_ptr + 1, 10, &lup);
  116 + ret = kstrtou64(slash_ptr + 1, 10, &lup);
99 117 if (ret) {
100 118 batadv_err(net_dev,
101 119 "Upload speed of gateway mode invalid: %s\n",
102 120  
103 121  
... ... @@ -105,13 +123,30 @@
105 123  
106 124 switch (bw_unit_type) {
107 125 case BATADV_BW_UNIT_MBIT:
108   - *up = lup * 10;
  126 + /* prevent overflow */
  127 + if (U64_MAX / 10 < lup) {
  128 + batadv_err(net_dev,
  129 + "Upload speed of gateway mode too large: %s\n",
  130 + slash_ptr + 1);
  131 + return false;
  132 + }
  133 +
  134 + lup *= 10;
109 135 break;
110 136 case BATADV_BW_UNIT_KBIT:
111 137 default:
112   - *up = lup / 100;
  138 + lup = div_u64(lup, 100);
113 139 break;
114 140 }
  141 +
  142 + if (U32_MAX < lup) {
  143 + batadv_err(net_dev,
  144 + "Upload speed of gateway mode too large: %s\n",
  145 + slash_ptr + 1);
  146 + return false;
  147 + }
  148 +
  149 + *up = lup;
115 150 }
116 151  
117 152 return true;