Enable stat syscall support on arm64.

x86 and arm64 use a different stat struct in Linux
kernel, so the stat() syscall implementation has
to handle the file stat data separately.

Signed-off-by: Haibo Xu <haibo.xu@arm.com>
Change-Id: If3986e915a667362257a54e7fbbcc1fe18951015
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/gvisor/pull/1493 from xiaobo55x:stat f15a216d9297eb9a96d2c483d396a9919145d7fa
PiperOrigin-RevId: 290274287
This commit is contained in:
Haibo Xu
2020-01-17 09:51:28 -08:00
committed by gVisor bot
parent c98e1bc23f
commit acf2d6dcc3
5 changed files with 162 additions and 51 deletions
+2
View File
@@ -42,6 +42,8 @@ go_library(
"sys_socket.go",
"sys_splice.go",
"sys_stat.go",
"sys_stat_amd64.go",
"sys_stat_arm64.go",
"sys_sync.go",
"sys_sysinfo.go",
"sys_syslog.go",
@@ -61,6 +61,7 @@ var ARM64 = &kernel.SyscallTable{
22: syscalls.Supported("epoll_pwait", EpollPwait),
23: syscalls.Supported("dup", Dup),
24: syscalls.Supported("dup3", Dup3),
25: syscalls.PartiallySupported("fcntl", Fcntl, "Not all options are supported.", nil),
26: syscalls.Supported("inotify_init1", InotifyInit1),
27: syscalls.PartiallySupported("inotify_add_watch", InotifyAddWatch, "inotify events are only available inside the sandbox.", nil),
28: syscalls.PartiallySupported("inotify_rm_watch", InotifyRmWatch, "inotify events are only available inside the sandbox.", nil),
@@ -78,7 +79,9 @@ var ARM64 = &kernel.SyscallTable{
40: syscalls.PartiallySupported("mount", Mount, "Not all options or file systems are supported.", nil),
41: syscalls.Error("pivot_root", syserror.EPERM, "", nil),
42: syscalls.Error("nfsservctl", syserror.ENOSYS, "Removed after Linux 3.1.", nil),
43: syscalls.PartiallySupported("statfs", Statfs, "Depends on the backing file system implementation.", nil),
44: syscalls.PartiallySupported("fstatfs", Fstatfs, "Depends on the backing file system implementation.", nil),
45: syscalls.Supported("truncate", Truncate),
46: syscalls.Supported("ftruncate", Ftruncate),
47: syscalls.PartiallySupported("fallocate", Fallocate, "Not all options are supported.", nil),
48: syscalls.Supported("faccessat", Faccessat),
@@ -112,6 +115,7 @@ var ARM64 = &kernel.SyscallTable{
76: syscalls.PartiallySupported("splice", Splice, "Stub implementation.", []string{"gvisor.dev/issue/138"}), // TODO(b/29354098)
77: syscalls.Supported("tee", Tee),
78: syscalls.Supported("readlinkat", Readlinkat),
79: syscalls.Supported("fstatat", Fstatat),
80: syscalls.Supported("fstat", Fstat),
81: syscalls.PartiallySupported("sync", Sync, "Full data flush is not guaranteed at this time.", nil),
82: syscalls.PartiallySupported("fsync", Fsync, "Full data flush is not guaranteed at this time.", nil),
@@ -254,6 +258,8 @@ var ARM64 = &kernel.SyscallTable{
219: syscalls.Error("keyctl", syserror.EACCES, "Not available to user.", nil),
220: syscalls.PartiallySupported("clone", Clone, "Mount namespace (CLONE_NEWNS) not supported. Options CLONE_PARENT, CLONE_SYSVSEM not supported.", nil),
221: syscalls.Supported("execve", Execve),
222: syscalls.PartiallySupported("mmap", Mmap, "Generally supported with exceptions. Options MAP_FIXED_NOREPLACE, MAP_SHARED_VALIDATE, MAP_SYNC MAP_GROWSDOWN, MAP_HUGETLB are not supported.", nil),
223: syscalls.PartiallySupported("fadvise64", Fadvise64, "Not all options are supported.", nil),
224: syscalls.CapError("swapon", linux.CAP_SYS_ADMIN, "", nil),
225: syscalls.CapError("swapoff", linux.CAP_SYS_ADMIN, "", nil),
226: syscalls.Supported("mprotect", Mprotect),
@@ -299,6 +305,8 @@ var ARM64 = &kernel.SyscallTable{
282: syscalls.ErrorWithEvent("userfaultfd", syserror.ENOSYS, "", []string{"gvisor.dev/issue/266"}), // TODO(b/118906345)
283: syscalls.ErrorWithEvent("membarrier", syserror.ENOSYS, "", []string{"gvisor.dev/issue/267"}), // TODO(gvisor.dev/issue/267)
284: syscalls.PartiallySupported("mlock2", Mlock2, "Stub implementation. The sandbox lacks appropriate permissions.", nil),
// Syscalls after 284 are "backports" from versions of Linux after 4.4.
285: syscalls.ErrorWithEvent("copy_file_range", syserror.ENOSYS, "", nil),
286: syscalls.Supported("preadv2", Preadv2),
287: syscalls.PartiallySupported("pwritev2", Pwritev2, "Flag RWF_HIPRI is not supported.", nil),
-51
View File
@@ -16,7 +16,6 @@ package linux
import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/binary"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
@@ -125,56 +124,6 @@ func fstat(t *kernel.Task, f *fs.File, statAddr usermem.Addr) error {
return copyOutStat(t, statAddr, f.Dirent.Inode.StableAttr, uattr)
}
// copyOutStat copies the attributes (sattr, uattr) to the struct stat at
// address dst in t's address space. It encodes the stat struct to bytes
// manually, as stat() is a very common syscall for many applications, and
// t.CopyObjectOut has noticeable performance impact due to its many slice
// allocations and use of reflection.
func copyOutStat(t *kernel.Task, dst usermem.Addr, sattr fs.StableAttr, uattr fs.UnstableAttr) error {
b := t.CopyScratchBuffer(int(linux.SizeOfStat))[:0]
// Dev (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.DeviceID))
// Ino (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.InodeID))
// Nlink (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uattr.Links)
// Mode (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, sattr.Type.LinuxType()|uint32(uattr.Perms.LinuxMode()))
// UID (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Owner.UID.In(t.UserNamespace()).OrOverflow()))
// GID (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Owner.GID.In(t.UserNamespace()).OrOverflow()))
// Padding (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, 0)
// Rdev (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(linux.MakeDeviceID(sattr.DeviceFileMajor, sattr.DeviceFileMinor)))
// Size (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(uattr.Size))
// Blksize (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.BlockSize))
// Blocks (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(uattr.Usage/512))
// ATime
atime := uattr.AccessTime.Timespec()
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(atime.Sec))
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(atime.Nsec))
// MTime
mtime := uattr.ModificationTime.Timespec()
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(mtime.Sec))
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(mtime.Nsec))
// CTime
ctime := uattr.StatusChangeTime.Timespec()
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(ctime.Sec))
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(ctime.Nsec))
_, err := t.CopyOutBytes(dst, b)
return err
}
// Statx implements linux syscall statx(2).
func Statx(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
fd := args[0].Int()
@@ -0,0 +1,75 @@
// Copyright 2020 The gVisor Authors.
//
// 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.
//+build amd64
package linux
import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/binary"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/usermem"
)
// copyOutStat copies the attributes (sattr, uattr) to the struct stat at
// address dst in t's address space. It encodes the stat struct to bytes
// manually, as stat() is a very common syscall for many applications, and
// t.CopyObjectOut has noticeable performance impact due to its many slice
// allocations and use of reflection.
func copyOutStat(t *kernel.Task, dst usermem.Addr, sattr fs.StableAttr, uattr fs.UnstableAttr) error {
b := t.CopyScratchBuffer(int(linux.SizeOfStat))[:0]
// Dev (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.DeviceID))
// Ino (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.InodeID))
// Nlink (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uattr.Links)
// Mode (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, sattr.Type.LinuxType()|uint32(uattr.Perms.LinuxMode()))
// UID (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Owner.UID.In(t.UserNamespace()).OrOverflow()))
// GID (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Owner.GID.In(t.UserNamespace()).OrOverflow()))
// Padding (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, 0)
// Rdev (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(linux.MakeDeviceID(sattr.DeviceFileMajor, sattr.DeviceFileMinor)))
// Size (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(uattr.Size))
// Blksize (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.BlockSize))
// Blocks (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(uattr.Usage/512))
// ATime
atime := uattr.AccessTime.Timespec()
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(atime.Sec))
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(atime.Nsec))
// MTime
mtime := uattr.ModificationTime.Timespec()
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(mtime.Sec))
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(mtime.Nsec))
// CTime
ctime := uattr.StatusChangeTime.Timespec()
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(ctime.Sec))
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(ctime.Nsec))
_, err := t.CopyOutBytes(dst, b)
return err
}
@@ -0,0 +1,77 @@
// Copyright 2020 The gVisor Authors.
//
// 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.
//+build arm64
package linux
import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/binary"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/usermem"
)
// copyOutStat copies the attributes (sattr, uattr) to the struct stat at
// address dst in t's address space. It encodes the stat struct to bytes
// manually, as stat() is a very common syscall for many applications, and
// t.CopyObjectOut has noticeable performance impact due to its many slice
// allocations and use of reflection.
func copyOutStat(t *kernel.Task, dst usermem.Addr, sattr fs.StableAttr, uattr fs.UnstableAttr) error {
b := t.CopyScratchBuffer(int(linux.SizeOfStat))[:0]
// Dev (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.DeviceID))
// Ino (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(sattr.InodeID))
// Mode (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, sattr.Type.LinuxType()|uint32(uattr.Perms.LinuxMode()))
// Nlink (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Links))
// UID (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Owner.UID.In(t.UserNamespace()).OrOverflow()))
// GID (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, uint32(uattr.Owner.GID.In(t.UserNamespace()).OrOverflow()))
// Rdev (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(linux.MakeDeviceID(sattr.DeviceFileMajor, sattr.DeviceFileMinor)))
// Padding (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, 0)
// Size (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(uattr.Size))
// Blksize (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, uint32(sattr.BlockSize))
// Padding (uint32)
b = binary.AppendUint32(b, usermem.ByteOrder, 0)
// Blocks (uint64)
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(uattr.Usage/512))
// ATime
atime := uattr.AccessTime.Timespec()
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(atime.Sec))
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(atime.Nsec))
// MTime
mtime := uattr.ModificationTime.Timespec()
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(mtime.Sec))
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(mtime.Nsec))
// CTime
ctime := uattr.StatusChangeTime.Timespec()
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(ctime.Sec))
b = binary.AppendUint64(b, usermem.ByteOrder, uint64(ctime.Nsec))
_, err := t.CopyOutBytes(dst, b)
return err
}