zebra:fix a zebra crash issue caused by mac change

When the MAC address of the neighbor changes, a possible crash issue may occur.

In the zebra_evpn_local_neigh_update function, the value of old_zmac (n->mac) will be updated to the new MAC address when the neighbor's MAC address changes.
The pointer to the memory that this pointer points to may be released in the zebra_evpn_local_neigh_deref_mac function. This will cause old_zmac to become a dangling pointer. Accessing this dangling pointer in the zebra_evpn_ip_inherit_dad_from_mac function below will cause the zebra process to crash.

Here is the backtrace:
(gdb) bt
0  0x00007fc12c5f1fbf in raise () from /lib/x86_64-linux-gnu/libpthread.so.0
1  0x00007fc12d52e19c in core_handler (signo=11, siginfo=0x7ffda1fd1570, context=<optimized out>) at lib/sigevent.c:262
2  <signal handler called>
3  zebra_evpn_ip_inherit_dad_from_mac (zvrf=<optimized out>, old_zmac=0x5579ac3ca520, new_zmac=0x5579aba82f80, nbr=0x5579abd65ec0) at zebra/ze
4  0x00005579aa8dbf6d in zebra_evpn_local_neigh_update (zevpn=0x5579abb81440, ifp=ifp@entry=0x5579ab8a1640, ip=ip@entry=0x7ffda1fd1b40, macadd
   local_inactive=local_inactive@entry=253, dp_static=false) at zebra/zebra_evpn_neigh.c:1729
5  0x00005579aa9190a9 in zebra_vxlan_handle_kernel_neigh_update (ifp=ifp@entry=0x5579ab8a1640, link_if=link_if@entry=0x5579abd14f90, ip=ip@ent
   is_ext=is_ext@entry=false, is_router=<optimized out>, local_inactive=false, dp_static=false) at zebra/zebra_vxlan.c:3791
6  0x00005579aa8b3048 in netlink_ipneigh_change (h=0x7ffda1fd1d50, len=<optimized out>, ns_id=<optimized out>) at zebra/rt_netlink.c:3649
7  0x00005579aa8ac667 in netlink_parse_info (filter=filter@entry=0x5579aa8ab630 <netlink_information_fetch>, nl=nl@entry=0x5579ab5861e8, zns=z
   startup=startup@entry=0) at zebra/kernel_netlink.c:965
8  0x00005579aa8ac8c8 in kernel_read (thread=<optimized out>) at zebra/kernel_netlink.c:402
9  0x00007fc12d53e60b in thread_call (thread=thread@entry=0x7ffda1fd9fd0) at lib/thread.c:1834
10 0x00007fc12d4fba78 in frr_run (master=0x5579ab3a1740) at lib/libfrr.c:1155
11 0x00005579aa89c6e3 in main (argc=11, argv=0x7ffda1fda3c8) at zebra/main.c:485
(gdb) f 3
3  zebra_evpn_ip_inherit_dad_from_mac (zvrf=<optimized out>, old_zmac=0x5579ac3ca520, new_zmac=0x5579aba82f80, nbr=0x5579abd65ec0) at zebra/ze
1230	zebra/zebra_evpn_neigh.c: No such file or directory.
(gdb) p *old_zmac
Cannot access memory at address 0x5579ac3ca520
(gdb)

To fix this issue, the ZEBRA_MAC_DUPLICATE flag should be retrieved before old_zmac is released and used in the zebra_evpn_ip_inherit_dad_from_mac function.

Signed-off-by: Jack.zhang <hanyu.zly@alibaba-inc.com>
This commit is contained in:
Jack.zhang 2023-07-19 17:46:46 +08:00
parent 3031b32ba8
commit a53159c8db

View File

@ -1038,11 +1038,10 @@ static inline void zebra_evpn_local_neigh_update_log(
* from MAC.
*/
static int zebra_evpn_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
struct zebra_mac *old_zmac,
bool is_old_mac_dup,
struct zebra_mac *new_zmac,
struct zebra_neigh *nbr)
{
bool is_old_mac_dup = false;
bool is_new_mac_dup = false;
if (!zebra_evpn_do_dup_addr_detect(zvrf))
@ -1050,9 +1049,6 @@ static int zebra_evpn_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
/* Check old or new MAC is detected as duplicate
* mark this neigh as duplicate
*/
if (old_zmac)
is_old_mac_dup =
CHECK_FLAG(old_zmac->flags, ZEBRA_MAC_DUPLICATE);
if (new_zmac)
is_new_mac_dup =
CHECK_FLAG(new_zmac->flags, ZEBRA_MAC_DUPLICATE);
@ -1262,6 +1258,7 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn,
bool new_static = false;
bool old_bgp_ready = false;
bool new_bgp_ready;
bool is_old_mac_dup = false;
/* Check if the MAC exists. */
zmac = zebra_evpn_mac_lookup(zevpn, macaddr);
@ -1408,6 +1405,7 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn,
old_bgp_ready = false;
}
if (old_zmac) {
is_old_mac_dup = CHECK_FLAG(old_zmac->flags, ZEBRA_MAC_DUPLICATE);
old_mac_seq = CHECK_FLAG(old_zmac->flags,
ZEBRA_MAC_REMOTE)
? old_zmac->rem_seq
@ -1437,6 +1435,7 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn,
!= 0) {
old_zmac = n->mac;
if (old_zmac) {
is_old_mac_dup = CHECK_FLAG(old_zmac->flags, ZEBRA_MAC_DUPLICATE);
old_mac_seq =
CHECK_FLAG(old_zmac->flags,
ZEBRA_MAC_REMOTE)
@ -1499,7 +1498,7 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn,
/* Check old and/or new MAC detected as duplicate mark
* the neigh as duplicate
*/
if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, old_zmac, zmac, n)) {
if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, is_old_mac_dup, zmac, n)) {
flog_warn(
EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
"VNI %u: MAC %pEA IP %pIA detected as duplicate during local update, inherit duplicate from MAC",
@ -2034,6 +2033,7 @@ void zebra_evpn_neigh_remote_macip_add(struct zebra_evpn *zevpn,
bool do_dad = false;
bool is_dup_detect = false;
bool is_router;
bool is_old_mac_dup = false;
assert(mac);
is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
@ -2086,6 +2086,7 @@ void zebra_evpn_neigh_remote_macip_add(struct zebra_evpn *zevpn,
old_mac =
zebra_evpn_mac_lookup(zevpn, &n->emac);
if (old_mac) {
is_old_mac_dup = CHECK_FLAG(old_mac->flags, ZEBRA_MAC_DUPLICATE);
listnode_delete(old_mac->neigh_list, n);
n->mac = NULL;
zebra_evpn_deref_ip2mac(zevpn, old_mac);
@ -2128,7 +2129,7 @@ void zebra_evpn_neigh_remote_macip_add(struct zebra_evpn *zevpn,
/* Check old or new MAC detected as duplicate,
* inherit duplicate flag to this neigh.
*/
if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, old_mac, mac, n)) {
if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, is_old_mac_dup, mac, n)) {
flog_warn(
EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
"VNI %u: MAC %pEA IP %pIA detected as duplicate during remote update, inherit duplicate from MAC",