github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/sys/kcov.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package sys 16 17 import ( 18 "github.com/SagerNet/gvisor/pkg/abi/linux" 19 "github.com/SagerNet/gvisor/pkg/context" 20 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 21 "github.com/SagerNet/gvisor/pkg/sentry/arch" 22 "github.com/SagerNet/gvisor/pkg/sentry/fsimpl/kernfs" 23 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 24 "github.com/SagerNet/gvisor/pkg/sentry/kernel/auth" 25 "github.com/SagerNet/gvisor/pkg/sentry/memmap" 26 "github.com/SagerNet/gvisor/pkg/sentry/vfs" 27 "github.com/SagerNet/gvisor/pkg/syserror" 28 "github.com/SagerNet/gvisor/pkg/usermem" 29 ) 30 31 func (fs *filesystem) newKcovFile(ctx context.Context, creds *auth.Credentials) kernfs.Inode { 32 k := &kcovInode{} 33 k.InodeAttrs.Init(ctx, creds, 0, 0, fs.NextIno(), linux.S_IFREG|0600) 34 return k 35 } 36 37 // kcovInode implements kernfs.Inode. 38 // 39 // +stateify savable 40 type kcovInode struct { 41 kernfs.InodeAttrs 42 kernfs.InodeNoopRefCount 43 kernfs.InodeNotDirectory 44 kernfs.InodeNotSymlink 45 implStatFS 46 } 47 48 func (i *kcovInode) Open(ctx context.Context, rp *vfs.ResolvingPath, d *kernfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) { 49 k := kernel.KernelFromContext(ctx) 50 if k == nil { 51 panic("KernelFromContext returned nil") 52 } 53 fd := &kcovFD{ 54 inode: i, 55 kcov: k.NewKcov(), 56 } 57 58 if err := fd.vfsfd.Init(fd, opts.Flags, rp.Mount(), d.VFSDentry(), &vfs.FileDescriptionOptions{ 59 DenyPRead: true, 60 DenyPWrite: true, 61 }); err != nil { 62 return nil, err 63 } 64 return &fd.vfsfd, nil 65 } 66 67 // +stateify savable 68 type kcovFD struct { 69 vfs.FileDescriptionDefaultImpl 70 vfs.NoLockFD 71 72 vfsfd vfs.FileDescription 73 inode *kcovInode 74 kcov *kernel.Kcov 75 } 76 77 // Ioctl implements vfs.FileDescriptionImpl.Ioctl. 78 func (fd *kcovFD) Ioctl(ctx context.Context, uio usermem.IO, args arch.SyscallArguments) (uintptr, error) { 79 cmd := uint32(args[1].Int()) 80 arg := args[2].Uint64() 81 switch uint32(cmd) { 82 case linux.KCOV_INIT_TRACE: 83 return 0, fd.kcov.InitTrace(arg) 84 case linux.KCOV_ENABLE: 85 return 0, fd.kcov.EnableTrace(ctx, uint8(arg)) 86 case linux.KCOV_DISABLE: 87 if arg != 0 { 88 // This arg is unused; it should be 0. 89 return 0, linuxerr.EINVAL 90 } 91 return 0, fd.kcov.DisableTrace(ctx) 92 default: 93 return 0, syserror.ENOTTY 94 } 95 } 96 97 // ConfigureMmap implements vfs.FileDescriptionImpl.ConfigureMmap. 98 func (fd *kcovFD) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error { 99 return fd.kcov.ConfigureMMap(ctx, opts) 100 } 101 102 // Release implements vfs.FileDescriptionImpl.Release. 103 func (fd *kcovFD) Release(ctx context.Context) { 104 // kcov instances have reference counts in Linux, but this seems sufficient 105 // for our purposes. 106 fd.kcov.Clear(ctx) 107 } 108 109 // SetStat implements vfs.FileDescriptionImpl.SetStat. 110 func (fd *kcovFD) SetStat(ctx context.Context, opts vfs.SetStatOptions) error { 111 creds := auth.CredentialsFromContext(ctx) 112 fs := fd.vfsfd.VirtualDentry().Mount().Filesystem() 113 return fd.inode.SetStat(ctx, fs, creds, opts) 114 } 115 116 // Stat implements vfs.FileDescriptionImpl.Stat. 117 func (fd *kcovFD) Stat(ctx context.Context, opts vfs.StatOptions) (linux.Statx, error) { 118 return fd.inode.Stat(ctx, fd.vfsfd.Mount().Filesystem(), opts) 119 }