Complete async signal delivery support in vfs2.

- Support FIOASYNC, FIO{SET,GET}OWN, SIOC{G,S}PGRP (refactor getting/setting
  owner in the process).
- Unset signal recipient when setting owner with pid == 0 and
  valid owner type.

Updates #2923.

PiperOrigin-RevId: 319231420
This commit is contained in:
Dean Deng
2020-07-01 08:42:12 -07:00
committed by gVisor bot
parent b8f165ab1c
commit cda2979b63
5 changed files with 144 additions and 21 deletions
+10
View File
@@ -176,3 +176,13 @@ func (a *FileAsync) SetOwnerProcessGroup(requester *kernel.Task, recipient *kern
a.recipientTG = nil
a.recipientPG = recipient
}
// ClearOwner unsets the current signal recipient.
func (a *FileAsync) ClearOwner() {
a.mu.Lock()
defer a.mu.Unlock()
a.requester = nil
a.recipientT = nil
a.recipientTG = nil
a.recipientPG = nil
}
+33 -21
View File
@@ -156,11 +156,10 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
}
return uintptr(n), nil, nil
case linux.F_GETOWN:
a := file.AsyncHandler()
if a == nil {
owner, hasOwner := getAsyncOwner(t, file)
if !hasOwner {
return 0, nil, nil
}
owner := getAsyncOwner(t, a.(*fasync.FileAsync))
if owner.Type == linux.F_OWNER_PGRP {
return uintptr(-owner.PID), nil, nil
}
@@ -176,26 +175,21 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
ownerType = linux.F_OWNER_PGRP
who = -who
}
a := file.SetAsyncHandler(fasync.NewVFS2).(*fasync.FileAsync)
return 0, nil, setAsyncOwner(t, a, ownerType, who)
return 0, nil, setAsyncOwner(t, file, ownerType, who)
case linux.F_GETOWN_EX:
a := file.AsyncHandler()
if a == nil {
owner, hasOwner := getAsyncOwner(t, file)
if !hasOwner {
return 0, nil, nil
}
addr := args[2].Pointer()
owner := getAsyncOwner(t, a.(*fasync.FileAsync))
_, err := t.CopyOut(addr, &owner)
_, err := t.CopyOut(args[2].Pointer(), &owner)
return 0, nil, err
case linux.F_SETOWN_EX:
addr := args[2].Pointer()
var owner linux.FOwnerEx
n, err := t.CopyIn(addr, &owner)
n, err := t.CopyIn(args[2].Pointer(), &owner)
if err != nil {
return 0, nil, err
}
a := file.SetAsyncHandler(fasync.NewVFS2).(*fasync.FileAsync)
return uintptr(n), nil, setAsyncOwner(t, a, owner.Type, owner.PID)
return uintptr(n), nil, setAsyncOwner(t, file, owner.Type, owner.PID)
case linux.F_GETPIPE_SZ:
pipefile, ok := file.Impl().(*pipe.VFSPipeFD)
if !ok {
@@ -219,30 +213,48 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
}
}
func getAsyncOwner(t *kernel.Task, a *fasync.FileAsync) linux.FOwnerEx {
ot, otg, opg := a.Owner()
func getAsyncOwner(t *kernel.Task, fd *vfs.FileDescription) (ownerEx linux.FOwnerEx, hasOwner bool) {
a := fd.AsyncHandler()
if a == nil {
return linux.FOwnerEx{}, false
}
ot, otg, opg := a.(*fasync.FileAsync).Owner()
switch {
case ot != nil:
return linux.FOwnerEx{
Type: linux.F_OWNER_TID,
PID: int32(t.PIDNamespace().IDOfTask(ot)),
}
}, true
case otg != nil:
return linux.FOwnerEx{
Type: linux.F_OWNER_PID,
PID: int32(t.PIDNamespace().IDOfThreadGroup(otg)),
}
}, true
case opg != nil:
return linux.FOwnerEx{
Type: linux.F_OWNER_PGRP,
PID: int32(t.PIDNamespace().IDOfProcessGroup(opg)),
}
}, true
default:
return linux.FOwnerEx{}
return linux.FOwnerEx{}, true
}
}
func setAsyncOwner(t *kernel.Task, a *fasync.FileAsync, ownerType, pid int32) error {
func setAsyncOwner(t *kernel.Task, fd *vfs.FileDescription, ownerType, pid int32) error {
switch ownerType {
case linux.F_OWNER_TID, linux.F_OWNER_PID, linux.F_OWNER_PGRP:
// Acceptable type.
default:
return syserror.EINVAL
}
a := fd.SetAsyncHandler(fasync.NewVFS2).(*fasync.FileAsync)
if pid == 0 {
a.ClearOwner()
return nil
}
switch ownerType {
case linux.F_OWNER_TID:
task := t.PIDNamespace().TaskWithID(kernel.ThreadID(pid))
+43
View File
@@ -57,6 +57,49 @@ func Ioctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
flags &^= linux.O_NONBLOCK
}
return 0, nil, file.SetStatusFlags(t, t.Credentials(), flags)
case linux.FIOASYNC:
var set int32
if _, err := t.CopyIn(args[2].Pointer(), &set); err != nil {
return 0, nil, err
}
flags := file.StatusFlags()
if set != 0 {
flags |= linux.O_ASYNC
} else {
flags &^= linux.O_ASYNC
}
file.SetStatusFlags(t, t.Credentials(), flags)
return 0, nil, nil
case linux.FIOGETOWN, linux.SIOCGPGRP:
var who int32
owner, hasOwner := getAsyncOwner(t, file)
if hasOwner {
if owner.Type == linux.F_OWNER_PGRP {
who = -owner.PID
} else {
who = owner.PID
}
}
_, err := t.CopyOut(args[2].Pointer(), &who)
return 0, nil, err
case linux.FIOSETOWN, linux.SIOCSPGRP:
var who int32
if _, err := t.CopyIn(args[2].Pointer(), &who); err != nil {
return 0, nil, err
}
ownerType := int32(linux.F_OWNER_PID)
if who < 0 {
// Check for overflow before flipping the sign.
if who-1 > who {
return 0, nil, syserror.EINVAL
}
ownerType = linux.F_OWNER_PGRP
who = -who
}
return 0, nil, setAsyncOwner(t, file, ownerType, who)
}
ret, err := file.Ioctl(t, t.MemoryManager(), args)
+1
View File
@@ -288,6 +288,7 @@ syscall_test(
size = "medium",
add_overlay = True,
test = "//test/syscalls/linux:ioctl_test",
vfs2 = "True",
)
syscall_test(
+57
View File
@@ -1031,6 +1031,30 @@ TEST(FcntlTest, SetOwnPgrp) {
MaybeSave();
}
TEST(FcntlTest, SetOwnUnset) {
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
// Set and unset pid.
pid_t pid;
EXPECT_THAT(pid = getpid(), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, pid), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, 0), SyscallSucceeds());
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
SyscallSucceedsWithValue(0));
// Set and unset pgid.
pid_t pgid;
EXPECT_THAT(pgid = getpgrp(), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, -pgid), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN, 0), SyscallSucceeds());
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
SyscallSucceedsWithValue(0));
MaybeSave();
}
// F_SETOWN flips the sign of negative values, an operation that is guarded
// against overflow.
TEST(FcntlTest, SetOwnOverflow) {
@@ -1141,6 +1165,39 @@ TEST(FcntlTest, SetOwnExPgrp) {
MaybeSave();
}
TEST(FcntlTest, SetOwnExUnset) {
SKIP_IF(IsRunningWithVFS1());
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
// Set and unset pid.
f_owner_ex owner = {};
owner.type = F_OWNER_PID;
EXPECT_THAT(owner.pid = getpid(), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
SyscallSucceeds());
owner.pid = 0;
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
SyscallSucceeds());
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
SyscallSucceedsWithValue(0));
// Set and unset pgid.
owner.type = F_OWNER_PGRP;
EXPECT_THAT(owner.pid = getpgrp(), SyscallSucceeds());
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
SyscallSucceeds());
owner.pid = 0;
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
SyscallSucceeds());
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
SyscallSucceedsWithValue(0));
MaybeSave();
}
TEST(FcntlTest, GetOwnExTid) {
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));