mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Implement F_GETOWN_EX and F_SETOWN_EX.
Some versions of glibc will convert F_GETOWN fcntl(2) calls into F_GETOWN_EX in some cases. PiperOrigin-RevId: 284089373
This commit is contained in:
+28
-13
@@ -16,15 +16,17 @@ package linux
|
||||
|
||||
// Commands from linux/fcntl.h.
|
||||
const (
|
||||
F_DUPFD = 0x0
|
||||
F_GETFD = 0x1
|
||||
F_SETFD = 0x2
|
||||
F_GETFL = 0x3
|
||||
F_SETFL = 0x4
|
||||
F_SETLK = 0x6
|
||||
F_SETLKW = 0x7
|
||||
F_SETOWN = 0x8
|
||||
F_GETOWN = 0x9
|
||||
F_DUPFD = 0
|
||||
F_GETFD = 1
|
||||
F_SETFD = 2
|
||||
F_GETFL = 3
|
||||
F_SETFL = 4
|
||||
F_SETLK = 6
|
||||
F_SETLKW = 7
|
||||
F_SETOWN = 8
|
||||
F_GETOWN = 9
|
||||
F_SETOWN_EX = 15
|
||||
F_GETOWN_EX = 16
|
||||
F_DUPFD_CLOEXEC = 1024 + 6
|
||||
F_SETPIPE_SZ = 1024 + 7
|
||||
F_GETPIPE_SZ = 1024 + 8
|
||||
@@ -32,9 +34,9 @@ const (
|
||||
|
||||
// Commands for F_SETLK.
|
||||
const (
|
||||
F_RDLCK = 0x0
|
||||
F_WRLCK = 0x1
|
||||
F_UNLCK = 0x2
|
||||
F_RDLCK = 0
|
||||
F_WRLCK = 1
|
||||
F_UNLCK = 2
|
||||
)
|
||||
|
||||
// Flags for fcntl.
|
||||
@@ -42,7 +44,7 @@ const (
|
||||
FD_CLOEXEC = 00000001
|
||||
)
|
||||
|
||||
// Lock structure for F_SETLK.
|
||||
// Flock is the lock structure for F_SETLK.
|
||||
type Flock struct {
|
||||
Type int16
|
||||
Whence int16
|
||||
@@ -52,3 +54,16 @@ type Flock struct {
|
||||
Pid int32
|
||||
_ [4]byte
|
||||
}
|
||||
|
||||
// Flags for F_SETOWN_EX and F_GETOWN_EX.
|
||||
const (
|
||||
F_OWNER_TID = 0
|
||||
F_OWNER_PID = 1
|
||||
F_OWNER_PGRP = 2
|
||||
)
|
||||
|
||||
// FOwnerEx is the owner structure for F_SETOWN_EX and F_GETOWN_EX.
|
||||
type FOwnerEx struct {
|
||||
Type int32
|
||||
PID int32
|
||||
}
|
||||
|
||||
@@ -840,25 +840,42 @@ func Dup3(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallC
|
||||
return uintptr(newfd), nil, nil
|
||||
}
|
||||
|
||||
func fGetOwn(t *kernel.Task, file *fs.File) int32 {
|
||||
func fGetOwnEx(t *kernel.Task, file *fs.File) linux.FOwnerEx {
|
||||
ma := file.Async(nil)
|
||||
if ma == nil {
|
||||
return 0
|
||||
return linux.FOwnerEx{}
|
||||
}
|
||||
a := ma.(*fasync.FileAsync)
|
||||
ot, otg, opg := a.Owner()
|
||||
switch {
|
||||
case ot != nil:
|
||||
return int32(t.PIDNamespace().IDOfTask(ot))
|
||||
return linux.FOwnerEx{
|
||||
Type: linux.F_OWNER_TID,
|
||||
PID: int32(t.PIDNamespace().IDOfTask(ot)),
|
||||
}
|
||||
case otg != nil:
|
||||
return int32(t.PIDNamespace().IDOfThreadGroup(otg))
|
||||
return linux.FOwnerEx{
|
||||
Type: linux.F_OWNER_PID,
|
||||
PID: int32(t.PIDNamespace().IDOfThreadGroup(otg)),
|
||||
}
|
||||
case opg != nil:
|
||||
return int32(-t.PIDNamespace().IDOfProcessGroup(opg))
|
||||
return linux.FOwnerEx{
|
||||
Type: linux.F_OWNER_PGRP,
|
||||
PID: int32(t.PIDNamespace().IDOfProcessGroup(opg)),
|
||||
}
|
||||
default:
|
||||
return 0
|
||||
return linux.FOwnerEx{}
|
||||
}
|
||||
}
|
||||
|
||||
func fGetOwn(t *kernel.Task, file *fs.File) int32 {
|
||||
owner := fGetOwnEx(t, file)
|
||||
if owner.Type == linux.F_OWNER_PGRP {
|
||||
return -owner.PID
|
||||
}
|
||||
return owner.PID
|
||||
}
|
||||
|
||||
// fSetOwn sets the file's owner with the semantics of F_SETOWN in Linux.
|
||||
//
|
||||
// If who is positive, it represents a PID. If negative, it represents a PGID.
|
||||
@@ -901,11 +918,13 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
|
||||
t.FDTable().SetFlags(fd, kernel.FDFlags{
|
||||
CloseOnExec: flags&linux.FD_CLOEXEC != 0,
|
||||
})
|
||||
return 0, nil, nil
|
||||
case linux.F_GETFL:
|
||||
return uintptr(file.Flags().ToLinux()), nil, nil
|
||||
case linux.F_SETFL:
|
||||
flags := uint(args[2].Uint())
|
||||
file.SetFlags(linuxToFlags(flags).Settable())
|
||||
return 0, nil, nil
|
||||
case linux.F_SETLK, linux.F_SETLKW:
|
||||
// In Linux the file system can choose to provide lock operations for an inode.
|
||||
// Normally pipe and socket types lack lock operations. We diverge and use a heavy
|
||||
@@ -1008,6 +1027,44 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
|
||||
case linux.F_SETOWN:
|
||||
fSetOwn(t, file, args[2].Int())
|
||||
return 0, nil, nil
|
||||
case linux.F_GETOWN_EX:
|
||||
addr := args[2].Pointer()
|
||||
owner := fGetOwnEx(t, file)
|
||||
_, err := t.CopyOut(addr, &owner)
|
||||
return 0, nil, err
|
||||
case linux.F_SETOWN_EX:
|
||||
addr := args[2].Pointer()
|
||||
var owner linux.FOwnerEx
|
||||
n, err := t.CopyIn(addr, &owner)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
a := file.Async(fasync.New).(*fasync.FileAsync)
|
||||
switch owner.Type {
|
||||
case linux.F_OWNER_TID:
|
||||
task := t.PIDNamespace().TaskWithID(kernel.ThreadID(owner.PID))
|
||||
if task == nil {
|
||||
return 0, nil, syserror.ESRCH
|
||||
}
|
||||
a.SetOwnerTask(t, task)
|
||||
return uintptr(n), nil, nil
|
||||
case linux.F_OWNER_PID:
|
||||
tg := t.PIDNamespace().ThreadGroupWithID(kernel.ThreadID(owner.PID))
|
||||
if tg == nil {
|
||||
return 0, nil, syserror.ESRCH
|
||||
}
|
||||
a.SetOwnerThreadGroup(t, tg)
|
||||
return uintptr(n), nil, nil
|
||||
case linux.F_OWNER_PGRP:
|
||||
pg := t.PIDNamespace().ProcessGroupWithID(kernel.ProcessGroupID(owner.PID))
|
||||
if pg == nil {
|
||||
return 0, nil, syserror.ESRCH
|
||||
}
|
||||
a.SetOwnerProcessGroup(t, pg)
|
||||
return uintptr(n), nil, nil
|
||||
default:
|
||||
return 0, nil, syserror.EINVAL
|
||||
}
|
||||
case linux.F_GET_SEALS:
|
||||
val, err := tmpfs.GetSeals(file.Dirent.Inode)
|
||||
return uintptr(val), nil, err
|
||||
@@ -1035,7 +1092,6 @@ func Fcntl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
|
||||
// Everything else is not yet supported.
|
||||
return 0, nil, syserror.EINVAL
|
||||
}
|
||||
return 0, nil, nil
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
@@ -753,6 +753,7 @@ cc_binary(
|
||||
"//test/util:eventfd_util",
|
||||
"//test/util:multiprocess_util",
|
||||
"//test/util:posix_error",
|
||||
"//test/util:save_util",
|
||||
"//test/util:temp_path",
|
||||
"//test/util:test_util",
|
||||
"//test/util:timer_util",
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -32,6 +33,7 @@
|
||||
#include "test/util/eventfd_util.h"
|
||||
#include "test/util/multiprocess_util.h"
|
||||
#include "test/util/posix_error.h"
|
||||
#include "test/util/save_util.h"
|
||||
#include "test/util/temp_path.h"
|
||||
#include "test/util/test_util.h"
|
||||
#include "test/util/timer_util.h"
|
||||
@@ -910,10 +912,168 @@ TEST(FcntlTest, GetOwn) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN),
|
||||
EXPECT_EQ(syscall(__NR_fcntl, s.get(), F_GETOWN), 0);
|
||||
MaybeSave();
|
||||
}
|
||||
|
||||
TEST(FcntlTest, GetOwnEx) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
f_owner_ex owner = {};
|
||||
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN_EX, &owner),
|
||||
SyscallSucceedsWithValue(0));
|
||||
}
|
||||
|
||||
TEST(FcntlTest, SetOwnExInvalidType) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
f_owner_ex owner = {};
|
||||
owner.type = __pid_type(-1);
|
||||
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
|
||||
SyscallFailsWithErrno(EINVAL));
|
||||
}
|
||||
|
||||
TEST(FcntlTest, SetOwnExInvalidTid) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
f_owner_ex owner = {};
|
||||
owner.type = F_OWNER_TID;
|
||||
owner.pid = -1;
|
||||
|
||||
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
|
||||
SyscallFailsWithErrno(ESRCH));
|
||||
}
|
||||
|
||||
TEST(FcntlTest, SetOwnExInvalidPid) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
f_owner_ex owner = {};
|
||||
owner.type = F_OWNER_PID;
|
||||
owner.pid = -1;
|
||||
|
||||
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
|
||||
SyscallFailsWithErrno(ESRCH));
|
||||
}
|
||||
|
||||
TEST(FcntlTest, SetOwnExInvalidPgrp) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
f_owner_ex owner = {};
|
||||
owner.type = F_OWNER_PGRP;
|
||||
owner.pid = -1;
|
||||
|
||||
EXPECT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
|
||||
SyscallFailsWithErrno(ESRCH));
|
||||
}
|
||||
|
||||
TEST(FcntlTest, SetOwnExTid) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
f_owner_ex owner = {};
|
||||
owner.type = F_OWNER_TID;
|
||||
EXPECT_THAT(owner.pid = syscall(__NR_gettid), SyscallSucceeds());
|
||||
|
||||
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
|
||||
SyscallSucceeds());
|
||||
|
||||
EXPECT_EQ(syscall(__NR_fcntl, s.get(), F_GETOWN), owner.pid);
|
||||
MaybeSave();
|
||||
}
|
||||
|
||||
TEST(FcntlTest, SetOwnExPid) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
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());
|
||||
|
||||
EXPECT_EQ(syscall(__NR_fcntl, s.get(), F_GETOWN), owner.pid);
|
||||
MaybeSave();
|
||||
}
|
||||
|
||||
TEST(FcntlTest, SetOwnExPgrp) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
f_owner_ex owner = {};
|
||||
owner.type = F_OWNER_PGRP;
|
||||
EXPECT_THAT(owner.pid = getpgrp(), SyscallSucceeds());
|
||||
|
||||
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &owner),
|
||||
SyscallSucceeds());
|
||||
|
||||
// NOTE(igudger): I don't understand why, but this is flaky on Linux.
|
||||
// GetOwnExPgrp (below) does not have this issue.
|
||||
SKIP_IF(!IsRunningOnGvisor());
|
||||
|
||||
EXPECT_EQ(syscall(__NR_fcntl, s.get(), F_GETOWN), -owner.pid);
|
||||
MaybeSave();
|
||||
}
|
||||
|
||||
TEST(FcntlTest, GetOwnExTid) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
f_owner_ex set_owner = {};
|
||||
set_owner.type = F_OWNER_TID;
|
||||
EXPECT_THAT(set_owner.pid = syscall(__NR_gettid), SyscallSucceeds());
|
||||
|
||||
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &set_owner),
|
||||
SyscallSucceeds());
|
||||
|
||||
f_owner_ex got_owner = {};
|
||||
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN_EX, &got_owner),
|
||||
SyscallSucceedsWithValue(0));
|
||||
EXPECT_EQ(got_owner.type, set_owner.type);
|
||||
EXPECT_EQ(got_owner.pid, set_owner.pid);
|
||||
}
|
||||
|
||||
TEST(FcntlTest, GetOwnExPid) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
f_owner_ex set_owner = {};
|
||||
set_owner.type = F_OWNER_PID;
|
||||
EXPECT_THAT(set_owner.pid = getpid(), SyscallSucceeds());
|
||||
|
||||
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &set_owner),
|
||||
SyscallSucceeds());
|
||||
|
||||
f_owner_ex got_owner = {};
|
||||
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN_EX, &got_owner),
|
||||
SyscallSucceedsWithValue(0));
|
||||
EXPECT_EQ(got_owner.type, set_owner.type);
|
||||
EXPECT_EQ(got_owner.pid, set_owner.pid);
|
||||
}
|
||||
|
||||
TEST(FcntlTest, GetOwnExPgrp) {
|
||||
FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(
|
||||
Socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
|
||||
f_owner_ex set_owner = {};
|
||||
set_owner.type = F_OWNER_PGRP;
|
||||
EXPECT_THAT(set_owner.pid = getpgrp(), SyscallSucceeds());
|
||||
|
||||
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_SETOWN_EX, &set_owner),
|
||||
SyscallSucceeds());
|
||||
|
||||
f_owner_ex got_owner = {};
|
||||
ASSERT_THAT(syscall(__NR_fcntl, s.get(), F_GETOWN_EX, &got_owner),
|
||||
SyscallSucceedsWithValue(0));
|
||||
EXPECT_EQ(got_owner.type, set_owner.type);
|
||||
EXPECT_EQ(got_owner.pid, set_owner.pid);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace testing
|
||||
|
||||
@@ -215,7 +215,8 @@ TEST_F(IoctlTest, FIOASYNCSelfTarget2) {
|
||||
auto mask_cleanup =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGIO));
|
||||
|
||||
pid_t pid = getpid();
|
||||
pid_t pid = -1;
|
||||
EXPECT_THAT(pid = getpid(), SyscallSucceeds());
|
||||
EXPECT_THAT(ioctl(pair->second_fd(), FIOSETOWN, &pid), SyscallSucceeds());
|
||||
|
||||
int set = 1;
|
||||
|
||||
Reference in New Issue
Block a user