1
0
mirror of https://github.com/golang/go synced 2024-11-16 20:14:48 -07:00

net: pass C string to res_nsearch, in case it stores the pointer

The current code passes a Go pointer to a NUL-terminated C string
to the C function res_nsearch (or res_search), but that function may
in turn store the pointer into the res_state, which is a violation of the
cgo pointer rules and is being detected on the linux-amd64-wsl builder.

Allocating the string in C memory is safer and should resolve
the cgo pointer check. When using libc/syscall mode, the memory
is still allocated Go-side, which could potentially be a problem
if we ever add a moving collector. For now it is OK.

Fixes #56658.

Change-Id: Ibd84a9665be16c71994ddb1eedf09d45a6553a3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/448795
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Bypass: Russ Cox <rsc@golang.org>
This commit is contained in:
Russ Cox 2022-11-08 14:04:24 -05:00
parent a6642e67e1
commit 12ab0ac184
3 changed files with 32 additions and 9 deletions

View File

@ -345,17 +345,17 @@ func resSearch(ctx context.Context, hostname string, rtype, class int) ([]dnsmes
// giving us no way to find out how big the packet is.
// For now, we are willing to take res_search's word that there's nothing
// useful in the response, even though there *is* a response.
var buf [1500]byte
s, err := syscall.BytePtrFromString(hostname)
if err != nil {
return nil, err
}
size, err := _C_res_nsearch(&state, (*_C_char)(unsafe.Pointer(s)), class, rtype, (*_C_uchar)(unsafe.Pointer(&buf[0])), len(buf))
if size <= 0 {
const bufSize = 1500
buf := (*_C_uchar)(_C_malloc(bufSize))
defer _C_free(unsafe.Pointer(buf))
s := _C_CString(hostname)
defer _C_FreeCString(s)
size, err := _C_res_nsearch(&state, s, class, rtype, buf, bufSize)
if size <= 0 || size > bufSize {
return nil, errors.New("res_nsearch failure")
}
var p dnsmessage.Parser
if _, err := p.Start(buf[:size]); err != nil {
if _, err := p.Start(unsafe.Slice((*byte)(unsafe.Pointer(buf)), size)); err != nil {
return nil, err
}
p.SkipAllQuestions()

View File

@ -13,6 +13,7 @@ package net
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
// If nothing else defined EAI_OVERFLOW, make sure it has a value.
#ifndef EAI_OVERFLOW
@ -20,6 +21,7 @@ package net
#endif
*/
import "C"
import "unsafe"
const (
_C_AF_INET = C.AF_INET
@ -45,7 +47,11 @@ type (
_C_struct_sockaddr = C.struct_sockaddr
)
func _C_GoString(p *_C_char) string { return C.GoString(p) }
func _C_GoString(p *_C_char) string { return C.GoString(p) }
func _C_CString(s string) *_C_char { return C.CString(s) }
func _C_FreeCString(p *_C_char) { C.free(unsafe.Pointer(p)) }
func _C_malloc(n uintptr) unsafe.Pointer { return C.malloc(C.size_t(n)) }
func _C_free(p unsafe.Pointer) { C.free(p) }
func _C_ai_addr(ai *_C_struct_addrinfo) **_C_struct_sockaddr { return &ai.ai_addr }
func _C_ai_canonname(ai *_C_struct_addrinfo) **_C_char { return &ai.ai_canonname }

View File

@ -8,6 +8,7 @@ package net
import (
"internal/syscall/unix"
"runtime"
"syscall"
"unsafe"
)
@ -41,6 +42,22 @@ func _C_GoString(p *_C_char) string {
return unix.GoString(p)
}
func _C_CString(s string) *_C_char {
p := make([]byte, len(s)+1)
copy(p, s)
return &p[0]
}
func _C_FreeCString(p *_C_char) { _C_free(unsafe.Pointer(p)) }
func _C_free(p unsafe.Pointer) { runtime.KeepAlive(p) }
func _C_malloc(n uintptr) unsafe.Pointer {
if n <= 0 {
n = 1
}
return unsafe.Pointer(&make([]byte, n)[0])
}
func _C_ai_addr(ai *_C_struct_addrinfo) **_C_struct_sockaddr { return &ai.Addr }
func _C_ai_canonname(ai *_C_struct_addrinfo) **_C_char { return &ai.Canonname }
func _C_ai_family(ai *_C_struct_addrinfo) *_C_int { return &ai.Family }