diff --git a/nogo.yaml b/nogo.yaml index 6f8b5f93c7..a086547cf8 100644 --- a/nogo.yaml +++ b/nogo.yaml @@ -190,6 +190,8 @@ analyzers: - pkg/aio/aio_linux_unsafe.go # Special case. - pkg/eventfd/eventfd_unsafe.go # Special case. - "pkg/flipcall/.*_unsafe.go" # Special case. + - pkg/memutil/memutil_unsafe.go # Special case. + - pkg/tcpip/link/sharedmem/sharedmem_unsafe.go # Special case. - pkg/gohacks/noescape_unsafe.go # Special case. - pkg/ring0/pagetables/allocator_unsafe.go # Special case. - pkg/sentry/devices/nvproxy/frontend_mmap_unsafe.go # Special case. diff --git a/pkg/buffer/view_unsafe.go b/pkg/buffer/view_unsafe.go index cef7e7ed8a..b03fec95b5 100644 --- a/pkg/buffer/view_unsafe.go +++ b/pkg/buffer/view_unsafe.go @@ -15,12 +15,10 @@ package buffer import ( - "reflect" "unsafe" ) // BasePtr returns a pointer to the view's chunk. func (v *View) BasePtr() *byte { - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&v.chunk.data)) - return (*byte)(unsafe.Pointer(hdr.Data)) + return unsafe.SliceData(v.chunk.data) } diff --git a/pkg/flipcall/flipcall_unsafe.go b/pkg/flipcall/flipcall_unsafe.go index cfd96bfa1c..21bcbb1217 100644 --- a/pkg/flipcall/flipcall_unsafe.go +++ b/pkg/flipcall/flipcall_unsafe.go @@ -15,7 +15,6 @@ package flipcall import ( - "reflect" "unsafe" "gvisor.dev/gvisor/pkg/atomicbitops" @@ -62,12 +61,9 @@ func (ep *Endpoint) dataLen() *atomicbitops.Uint32 { // - Writers must not assume that they will read back the same data that they // have written. In other words, writers should avoid reading from Data() at // all. -func (ep *Endpoint) Data() (bs []byte) { - bshdr := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) - bshdr.Data = ep.packet + PacketHeaderBytes - bshdr.Len = int(ep.dataCap) - bshdr.Cap = int(ep.dataCap) - return +func (ep *Endpoint) Data() []byte { + ptr := unsafe.Pointer(ep.packet + PacketHeaderBytes) + return unsafe.Slice((*byte)(ptr), int(ep.dataCap)) } // ioSync is a dummy variable used to indicate synchronization to the Go race diff --git a/pkg/memutil/memutil_unsafe.go b/pkg/memutil/memutil_unsafe.go index 3c5ebd745c..24d811cbfb 100644 --- a/pkg/memutil/memutil_unsafe.go +++ b/pkg/memutil/memutil_unsafe.go @@ -16,7 +16,6 @@ package memutil import ( - "reflect" "unsafe" "golang.org/x/sys/unix" @@ -28,17 +27,13 @@ func MapSlice(addr, size, prot, flags, fd, offset uintptr) ([]byte, error) { if err != nil { return nil, err } - var slice []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice)) - hdr.Data = addr - hdr.Len = int(size) - hdr.Cap = int(size) - return slice, nil + + return unsafe.Slice((*byte)(unsafe.Pointer(addr)), int(size)), nil } // UnmapSlice unmaps a mapping returned by MapSlice. func UnmapSlice(slice []byte) error { - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&slice)) - _, _, err := unix.RawSyscall6(unix.SYS_MUNMAP, uintptr(unsafe.Pointer(hdr.Data)), uintptr(hdr.Cap), 0, 0, 0, 0) + ptr := unsafe.SliceData(slice) + _, _, err := unix.RawSyscall6(unix.SYS_MUNMAP, uintptr(unsafe.Pointer(ptr)), uintptr(cap(slice)), 0, 0, 0, 0) return err } diff --git a/pkg/rawfile/rawfile_unsafe.go b/pkg/rawfile/rawfile_unsafe.go index 4ec671ae45..1bdf38cca7 100644 --- a/pkg/rawfile/rawfile_unsafe.go +++ b/pkg/rawfile/rawfile_unsafe.go @@ -19,7 +19,6 @@ package rawfile import ( - "reflect" "unsafe" "golang.org/x/sys/unix" @@ -43,12 +42,9 @@ func IovecFromBytes(bs []byte) unix.Iovec { return iov } -func bytesFromIovec(iov unix.Iovec) (bs []byte) { - sh := (*reflect.SliceHeader)(unsafe.Pointer(&bs)) - sh.Data = uintptr(unsafe.Pointer(iov.Base)) - sh.Len = int(iov.Len) - sh.Cap = int(iov.Len) - return +func bytesFromIovec(iov unix.Iovec) []byte { + ptr := unsafe.Pointer(iov.Base) + return unsafe.Slice((*byte)(ptr), int(iov.Len)) } // AppendIovecFromBytes returns append(iovs, IovecFromBytes(bs)). If len(bs) == diff --git a/pkg/sentry/platform/systrap/stub_unsafe.go b/pkg/sentry/platform/systrap/stub_unsafe.go index 26371e9faa..d376d0818b 100644 --- a/pkg/sentry/platform/systrap/stub_unsafe.go +++ b/pkg/sentry/platform/systrap/stub_unsafe.go @@ -18,7 +18,6 @@ import ( "fmt" "io/ioutil" "math/rand" - "reflect" "strconv" "strings" "unsafe" @@ -69,11 +68,7 @@ func copySeccompRulesToStub(instrs []bpf.Instruction, stubAddr, size uintptr) { panic("not enough space for sysmsg seccomp rules") } - var targetSlice []bpf.Instruction - sh := (*reflect.SliceHeader)(unsafe.Pointer(&targetSlice)) - sh.Data = progPtr - sh.Cap = len(instrs) - sh.Len = sh.Cap + targetSlice := unsafe.Slice((*bpf.Instruction)(unsafe.Pointer(progPtr)), len(instrs)) copy(targetSlice, instrs) diff --git a/pkg/tcpip/link/sharedmem/sharedmem_unsafe.go b/pkg/tcpip/link/sharedmem/sharedmem_unsafe.go index ad428a92bd..8f9ed3d670 100644 --- a/pkg/tcpip/link/sharedmem/sharedmem_unsafe.go +++ b/pkg/tcpip/link/sharedmem/sharedmem_unsafe.go @@ -16,7 +16,6 @@ package sharedmem import ( "fmt" - "reflect" "unsafe" "golang.org/x/sys/unix" @@ -48,12 +47,7 @@ func getBuffer(fd int) ([]byte, error) { return nil, fmt.Errorf("failed to map memory for buffer fd: %d, error: %s", fd, err) } - // Use unsafe to convert addr into a []byte. - var b []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b)) - hdr.Data = addr - hdr.Len = int(s.Size) - hdr.Cap = int(s.Size) + b := unsafe.Slice((*byte)(unsafe.Pointer(addr)), int(s.Size)) return b, nil } diff --git a/pkg/tcpip/transport/tcp/connect_unsafe.go b/pkg/tcpip/transport/tcp/connect_unsafe.go index cfc304616c..0fa7793ca4 100644 --- a/pkg/tcpip/transport/tcp/connect_unsafe.go +++ b/pkg/tcpip/transport/tcp/connect_unsafe.go @@ -15,7 +15,6 @@ package tcp import ( - "reflect" "unsafe" ) @@ -26,5 +25,5 @@ import ( func optionsToArray(options []byte) *[maxOptionSize]byte { // Reslice to full capacity. options = options[0:maxOptionSize] - return (*[maxOptionSize]byte)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&options)).Data)) + return (*[maxOptionSize]byte)(unsafe.Pointer(&options[0])) } diff --git a/pkg/xdp/xdp_unsafe.go b/pkg/xdp/xdp_unsafe.go index 75ff263edc..d8a41a9505 100644 --- a/pkg/xdp/xdp_unsafe.go +++ b/pkg/xdp/xdp_unsafe.go @@ -16,7 +16,6 @@ package xdp import ( "fmt" - "reflect" "unsafe" "golang.org/x/sys/unix" @@ -62,20 +61,16 @@ func sizeOfTXQueueDesc() uint64 { } func (fq *FillQueue) init(off unix.XDPMmapOffsets, opts Opts) { - fillQueueRingHdr := (*reflect.SliceHeader)(unsafe.Pointer(&fq.ring)) - fillQueueRingHdr.Data = uintptr(unsafe.Pointer(&fq.mem[off.Fr.Desc])) - fillQueueRingHdr.Len = int(opts.NDescriptors) - fillQueueRingHdr.Cap = fillQueueRingHdr.Len + base := unsafe.Pointer(&fq.mem[off.Fr.Desc]) + fq.ring = unsafe.Slice((*uint64)(base), int(opts.NDescriptors)) fq.producer = (*atomicbitops.Uint32)(unsafe.Pointer(&fq.mem[off.Fr.Producer])) fq.consumer = (*atomicbitops.Uint32)(unsafe.Pointer(&fq.mem[off.Fr.Consumer])) fq.flags = (*atomicbitops.Uint32)(unsafe.Pointer(&fq.mem[off.Fr.Flags])) } func (rq *RXQueue) init(off unix.XDPMmapOffsets, opts Opts) { - rxQueueRingHdr := (*reflect.SliceHeader)(unsafe.Pointer(&rq.ring)) - rxQueueRingHdr.Data = uintptr(unsafe.Pointer(&rq.mem[off.Rx.Desc])) - rxQueueRingHdr.Len = int(opts.NDescriptors) - rxQueueRingHdr.Cap = rxQueueRingHdr.Len + base := unsafe.Pointer(&rq.mem[off.Rx.Desc]) + rq.ring = unsafe.Slice((*unix.XDPDesc)(base), int(opts.NDescriptors)) rq.producer = (*atomicbitops.Uint32)(unsafe.Pointer(&rq.mem[off.Rx.Producer])) rq.consumer = (*atomicbitops.Uint32)(unsafe.Pointer(&rq.mem[off.Rx.Consumer])) rq.flags = (*atomicbitops.Uint32)(unsafe.Pointer(&rq.mem[off.Rx.Flags])) @@ -86,10 +81,8 @@ func (rq *RXQueue) init(off unix.XDPMmapOffsets, opts Opts) { } func (cq *CompletionQueue) init(off unix.XDPMmapOffsets, opts Opts) { - completionQueueRingHdr := (*reflect.SliceHeader)(unsafe.Pointer(&cq.ring)) - completionQueueRingHdr.Data = uintptr(unsafe.Pointer(&cq.mem[off.Cr.Desc])) - completionQueueRingHdr.Len = int(opts.NDescriptors) - completionQueueRingHdr.Cap = completionQueueRingHdr.Len + base := unsafe.Pointer(&cq.mem[off.Cr.Desc]) + cq.ring = unsafe.Slice((*uint64)(base), int(opts.NDescriptors)) cq.producer = (*atomicbitops.Uint32)(unsafe.Pointer(&cq.mem[off.Cr.Producer])) cq.consumer = (*atomicbitops.Uint32)(unsafe.Pointer(&cq.mem[off.Cr.Consumer])) cq.flags = (*atomicbitops.Uint32)(unsafe.Pointer(&cq.mem[off.Cr.Flags])) @@ -100,10 +93,8 @@ func (cq *CompletionQueue) init(off unix.XDPMmapOffsets, opts Opts) { } func (tq *TXQueue) init(off unix.XDPMmapOffsets, opts Opts) { - txQueueRingHdr := (*reflect.SliceHeader)(unsafe.Pointer(&tq.ring)) - txQueueRingHdr.Data = uintptr(unsafe.Pointer(&tq.mem[off.Tx.Desc])) - txQueueRingHdr.Len = int(opts.NDescriptors) - txQueueRingHdr.Cap = txQueueRingHdr.Len + base := unsafe.Pointer(&tq.mem[off.Tx.Desc]) + tq.ring = unsafe.Slice((*unix.XDPDesc)(base), int(opts.NDescriptors)) tq.producer = (*atomicbitops.Uint32)(unsafe.Pointer(&tq.mem[off.Tx.Producer])) tq.consumer = (*atomicbitops.Uint32)(unsafe.Pointer(&tq.mem[off.Tx.Consumer])) tq.flags = (*atomicbitops.Uint32)(unsafe.Pointer(&tq.mem[off.Tx.Flags])) diff --git a/tools/go_marshal/analysis/analysis_unsafe.go b/tools/go_marshal/analysis/analysis_unsafe.go index 81655f2354..c00c80f94d 100644 --- a/tools/go_marshal/analysis/analysis_unsafe.go +++ b/tools/go_marshal/analysis/analysis_unsafe.go @@ -54,13 +54,9 @@ func RandomizeValue(x any) { panic("RandomizeType() called with an unaddressable value. You probably need to pass a pointer to the argument") } - // Cast the underlying memory for the type into a byte slice. - var b []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b)) + size := int(v.Type().Size()) // Note: v.UnsafeAddr panics if x is passed by value. x should be a pointer. - hdr.Data = v.UnsafeAddr() - hdr.Len = int(v.Type().Size()) - hdr.Cap = hdr.Len + b := unsafe.Slice((*byte)(unsafe.Pointer(v.UnsafeAddr())), size) // Fill the byte slice with random data, which in effect fills the type with // random values. diff --git a/tools/go_marshal/test/marshal_test.go b/tools/go_marshal/test/marshal_test.go index 6bbd5fe21d..20a3a372af 100644 --- a/tools/go_marshal/test/marshal_test.go +++ b/tools/go_marshal/test/marshal_test.go @@ -83,9 +83,6 @@ func (t *mockCopyContext) CopyInBytes(_ hostarch.Addr, b []byte) (int, error) { return t.taskMem.CopyIn(nil, 0, b, usermem.IOOpts{}) } -// unsafeMemory returns the underlying memory for m. The returned slice is only -// valid for the lifetime for m. The garbage collector isn't aware that the -// returned slice is related to m, the caller must ensure m lives long enough. func unsafeMemory(m marshal.Marshallable) []byte { if !m.Packed() { // We can't return a slice pointing to the underlying memory @@ -100,25 +97,14 @@ func unsafeMemory(m marshal.Marshallable) []byte { // reflect.ValueOf(m) // .Elem() // Unwrap interface to inner concrete object - // .Addr() // Pointer value to object - // .Pointer() // Actual address from the pointer value - ptr := reflect.ValueOf(m).Elem().Addr().Pointer() - + ptr := unsafe.Pointer(reflect.ValueOf(m).Elem().UnsafeAddr()) size := m.SizeBytes() - var mem []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&mem)) - hdr.Data = ptr - hdr.Len = size - hdr.Cap = size + mem := unsafe.Slice((*byte)(ptr), size) return mem } -// unsafeMemorySlice returns the underlying memory for m. The returned slice is -// only valid for the lifetime for m. The garbage collector isn't aware that the -// returned slice is related to m, the caller must ensure m lives long enough. -// // Precondition: m must be a slice. func unsafeMemorySlice(m any, elt marshal.Marshallable) []byte { kind := reflect.TypeOf(m).Kind() @@ -140,11 +126,8 @@ func unsafeMemorySlice(m any, elt marshal.Marshallable) []byte { v := reflect.ValueOf(m) length := v.Len() * elt.SizeBytes() - var mem []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&mem)) - hdr.Data = v.Pointer() // This is a pointer to the first elem for slices. - hdr.Len = length - hdr.Cap = length + ptr := unsafe.Pointer(v.Pointer()) + mem := unsafe.Slice((*byte)(ptr), length) return mem }