Skip to content

Commit

Permalink
wasi: prohibits closing pre-opens
Browse files Browse the repository at this point in the history
See WebAssembly/wasi-testsuite#50

Signed-off-by: Adrian Cole <adrian@tetrate.io>
  • Loading branch information
Adrian Cole committed Jan 31, 2023
1 parent 67125fc commit 5cf1816
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 5 deletions.
1 change: 1 addition & 0 deletions imports/wasi_snapshot_preview1/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ var fdAllocate = stubFunction(
//
// The return value is ErrnoSuccess except the following error conditions:
// - ErrnoBadf: the fd was not open.
// - ErrnoNotsup: the fs was a pre-open
//
// Note: This is similar to `close` in POSIX.
// See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_close
Expand Down
8 changes: 8 additions & 0 deletions imports/wasi_snapshot_preview1/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ func Test_fdClose(t *testing.T) {
require.Equal(t, `
==> wasi_snapshot_preview1.fd_close(fd=42)
<== errno=EBADF
`, "\n"+log.String())
})
log.Reset()
t.Run("ErrnoNotsup for a preopen", func(t *testing.T) {
requireErrno(t, ErrnoNotsup, mod, FdCloseName, uint64(sys.FdPreopen))
require.Equal(t, `
==> wasi_snapshot_preview1.fd_close(fd=3)
<== errno=ENOTSUP
`, "\n"+log.String())
})
}
Expand Down
8 changes: 6 additions & 2 deletions internal/sys/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,15 +259,15 @@ func stdinReader(r io.Reader) *FileEntry {
r = eofReader{}
}
s := stdioStat(r, noopStdinStat)
return &FileEntry{IsPreopen: true, Name: noopStdinStat.Name(), File: &stdioFileReader{r: r, s: s}}
return &FileEntry{Name: noopStdinStat.Name(), File: &stdioFileReader{r: r, s: s}}
}

func stdioWriter(w io.Writer, defaultStat stdioFileInfo) *FileEntry {
if w == nil {
w = io.Discard
}
s := stdioStat(w, defaultStat)
return &FileEntry{IsPreopen: true, Name: s.Name(), File: &stdioFileWriter{w: w, s: s}}
return &FileEntry{Name: s.Name(), File: &stdioFileWriter{w: w, s: s}}
}

func stdioStat(f interface{}, defaultStat stdioFileInfo) fs.FileInfo {
Expand Down Expand Up @@ -350,6 +350,10 @@ func (c *FSContext) CloseFile(fd uint32) error {
f, ok := c.openedFiles.Lookup(fd)
if !ok {
return syscall.EBADF
} else if f.IsPreopen {
// WASI is the only user of pre-opens and wasi-testsuite disallows this
// See https://github.com/WebAssembly/wasi-testsuite/issues/50
return syscall.ENOTSUP
}
c.openedFiles.Delete(fd)
return f.File.Close()
Expand Down
40 changes: 37 additions & 3 deletions internal/sys/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import (
var testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary")

var (
noopStdin = &FileEntry{IsPreopen: true, Name: "stdin", File: &stdioFileReader{r: eofReader{}, s: noopStdinStat}}
noopStdout = &FileEntry{IsPreopen: true, Name: "stdout", File: &stdioFileWriter{w: io.Discard, s: noopStdoutStat}}
noopStderr = &FileEntry{IsPreopen: true, Name: "stderr", File: &stdioFileWriter{w: io.Discard, s: noopStderrStat}}
noopStdin = &FileEntry{Name: "stdin", File: &stdioFileReader{r: eofReader{}, s: noopStdinStat}}
noopStdout = &FileEntry{Name: "stdout", File: &stdioFileWriter{w: io.Discard, s: noopStdoutStat}}
noopStderr = &FileEntry{Name: "stderr", File: &stdioFileWriter{w: io.Discard, s: noopStderrStat}}
)

//go:embed testdata
Expand Down Expand Up @@ -94,6 +94,40 @@ func TestNewFSContext(t *testing.T) {
}
}

func TestFSContext_CloseFile(t *testing.T) {
embedFS, err := fs.Sub(testdata, "testdata")
require.NoError(t, err)
testFS := sysfs.Adapt(embedFS)

fsc, err := NewFSContext(nil, nil, nil, testFS)
require.NoError(t, err)
defer fsc.Close(testCtx)

fdToClose, err := fsc.OpenFile(testFS, "empty.txt", os.O_RDONLY, 0)
require.NoError(t, err)

fdToKeep, err := fsc.OpenFile(testFS, "test.txt", os.O_RDONLY, 0)
require.NoError(t, err)

// Close
require.NoError(t, fsc.CloseFile(fdToClose))

// Verify fdToClose is closed and removed from the opened FDs.
_, ok := fsc.LookupFile(fdToClose)
require.False(t, ok)

// Verify fdToKeep is not closed
_, ok = fsc.LookupFile(fdToKeep)
require.True(t, ok)

t.Run("EBADF for an invalid FD", func(t *testing.T) {
require.Equal(t, syscall.EBADF, fsc.CloseFile(42)) // 42 is an arbitrary invalid FD
})
t.Run("ENOTSUP for a preopen", func(t *testing.T) {
require.Equal(t, syscall.ENOTSUP, fsc.CloseFile(FdPreopen)) // 42 is an arbitrary invalid FD
})
}

func TestUnimplementedFSContext(t *testing.T) {
testFS, err := NewFSContext(nil, nil, nil, sysfs.UnimplementedFS{})
require.NoError(t, err)
Expand Down
2 changes: 2 additions & 0 deletions internal/wasi_snapshot_preview1/errno.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ func ToErrno(err error) Errno {
return ErrnoNoent
case errors.Is(err, syscall.ENOSYS):
return ErrnoNosys
case errors.Is(err, syscall.ENOTSUP):
return ErrnoNotsup
case errors.Is(err, syscall.ENOTDIR):
return ErrnoNotdir
case errors.Is(err, syscall.EPERM), errors.Is(err, fs.ErrPermission):
Expand Down

0 comments on commit 5cf1816

Please sign in to comment.