Skip to content

Commit

Permalink
map: replace hacky unsafe.Pointer conversion with PROT_NONE page
Browse files Browse the repository at this point in the history
One of our legacy code paths currently does a dodgy pointer conversion:

    unsafe.Pointer(^uintptr(0))

This is (correctly) flagged by linters as being a bit bogus, since
unsafe.Pointer conversions do have an effect on the GC (I believe).
It also assumes that the highest address is never used.

Map an inaccessible page and use that instead of the bogus pointer.
This has the same effect but is much safer.

Signed-off-by: Lorenz Bauer <[email protected]>
  • Loading branch information
lmb committed Jan 24, 2023
1 parent c89e687 commit 41dbd37
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 2 deletions.
3 changes: 3 additions & 0 deletions internal/unix/types_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,12 @@ const (
EPOLL_CLOEXEC = linux.EPOLL_CLOEXEC
O_CLOEXEC = linux.O_CLOEXEC
O_NONBLOCK = linux.O_NONBLOCK
PROT_NONE = linux.PROT_NONE
PROT_READ = linux.PROT_READ
PROT_WRITE = linux.PROT_WRITE
MAP_ANON = linux.MAP_ANON
MAP_SHARED = linux.MAP_SHARED
MAP_PRIVATE = linux.MAP_PRIVATE
PERF_ATTR_SIZE_VER1 = linux.PERF_ATTR_SIZE_VER1
PERF_TYPE_SOFTWARE = linux.PERF_TYPE_SOFTWARE
PERF_TYPE_TRACEPOINT = linux.PERF_TYPE_TRACEPOINT
Expand Down
3 changes: 3 additions & 0 deletions internal/unix/types_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ const (
EPOLL_CLOEXEC
O_CLOEXEC
O_NONBLOCK
PROT_NONE
PROT_READ
PROT_WRITE
MAP_ANON
MAP_SHARED
MAP_PRIVATE
PERF_ATTR_SIZE_VER1
PERF_TYPE_SOFTWARE
PERF_TYPE_TRACEPOINT
Expand Down
15 changes: 13 additions & 2 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"io"
"math/rand"
"os"
"path/filepath"
"reflect"
"time"
Expand Down Expand Up @@ -792,12 +793,22 @@ func (m *Map) nextKey(key interface{}, nextKeyOut sys.Pointer) error {
return nil
}

var mmapProtectedPage = internal.Memoize(func() ([]byte, error) {
return unix.Mmap(-1, 0, os.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_SHARED)
})

// guessNonExistentKey attempts to perform a map lookup that returns ENOENT.
// This is necessary on kernels before 4.4.132, since those don't support
// iterating maps from the start by providing an invalid key pointer.
func (m *Map) guessNonExistentKey() ([]byte, error) {
// Provide an invalid value pointer to prevent a copy on the kernel side.
valuePtr := sys.NewPointer(unsafe.Pointer(^uintptr(0)))
// Map a protected page and use that as the value pointer. This saves some
// work copying out the value, which we're not interested in.
page, err := mmapProtectedPage()
if err != nil {
return nil, err
}
valuePtr := sys.NewPointer(unsafe.Pointer(&page[0]))

randKey := make([]byte, int(m.keySize))

for i := 0; i < 4; i++ {
Expand Down

0 comments on commit 41dbd37

Please sign in to comment.