api: xmlDecoder should honor contentLength. (#2226)

This is needed so that we avoid reading large amounts
of data from compromised clients.
master
Harshavardhana 8 years ago committed by GitHub
parent 5cc9e4e214
commit 1f706e067d
  1. 7
      bucket-handlers.go
  2. 64
      handler-utils.go
  3. 22
      handler-utils_test.go
  4. 10
      utils.go

@ -322,10 +322,9 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
} }
} }
// the location value in the request body should match the Region in serverConfig. // Validate if incoming location constraint is valid, reject
// other values of location are not accepted. // requests which do not follow valid region requirements.
// make bucket fails in such cases. errCode := isValidLocationConstraint(r)
errCode := isValidLocationContraint(r.Body, serverConfig.GetRegion())
if errCode != ErrNone { if errCode != ErrNone {
writeErrorResponse(w, r, errCode, r.URL.Path) writeErrorResponse(w, r, errCode, r.URL.Path)
return return

@ -18,37 +18,43 @@ package main
import ( import (
"io" "io"
"net/http"
) )
// validates location constraint from the request body. // Validates location constraint in PutBucket request body.
// the location value in the request body should match the Region in serverConfig. // The location value in the request body should match the
// other values of location are not accepted. // region configured at serverConfig, otherwise error is returned.
// make bucket fails in such cases. func isValidLocationConstraint(r *http.Request) (s3Error APIErrorCode) {
func isValidLocationContraint(reqBody io.Reader, serverRegion string) APIErrorCode { serverRegion := serverConfig.GetRegion()
var locationContraint createBucketLocationConfiguration // If the request has no body with content-length set to 0,
var errCode APIErrorCode // we do not have to validate location constraint. Bucket will
errCode = ErrNone // be created at default region.
e := xmlDecoder(reqBody, &locationContraint) if r.ContentLength == 0 {
if e != nil { return ErrNone
if e == io.EOF { }
// Do nothing. locationConstraint := createBucketLocationConfiguration{}
// failed due to empty body. The location will be set to default value from the serverConfig. if err := xmlDecoder(r.Body, &locationConstraint, r.ContentLength); err != nil {
// this is valid. if err == io.EOF && r.ContentLength == -1 {
errCode = ErrNone // EOF is a valid condition here when ContentLength is -1.
} else { return ErrNone
// Failed due to malformed configuration.
errCode = ErrMalformedXML
//writeErrorResponse(w, r, ErrMalformedXML, r.URL.Path)
}
} else {
// Region obtained from the body.
// It should be equal to Region in serverConfig.
// Else ErrInvalidRegion returned.
// For empty value location will be to set to default value from the serverConfig.
if locationContraint.Location != "" && serverRegion != locationContraint.Location {
//writeErrorResponse(w, r, ErrInvalidRegion, r.URL.Path)
errCode = ErrInvalidRegion
} }
errorIf(err, "Unable to xml decode location constraint")
// Treat all other failures as XML parsing errors.
return ErrMalformedXML
} // Successfully decoded, proceed to verify the region.
// Once region has been obtained we proceed to verify it.
incomingRegion := locationConstraint.Location
if incomingRegion == "" {
// Location constraint is empty for region "us-east-1",
// in accordance with protocol.
incomingRegion = "us-east-1"
}
// Return errInvalidRegion if location constraint does not match
// with configured region.
s3Error = ErrNone
if serverRegion != incomingRegion {
s3Error = ErrInvalidRegion
} }
return errCode return s3Error
} }

@ -26,6 +26,24 @@ import (
// Tests validate bucket LocationConstraint. // Tests validate bucket LocationConstraint.
func TestIsValidLocationContraint(t *testing.T) { func TestIsValidLocationContraint(t *testing.T) {
savedServerConfig := serverConfig
defer func() {
serverConfig = savedServerConfig
}()
serverConfig = nil
// Test initialized config file.
path, err := ioutil.TempDir("", "minio-")
if err != nil {
t.Fatalf("Unable to create a temporary directory, %s", err)
}
defer removeAll(path)
setGlobalConfigPath(path)
if err := initConfig(); err != nil {
t.Fatalf("unable initialize config file, %s", err)
}
// generates the input request with XML bucket configuration set to the request body. // generates the input request with XML bucket configuration set to the request body.
createExpectedRequest := func(req *http.Request, location string) (*http.Request, error) { createExpectedRequest := func(req *http.Request, location string) (*http.Request, error) {
createBucketConfig := createBucketLocationConfiguration{} createBucketConfig := createBucketLocationConfiguration{}
@ -37,6 +55,7 @@ func TestIsValidLocationContraint(t *testing.T) {
} }
createBucketConfigBuffer := bytes.NewBuffer(createBucketConfigBytes) createBucketConfigBuffer := bytes.NewBuffer(createBucketConfigBytes)
req.Body = ioutil.NopCloser(createBucketConfigBuffer) req.Body = ioutil.NopCloser(createBucketConfigBuffer)
req.ContentLength = int64(createBucketConfigBuffer.Len())
return req, nil return req, nil
} }
@ -58,7 +77,8 @@ func TestIsValidLocationContraint(t *testing.T) {
if e != nil { if e != nil {
t.Fatalf("Test %d: Failed to Marshal bucket configuration", i+1) t.Fatalf("Test %d: Failed to Marshal bucket configuration", i+1)
} }
actualCode := isValidLocationContraint(inputRequest.Body, testCase.serverConfigRegion) serverConfig.SetRegion(testCase.serverConfigRegion)
actualCode := isValidLocationConstraint(inputRequest)
if testCase.expectedCode != actualCode { if testCase.expectedCode != actualCode {
t.Errorf("Test %d: Expected the APIErrCode to be %d, but instead found %d", i+1, testCase.expectedCode, actualCode) t.Errorf("Test %d: Expected the APIErrCode to be %d, but instead found %d", i+1, testCase.expectedCode, actualCode)
} }

@ -24,8 +24,14 @@ import (
) )
// xmlDecoder provide decoded value in xml. // xmlDecoder provide decoded value in xml.
func xmlDecoder(body io.Reader, v interface{}) error { func xmlDecoder(body io.Reader, v interface{}, size int64) error {
d := xml.NewDecoder(body) var lbody io.Reader
if size > 0 {
lbody = io.LimitReader(body, size)
} else {
lbody = body
}
d := xml.NewDecoder(lbody)
return d.Decode(v) return d.Decode(v)
} }

Loading…
Cancel
Save