mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
fix: validate FileSize in NewDataBuilder to prevent OOM DoS (#25710)
`NewDataBuilder` allocated `make([]byte, 0, req.FileSize)` using the client-supplied `int64` with no upper-bound check. The DRPC 4 MiB wire cap limits message size but not the integer value, so a crafted message with `FileSize = 1<<40` forces a 1 TiB allocation, triggering an unrecoverable `runtime.throw` that kills the entire `coderd` process. Add a `MaxFileSize` constant (100 MiB, matching `HTTPFileMaxBytes` in `coderd/files.go`) and reject negative or oversized `FileSize`, plus negative or excessive `Chunks`, before the allocation. `BytesToDataUpload` also returns an error for oversized data to preserve the encode/decode round-trip contract. Fix a pre-existing reversed subtraction in the `Add()` overflow error message. Closes https://linear.app/codercom/issue/PLAT-231 <details> <summary>Implementation details</summary> - `provisionersdk/proto/dataupload.go`: New exported `MaxFileSize` constant; validation in `NewDataBuilder` and `BytesToDataUpload`. Fixed reversed subtraction in `Add()` error. - `provisionersdk/proto/dataupload_test.go`: New `TestNewDataBuilderValidation` with 7 subtests. - Updated all 5 callers of `BytesToDataUpload` for new error return. - Audited all `make([]byte, ...)` in provisioner paths; no other client-supplied sizes. </details> > Generated by Coder Agents on behalf of @f0ssel
This commit is contained in:
@@ -1588,7 +1588,10 @@ func (s *server) DownloadFile(request *proto.FileRequest, stream proto.DRPCProvi
|
||||
return fail(xerrors.Errorf("unsupported file upload type: %s", request.UploadType))
|
||||
}
|
||||
|
||||
upload, chunks := sdkproto.BytesToDataUpload(sdkproto.DataUploadType_UPLOAD_TYPE_MODULE_FILES, file.Data)
|
||||
upload, chunks, err := sdkproto.BytesToDataUpload(sdkproto.DataUploadType_UPLOAD_TYPE_MODULE_FILES, file.Data)
|
||||
if err != nil {
|
||||
return fail(xerrors.Errorf("prepare file upload: %w", err))
|
||||
}
|
||||
|
||||
err = stream.Send(&sdkproto.FileUpload{
|
||||
Type: &sdkproto.FileUpload_DataUpload{DataUpload: upload},
|
||||
|
||||
@@ -48,7 +48,8 @@ func TestUploadFileLargeModuleFiles(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Convert to upload format
|
||||
upload, chunks := sdkproto.BytesToDataUpload(sdkproto.DataUploadType_UPLOAD_TYPE_MODULE_FILES, moduleData)
|
||||
upload, chunks, err := sdkproto.BytesToDataUpload(sdkproto.DataUploadType_UPLOAD_TYPE_MODULE_FILES, moduleData)
|
||||
require.NoError(t, err)
|
||||
|
||||
stream := newMockUploadStream(upload, chunks...)
|
||||
|
||||
@@ -93,7 +94,8 @@ func TestUploadFileErrorScenarios(t *testing.T) {
|
||||
_, err := crand.Read(moduleData)
|
||||
require.NoError(t, err)
|
||||
|
||||
upload, chunks := sdkproto.BytesToDataUpload(sdkproto.DataUploadType_UPLOAD_TYPE_MODULE_FILES, moduleData)
|
||||
upload, chunks, err := sdkproto.BytesToDataUpload(sdkproto.DataUploadType_UPLOAD_TYPE_MODULE_FILES, moduleData)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("chunk_before_upload", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
Reference in New Issue
Block a user