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:
Adin Scannell
2019-06-28 17:20:25 -07:00
committed by gVisor bot
parent d3f97aec49
commit 7dae043fec
14 changed files with 2 additions and 1105 deletions
-2
View File
@@ -10,9 +10,7 @@ go_library(
name = "linux",
srcs = [
"aio.go",
"ashmem.go",
"audit.go",
"binder.go",
"bpf.go",
"capability.go",
"dev.go",
-29
View File
@@ -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
}
-20
View File
@@ -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
}
-25
View File
@@ -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
)
-65
View File
@@ -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",
},
)
-308
View File
@@ -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")
}
}
-61
View File
@@ -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
}
-127
View File
@@ -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),
}
}
-130
View File
@@ -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.")
}
}
-27
View File
@@ -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",
],
)
-260
View File
@@ -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
}
-2
View File
@@ -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",
+1 -13
View File
@@ -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
View File
@@ -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
}