libnet/osl: stop assuming caller thread is clean
(*networkNamespace).InvokeFunc() cleaned up the state of the locked thread by setting its network namespace to the netns of the goroutine which called InvokeFunc(). If InvokeFunc() was to be called after the caller had modified its thread's network namespace, InvokeFunc() would incorrectly "restore" the state of its goroutine thread to the wrong namespace, violating the invariant that unlocked threads are fungible. Change the implementation to restore the thread's netns to the netns that particular thread had before InvokeFunc() modified it. Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
parent
4f3c5b2568
commit
8404507b9b
1 changed files with 12 additions and 6 deletions
|
@ -420,12 +420,6 @@ func (n *networkNamespace) DisableARPForVIP(srcName string) (Err error) {
|
|||
}
|
||||
|
||||
func (n *networkNamespace) InvokeFunc(f func()) error {
|
||||
origNS, err := netns.Get()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get original network namespace: %w", err)
|
||||
}
|
||||
defer origNS.Close()
|
||||
|
||||
path := n.nsPath()
|
||||
newNS, err := netns.GetFromPath(path)
|
||||
if err != nil {
|
||||
|
@ -436,6 +430,18 @@ func (n *networkNamespace) InvokeFunc(f func()) error {
|
|||
done := make(chan error, 1)
|
||||
go func() {
|
||||
runtime.LockOSThread()
|
||||
// InvokeFunc() could have been called from a goroutine with
|
||||
// tampered thread state, e.g. from another InvokeFunc()
|
||||
// callback. The outer goroutine's thread state cannot be
|
||||
// trusted.
|
||||
origNS, err := netns.Get()
|
||||
if err != nil {
|
||||
runtime.UnlockOSThread()
|
||||
done <- fmt.Errorf("failed to get original network namespace: %w", err)
|
||||
return
|
||||
}
|
||||
defer origNS.Close()
|
||||
|
||||
if err := netns.Set(newNS); err != nil {
|
||||
runtime.UnlockOSThread()
|
||||
done <- err
|
||||
|
|
Loading…
Reference in a new issue