Format struct pollfd in poll(2)/ppoll(2)

I0410 15:40:38.854295    3776 x:0] [   1] poll_test E poll(0x2b00bfb5c020 [{FD: 0x3 anon_inode:[eventfd], Events: POLLOUT, REvents: ...}], 0x1, 0x1)
I0410 15:40:38.854348    3776 x:0] [   1] poll_test X poll(0x2b00bfb5c020 [{FD: 0x3 anon_inode:[eventfd], Events: POLLOUT|POLLERR|POLLHUP, REvents: POLLOUT}], 0x1, 0x1) = 0x1 (10.765?s)

PiperOrigin-RevId: 244269879
Change-Id: If07ba54a486fdeaaedfc0123769b78d1da862307
This commit is contained in:
Michael Pratt 2019-04-18 15:22:47 -07:00 committed by Shentubot
parent ce64d9ebf0
commit c931c8e082
6 changed files with 98 additions and 7 deletions

View File

@ -11,6 +11,7 @@ go_library(
"futex.go", "futex.go",
"linux64.go", "linux64.go",
"open.go", "open.go",
"poll.go",
"ptrace.go", "ptrace.go",
"signal.go", "signal.go",
"socket.go", "socket.go",

View File

@ -24,7 +24,7 @@ var linuxAMD64 = SyscallMap{
4: makeSyscallInfo("stat", Path, Stat), 4: makeSyscallInfo("stat", Path, Stat),
5: makeSyscallInfo("fstat", FD, Stat), 5: makeSyscallInfo("fstat", FD, Stat),
6: makeSyscallInfo("lstat", Path, Stat), 6: makeSyscallInfo("lstat", Path, Stat),
7: makeSyscallInfo("poll", Hex, Hex, Hex), 7: makeSyscallInfo("poll", PollFDs, Hex, Hex),
8: makeSyscallInfo("lseek", Hex, Hex, Hex), 8: makeSyscallInfo("lseek", Hex, Hex, Hex),
9: makeSyscallInfo("mmap", Hex, Hex, Hex, Hex, FD, Hex), 9: makeSyscallInfo("mmap", Hex, Hex, Hex, Hex, FD, Hex),
10: makeSyscallInfo("mprotect", Hex, Hex, Hex), 10: makeSyscallInfo("mprotect", Hex, Hex, Hex),
@ -288,7 +288,7 @@ var linuxAMD64 = SyscallMap{
268: makeSyscallInfo("fchmodat", FD, Path, Mode), 268: makeSyscallInfo("fchmodat", FD, Path, Mode),
269: makeSyscallInfo("faccessat", FD, Path, Oct, Hex), 269: makeSyscallInfo("faccessat", FD, Path, Oct, Hex),
270: makeSyscallInfo("pselect6", Hex, Hex, Hex, Hex, Hex, Hex), 270: makeSyscallInfo("pselect6", Hex, Hex, Hex, Hex, Hex, Hex),
271: makeSyscallInfo("ppoll", Hex, Hex, Timespec, SigSet, Hex), 271: makeSyscallInfo("ppoll", PollFDs, Hex, Timespec, SigSet, Hex),
272: makeSyscallInfo("unshare", CloneFlags), 272: makeSyscallInfo("unshare", CloneFlags),
273: makeSyscallInfo("set_robust_list", Hex, Hex), 273: makeSyscallInfo("set_robust_list", Hex, Hex),
274: makeSyscallInfo("get_robust_list", Hex, Hex, Hex), 274: makeSyscallInfo("get_robust_list", Hex, Hex, Hex),

72
pkg/sentry/strace/poll.go Normal file
View File

@ -0,0 +1,72 @@
// Copyright 2019 Google LLC
//
// 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 strace
import (
"fmt"
"strings"
"gvisor.googlesource.com/gvisor/pkg/abi"
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/kdefs"
slinux "gvisor.googlesource.com/gvisor/pkg/sentry/syscalls/linux"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
)
// PollEventSet is the set of poll(2) event flags.
var PollEventSet = abi.FlagSet{
{Flag: linux.POLLIN, Name: "POLLIN"},
{Flag: linux.POLLPRI, Name: "POLLPRI"},
{Flag: linux.POLLOUT, Name: "POLLOUT"},
{Flag: linux.POLLERR, Name: "POLLERR"},
{Flag: linux.POLLHUP, Name: "POLLHUP"},
{Flag: linux.POLLNVAL, Name: "POLLNVAL"},
{Flag: linux.POLLRDNORM, Name: "POLLRDNORM"},
{Flag: linux.POLLRDBAND, Name: "POLLRDBAND"},
{Flag: linux.POLLWRNORM, Name: "POLLWRNORM"},
{Flag: linux.POLLWRBAND, Name: "POLLWRBAND"},
{Flag: linux.POLLMSG, Name: "POLLMSG"},
{Flag: linux.POLLREMOVE, Name: "POLLREMOVE"},
{Flag: linux.POLLRDHUP, Name: "POLLRDHUP"},
{Flag: linux.POLLFREE, Name: "POLLFREE"},
{Flag: linux.POLL_BUSY_LOOP, Name: "POLL_BUSY_LOOP"},
}
func pollFD(t *kernel.Task, pfd *linux.PollFD, post bool) string {
revents := "..."
if post {
revents = PollEventSet.Parse(uint64(pfd.REvents))
}
return fmt.Sprintf("{FD: %s, Events: %s, REvents: %s}", fd(t, kdefs.FD(pfd.FD)), PollEventSet.Parse(uint64(pfd.Events)), revents)
}
func pollFDs(t *kernel.Task, addr usermem.Addr, nfds uint, post bool) string {
if addr == 0 {
return "null"
}
pfds, err := slinux.CopyInPollFDs(t, addr, nfds)
if err != nil {
return fmt.Sprintf("%#x (error decoding pollfds: %s)", addr, err)
}
s := make([]string, 0, len(pfds))
for i := range pfds {
s = append(s, pollFD(t, &pfds[i], post))
}
return fmt.Sprintf("%#x [%s]", addr, strings.Join(s, ", "))
}

View File

@ -438,6 +438,8 @@ func (i *SyscallInfo) pre(t *kernel.Task, args arch.SyscallArguments, maximumBlo
output = append(output, capHeader(t, args[arg].Pointer())) output = append(output, capHeader(t, args[arg].Pointer()))
case CapData: case CapData:
output = append(output, capData(t, args[arg-1].Pointer(), args[arg].Pointer())) output = append(output, capData(t, args[arg-1].Pointer(), args[arg].Pointer()))
case PollFDs:
output = append(output, pollFDs(t, args[arg].Pointer(), uint(args[arg+1].Uint()), false))
case Oct: case Oct:
output = append(output, "0o"+strconv.FormatUint(args[arg].Uint64(), 8)) output = append(output, "0o"+strconv.FormatUint(args[arg].Uint64(), 8))
case Hex: case Hex:
@ -502,6 +504,8 @@ func (i *SyscallInfo) post(t *kernel.Task, args arch.SyscallArguments, rval uint
output[arg] = sigAction(t, args[arg].Pointer()) output[arg] = sigAction(t, args[arg].Pointer())
case PostCapData: case PostCapData:
output[arg] = capData(t, args[arg-1].Pointer(), args[arg].Pointer()) output[arg] = capData(t, args[arg-1].Pointer(), args[arg].Pointer())
case PollFDs:
output[arg] = pollFDs(t, args[arg].Pointer(), uint(args[arg+1].Uint()), true)
} }
} }
} }

View File

@ -202,6 +202,10 @@ const (
// PostCapData is the data argument to capget(2)/capset(2), formatted // PostCapData is the data argument to capget(2)/capset(2), formatted
// after syscall execution. The previous argument must be CapHeader. // after syscall execution. The previous argument must be CapHeader.
PostCapData PostCapData
// PollFDs is an array of struct pollfd. The number of entries in the
// array is in the next argument.
PollFDs
) )
// defaultFormat is the syscall argument format to use if the actual format is // defaultFormat is the syscall argument format to use if the actual format is

View File

@ -155,18 +155,28 @@ func pollBlock(t *kernel.Task, pfd []linux.PollFD, timeout time.Duration) (time.
return timeout, n, nil return timeout, n, nil
} }
func doPoll(t *kernel.Task, pfdAddr usermem.Addr, nfds uint, timeout time.Duration) (time.Duration, uintptr, error) { // CopyInPollFDs copies an array of struct pollfd unless nfds exceeds the max.
func CopyInPollFDs(t *kernel.Task, addr usermem.Addr, nfds uint) ([]linux.PollFD, error) {
if uint64(nfds) > t.ThreadGroup().Limits().GetCapped(limits.NumberOfFiles, fileCap) { if uint64(nfds) > t.ThreadGroup().Limits().GetCapped(limits.NumberOfFiles, fileCap) {
return timeout, 0, syserror.EINVAL return nil, syserror.EINVAL
} }
pfd := make([]linux.PollFD, nfds) pfd := make([]linux.PollFD, nfds)
if nfds > 0 { if nfds > 0 {
if _, err := t.CopyIn(pfdAddr, &pfd); err != nil { if _, err := t.CopyIn(addr, &pfd); err != nil {
return timeout, 0, err return nil, err
} }
} }
return pfd, nil
}
func doPoll(t *kernel.Task, addr usermem.Addr, nfds uint, timeout time.Duration) (time.Duration, uintptr, error) {
pfd, err := CopyInPollFDs(t, addr, nfds)
if err != nil {
return timeout, 0, err
}
// Compatibility warning: Linux adds POLLHUP and POLLERR just before // Compatibility warning: Linux adds POLLHUP and POLLERR just before
// polling, in fs/select.c:do_pollfd(). Since pfd is copied out after // polling, in fs/select.c:do_pollfd(). Since pfd is copied out after
// polling, changing event masks here is an application-visible difference. // polling, changing event masks here is an application-visible difference.
@ -180,7 +190,7 @@ func doPoll(t *kernel.Task, pfdAddr usermem.Addr, nfds uint, timeout time.Durati
// The poll entries are copied out regardless of whether // The poll entries are copied out regardless of whether
// any are set or not. This aligns with the Linux behavior. // any are set or not. This aligns with the Linux behavior.
if nfds > 0 && err == nil { if nfds > 0 && err == nil {
if _, err := t.CopyOut(pfdAddr, pfd); err != nil { if _, err := t.CopyOut(addr, pfd); err != nil {
return remainingTimeout, 0, err return remainingTimeout, 0, err
} }
} }