test: fuzz bounded protocol parsers
This commit is contained in:
@@ -55,20 +55,9 @@ func (handler *JSONRPCHandler) ServeHTTP(response http.ResponseWriter, request *
|
||||
handler.writeRPCError(response, nil, jsonRPCParseError, "could not read request", nil)
|
||||
return
|
||||
}
|
||||
if int64(len(body)) > handler.MaxBody {
|
||||
handler.writeRPCError(response, nil, jsonRPCInvalid, "request body exceeds limit", nil)
|
||||
return
|
||||
}
|
||||
var envelope jsonRPCRequest
|
||||
decoder := json.NewDecoder(bytes.NewReader(body))
|
||||
decoder.DisallowUnknownFields()
|
||||
if err := decoder.Decode(&envelope); err != nil {
|
||||
handler.writeRPCError(response, nil, jsonRPCParseError, "invalid JSON", nil)
|
||||
return
|
||||
}
|
||||
var trailing any
|
||||
if err := decoder.Decode(&trailing); err != io.EOF || envelope.JSONRPC != jsonRPCVersion || envelope.Method == "" || len(envelope.ID) == 0 || bytes.Equal(bytes.TrimSpace(envelope.ID), []byte("null")) {
|
||||
handler.writeRPCError(response, nil, jsonRPCInvalid, "invalid JSON-RPC request", nil)
|
||||
envelope, errorCode, errorMessage := decodeJSONRPCRequest(body, handler.MaxBody)
|
||||
if errorCode != 0 {
|
||||
handler.writeRPCError(response, nil, errorCode, errorMessage, nil)
|
||||
return
|
||||
}
|
||||
result, callErr := handler.call(request.Context(), envelope.Method, envelope.Params)
|
||||
@@ -87,6 +76,29 @@ type jsonRPCRequest struct {
|
||||
Params json.RawMessage `json:"params"`
|
||||
}
|
||||
|
||||
// decodeJSONRPCRequest keeps the hostile JSON boundary independently bounded
|
||||
// and fuzzable. The returned code/message are the externally stable JSON-RPC
|
||||
// parse or invalid-request result; callers must not inspect partial fields.
|
||||
func decodeJSONRPCRequest(body []byte, maxBody int64) (jsonRPCRequest, int, string) {
|
||||
if maxBody <= 0 {
|
||||
maxBody = defaultJSONRPCBody
|
||||
}
|
||||
if int64(len(body)) > maxBody {
|
||||
return jsonRPCRequest{}, jsonRPCInvalid, "request body exceeds limit"
|
||||
}
|
||||
var envelope jsonRPCRequest
|
||||
decoder := json.NewDecoder(bytes.NewReader(body))
|
||||
decoder.DisallowUnknownFields()
|
||||
if err := decoder.Decode(&envelope); err != nil {
|
||||
return jsonRPCRequest{}, jsonRPCParseError, "invalid JSON"
|
||||
}
|
||||
var trailing any
|
||||
if err := decoder.Decode(&trailing); err != io.EOF || envelope.JSONRPC != jsonRPCVersion || envelope.Method == "" || len(envelope.ID) == 0 || bytes.Equal(bytes.TrimSpace(envelope.ID), []byte("null")) {
|
||||
return jsonRPCRequest{}, jsonRPCInvalid, "invalid JSON-RPC request"
|
||||
}
|
||||
return envelope, 0, ""
|
||||
}
|
||||
|
||||
type jsonRPCResponse struct {
|
||||
JSONRPC string `json:"jsonrpc"`
|
||||
ID json.RawMessage `json:"id"`
|
||||
|
||||
Reference in New Issue
Block a user