Implement ioctl(fd, FIONREAD) for host FDs

Closes #6796

PiperOrigin-RevId: 409013591
This commit is contained in:
Fabricio Voznika
2021-11-10 17:07:06 -08:00
committed by gVisor bot
parent ffc3a0d840
commit 07836a3ff1
7 changed files with 98 additions and 2 deletions
@@ -11,3 +11,4 @@ RUN gcc -O2 -o test_copy_up test_copy_up.c
RUN gcc -O2 -o test_rewinddir test_rewinddir.c
RUN gcc -O2 -o link_test link_test.c
RUN gcc -O2 -o test_sticky test_sticky.c
RUN gcc -O2 -o host_fd host_fd.c
+29
View File
@@ -0,0 +1,29 @@
// Copyright 2021 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <err.h>
#include <sys/ioctl.h>
#include <unistd.h>
// Tests that FIONREAD is supported with host FD.
int main(int argc, char** argv) {
int size = 0;
if (ioctl(STDOUT_FILENO, FIONREAD, &size) < 0) {
err(1, "ioctl(stdin, FIONREAD)");
}
if (size != 0) {
err(1, "FIONREAD wrong size, want: 0, got: %d", size);
}
return 0;
}
+1
View File
@@ -31,6 +31,7 @@ go_library(
"connected_endpoint_refs.go",
"control.go",
"host.go",
"host_unsafe.go",
"inode_refs.go",
"ioctl_unsafe.go",
"save_restore.go",
+19
View File
@@ -29,6 +29,7 @@ import (
"gvisor.dev/gvisor/pkg/fspath"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
"gvisor.dev/gvisor/pkg/sentry/hostfd"
"gvisor.dev/gvisor/pkg/sentry/kernel"
@@ -910,3 +911,21 @@ func (f *fileDescription) EventUnregister(e *waiter.Entry) {
func (f *fileDescription) Readiness(mask waiter.EventMask) waiter.EventMask {
return fdnotifier.NonBlockingPoll(int32(f.inode.hostFD), mask)
}
// Ioctl queries the underlying FD for allowed ioctl commands.
func (f *fileDescription) Ioctl(ctx context.Context, uio usermem.IO, args arch.SyscallArguments) (uintptr, error) {
switch cmd := args[1].Int(); cmd {
case linux.FIONREAD:
v, err := ioctlFionread(f.inode.hostFD)
if err != nil {
return 0, err
}
var buf [4]byte
hostarch.ByteOrder.PutUint32(buf[:], v)
_, err = uio.CopyOut(ctx, args[2].Pointer(), buf[:], usermem.IOOpts{})
return 0, err
}
return f.FileDescriptionDefaultImpl.Ioctl(ctx, uio, args)
}
+30
View File
@@ -0,0 +1,30 @@
// Copyright 2021 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package host
import (
"unsafe"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux"
)
func ioctlFionread(fd int) (uint32, error) {
var v uint32
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), linux.FIONREAD, uintptr(unsafe.Pointer(&v))); errno != 0 {
return 0, errno
}
return v, nil
}
+8 -2
View File
@@ -134,9 +134,15 @@ var allowedSyscalls = seccomp.SyscallRules{
},
unix.SYS_GETTID: {},
unix.SYS_GETTIMEOFDAY: {},
// SYS_IOCTL is needed for terminal support, but we only allow
// setting/getting termios and winsize.
unix.SYS_IOCTL: []seccomp.Rule{
// These commands are needed for host FD.
{
seccomp.MatchAny{}, /* fd */
seccomp.EqualTo(linux.FIONREAD),
seccomp.MatchAny{}, /* int* */
},
// These commands are needed for terminal support, but we only allow
// setting/getting termios and winsize.
{
seccomp.MatchAny{}, /* fd */
seccomp.EqualTo(linux.TCGETS),
+10
View File
@@ -612,6 +612,16 @@ func TestStickyDir(t *testing.T) {
runIntegrationTest(t, nil, "./test_sticky")
}
func TestHostFD(t *testing.T) {
if vfs2Used, err := dockerutil.UsingVFS2(); err != nil {
t.Fatalf("failed to read config for runtime %s: %v", dockerutil.Runtime(), err)
} else if !vfs2Used {
t.Skip("test fails on VFS1.")
}
runIntegrationTest(t, nil, "./host_fd")
}
func runIntegrationTest(t *testing.T, capAdd []string, args ...string) {
ctx := context.Background()
d := dockerutil.MakeContainer(ctx, t)