Commit 0b8336f5fc26f263821534d7a9a3633748692207
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; |