Validate DAD configs when initializing DAD state

Make sure that the initial configurations used by the DAD state is
valid.

Before this change, an invalid DAD configuration (with a zero-valued
retransmit timer) was used so the DAD state would attempt to resolve
DAD immediately.

This lead to a deadlock in TestDADResolve as when DAD resolves, the
stack notifies the NDP dispatcher which would attempt to write to an
unbuffered channel while holding a lock. The test goroutine also
attempts to obtain a stack.Route (before receiving from the channel)
which ends up attempting to take the same lock.

Test: stack_test.TestDADResolve
PiperOrigin-RevId: 373888540
This commit is contained in:
Ghanan Gowripalan 2021-05-14 16:32:28 -07:00 committed by gVisor bot
parent df2352796d
commit 820c77d5e7
2 changed files with 10 additions and 13 deletions

View File

@ -83,6 +83,8 @@ func (d *DAD) Init(protocolMU sync.Locker, configs stack.DADConfigurations, opts
panic(fmt.Sprintf("given a non-zero value for NonceSize (%d) but zero for ExtendDADTransmits", opts.NonceSize))
}
configs.Validate()
*d = DAD{
opts: opts,
configs: configs,

View File

@ -481,13 +481,9 @@ func TestDADResolve(t *testing.T) {
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
ndpDisp := ndpDispatcher{
dadC: make(chan ndpDADEvent),
dadC: make(chan ndpDADEvent, 1),
}
e := channelLinkWithHeaderLength{
@ -499,7 +495,9 @@ func TestDADResolve(t *testing.T) {
var secureRNG bytes.Reader
secureRNG.Reset(secureRNGBytes)
clock := faketime.NewManualClock()
s := stack.New(stack.Options{
Clock: clock,
SecureRNG: &secureRNG,
NetworkProtocols: []stack.NetworkProtocolFactory{ipv6.NewProtocolWithOptions(ipv6.Options{
NDPDisp: &ndpDisp,
@ -529,14 +527,10 @@ func TestDADResolve(t *testing.T) {
t.Fatalf("AddAddressWithPrefix(%d, %d, %s) = %s", nicID, header.IPv6ProtocolNumber, addrWithPrefix, err)
}
// Address should not be considered bound to the NIC yet (DAD ongoing).
if err := checkGetMainNICAddress(s, nicID, header.IPv6ProtocolNumber, tcpip.AddressWithPrefix{}); err != nil {
t.Fatal(err)
}
// Make sure the address does not resolve before the resolution time has
// passed.
time.Sleep(test.expectedRetransmitTimer*time.Duration(test.dupAddrDetectTransmits) - defaultAsyncNegativeEventTimeout)
const delta = time.Nanosecond
clock.Advance(test.expectedRetransmitTimer*time.Duration(test.dupAddrDetectTransmits) - delta)
if err := checkGetMainNICAddress(s, nicID, header.IPv6ProtocolNumber, tcpip.AddressWithPrefix{}); err != nil {
t.Error(err)
}
@ -566,13 +560,14 @@ func TestDADResolve(t *testing.T) {
}
// Wait for DAD to resolve.
clock.Advance(delta)
select {
case <-time.After(defaultAsyncPositiveEventTimeout):
t.Fatal("timed out waiting for DAD resolution")
case e := <-ndpDisp.dadC:
if diff := checkDADEvent(e, nicID, addr1, &stack.DADSucceeded{}); diff != "" {
t.Errorf("DAD event mismatch (-want +got):\n%s", diff)
}
default:
t.Fatalf("expected DAD event for %s on NIC(%d)", addr1, nicID)
}
if err := checkGetMainNICAddress(s, nicID, header.IPv6ProtocolNumber, addrWithPrefix); err != nil {
t.Error(err)