mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Drop ashmem and binder.
These are unfortunately unused and unmaintained. They can be brought back in the future if need requires it. PiperOrigin-RevId: 255697132
This commit is contained in:
committed by
gVisor bot
parent
d3f97aec49
commit
7dae043fec
@@ -10,9 +10,7 @@ go_library(
|
||||
name = "linux",
|
||||
srcs = [
|
||||
"aio.go",
|
||||
"ashmem.go",
|
||||
"audit.go",
|
||||
"binder.go",
|
||||
"bpf.go",
|
||||
"capability.go",
|
||||
"dev.go",
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
package linux
|
||||
|
||||
// Constants used by ashmem in pin-related ioctls.
|
||||
const (
|
||||
AshmemNotPurged = 0
|
||||
AshmemWasPurged = 1
|
||||
AshmemIsUnpinned = 0
|
||||
AshmemIsPinned = 1
|
||||
)
|
||||
|
||||
// AshmemPin structure is used for pin-related ioctls.
|
||||
type AshmemPin struct {
|
||||
Offset uint32
|
||||
Len uint32
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
package linux
|
||||
|
||||
// BinderVersion structure is used for BINDER_VERSION ioctl.
|
||||
type BinderVersion struct {
|
||||
ProtocolVersion int32
|
||||
}
|
||||
@@ -72,28 +72,3 @@ const (
|
||||
SIOCGMIIPHY = 0x8947
|
||||
SIOCGMIIREG = 0x8948
|
||||
)
|
||||
|
||||
// ioctl(2) requests provided by uapi/linux/android/binder.h
|
||||
const (
|
||||
BinderWriteReadIoctl = 0xc0306201
|
||||
BinderSetIdleTimeoutIoctl = 0x40086203
|
||||
BinderSetMaxThreadsIoctl = 0x40046205
|
||||
BinderSetIdlePriorityIoctl = 0x40046206
|
||||
BinderSetContextMgrIoctl = 0x40046207
|
||||
BinderThreadExitIoctl = 0x40046208
|
||||
BinderVersionIoctl = 0xc0046209
|
||||
)
|
||||
|
||||
// ioctl(2) requests provided by drivers/staging/android/uapi/ashmem.h
|
||||
const (
|
||||
AshmemSetNameIoctl = 0x41007701
|
||||
AshmemGetNameIoctl = 0x81007702
|
||||
AshmemSetSizeIoctl = 0x40087703
|
||||
AshmemGetSizeIoctl = 0x00007704
|
||||
AshmemSetProtMaskIoctl = 0x40087705
|
||||
AshmemGetProtMaskIoctl = 0x00007706
|
||||
AshmemPinIoctl = 0x40087707
|
||||
AshmemUnpinIoctl = 0x40087708
|
||||
AshmemGetPinStatusIoctl = 0x00007709
|
||||
AshmemPurgeAllCachesIoctl = 0x0000770a
|
||||
)
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package(licenses = ["notice"])
|
||||
|
||||
load("//tools/go_stateify:defs.bzl", "go_library", "go_test")
|
||||
load("//tools/go_generics:defs.bzl", "go_template_instance")
|
||||
|
||||
go_library(
|
||||
name = "ashmem",
|
||||
srcs = [
|
||||
"area.go",
|
||||
"device.go",
|
||||
"pin_board.go",
|
||||
"uint64_range.go",
|
||||
"uint64_set.go",
|
||||
],
|
||||
importpath = "gvisor.dev/gvisor/pkg/sentry/fs/ashmem",
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/context",
|
||||
"//pkg/sentry/fs",
|
||||
"//pkg/sentry/fs/fsutil",
|
||||
"//pkg/sentry/fs/tmpfs",
|
||||
"//pkg/sentry/kernel/time",
|
||||
"//pkg/sentry/memmap",
|
||||
"//pkg/sentry/usage",
|
||||
"//pkg/sentry/usermem",
|
||||
"//pkg/syserror",
|
||||
"//pkg/waiter",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "ashmem_test",
|
||||
size = "small",
|
||||
srcs = ["pin_board_test.go"],
|
||||
embed = [":ashmem"],
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/sentry/usermem",
|
||||
],
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "uint64_range",
|
||||
out = "uint64_range.go",
|
||||
package = "ashmem",
|
||||
template = "//pkg/segment:generic_range",
|
||||
types = {
|
||||
"T": "uint64",
|
||||
},
|
||||
)
|
||||
|
||||
go_template_instance(
|
||||
name = "uint64_set",
|
||||
out = "uint64_set.go",
|
||||
package = "ashmem",
|
||||
template = "//pkg/segment:generic_set",
|
||||
types = {
|
||||
"Key": "uint64",
|
||||
"Range": "Range",
|
||||
"Value": "noValue",
|
||||
"Functions": "setFunctions",
|
||||
},
|
||||
)
|
||||
@@ -1,308 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
package ashmem
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/fsutil"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/tmpfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/memmap"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usage"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
const (
|
||||
// namePrefix is the name prefix assumed and forced by the Linux implementation.
|
||||
namePrefix = "dev/ashmem"
|
||||
|
||||
// nameLen is the maximum name length.
|
||||
nameLen = 256
|
||||
)
|
||||
|
||||
// Area implements fs.FileOperations.
|
||||
//
|
||||
// +stateify savable
|
||||
type Area struct {
|
||||
fsutil.FileNoFsync `state:"nosave"`
|
||||
fsutil.FileNoSplice `state:"nosave"`
|
||||
fsutil.FileNoopFlush `state:"nosave"`
|
||||
fsutil.FileNotDirReaddir `state:"nosave"`
|
||||
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
|
||||
waiter.AlwaysReady `state:"nosave"`
|
||||
|
||||
ad *Device
|
||||
|
||||
// mu protects fields below.
|
||||
mu sync.Mutex `state:"nosave"`
|
||||
tmpfsFile *fs.File
|
||||
name string
|
||||
size uint64
|
||||
perms usermem.AccessType
|
||||
pb *PinBoard
|
||||
}
|
||||
|
||||
// Release implements fs.FileOperations.Release.
|
||||
func (a *Area) Release() {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if a.tmpfsFile != nil {
|
||||
a.tmpfsFile.DecRef()
|
||||
a.tmpfsFile = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Seek implements fs.FileOperations.Seek.
|
||||
func (a *Area) Seek(ctx context.Context, file *fs.File, whence fs.SeekWhence, offset int64) (int64, error) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if a.size == 0 {
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
if a.tmpfsFile == nil {
|
||||
return 0, syserror.EBADF
|
||||
}
|
||||
return a.tmpfsFile.FileOperations.Seek(ctx, file, whence, offset)
|
||||
}
|
||||
|
||||
// Read implements fs.FileOperations.Read.
|
||||
func (a *Area) Read(ctx context.Context, file *fs.File, dst usermem.IOSequence, offset int64) (int64, error) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if a.size == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
if a.tmpfsFile == nil {
|
||||
return 0, syserror.EBADF
|
||||
}
|
||||
return a.tmpfsFile.FileOperations.Read(ctx, file, dst, offset)
|
||||
}
|
||||
|
||||
// Write implements fs.FileOperations.Write.
|
||||
func (a *Area) Write(ctx context.Context, file *fs.File, src usermem.IOSequence, offset int64) (int64, error) {
|
||||
return 0, syserror.ENOSYS
|
||||
}
|
||||
|
||||
// ConfigureMMap implements fs.FileOperations.ConfigureMMap.
|
||||
func (a *Area) ConfigureMMap(ctx context.Context, file *fs.File, opts *memmap.MMapOpts) error {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if a.size == 0 {
|
||||
return syserror.EINVAL
|
||||
}
|
||||
|
||||
if !a.perms.SupersetOf(opts.Perms) {
|
||||
return syserror.EPERM
|
||||
}
|
||||
opts.MaxPerms = opts.MaxPerms.Intersect(a.perms)
|
||||
|
||||
if a.tmpfsFile == nil {
|
||||
tmpfsInodeOps := tmpfs.NewInMemoryFile(ctx, usage.Tmpfs, fs.UnstableAttr{})
|
||||
tmpfsInode := fs.NewInode(ctx, tmpfsInodeOps, fs.NewPseudoMountSource(ctx), fs.StableAttr{})
|
||||
dirent := fs.NewDirent(ctx, tmpfsInode, namePrefix+"/"+a.name)
|
||||
tmpfsFile, err := tmpfsInode.GetFile(ctx, dirent, fs.FileFlags{Read: true, Write: true})
|
||||
// Drop the extra reference on the Dirent.
|
||||
dirent.DecRef()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Truncate to the size set by ASHMEM_SET_SIZE ioctl.
|
||||
err = tmpfsInodeOps.Truncate(ctx, tmpfsInode, int64(a.size))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.tmpfsFile = tmpfsFile
|
||||
a.pb = NewPinBoard()
|
||||
}
|
||||
|
||||
return a.tmpfsFile.ConfigureMMap(ctx, opts)
|
||||
}
|
||||
|
||||
// Ioctl implements fs.FileOperations.Ioctl.
|
||||
func (a *Area) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
|
||||
// Switch on ioctl request.
|
||||
switch args[1].Uint() {
|
||||
case linux.AshmemSetNameIoctl:
|
||||
name, err := usermem.CopyStringIn(ctx, io, args[2].Pointer(), nameLen-1, usermem.IOOpts{
|
||||
AddressSpaceActive: true,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
// Cannot set name for already mapped ashmem.
|
||||
if a.tmpfsFile != nil {
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
a.name = name
|
||||
return 0, nil
|
||||
|
||||
case linux.AshmemGetNameIoctl:
|
||||
a.mu.Lock()
|
||||
var local []byte
|
||||
if a.name != "" {
|
||||
nameLen := len([]byte(a.name))
|
||||
local = make([]byte, nameLen, nameLen+1)
|
||||
copy(local, []byte(a.name))
|
||||
local = append(local, 0)
|
||||
} else {
|
||||
nameLen := len([]byte(namePrefix))
|
||||
local = make([]byte, nameLen, nameLen+1)
|
||||
copy(local, []byte(namePrefix))
|
||||
local = append(local, 0)
|
||||
}
|
||||
a.mu.Unlock()
|
||||
|
||||
if _, err := io.CopyOut(ctx, args[2].Pointer(), local, usermem.IOOpts{
|
||||
AddressSpaceActive: true,
|
||||
}); err != nil {
|
||||
return 0, syserror.EFAULT
|
||||
}
|
||||
return 0, nil
|
||||
|
||||
case linux.AshmemSetSizeIoctl:
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
// Cannot set size for already mapped ashmem.
|
||||
if a.tmpfsFile != nil {
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
a.size = uint64(args[2].SizeT())
|
||||
return 0, nil
|
||||
|
||||
case linux.AshmemGetSizeIoctl:
|
||||
return uintptr(a.size), nil
|
||||
|
||||
case linux.AshmemPinIoctl, linux.AshmemUnpinIoctl, linux.AshmemGetPinStatusIoctl:
|
||||
// Locking and unlocking is ok since once tmpfsFile is set, it won't be nil again
|
||||
// even after unmapping! Unlocking is needed in order to avoid a deadlock on
|
||||
// usermem.CopyObjectIn.
|
||||
|
||||
// Cannot execute pin-related ioctls before mapping.
|
||||
a.mu.Lock()
|
||||
if a.tmpfsFile == nil {
|
||||
a.mu.Unlock()
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
a.mu.Unlock()
|
||||
|
||||
var pin linux.AshmemPin
|
||||
_, err := usermem.CopyObjectIn(ctx, io, args[2].Pointer(), &pin, usermem.IOOpts{
|
||||
AddressSpaceActive: true,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, syserror.EFAULT
|
||||
}
|
||||
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
return a.pinOperation(pin, args[1].Uint())
|
||||
|
||||
case linux.AshmemPurgeAllCachesIoctl:
|
||||
return 0, nil
|
||||
|
||||
case linux.AshmemSetProtMaskIoctl:
|
||||
prot := uint64(args[2].ModeT())
|
||||
perms := usermem.AccessType{
|
||||
Read: prot&linux.PROT_READ != 0,
|
||||
Write: prot&linux.PROT_WRITE != 0,
|
||||
Execute: prot&linux.PROT_EXEC != 0,
|
||||
}
|
||||
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
// Can only narrow prot mask.
|
||||
if !a.perms.SupersetOf(perms) {
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
|
||||
// TODO(b/30946773,gvisor.dev/issue/153): If personality flag
|
||||
// READ_IMPLIES_EXEC is set, set PROT_EXEC if PORT_READ is set.
|
||||
|
||||
a.perms = perms
|
||||
return 0, nil
|
||||
|
||||
case linux.AshmemGetProtMaskIoctl:
|
||||
return uintptr(a.perms.Prot()), nil
|
||||
default:
|
||||
// Ioctls irrelevant to Ashmem.
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
// pinOperation should only be called while holding a.mu.
|
||||
func (a *Area) pinOperation(pin linux.AshmemPin, op uint32) (uintptr, error) {
|
||||
// Page-align a.size for checks.
|
||||
pageAlignedSize, ok := usermem.Addr(a.size).RoundUp()
|
||||
if !ok {
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
// Len 0 means everything onward.
|
||||
if pin.Len == 0 {
|
||||
pin.Len = uint32(pageAlignedSize) - pin.Offset
|
||||
}
|
||||
// Both Offset and Len have to be page-aligned.
|
||||
if pin.Offset%uint32(usermem.PageSize) != 0 {
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
if pin.Len%uint32(usermem.PageSize) != 0 {
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
// Adding Offset and Len must not cause an uint32 overflow.
|
||||
if end := pin.Offset + pin.Len; end < pin.Offset {
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
// Pin range must not exceed a's size.
|
||||
if uint32(pageAlignedSize) < pin.Offset+pin.Len {
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
// Handle each operation.
|
||||
r := RangeFromAshmemPin(pin)
|
||||
switch op {
|
||||
case linux.AshmemPinIoctl:
|
||||
if a.pb.PinRange(r) {
|
||||
return linux.AshmemWasPurged, nil
|
||||
}
|
||||
return linux.AshmemNotPurged, nil
|
||||
|
||||
case linux.AshmemUnpinIoctl:
|
||||
// TODO(b/30946773): Implement purge on unpin.
|
||||
a.pb.UnpinRange(r)
|
||||
return 0, nil
|
||||
|
||||
case linux.AshmemGetPinStatusIoctl:
|
||||
if a.pb.RangePinnedStatus(r) {
|
||||
return linux.AshmemIsPinned, nil
|
||||
}
|
||||
return linux.AshmemIsUnpinned, nil
|
||||
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Package ashmem implements Android ashmem module (Anonymus Shared Memory).
|
||||
package ashmem
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/sentry/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/fsutil"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
||||
)
|
||||
|
||||
// Device implements fs.InodeOperations.
|
||||
//
|
||||
// +stateify savable
|
||||
type Device struct {
|
||||
fsutil.InodeGenericChecker `state:"nosave"`
|
||||
fsutil.InodeNoExtendedAttributes `state:"nosave"`
|
||||
fsutil.InodeNoopAllocate `state:"nosave"`
|
||||
fsutil.InodeNoopRelease `state:"nosave"`
|
||||
fsutil.InodeNoopTruncate `state:"nosave"`
|
||||
fsutil.InodeNoopWriteOut `state:"nosave"`
|
||||
fsutil.InodeNotDirectory `state:"nosave"`
|
||||
fsutil.InodeNotMappable `state:"nosave"`
|
||||
fsutil.InodeNotSocket `state:"nosave"`
|
||||
fsutil.InodeNotSymlink `state:"nosave"`
|
||||
fsutil.InodeVirtual `state:"nosave"`
|
||||
|
||||
fsutil.InodeSimpleAttributes
|
||||
}
|
||||
|
||||
var _ fs.InodeOperations = (*Device)(nil)
|
||||
|
||||
// NewDevice creates and initializes a Device structure.
|
||||
func NewDevice(ctx context.Context, owner fs.FileOwner, fp fs.FilePermissions) *Device {
|
||||
return &Device{
|
||||
InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, owner, fp, linux.ANON_INODE_FS_MAGIC),
|
||||
}
|
||||
}
|
||||
|
||||
// GetFile implements fs.InodeOperations.GetFile.
|
||||
func (ad *Device) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
|
||||
return fs.NewFile(ctx, d, flags, &Area{
|
||||
ad: ad,
|
||||
tmpfsFile: nil,
|
||||
perms: usermem.AnyAccess,
|
||||
}), nil
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
package ashmem
|
||||
|
||||
import "gvisor.dev/gvisor/pkg/abi/linux"
|
||||
|
||||
const maxUint64 = ^uint64(0)
|
||||
|
||||
// setFunctions implements segment.Functions generated from segment.Functions for
|
||||
// uint64 Key and noValue Value. For more information, see the build file and
|
||||
// segment set implementation at pkg/segment/set.go.
|
||||
type setFunctions struct{}
|
||||
|
||||
// noValue is a type of range attached value, which is irrelevant here.
|
||||
type noValue struct{}
|
||||
|
||||
// MinKey implements segment.Functions.MinKey.
|
||||
func (setFunctions) MinKey() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// MaxKey implements segment.Functions.MaxKey.
|
||||
func (setFunctions) MaxKey() uint64 {
|
||||
return maxUint64
|
||||
}
|
||||
|
||||
// ClearValue implements segment.Functions.ClearValue.
|
||||
func (setFunctions) ClearValue(*noValue) {
|
||||
return
|
||||
}
|
||||
|
||||
// Merge implements segment.Functions.Merge.
|
||||
func (setFunctions) Merge(Range, noValue, Range, noValue) (noValue, bool) {
|
||||
return noValue{}, true
|
||||
}
|
||||
|
||||
// Split implements segment.Functions.Split.
|
||||
func (setFunctions) Split(Range, noValue, uint64) (noValue, noValue) {
|
||||
return noValue{}, noValue{}
|
||||
}
|
||||
|
||||
// PinBoard represents a set of pinned ranges in ashmem.
|
||||
//
|
||||
// segment.Set is used for implementation where segments represent
|
||||
// ranges of pinned bytes, while gaps represent ranges of unpinned
|
||||
// bytes. All ranges are page-aligned.
|
||||
//
|
||||
// +stateify savable
|
||||
type PinBoard struct {
|
||||
Set
|
||||
}
|
||||
|
||||
// NewPinBoard creates a new pin board with all pages pinned.
|
||||
func NewPinBoard() *PinBoard {
|
||||
var pb PinBoard
|
||||
pb.PinRange(Range{0, maxUint64})
|
||||
return &pb
|
||||
}
|
||||
|
||||
// PinRange pins all pages in the specified range and returns true
|
||||
// if there are any newly pinned pages.
|
||||
func (pb *PinBoard) PinRange(r Range) bool {
|
||||
pinnedPages := false
|
||||
for gap := pb.LowerBoundGap(r.Start); gap.Ok() && gap.Start() < r.End; {
|
||||
common := gap.Range().Intersect(r)
|
||||
if common.Length() == 0 {
|
||||
gap = gap.NextGap()
|
||||
continue
|
||||
}
|
||||
pinnedPages = true
|
||||
gap = pb.Insert(gap, common, noValue{}).NextGap()
|
||||
}
|
||||
return pinnedPages
|
||||
}
|
||||
|
||||
// UnpinRange unpins all pages in the specified range.
|
||||
func (pb *PinBoard) UnpinRange(r Range) {
|
||||
for seg := pb.LowerBoundSegment(r.Start); seg.Ok() && seg.Start() < r.End; {
|
||||
common := seg.Range().Intersect(r)
|
||||
if common.Length() == 0 {
|
||||
seg = seg.NextSegment()
|
||||
continue
|
||||
}
|
||||
seg = pb.RemoveRange(common).NextSegment()
|
||||
}
|
||||
}
|
||||
|
||||
// RangePinnedStatus returns false if there's at least one unpinned page in the
|
||||
// specified range.
|
||||
func (pb *PinBoard) RangePinnedStatus(r Range) bool {
|
||||
for gap := pb.LowerBoundGap(r.Start); gap.Ok() && gap.Start() < r.End; {
|
||||
common := gap.Range().Intersect(r)
|
||||
if common.Length() == 0 {
|
||||
gap = gap.NextGap()
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// RangeFromAshmemPin converts ashmem's original pin structure
|
||||
// to Range.
|
||||
func RangeFromAshmemPin(ap linux.AshmemPin) Range {
|
||||
if ap.Len == 0 {
|
||||
return Range{
|
||||
uint64(ap.Offset),
|
||||
maxUint64,
|
||||
}
|
||||
}
|
||||
return Range{
|
||||
uint64(ap.Offset),
|
||||
uint64(ap.Offset) + uint64(ap.Len),
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
package ashmem
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
||||
)
|
||||
|
||||
func TestPinBoard(t *testing.T) {
|
||||
pb := NewPinBoard()
|
||||
|
||||
// Confirm that all pages are pinned.
|
||||
if !pb.RangePinnedStatus(RangeFromAshmemPin(linux.AshmemPin{0, 0})) {
|
||||
t.Errorf("RangePinnedStatus(all pages) returned false (unpinned) at start.")
|
||||
}
|
||||
|
||||
// Unpin pages [1, 11) (counting from 0)
|
||||
pb.UnpinRange(RangeFromAshmemPin(linux.AshmemPin{
|
||||
usermem.PageSize,
|
||||
usermem.PageSize * 10,
|
||||
}))
|
||||
|
||||
// Confirm that pages [1, 11) are unpinned and that page 0 and pages
|
||||
// larger than 10 are pinned.
|
||||
pinned := []linux.AshmemPin{
|
||||
{
|
||||
0,
|
||||
usermem.PageSize,
|
||||
}, {
|
||||
usermem.PageSize * 11,
|
||||
0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, pin := range pinned {
|
||||
if !pb.RangePinnedStatus(RangeFromAshmemPin(pin)) {
|
||||
t.Errorf("RangePinnedStatus(AshmemPin{offset (pages): %v, len (pages): %v}) returned false (unpinned).",
|
||||
pin.Offset, pin.Len)
|
||||
}
|
||||
}
|
||||
|
||||
unpinned := []linux.AshmemPin{
|
||||
{
|
||||
usermem.PageSize,
|
||||
usermem.PageSize * 10,
|
||||
},
|
||||
}
|
||||
|
||||
for _, pin := range unpinned {
|
||||
if pb.RangePinnedStatus(RangeFromAshmemPin(pin)) {
|
||||
t.Errorf("RangePinnedStatus(AshmemPin{offset (pages): %v, len (pages): %v}) returned true (pinned).",
|
||||
pin.Offset, pin.Len)
|
||||
}
|
||||
}
|
||||
|
||||
// Pin pages [2, 6).
|
||||
pb.PinRange(RangeFromAshmemPin(linux.AshmemPin{
|
||||
usermem.PageSize * 2,
|
||||
usermem.PageSize * 4,
|
||||
}))
|
||||
|
||||
// Confirm that pages 0, [2, 6) and pages larger than 10 are pinned
|
||||
// while others remain unpinned.
|
||||
pinned = []linux.AshmemPin{
|
||||
{
|
||||
0,
|
||||
usermem.PageSize,
|
||||
},
|
||||
{
|
||||
usermem.PageSize * 2,
|
||||
usermem.PageSize * 4,
|
||||
},
|
||||
{
|
||||
usermem.PageSize * 11,
|
||||
0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, pin := range pinned {
|
||||
if !pb.RangePinnedStatus(RangeFromAshmemPin(pin)) {
|
||||
t.Errorf("RangePinnedStatus(AshmemPin{offset (pages): %v, len (pages): %v}) returned false (unpinned).",
|
||||
pin.Offset, pin.Len)
|
||||
}
|
||||
}
|
||||
|
||||
unpinned = []linux.AshmemPin{
|
||||
{
|
||||
usermem.PageSize,
|
||||
usermem.PageSize,
|
||||
}, {
|
||||
usermem.PageSize * 6,
|
||||
usermem.PageSize * 5,
|
||||
},
|
||||
}
|
||||
|
||||
for _, pin := range unpinned {
|
||||
if pb.RangePinnedStatus(RangeFromAshmemPin(pin)) {
|
||||
t.Errorf("RangePinnedStatus(AshmemPin{offset (pages): %v, len (pages): %v}) returned true (pinned).",
|
||||
pin.Offset, pin.Len)
|
||||
}
|
||||
}
|
||||
|
||||
// Status of a partially pinned range is unpinned.
|
||||
if pb.RangePinnedStatus(RangeFromAshmemPin(linux.AshmemPin{0, 0})) {
|
||||
t.Errorf("RangePinnedStatus(all pages) returned true (pinned).")
|
||||
}
|
||||
|
||||
// Pin the whole range again.
|
||||
pb.PinRange(RangeFromAshmemPin(linux.AshmemPin{0, 0}))
|
||||
|
||||
// Confirm that all pages are pinned.
|
||||
if !pb.RangePinnedStatus(RangeFromAshmemPin(linux.AshmemPin{0, 0})) {
|
||||
t.Errorf("RangePinnedStatus(all pages) returned false (unpinned) at start.")
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package(licenses = ["notice"])
|
||||
|
||||
load("//tools/go_stateify:defs.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "binder",
|
||||
srcs = [
|
||||
"binder.go",
|
||||
],
|
||||
importpath = "gvisor.dev/gvisor/pkg/sentry/fs/binder",
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/context",
|
||||
"//pkg/sentry/fs",
|
||||
"//pkg/sentry/fs/fsutil",
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/memmap",
|
||||
"//pkg/sentry/pgalloc",
|
||||
"//pkg/sentry/platform",
|
||||
"//pkg/sentry/usage",
|
||||
"//pkg/sentry/usermem",
|
||||
"//pkg/syserror",
|
||||
"//pkg/waiter",
|
||||
],
|
||||
)
|
||||
@@ -1,260 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Package binder implements Android Binder IPC module.
|
||||
package binder
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
"gvisor.dev/gvisor/pkg/sentry/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/fsutil"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/memmap"
|
||||
"gvisor.dev/gvisor/pkg/sentry/pgalloc"
|
||||
"gvisor.dev/gvisor/pkg/sentry/platform"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usage"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
const (
|
||||
currentProtocolVersion = 8
|
||||
|
||||
// mmapSizeLimit is the upper limit for mapped memory size in Binder.
|
||||
mmapSizeLimit = 4 * 1024 * 1024 // 4MB
|
||||
)
|
||||
|
||||
// Device implements fs.InodeOperations.
|
||||
//
|
||||
// +stateify savable
|
||||
type Device struct {
|
||||
fsutil.InodeGenericChecker `state:"nosave"`
|
||||
fsutil.InodeNoExtendedAttributes `state:"nosave"`
|
||||
fsutil.InodeNoopAllocate `state:"nosave"`
|
||||
fsutil.InodeNoopRelease `state:"nosave"`
|
||||
fsutil.InodeNoopTruncate `state:"nosave"`
|
||||
fsutil.InodeNoopWriteOut `state:"nosave"`
|
||||
fsutil.InodeNotDirectory `state:"nosave"`
|
||||
fsutil.InodeNotMappable `state:"nosave"`
|
||||
fsutil.InodeNotSocket `state:"nosave"`
|
||||
fsutil.InodeNotSymlink `state:"nosave"`
|
||||
fsutil.InodeVirtual `state:"nosave"`
|
||||
|
||||
fsutil.InodeSimpleAttributes
|
||||
}
|
||||
|
||||
var _ fs.InodeOperations = (*Device)(nil)
|
||||
|
||||
// NewDevice creates and initializes a Device structure.
|
||||
func NewDevice(ctx context.Context, owner fs.FileOwner, fp fs.FilePermissions) *Device {
|
||||
return &Device{
|
||||
InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(ctx, owner, fp, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// GetFile implements fs.InodeOperations.GetFile.
|
||||
//
|
||||
// TODO(b/30946773): Add functionality to GetFile: Additional fields will be
|
||||
// needed in the Device structure, initialize them here. Also, Device will need
|
||||
// to keep track of the created Procs in order to implement BINDER_READ_WRITE
|
||||
// ioctl.
|
||||
func (bd *Device) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
|
||||
return fs.NewFile(ctx, d, flags, &Proc{
|
||||
bd: bd,
|
||||
task: kernel.TaskFromContext(ctx),
|
||||
mfp: pgalloc.MemoryFileProviderFromContext(ctx),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// Proc implements fs.FileOperations and fs.IoctlGetter.
|
||||
//
|
||||
// +stateify savable
|
||||
type Proc struct {
|
||||
fsutil.FileNoFsync `state:"nosave"`
|
||||
fsutil.FileNoSplice `state:"nosave"`
|
||||
fsutil.FileNotDirReaddir `state:"nosave"`
|
||||
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
|
||||
waiter.AlwaysReady `state:"nosave"`
|
||||
|
||||
bd *Device
|
||||
task *kernel.Task
|
||||
mfp pgalloc.MemoryFileProvider
|
||||
|
||||
// mu protects fr.
|
||||
mu sync.Mutex `state:"nosave"`
|
||||
|
||||
// mapped is memory allocated from mfp.MemoryFile() by AddMapping.
|
||||
mapped platform.FileRange
|
||||
}
|
||||
|
||||
// Release implements fs.FileOperations.Release.
|
||||
func (bp *Proc) Release() {
|
||||
bp.mu.Lock()
|
||||
defer bp.mu.Unlock()
|
||||
if bp.mapped.Length() != 0 {
|
||||
bp.mfp.MemoryFile().DecRef(bp.mapped)
|
||||
}
|
||||
}
|
||||
|
||||
// Seek implements fs.FileOperations.Seek.
|
||||
//
|
||||
// Binder doesn't support seek operation (unless in debug mode).
|
||||
func (bp *Proc) Seek(ctx context.Context, file *fs.File, whence fs.SeekWhence, offset int64) (int64, error) {
|
||||
return offset, syserror.EOPNOTSUPP
|
||||
}
|
||||
|
||||
// Read implements fs.FileOperations.Read.
|
||||
//
|
||||
// Binder doesn't support read operation (unless in debug mode).
|
||||
func (bp *Proc) Read(ctx context.Context, file *fs.File, dst usermem.IOSequence, offset int64) (int64, error) {
|
||||
return 0, syserror.EOPNOTSUPP
|
||||
}
|
||||
|
||||
// Write implements fs.FileOperations.Write.
|
||||
//
|
||||
// Binder doesn't support write operation.
|
||||
func (bp *Proc) Write(ctx context.Context, file *fs.File, src usermem.IOSequence, offset int64) (int64, error) {
|
||||
return 0, syserror.EOPNOTSUPP
|
||||
}
|
||||
|
||||
// Flush implements fs.FileOperations.Flush.
|
||||
//
|
||||
// TODO(b/30946773): Implement.
|
||||
func (bp *Proc) Flush(ctx context.Context, file *fs.File) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigureMMap implements fs.FileOperations.ConfigureMMap.
|
||||
func (bp *Proc) ConfigureMMap(ctx context.Context, file *fs.File, opts *memmap.MMapOpts) error {
|
||||
// Compare drivers/android/binder.c:binder_mmap().
|
||||
if caller := kernel.TaskFromContext(ctx); caller != bp.task {
|
||||
return syserror.EINVAL
|
||||
}
|
||||
if opts.Length > mmapSizeLimit {
|
||||
opts.Length = mmapSizeLimit
|
||||
}
|
||||
opts.MaxPerms.Write = false
|
||||
|
||||
// TODO(b/30946773): Binder sets VM_DONTCOPY, preventing the created vma
|
||||
// from being copied across fork(), but we don't support this yet. As
|
||||
// a result, MMs containing a Binder mapping cannot be forked (MM.Fork will
|
||||
// fail when AddMapping returns EBUSY).
|
||||
|
||||
return fsutil.GenericConfigureMMap(file, bp, opts)
|
||||
}
|
||||
|
||||
// Ioctl implements fs.FileOperations.Ioctl.
|
||||
//
|
||||
// TODO(b/30946773): Implement.
|
||||
func (bp *Proc) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
|
||||
// Switch on ioctl request.
|
||||
switch uint32(args[1].Int()) {
|
||||
case linux.BinderVersionIoctl:
|
||||
ver := &linux.BinderVersion{
|
||||
ProtocolVersion: currentProtocolVersion,
|
||||
}
|
||||
// Copy result to user-space.
|
||||
_, err := usermem.CopyObjectOut(ctx, io, args[2].Pointer(), ver, usermem.IOOpts{
|
||||
AddressSpaceActive: true,
|
||||
})
|
||||
return 0, err
|
||||
case linux.BinderWriteReadIoctl:
|
||||
// TODO(b/30946773): Implement.
|
||||
fallthrough
|
||||
case linux.BinderSetIdleTimeoutIoctl:
|
||||
// TODO(b/30946773): Implement.
|
||||
fallthrough
|
||||
case linux.BinderSetMaxThreadsIoctl:
|
||||
// TODO(b/30946773): Implement.
|
||||
fallthrough
|
||||
case linux.BinderSetIdlePriorityIoctl:
|
||||
// TODO(b/30946773): Implement.
|
||||
fallthrough
|
||||
case linux.BinderSetContextMgrIoctl:
|
||||
// TODO(b/30946773): Implement.
|
||||
fallthrough
|
||||
case linux.BinderThreadExitIoctl:
|
||||
// TODO(b/30946773): Implement.
|
||||
return 0, syserror.ENOSYS
|
||||
default:
|
||||
// Ioctls irrelevant to Binder.
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
// AddMapping implements memmap.Mappable.AddMapping.
|
||||
func (bp *Proc) AddMapping(ctx context.Context, ms memmap.MappingSpace, ar usermem.AddrRange, offset uint64, _ bool) error {
|
||||
bp.mu.Lock()
|
||||
defer bp.mu.Unlock()
|
||||
if bp.mapped.Length() != 0 {
|
||||
// mmap has been called before, which binder_mmap() doesn't like.
|
||||
return syserror.EBUSY
|
||||
}
|
||||
// Binder only allocates and maps a single page up-front
|
||||
// (drivers/android/binder.c:binder_mmap() => binder_update_page_range()).
|
||||
fr, err := bp.mfp.MemoryFile().Allocate(usermem.PageSize, usage.Anonymous)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bp.mapped = fr
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveMapping implements memmap.Mappable.RemoveMapping.
|
||||
func (*Proc) RemoveMapping(context.Context, memmap.MappingSpace, usermem.AddrRange, uint64, bool) {
|
||||
// Nothing to do. Notably, we don't free bp.mapped to allow another mmap.
|
||||
}
|
||||
|
||||
// CopyMapping implements memmap.Mappable.CopyMapping.
|
||||
func (bp *Proc) CopyMapping(ctx context.Context, ms memmap.MappingSpace, srcAR, dstAR usermem.AddrRange, offset uint64, _ bool) error {
|
||||
// Nothing to do. Notably, this is one case where CopyMapping isn't
|
||||
// equivalent to AddMapping, as AddMapping would return EBUSY.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Translate implements memmap.Mappable.Translate.
|
||||
func (bp *Proc) Translate(ctx context.Context, required, optional memmap.MappableRange, at usermem.AccessType) ([]memmap.Translation, error) {
|
||||
// TODO(b/30946773): In addition to the page initially allocated and mapped
|
||||
// in AddMapping (Linux: binder_mmap), Binder allocates and maps pages for
|
||||
// each transaction (Linux: binder_ioctl => binder_ioctl_write_read =>
|
||||
// binder_thread_write => binder_transaction => binder_alloc_buf =>
|
||||
// binder_update_page_range). Since we don't actually implement
|
||||
// BinderWriteReadIoctl (Linux: BINDER_WRITE_READ), we only ever have the
|
||||
// first page.
|
||||
var err error
|
||||
if required.End > usermem.PageSize {
|
||||
err = &memmap.BusError{syserror.EFAULT}
|
||||
}
|
||||
if required.Start == 0 {
|
||||
return []memmap.Translation{
|
||||
{
|
||||
Source: memmap.MappableRange{0, usermem.PageSize},
|
||||
File: bp.mfp.MemoryFile(),
|
||||
Offset: bp.mapped.Start,
|
||||
Perms: usermem.AnyAccess,
|
||||
},
|
||||
}, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// InvalidateUnsavable implements memmap.Mappable.InvalidateUnsavable.
|
||||
func (bp *Proc) InvalidateUnsavable(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
@@ -20,8 +20,6 @@ go_library(
|
||||
"//pkg/sentry/context",
|
||||
"//pkg/sentry/device",
|
||||
"//pkg/sentry/fs",
|
||||
"//pkg/sentry/fs/ashmem",
|
||||
"//pkg/sentry/fs/binder",
|
||||
"//pkg/sentry/fs/fsutil",
|
||||
"//pkg/sentry/fs/ramfs",
|
||||
"//pkg/sentry/fs/tmpfs",
|
||||
|
||||
@@ -20,8 +20,6 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/sentry/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/ashmem"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/binder"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/ramfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/tmpfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
||||
@@ -81,7 +79,7 @@ func newSymlink(ctx context.Context, target string, msrc *fs.MountSource) *fs.In
|
||||
}
|
||||
|
||||
// New returns the root node of a device filesystem.
|
||||
func New(ctx context.Context, msrc *fs.MountSource, binderEnabled bool, ashmemEnabled bool) *fs.Inode {
|
||||
func New(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
|
||||
contents := map[string]*fs.Inode{
|
||||
"fd": newSymlink(ctx, "/proc/self/fd", msrc),
|
||||
"stdin": newSymlink(ctx, "/proc/self/fd/0", msrc),
|
||||
@@ -118,16 +116,6 @@ func New(ctx context.Context, msrc *fs.MountSource, binderEnabled bool, ashmemEn
|
||||
"ptmx": newSymlink(ctx, "pts/ptmx", msrc),
|
||||
}
|
||||
|
||||
if binderEnabled {
|
||||
binder := binder.NewDevice(ctx, fs.RootOwner, fs.FilePermsFromMode(0666))
|
||||
contents["binder"] = newCharacterDevice(ctx, binder, msrc)
|
||||
}
|
||||
|
||||
if ashmemEnabled {
|
||||
ashmem := ashmem.NewDevice(ctx, fs.RootOwner, fs.FilePermsFromMode(0666))
|
||||
contents["ashmem"] = newCharacterDevice(ctx, ashmem, msrc)
|
||||
}
|
||||
|
||||
iops := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
|
||||
return fs.NewInode(ctx, iops, msrc, fs.StableAttr{
|
||||
DeviceID: devDevice.DeviceID(),
|
||||
|
||||
+1
-36
@@ -15,19 +15,10 @@
|
||||
package dev
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/sentry/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
)
|
||||
|
||||
// Optional key containing boolean flag which specifies if Android Binder IPC should be enabled.
|
||||
const binderEnabledKey = "binder_enabled"
|
||||
|
||||
// Optional key containing boolean flag which specifies if Android ashmem should be enabled.
|
||||
const ashmemEnabledKey = "ashmem_enabled"
|
||||
|
||||
// filesystem is a devtmpfs.
|
||||
//
|
||||
// +stateify savable
|
||||
@@ -67,33 +58,7 @@ func (*filesystem) Flags() fs.FilesystemFlags {
|
||||
|
||||
// Mount returns a devtmpfs root that can be positioned in the vfs.
|
||||
func (f *filesystem) Mount(ctx context.Context, device string, flags fs.MountSourceFlags, data string, _ interface{}) (*fs.Inode, error) {
|
||||
// device is always ignored.
|
||||
// devtmpfs backed by ramfs ignores bad options. See fs/ramfs/inode.c:ramfs_parse_options.
|
||||
// -> we should consider parsing the mode and backing devtmpfs by this.
|
||||
|
||||
// Parse generic comma-separated key=value options.
|
||||
options := fs.GenericMountSourceOptions(data)
|
||||
|
||||
// binerEnabledKey is optional and binder is disabled by default.
|
||||
binderEnabled := false
|
||||
if beStr, exists := options[binderEnabledKey]; exists {
|
||||
var err error
|
||||
binderEnabled, err = strconv.ParseBool(beStr)
|
||||
if err != nil {
|
||||
return nil, syserror.EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
// ashmemEnabledKey is optional and ashmem is disabled by default.
|
||||
ashmemEnabled := false
|
||||
if aeStr, exists := options[ashmemEnabledKey]; exists {
|
||||
var err error
|
||||
ashmemEnabled, err = strconv.ParseBool(aeStr)
|
||||
if err != nil {
|
||||
return nil, syserror.EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the devtmpfs root.
|
||||
return New(ctx, fs.NewNonCachingMountSource(ctx, f, flags), binderEnabled, ashmemEnabled), nil
|
||||
return New(ctx, fs.NewNonCachingMountSource(ctx, f, flags)), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user