Fix an LLE lookup race.
After the afdata read lock was converted to epoch(9), readers could observe a linked LLE and block on the LLE while a thread was unlinking the LLE. The writer would then release the lock and schedule the LLE for deferred free, allowing readers to continue and potentially schedule the LLE timer. By the point the timer fires, the structure is freed, typically resulting in a crash in the callout subsystem. Fix the problem by modifying the lookup path to check for the LLE_LINKED flag upon acquiring the LLE lock. If it's not set, the lookup fails. PR: 234296 Reviewed by: bz Tested by: sbruno, Victor <chernov_victor@list.ru>, Mike Andrews <mandrews@bit0.com> MFC after: 3 days Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D18906
This commit is contained in:
parent
189fbd9cdb
commit
af69719726
@ -1399,6 +1399,17 @@ in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3add
|
||||
else
|
||||
LLE_RLOCK(lle);
|
||||
|
||||
/*
|
||||
* If the afdata lock is not held, the LLE may have been unlinked while
|
||||
* we were blocked on the LLE lock. Check for this case.
|
||||
*/
|
||||
if (__predict_false((lle->la_flags & LLE_LINKED) == 0)) {
|
||||
if (flags & LLE_EXCLUSIVE)
|
||||
LLE_WUNLOCK(lle);
|
||||
else
|
||||
LLE_RUNLOCK(lle);
|
||||
return (NULL);
|
||||
}
|
||||
return (lle);
|
||||
}
|
||||
|
||||
|
@ -2342,6 +2342,18 @@ in6_lltable_lookup(struct lltable *llt, u_int flags,
|
||||
LLE_WLOCK(lle);
|
||||
else
|
||||
LLE_RLOCK(lle);
|
||||
|
||||
/*
|
||||
* If the afdata lock is not held, the LLE may have been unlinked while
|
||||
* we were blocked on the LLE lock. Check for this case.
|
||||
*/
|
||||
if (__predict_false((lle->la_flags & LLE_LINKED) == 0)) {
|
||||
if (flags & LLE_EXCLUSIVE)
|
||||
LLE_WUNLOCK(lle);
|
||||
else
|
||||
LLE_RUNLOCK(lle);
|
||||
return (NULL);
|
||||
}
|
||||
return (lle);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user