Skip to content

Commit c79a742

Browse files
Bryan C. Millsgopherbot
Bryan C. Mills
authored andcommitted
unix: fix a use-after-free bug in PtraceIO on freebsd
In CL 419915, both pointer fields of the PtraceIoDesc struct were converted to type uintptr to address golang/go#54113. However, that change was overzealous: the fix needed to convert fields that refer to addresses in the child process, but the Addr field of PtraceIoDesc is not even in the child process! It is instead an address in the parent (Go) process. Go's unsafe.Pointer rules prohibit converting a Go pointer to a uintptr except when immediately converting back to an unsafe.Pointer or calling a system call. Populating a PtraceIoDesc struct is neither of those things, so converting the Addr field to uintptr introduced a use-after-free bug. This change reverts the change to the Addr field from CL 419915 and consolidates the implementation of PtraceIO to reduce the the amount of code that varies with GOARCH. This change does not address the remaining ptrace uintptr bug (golang/go#58387), which is also present in the Linux implementation. Fixes golang/go#58351. Updates golang/go#54113. For golang/go#41205. Change-Id: I14bdb4af42130aa7b4375e3f53fd1a0435f14307 Reviewed-on: https://go-review.googlesource.com/c/sys/+/465676 Auto-Submit: Bryan Mills <[email protected]> Run-TryBot: Bryan Mills <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 90c8f94 commit c79a742

12 files changed

+48
-62
lines changed

unix/mkpost.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,12 @@ func main() {
8989
return out
9090
})
9191

92-
// Inside PtraceIoDesc replace all *byte with uintptr
92+
// Inside PtraceIoDesc replace the Offs field, which refers to an address
93+
// in the child process (not the Go parent), with a uintptr.
9394
ptraceIoDescStruct := regexp.MustCompile(`(?s:type PtraceIoDesc struct \{.*?\})`)
95+
addrField := regexp.MustCompile(`(\bOffs\s+)\*byte`)
9496
b = ptraceIoDescStruct.ReplaceAllFunc(b, func(in []byte) []byte {
95-
return bytes.ReplaceAll(in, []byte("*byte"), []byte("uintptr"))
97+
return addrField.ReplaceAll(in, []byte(`${1}uintptr`))
9698
})
9799
}
98100

unix/syscall_freebsd.go

+19
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,25 @@ func PtraceGetRegs(pid int, regsout *Reg) (err error) {
274274
return ptrace(PT_GETREGS, pid, uintptr(unsafe.Pointer(regsout)), 0)
275275
}
276276

277+
func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
278+
ioDesc := PtraceIoDesc{
279+
Op: int32(req),
280+
Offs: offs,
281+
}
282+
if countin > 0 {
283+
_ = out[:countin] // check bounds
284+
ioDesc.Addr = &out[0]
285+
} else if out != nil {
286+
ioDesc.Addr = (*byte)(unsafe.Pointer(&_zero))
287+
}
288+
ioDesc.SetLen(countin)
289+
290+
// TODO(#58387): It's not actually safe to pass &ioDesc as a uintptr here.
291+
// Pass it as an unsafe.Pointer instead.
292+
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
293+
return int(ioDesc.Len), err
294+
}
295+
277296
func PtraceLwpEvents(pid int, enable int) (err error) {
278297
return ptrace(PT_LWP_EVENTS, pid, 0, enable)
279298
}

unix/syscall_freebsd_386.go

+4-11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
4242
cmsg.Len = uint32(length)
4343
}
4444

45+
func (d *PtraceIoDesc) SetLen(length int) {
46+
d.Len = uint32(length)
47+
}
48+
4549
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
4650
var writtenOut uint64 = 0
4751
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
@@ -59,14 +63,3 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
5963
func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
6064
return ptrace(PT_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
6165
}
62-
63-
func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
64-
ioDesc := PtraceIoDesc{
65-
Op: int32(req),
66-
Offs: offs,
67-
Addr: uintptr(unsafe.Pointer(&out[0])), // TODO(#58351): this is not safe.
68-
Len: uint32(countin),
69-
}
70-
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
71-
return int(ioDesc.Len), err
72-
}

unix/syscall_freebsd_amd64.go

+4-11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
4242
cmsg.Len = uint32(length)
4343
}
4444

45+
func (d *PtraceIoDesc) SetLen(length int) {
46+
d.Len = uint64(length)
47+
}
48+
4549
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
4650
var writtenOut uint64 = 0
4751
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
@@ -59,14 +63,3 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
5963
func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
6064
return ptrace(PT_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
6165
}
62-
63-
func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
64-
ioDesc := PtraceIoDesc{
65-
Op: int32(req),
66-
Offs: offs,
67-
Addr: uintptr(unsafe.Pointer(&out[0])), // TODO(#58351): this is not safe.
68-
Len: uint64(countin),
69-
}
70-
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
71-
return int(ioDesc.Len), err
72-
}

unix/syscall_freebsd_arm.go

+4-11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
4242
cmsg.Len = uint32(length)
4343
}
4444

45+
func (d *PtraceIoDesc) SetLen(length int) {
46+
d.Len = uint32(length)
47+
}
48+
4549
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
4650
var writtenOut uint64 = 0
4751
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
@@ -55,14 +59,3 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
5559
}
5660

5761
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
58-
59-
func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
60-
ioDesc := PtraceIoDesc{
61-
Op: int32(req),
62-
Offs: offs,
63-
Addr: uintptr(unsafe.Pointer(&out[0])), // TODO(#58351): this is not safe.
64-
Len: uint32(countin),
65-
}
66-
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
67-
return int(ioDesc.Len), err
68-
}

unix/syscall_freebsd_arm64.go

+4-11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
4242
cmsg.Len = uint32(length)
4343
}
4444

45+
func (d *PtraceIoDesc) SetLen(length int) {
46+
d.Len = uint64(length)
47+
}
48+
4549
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
4650
var writtenOut uint64 = 0
4751
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
@@ -55,14 +59,3 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
5559
}
5660

5761
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
58-
59-
func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
60-
ioDesc := PtraceIoDesc{
61-
Op: int32(req),
62-
Offs: offs,
63-
Addr: uintptr(unsafe.Pointer(&out[0])), // TODO(#58351): this is not safe.
64-
Len: uint64(countin),
65-
}
66-
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
67-
return int(ioDesc.Len), err
68-
}

unix/syscall_freebsd_riscv64.go

+4-11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ func (cmsg *Cmsghdr) SetLen(length int) {
4242
cmsg.Len = uint32(length)
4343
}
4444

45+
func (d *PtraceIoDesc) SetLen(length int) {
46+
d.Len = uint64(length)
47+
}
48+
4549
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
4650
var writtenOut uint64 = 0
4751
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
@@ -55,14 +59,3 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
5559
}
5660

5761
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
58-
59-
func PtraceIO(req int, pid int, offs uintptr, out []byte, countin int) (count int, err error) {
60-
ioDesc := PtraceIoDesc{
61-
Op: int32(req),
62-
Offs: offs,
63-
Addr: uintptr(unsafe.Pointer(&out[0])), // TODO(#58351): this is not safe.
64-
Len: uint64(countin),
65-
}
66-
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
67-
return int(ioDesc.Len), err
68-
}

unix/ztypes_freebsd_386.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

unix/ztypes_freebsd_amd64.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

unix/ztypes_freebsd_arm.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

unix/ztypes_freebsd_arm64.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

unix/ztypes_freebsd_riscv64.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)