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:
Ian Gudger
2019-12-05 17:28:52 -08:00
committed by gVisor bot
parent f053c52812
commit 13f0f6069a
5 changed files with 255 additions and 22 deletions
+28 -13
View File
@@ -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
}
+63 -7
View File
@@ -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 (
+1
View File
@@ -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",
+161 -1
View File
@@ -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
+2 -1
View File
@@ -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;