Page MenuHomeFreeBSD

ifnet: Fix races in if_vmove_reclaim()
Needs ReviewPublic

Authored by zlei on Fri, Mar 20, 6:54 PM.

Details

Reviewers
kp
glebius
Group Reviewers
network
Summary

The thread running if_vmove_reclaim() may race with other threads those
running if_detach(), if_vmove_loan() or if_vmove_reclaim(). In case it
loses race, there're two issues with it,

  1. It is unstable and unsafe to access ifp->if_vnet.
  2. The interface is removed from "active" list, hence if_unlink_ifnet() can fail.

For the first case, check against source prison's vnet instead, given
the interface is obtained from that vnet.

For the second case, return ENODEV to indicate the interface was on the
list but the current thread loses race, to distinguish from ENXIO, which
means the interface or child prison is not found. This is the same with
if_vmove_loan().

Fixes: a779388f8bb3 if: Protect V_ifnet in vnet_if_return()
MFC after: 1 week

Test Plan

Run with this regression test,

#!/bin/sh

error=0

IFCONFIG="ifconfig -n"

epair_a=$(ifconfig epair create)
epair_b=${epair_a%a}b

jail -c vnet name="epair_destroy" persist path=/

i=0
while [ $i -lt 10 ]
do
        $IFCONFIG $epair_b vnet epair_destroy

        $IFCONFIG $epair_b -vnet epair_destroy >/dev/null 2>&1 & p1=$!
        $IFCONFIG $epair_b -vnet epair_destroy >/dev/null 2>&1 & p2=$!

        wait $p1
        err1="$?"
        wait $p2
        err2="$?"

        if [ $err1 -eq 0 ] && [ $err2 -eq 0 ]; then
                echo "Conflict detected!"
                error=1
                break
        fi
        i=$(( i + 1 ))
done

jail -R epair_destroy
$IFCONFIG $epair_a destroy
exit $error

It is easy to repeat on 14.4-RELEASE, but need extra efforts on current . With this dtrace script it is easier to repeat.

#!/usr/sbin/dtrace -ws

fbt::if_unlink_ifnet:entry
{
        chill(100000);
}

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped