mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -288,6 +288,7 @@ syscall_test(
|
||||
size = "medium",
|
||||
add_overlay = True,
|
||||
test = "//test/syscalls/linux:ioctl_test",
|
||||
vfs2 = "True",
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user