Before/while a tracker packet is being searched for next hops for its destination entries, it will also be checked if the number of destination and mcast entries might exceed the tracker_packet_len. Otherwise we might read/write in unallocated memory. Such a broken tracker packet could potentially occure when we are going to reuse route_mcast_tracker_packet for tracker packets received from a neighbour node.
In such a case, we are just reducing the stated mcast / dest numbers in the tracker packet to fit the size of the allocated buffer. Signed-off-by: Linus Lüssing <[email protected]> --- multicast.c | 29 +++++++++++++++++++++++++---- 1 files changed, 25 insertions(+), 4 deletions(-) diff --git a/multicast.c b/multicast.c index bfb1410..2b3d613 100644 --- a/multicast.c +++ b/multicast.c @@ -293,25 +293,46 @@ free: return 1; } -/* Collect nexthops for all dest entries specified in this tracker packet */ +/* Collect nexthops for all dest entries specified in this tracker packet. + * It also reduces the number of elements in the tracker packet if they exceed + * the buffers length (i.g. because of a received, broken tracker packet) to + * avoid writing in unallocated memory. */ static int tracker_next_hops(struct mcast_tracker_packet *tracker_packet, + int tracker_packet_len, struct dest_entries_list *next_hops, struct bat_priv *bat_priv) { int num_next_hops = 0, mcast_num, dest_num, ret; struct mcast_entry *mcast_entry; uint8_t *dest_entry; + uint8_t *tail = (uint8_t *)tracker_packet + tracker_packet_len; INIT_LIST_HEAD(&next_hops->list); tracker_packet_for_each_dest(mcast_entry, dest_entry, mcast_num, dest_num, tracker_packet) { + /* avoid writing outside of unallocated memory later */ + if (dest_entry + ETH_ALEN > tail) { + bat_dbg(DBG_BATMAN, bat_priv, + "mcast tracker packet is broken, too many " + "entries claimed for its length, repairing"); + + tracker_packet->num_mcast_entries = mcast_num; + + if (dest_num) { + tracker_packet->num_mcast_entries++; + mcast_entry->num_dest = dest_num; + } + + goto out; + } + ret = add_router_of_dest(next_hops, dest_entry, bat_priv); if (!ret) num_next_hops++; } - +out: return num_next_hops; } @@ -450,8 +471,8 @@ void route_mcast_tracker_packet( int *tracker_packet_lengths; rcu_read_lock(); - num_next_hops = tracker_next_hops(tracker_packet, &next_hops, - bat_priv); + num_next_hops = tracker_next_hops(tracker_packet, tracker_packet_len, + &next_hops, bat_priv); if (!num_next_hops) goto out; next_hop_tracker_packets = kmalloc(tracker_packet_len * num_next_hops, -- 1.7.1
