fix: potential crash when using apache_request_headers()

This commit is contained in:
Kévin Dunglas 2024-02-01 00:14:33 +01:00
parent ab7ce9cb18
commit e118b9f681
No known key found for this signature in database
GPG Key ID: 4D04EBEF06AAF3A6
3 changed files with 24 additions and 6 deletions

View File

@ -262,6 +262,7 @@ PHP_FUNCTION(frankenphp_request_headers) {
}
free(headers.r0);
go_apache_request_cleanup(headers.r2);
}
/* }}} */

View File

@ -582,24 +582,41 @@ func go_register_variables(rh C.uintptr_t, trackVarsArray *C.zval) {
}
//export go_apache_request_headers
func go_apache_request_headers(rh C.uintptr_t) (*C.go_string, C.size_t) {
func go_apache_request_headers(rh C.uintptr_t) (*C.go_string, C.size_t, C.uintptr_t) {
r := cgo.Handle(rh).Value().(*http.Request)
pinner := runtime.Pinner{}
pinnerHandle := C.uintptr_t(cgo.NewHandle(pinner))
rl := len(r.Header)
scs := unsafe.Sizeof(C.go_string{})
headers := (*C.go_string)(unsafe.Pointer(C.malloc(C.size_t(rl*2) * (C.size_t)(scs))))
header := headers
for field, val := range r.Header {
*header = C.go_string{C.size_t(len(field)), (*C.char)(unsafe.Pointer(unsafe.StringData(field)))}
fd := unsafe.StringData(field)
pinner.Pin(fd)
*header = C.go_string{C.size_t(len(field)), (*C.char)(unsafe.Pointer(fd))}
header = (*C.go_string)(unsafe.Add(unsafe.Pointer(header), scs))
cv := strings.Join(val, ", ")
*header = C.go_string{C.size_t(len(cv)), (*C.char)(unsafe.Pointer(unsafe.StringData(cv)))}
vd := unsafe.StringData(cv)
pinner.Pin(vd)
*header = C.go_string{C.size_t(len(cv)), (*C.char)(unsafe.Pointer(vd))}
header = (*C.go_string)(unsafe.Add(unsafe.Pointer(header), scs))
}
return headers, C.size_t(rl)
return headers, C.size_t(rl), pinnerHandle
}
//export go_apache_request_cleanup
func go_apache_request_cleanup(rh C.uintptr_t) {
h := cgo.Handle(rh)
p := h.Value().(runtime.Pinner)
p.Unpin()
h.Delete()
}
func addHeader(fc *FrankenPHPContext, cString *C.char, length C.int) {

View File

@ -581,8 +581,8 @@ func TestRequestHeaders_worker(t *testing.T) {
func testRequestHeaders(t *testing.T, opts *testOptions) {
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/request-headers.php?i=%d", i), nil)
req.Header.Add("Content-Type", "text/plain")
req.Header.Add("Frankenphp-I", strconv.Itoa(i))
req.Header.Add(strings.Clone("Content-Type"), strings.Clone("text/plain"))
req.Header.Add(strings.Clone("Frankenphp-I"), strings.Clone(strconv.Itoa(i)))
w := httptest.NewRecorder()
handler(w, req)