diff options
author | Sven Eckelmann <sven@narfation.org> | 2018-08-31 10:56:29 -0400 |
---|---|---|
committer | Simon Wunderlich <sw@simonwunderlich.de> | 2018-09-06 07:54:48 -0400 |
commit | a25bab9d723a08bd0bdafb1529faf9094c690b70 (patch) | |
tree | 284b63130f2d9a96cf1cc82d2f7a809805a7afbf | |
parent | b9fd14c20871e6189f635e49b32d7789e430b3c8 (diff) |
batman-adv: Fix segfault when writing to sysfs elp_interval
The per hardif sysfs file "batman_adv/elp_interval" is using the generic
functions to store/show uint values. The helper __batadv_store_uint_attr
requires the softif net_device as parameter to print the resulting change
as info text when the users writes to this file. It uses the helper
function batadv_info to add it at the same time to the kernel ring buffer
and to the batman-adv debug log (when CONFIG_BATMAN_ADV_DEBUG is enabled).
The function batadv_info requires as first parameter the batman-adv softif
net_device. This parameter is then used to find the private buffer which
contains the debug log for this batman-adv interface. But
batadv_store_throughput_override used as first argument the slave
net_device. This slave device doesn't have the batadv_priv private data
which is access by batadv_info.
Writing to this file with CONFIG_BATMAN_ADV_DEBUG enabled can either lead
to a segfault or to memory corruption.
Fixes: 0744ff8fa8fa ("batman-adv: Add hard_iface specific sysfs wrapper macros for UINT")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Acked-by: Marek Lindner <mareklindner@neomailbox.ch>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
-rw-r--r-- | net/batman-adv/sysfs.c | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index 3a76e8970c02..09427fc6494a 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c | |||
@@ -188,7 +188,8 @@ ssize_t batadv_store_##_name(struct kobject *kobj, \ | |||
188 | \ | 188 | \ |
189 | return __batadv_store_uint_attr(buff, count, _min, _max, \ | 189 | return __batadv_store_uint_attr(buff, count, _min, _max, \ |
190 | _post_func, attr, \ | 190 | _post_func, attr, \ |
191 | &bat_priv->_var, net_dev); \ | 191 | &bat_priv->_var, net_dev, \ |
192 | NULL); \ | ||
192 | } | 193 | } |
193 | 194 | ||
194 | #define BATADV_ATTR_SIF_SHOW_UINT(_name, _var) \ | 195 | #define BATADV_ATTR_SIF_SHOW_UINT(_name, _var) \ |
@@ -262,7 +263,9 @@ ssize_t batadv_store_##_name(struct kobject *kobj, \ | |||
262 | \ | 263 | \ |
263 | length = __batadv_store_uint_attr(buff, count, _min, _max, \ | 264 | length = __batadv_store_uint_attr(buff, count, _min, _max, \ |
264 | _post_func, attr, \ | 265 | _post_func, attr, \ |
265 | &hard_iface->_var, net_dev); \ | 266 | &hard_iface->_var, \ |
267 | hard_iface->soft_iface, \ | ||
268 | net_dev); \ | ||
266 | \ | 269 | \ |
267 | batadv_hardif_put(hard_iface); \ | 270 | batadv_hardif_put(hard_iface); \ |
268 | return length; \ | 271 | return length; \ |
@@ -356,10 +359,12 @@ __batadv_store_bool_attr(char *buff, size_t count, | |||
356 | 359 | ||
357 | static int batadv_store_uint_attr(const char *buff, size_t count, | 360 | static int batadv_store_uint_attr(const char *buff, size_t count, |
358 | struct net_device *net_dev, | 361 | struct net_device *net_dev, |
362 | struct net_device *slave_dev, | ||
359 | const char *attr_name, | 363 | const char *attr_name, |
360 | unsigned int min, unsigned int max, | 364 | unsigned int min, unsigned int max, |
361 | atomic_t *attr) | 365 | atomic_t *attr) |
362 | { | 366 | { |
367 | char ifname[IFNAMSIZ + 3] = ""; | ||
363 | unsigned long uint_val; | 368 | unsigned long uint_val; |
364 | int ret; | 369 | int ret; |
365 | 370 | ||
@@ -385,8 +390,11 @@ static int batadv_store_uint_attr(const char *buff, size_t count, | |||
385 | if (atomic_read(attr) == uint_val) | 390 | if (atomic_read(attr) == uint_val) |
386 | return count; | 391 | return count; |
387 | 392 | ||
388 | batadv_info(net_dev, "%s: Changing from: %i to: %lu\n", | 393 | if (slave_dev) |
389 | attr_name, atomic_read(attr), uint_val); | 394 | snprintf(ifname, sizeof(ifname), "%s: ", slave_dev->name); |
395 | |||
396 | batadv_info(net_dev, "%s: %sChanging from: %i to: %lu\n", | ||
397 | attr_name, ifname, atomic_read(attr), uint_val); | ||
390 | 398 | ||
391 | atomic_set(attr, uint_val); | 399 | atomic_set(attr, uint_val); |
392 | return count; | 400 | return count; |
@@ -397,12 +405,13 @@ static ssize_t __batadv_store_uint_attr(const char *buff, size_t count, | |||
397 | void (*post_func)(struct net_device *), | 405 | void (*post_func)(struct net_device *), |
398 | const struct attribute *attr, | 406 | const struct attribute *attr, |
399 | atomic_t *attr_store, | 407 | atomic_t *attr_store, |
400 | struct net_device *net_dev) | 408 | struct net_device *net_dev, |
409 | struct net_device *slave_dev) | ||
401 | { | 410 | { |
402 | int ret; | 411 | int ret; |
403 | 412 | ||
404 | ret = batadv_store_uint_attr(buff, count, net_dev, attr->name, min, max, | 413 | ret = batadv_store_uint_attr(buff, count, net_dev, slave_dev, |
405 | attr_store); | 414 | attr->name, min, max, attr_store); |
406 | if (post_func && ret) | 415 | if (post_func && ret) |
407 | post_func(net_dev); | 416 | post_func(net_dev); |
408 | 417 | ||
@@ -571,7 +580,7 @@ static ssize_t batadv_store_gw_sel_class(struct kobject *kobj, | |||
571 | return __batadv_store_uint_attr(buff, count, 1, BATADV_TQ_MAX_VALUE, | 580 | return __batadv_store_uint_attr(buff, count, 1, BATADV_TQ_MAX_VALUE, |
572 | batadv_post_gw_reselect, attr, | 581 | batadv_post_gw_reselect, attr, |
573 | &bat_priv->gw.sel_class, | 582 | &bat_priv->gw.sel_class, |
574 | bat_priv->soft_iface); | 583 | bat_priv->soft_iface, NULL); |
575 | } | 584 | } |
576 | 585 | ||
577 | static ssize_t batadv_show_gw_bwidth(struct kobject *kobj, | 586 | static ssize_t batadv_show_gw_bwidth(struct kobject *kobj, |