Increase body size limits for osquerylog and osquery/dist/write endpoints (#40946)
Resolves #40813 * Added configurable body size limits for the `/api/osquery/log`, `/api/osquery/distributed/write` and `/api/osquery/config` endpoints. * Fixed false positive `PayloadTooLargeError` errors. --------- Co-authored-by: Lucas Manuel Rodriguez <lucas@fleetdm.com>
This commit is contained in:
co-authored by
Lucas Manuel Rodriguez
parent
6527ab7145
commit
eec2ce111a
@@ -500,6 +500,23 @@ type requestValidator interface {
|
||||
// query parameter decoding logic.
|
||||
//
|
||||
// If adding a new way to parse/decode the requset, make sure to wrap the body in a limited reader with the maxRequestBodySize
|
||||
|
||||
// limitExhaustedBody returns true when the LimitedReader was the cause of an
|
||||
// unexpected EOF — i.e. the underlying body actually had more data beyond the
|
||||
// limit. It does this by attempting a single-byte read from the underlying
|
||||
// reader (limitedReader.R) which bypasses the limit wrapper. A successful read
|
||||
// means the body exceeded the limit; an immediate EOF means the body ended
|
||||
// exactly at the limit (malformed JSON, not an oversized payload).
|
||||
//
|
||||
// This is used to avoid false-positive PayloadTooLargeError responses for
|
||||
// bodies whose JSON is malformed and happen to be exactly maxRequestBodySize
|
||||
// bytes long.
|
||||
func limitExhaustedBody(limitedReader *io.LimitedReader) bool {
|
||||
var peek [1]byte
|
||||
n, _ := limitedReader.R.Read(peek[:])
|
||||
return n > 0
|
||||
}
|
||||
|
||||
func MakeDecoder(
|
||||
iface interface{},
|
||||
jsonUnmarshal func(body io.Reader, req any) error,
|
||||
@@ -518,8 +535,9 @@ func MakeDecoder(
|
||||
}
|
||||
if rd, ok := iface.(RequestDecoder); ok {
|
||||
return func(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
var limitedReader *io.LimitedReader
|
||||
if maxRequestBodySize != -1 {
|
||||
limitedReader := io.LimitReader(r.Body, maxRequestBodySize).(*io.LimitedReader)
|
||||
limitedReader = io.LimitReader(r.Body, maxRequestBodySize).(*io.LimitedReader)
|
||||
|
||||
r.Body = &LimitedReadCloser{
|
||||
LimitedReader: limitedReader,
|
||||
@@ -527,7 +545,7 @@ func MakeDecoder(
|
||||
}
|
||||
}
|
||||
ret, err := rd.DecodeRequest(ctx, r)
|
||||
if err != nil && errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
if err != nil && errors.Is(err, io.ErrUnexpectedEOF) && limitedReader != nil && limitedReader.N == 0 && limitExhaustedBody(limitedReader) {
|
||||
return nil, platform_http.PayloadTooLargeError{ContentLength: r.Header.Get("Content-Length"), MaxRequestSize: maxRequestBodySize}
|
||||
}
|
||||
return ret, err
|
||||
@@ -544,8 +562,9 @@ func MakeDecoder(
|
||||
nilBody := false
|
||||
var rewriter *JSONKeyRewriteReader
|
||||
|
||||
var limitedReader *io.LimitedReader
|
||||
if maxRequestBodySize != -1 {
|
||||
limitedReader := io.LimitReader(r.Body, maxRequestBodySize).(*io.LimitedReader)
|
||||
limitedReader = io.LimitReader(r.Body, maxRequestBodySize).(*io.LimitedReader)
|
||||
|
||||
r.Body = &LimitedReadCloser{
|
||||
LimitedReader: limitedReader,
|
||||
@@ -590,7 +609,7 @@ func MakeDecoder(
|
||||
}
|
||||
}
|
||||
|
||||
if errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
if errors.Is(err, io.ErrUnexpectedEOF) && limitedReader != nil && limitedReader.N == 0 && limitExhaustedBody(limitedReader) {
|
||||
return nil, platform_http.PayloadTooLargeError{ContentLength: r.Header.Get("Content-Length"), MaxRequestSize: maxRequestBodySize}
|
||||
}
|
||||
|
||||
@@ -681,7 +700,10 @@ func MakeDecoder(
|
||||
}
|
||||
|
||||
if errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
return nil, platform_http.PayloadTooLargeError{ContentLength: r.Header.Get("Content-Length"), MaxRequestSize: maxRequestBodySize}
|
||||
if limitedReader != nil && limitedReader.N == 0 && limitExhaustedBody(limitedReader) {
|
||||
return nil, platform_http.PayloadTooLargeError{ContentLength: r.Header.Get("Content-Length"), MaxRequestSize: maxRequestBodySize}
|
||||
}
|
||||
return nil, BadRequestErr("json decoder error", err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user