diff options
author | Ayush Ranjan <ayushranjan@google.com> | 2020-12-15 15:25:35 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-12-15 15:27:35 -0800 |
commit | f6407de6bafbf8fe3e4579c876640672380fa96c (patch) | |
tree | 313172f5a4285887629379df898f09fcda65919a /pkg/sentry/mm/mm_test.go | |
parent | cc28d36845cd3b2267ececbdf81b2c265267cdec (diff) |
[syzkaller] Avoid AIOContext from resurrecting after being marked dead.
syzkaller reported the closing of a nil channel. This is only possible when the
AIOContext was destroyed twice.
Some scenarios that could lead to this:
- It died and then some called aioCtx.Prepare() on it and then killed it again
which could cause the double destroy. The context could have been destroyed
in between the call to LookupAIOContext() and Prepare().
- aioManager was destroyed but it did not update the contexts map. So
Lookup could still return a dead AIOContext and then someone could call
Prepare on it and kill it again.
So added a check in aioCtx.Prepare() for the context being dead. This will
prevent a dead context from resurrecting.
Also refactored code to destroy the aioContext consistently. Earlier we were not
munmapping the aioContexts that were destroyed upon aioManager destruction.
Reported-by: syzbot+ef6a588d0ce6059991d2@syzkaller.appspotmail.com
PiperOrigin-RevId: 347704347
Diffstat (limited to 'pkg/sentry/mm/mm_test.go')
-rw-r--r-- | pkg/sentry/mm/mm_test.go | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/pkg/sentry/mm/mm_test.go b/pkg/sentry/mm/mm_test.go index acac3d357..bc53bd41e 100644 --- a/pkg/sentry/mm/mm_test.go +++ b/pkg/sentry/mm/mm_test.go @@ -229,3 +229,46 @@ func TestIOAfterMProtect(t *testing.T) { t.Errorf("CopyOut got %d want 1", n) } } + +// TestAIOPrepareAfterDestroy tests that AIOContext should not be able to be +// prepared after destruction. +func TestAIOPrepareAfterDestroy(t *testing.T) { + ctx := contexttest.Context(t) + mm := testMemoryManager(ctx) + defer mm.DecUsers(ctx) + + id, err := mm.NewAIOContext(ctx, 1) + if err != nil { + t.Fatalf("mm.NewAIOContext got err %v want nil", err) + } + aioCtx, ok := mm.LookupAIOContext(ctx, id) + if !ok { + t.Fatalf("AIOContext not found") + } + mm.DestroyAIOContext(ctx, id) + + // Prepare should fail because aioCtx should be destroyed. + if err := aioCtx.Prepare(); err != syserror.EINVAL { + t.Errorf("aioCtx.Prepare got err %v want nil", err) + } else if err == nil { + aioCtx.CancelPendingRequest() + } +} + +// TestAIOLookupAfterDestroy tests that AIOContext should not be able to be +// looked up after memory manager is destroyed. +func TestAIOLookupAfterDestroy(t *testing.T) { + ctx := contexttest.Context(t) + mm := testMemoryManager(ctx) + + id, err := mm.NewAIOContext(ctx, 1) + if err != nil { + mm.DecUsers(ctx) + t.Fatalf("mm.NewAIOContext got err %v want nil", err) + } + mm.DecUsers(ctx) // This destroys the AIOContext manager. + + if _, ok := mm.LookupAIOContext(ctx, id); ok { + t.Errorf("AIOContext found even after AIOContext manager is destroyed") + } +} |