summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/platform/safecopy
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/platform/safecopy')
-rw-r--r--pkg/sentry/platform/safecopy/BUILD4
-rw-r--r--pkg/sentry/platform/safecopy/atomic_amd64.s28
-rw-r--r--pkg/sentry/platform/safecopy/atomic_arm64.s28
-rw-r--r--pkg/sentry/platform/safecopy/safecopy.go4
-rw-r--r--pkg/sentry/platform/safecopy/safecopy_unsafe.go20
-rw-r--r--pkg/sentry/platform/safecopy/sighandler_amd64.s9
-rw-r--r--pkg/sentry/platform/safecopy/sighandler_arm64.s11
7 files changed, 101 insertions, 3 deletions
diff --git a/pkg/sentry/platform/safecopy/BUILD b/pkg/sentry/platform/safecopy/BUILD
index 05a6a61ae..d97a40297 100644
--- a/pkg/sentry/platform/safecopy/BUILD
+++ b/pkg/sentry/platform/safecopy/BUILD
@@ -18,9 +18,7 @@ go_library(
],
importpath = "gvisor.googlesource.com/gvisor/pkg/sentry/platform/safecopy",
visibility = ["//pkg/sentry:internal"],
- deps = [
- "//pkg/syserror",
- ],
+ deps = ["//pkg/syserror"],
)
go_test(
diff --git a/pkg/sentry/platform/safecopy/atomic_amd64.s b/pkg/sentry/platform/safecopy/atomic_amd64.s
index 873ffa046..f90b4bfd1 100644
--- a/pkg/sentry/platform/safecopy/atomic_amd64.s
+++ b/pkg/sentry/platform/safecopy/atomic_amd64.s
@@ -106,3 +106,31 @@ TEXT ·compareAndSwapUint32(SB), NOSPLIT, $0-24
CMPXCHGL DX, 0(DI)
MOVL AX, prev+16(FP)
RET
+
+// handleLoadUint32Fault returns the value stored in DI. Control is transferred
+// to it when LoadUint32 below receives SIGSEGV or SIGBUS, with the signal
+// number stored in DI.
+//
+// It must have the same frame configuration as loadUint32 so that it can undo
+// any potential call frame set up by the assembler.
+TEXT handleLoadUint32Fault(SB), NOSPLIT, $0-16
+ MOVL DI, sig+12(FP)
+ RET
+
+// loadUint32 atomically loads *addr and returns it. If a SIGSEGV or SIGBUS
+// signal is received, the value returned is unspecified, and sig is the number
+// of the signal that was received.
+//
+// Preconditions: addr must be aligned to a 4-byte boundary.
+//
+//func loadUint32(ptr unsafe.Pointer) (val uint32, sig int32)
+TEXT ·loadUint32(SB), NOSPLIT, $0-16
+ // Store 0 as the returned signal number. If we run to completion,
+ // this is the value the caller will see; if a signal is received,
+ // handleLoadUint32Fault will store a different value in this address.
+ MOVL $0, sig+12(FP)
+
+ MOVQ addr+0(FP), AX
+ MOVL (AX), BX
+ MOVL BX, val+8(FP)
+ RET
diff --git a/pkg/sentry/platform/safecopy/atomic_arm64.s b/pkg/sentry/platform/safecopy/atomic_arm64.s
index 554a5c1e1..d58ed71f7 100644
--- a/pkg/sentry/platform/safecopy/atomic_arm64.s
+++ b/pkg/sentry/platform/safecopy/atomic_arm64.s
@@ -96,3 +96,31 @@ again:
done:
MOVW R3, prev+16(FP)
RET
+
+// handleLoadUint32Fault returns the value stored in DI. Control is transferred
+// to it when LoadUint32 below receives SIGSEGV or SIGBUS, with the signal
+// number stored in DI.
+//
+// It must have the same frame configuration as loadUint32 so that it can undo
+// any potential call frame set up by the assembler.
+TEXT handleLoadUint32Fault(SB), NOSPLIT, $0-16
+ MOVW R1, sig+12(FP)
+ RET
+
+// loadUint32 atomically loads *addr and returns it. If a SIGSEGV or SIGBUS
+// signal is received, the value returned is unspecified, and sig is the number
+// of the signal that was received.
+//
+// Preconditions: addr must be aligned to a 4-byte boundary.
+//
+//func loadUint32(ptr unsafe.Pointer) (val uint32, sig int32)
+TEXT ·loadUint32(SB), NOSPLIT, $0-16
+ // Store 0 as the returned signal number. If we run to completion,
+ // this is the value the caller will see; if a signal is received,
+ // handleLoadUint32Fault will store a different value in this address.
+ MOVW $0, sig+12(FP)
+
+ MOVD addr+0(FP), R0
+ LDARW (R0), R1
+ MOVW R1, val+8(FP)
+ RET
diff --git a/pkg/sentry/platform/safecopy/safecopy.go b/pkg/sentry/platform/safecopy/safecopy.go
index c60f73103..69c66a3b7 100644
--- a/pkg/sentry/platform/safecopy/safecopy.go
+++ b/pkg/sentry/platform/safecopy/safecopy.go
@@ -75,6 +75,8 @@ var (
swapUint64End uintptr
compareAndSwapUint32Begin uintptr
compareAndSwapUint32End uintptr
+ loadUint32Begin uintptr
+ loadUint32End uintptr
// savedSigSegVHandler is a pointer to the SIGSEGV handler that was
// configured before we replaced it with our own. We still call into it
@@ -119,6 +121,8 @@ func initializeAddresses() {
swapUint64End = FindEndAddress(swapUint64Begin)
compareAndSwapUint32Begin = reflect.ValueOf(compareAndSwapUint32).Pointer()
compareAndSwapUint32End = FindEndAddress(compareAndSwapUint32Begin)
+ loadUint32Begin = reflect.ValueOf(loadUint32).Pointer()
+ loadUint32End = FindEndAddress(loadUint32Begin)
}
func init() {
diff --git a/pkg/sentry/platform/safecopy/safecopy_unsafe.go b/pkg/sentry/platform/safecopy/safecopy_unsafe.go
index e78a6714e..f84527484 100644
--- a/pkg/sentry/platform/safecopy/safecopy_unsafe.go
+++ b/pkg/sentry/platform/safecopy/safecopy_unsafe.go
@@ -79,6 +79,14 @@ func swapUint64(ptr unsafe.Pointer, new uint64) (old uint64, sig int32)
//go:noescape
func compareAndSwapUint32(ptr unsafe.Pointer, old, new uint32) (prev uint32, sig int32)
+// LoadUint32 is like sync/atomic.LoadUint32, but operates with user memory. It
+// may fail with SIGSEGV or SIGBUS if it is received while reading from ptr.
+//
+// Preconditions: ptr must be aligned to a 4-byte boundary.
+//
+//go:noescape
+func loadUint32(ptr unsafe.Pointer) (val uint32, sig int32)
+
// CopyIn copies len(dst) bytes from src to dst. It returns the number of bytes
// copied and an error if SIGSEGV or SIGBUS is received while reading from src.
func CopyIn(dst []byte, src unsafe.Pointer) (int, error) {
@@ -260,6 +268,18 @@ func CompareAndSwapUint32(ptr unsafe.Pointer, old, new uint32) (uint32, error) {
return prev, errorFromFaultSignal(ptr, sig)
}
+// LoadUint32 is like sync/atomic.LoadUint32, but operates with user memory. It
+// may fail with SIGSEGV or SIGBUS if it is received while reading from ptr.
+//
+// Preconditions: ptr must be aligned to a 4-byte boundary.
+func LoadUint32(ptr unsafe.Pointer) (uint32, error) {
+ if addr := uintptr(ptr); addr&3 != 0 {
+ return 0, AlignmentError{addr, 4}
+ }
+ val, sig := loadUint32(ptr)
+ return val, errorFromFaultSignal(ptr, sig)
+}
+
func errorFromFaultSignal(addr unsafe.Pointer, sig int32) error {
switch sig {
case 0:
diff --git a/pkg/sentry/platform/safecopy/sighandler_amd64.s b/pkg/sentry/platform/safecopy/sighandler_amd64.s
index 06614f1b4..db7701a29 100644
--- a/pkg/sentry/platform/safecopy/sighandler_amd64.s
+++ b/pkg/sentry/platform/safecopy/sighandler_amd64.s
@@ -101,6 +101,15 @@ not_swapuint64:
JMP handle_fault
not_casuint32:
+ CMPQ CX, ·loadUint32Begin(SB)
+ JB not_loaduint32
+ CMPQ CX, ·loadUint32End(SB)
+ JAE not_loaduint32
+
+ LEAQ handleLoadUint32Fault(SB), CX
+ JMP handle_fault
+
+not_loaduint32:
original_handler:
// Jump to the previous signal handler, which is likely the golang one.
XORQ CX, CX
diff --git a/pkg/sentry/platform/safecopy/sighandler_arm64.s b/pkg/sentry/platform/safecopy/sighandler_arm64.s
index 5e8e193e7..cdfca8207 100644
--- a/pkg/sentry/platform/safecopy/sighandler_arm64.s
+++ b/pkg/sentry/platform/safecopy/sighandler_arm64.s
@@ -110,6 +110,17 @@ not_swapuint64:
B handle_fault
not_casuint32:
+ MOVD ·loadUint32Begin(SB), R8
+ CMP R8, R7
+ BLO not_loaduint32
+ MOVD ·loadUint32End(SB), R8
+ CMP R8, R7
+ BHS not_loaduint32
+
+ MOVD $handleLoadUint32Fault(SB), R7
+ B handle_fault
+
+not_loaduint32:
original_handler:
// Jump to the previous signal handler, which is likely the golang one.
MOVD ·savedSigBusHandler(SB), R7