Limit YAML/JSON decode size
Kubernetes-commit: 8ef4566cefebf49f9a806a36df2105c9149785a1
This commit is contained in:
parent
3653eff0ed
commit
f7fbf2eee4
|
@ -195,11 +195,11 @@ func (f *fieldManager) Apply(liveObj runtime.Object, patch []byte, fieldManager
|
||||||
patchObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
patchObj := &unstructured.Unstructured{Object: map[string]interface{}{}}
|
||||||
|
|
||||||
if err := yaml.Unmarshal(patch, &patchObj.Object); err != nil {
|
if err := yaml.Unmarshal(patch, &patchObj.Object); err != nil {
|
||||||
return nil, fmt.Errorf("error decoding YAML: %v", err)
|
return nil, errors.NewBadRequest(fmt.Sprintf("error decoding YAML: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if patchObj.GetManagedFields() != nil {
|
if patchObj.GetManagedFields() != nil {
|
||||||
return nil, fmt.Errorf("managed fields must be nil but was %v", patchObj.GetManagedFields())
|
return nil, errors.NewBadRequest(fmt.Sprintf("metadata.managedFields must be nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if patchObj.GetAPIVersion() != f.groupVersion.String() {
|
if patchObj.GetAPIVersion() != f.groupVersion.String() {
|
||||||
|
|
|
@ -337,6 +337,15 @@ func (p *jsonPatcher) createNewObject() (runtime.Object, error) {
|
||||||
func (p *jsonPatcher) applyJSPatch(versionedJS []byte) (patchedJS []byte, retErr error) {
|
func (p *jsonPatcher) applyJSPatch(versionedJS []byte) (patchedJS []byte, retErr error) {
|
||||||
switch p.patchType {
|
switch p.patchType {
|
||||||
case types.JSONPatchType:
|
case types.JSONPatchType:
|
||||||
|
// sanity check potentially abusive patches
|
||||||
|
// TODO(liggitt): drop this once golang json parser limits stack depth (https://github.com/golang/go/issues/31789)
|
||||||
|
if len(p.patchBytes) > 1024*1024 {
|
||||||
|
v := []interface{}{}
|
||||||
|
if err := json.Unmarshal(p.patchBytes, v); err != nil {
|
||||||
|
return nil, errors.NewBadRequest(fmt.Sprintf("error decoding patch: %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
patchObj, err := jsonpatch.DecodePatch(p.patchBytes)
|
patchObj, err := jsonpatch.DecodePatch(p.patchBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.NewBadRequest(err.Error())
|
return nil, errors.NewBadRequest(err.Error())
|
||||||
|
@ -352,6 +361,15 @@ func (p *jsonPatcher) applyJSPatch(versionedJS []byte) (patchedJS []byte, retErr
|
||||||
}
|
}
|
||||||
return patchedJS, nil
|
return patchedJS, nil
|
||||||
case types.MergePatchType:
|
case types.MergePatchType:
|
||||||
|
// sanity check potentially abusive patches
|
||||||
|
// TODO(liggitt): drop this once golang json parser limits stack depth (https://github.com/golang/go/issues/31789)
|
||||||
|
if len(p.patchBytes) > 1024*1024 {
|
||||||
|
v := map[string]interface{}{}
|
||||||
|
if err := json.Unmarshal(p.patchBytes, v); err != nil {
|
||||||
|
return nil, errors.NewBadRequest(fmt.Sprintf("error decoding patch: %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return jsonpatch.MergePatch(versionedJS, p.patchBytes)
|
return jsonpatch.MergePatch(versionedJS, p.patchBytes)
|
||||||
default:
|
default:
|
||||||
// only here as a safety net - go-restful filters content-type
|
// only here as a safety net - go-restful filters content-type
|
||||||
|
|
|
@ -180,7 +180,7 @@ type Config struct {
|
||||||
// patch may cause.
|
// patch may cause.
|
||||||
// This affects all places that applies json patch in the binary.
|
// This affects all places that applies json patch in the binary.
|
||||||
JSONPatchMaxCopyBytes int64
|
JSONPatchMaxCopyBytes int64
|
||||||
// The limit on the request body size that would be accepted and decoded in a write request.
|
// The limit on the request size that would be accepted and decoded in a write request
|
||||||
// 0 means no limit.
|
// 0 means no limit.
|
||||||
MaxRequestBodyBytes int64
|
MaxRequestBodyBytes int64
|
||||||
// MaxRequestsInFlight is the maximum number of parallel non-long-running requests. Every further
|
// MaxRequestsInFlight is the maximum number of parallel non-long-running requests. Every further
|
||||||
|
@ -295,22 +295,20 @@ func NewConfig(codecs serializer.CodecFactory) *Config {
|
||||||
MinRequestTimeout: 1800,
|
MinRequestTimeout: 1800,
|
||||||
LivezGracePeriod: time.Duration(0),
|
LivezGracePeriod: time.Duration(0),
|
||||||
ShutdownDelayDuration: time.Duration(0),
|
ShutdownDelayDuration: time.Duration(0),
|
||||||
// 10MB is the recommended maximum client request size in bytes
|
// 1.5MB is the default client request size in bytes
|
||||||
// the etcd server should accept. See
|
// the etcd server should accept. See
|
||||||
// https://github.com/etcd-io/etcd/blob/release-3.3/etcdserver/server.go#L90.
|
// https://github.com/etcd-io/etcd/blob/release-3.4/embed/config.go#L56.
|
||||||
// A request body might be encoded in json, and is converted to
|
// A request body might be encoded in json, and is converted to
|
||||||
// proto when persisted in etcd. Assuming the upper bound of
|
// proto when persisted in etcd, so we allow 2x as the largest size
|
||||||
// the size ratio is 10:1, we set 100MB as the largest size
|
|
||||||
// increase the "copy" operations in a json patch may cause.
|
// increase the "copy" operations in a json patch may cause.
|
||||||
JSONPatchMaxCopyBytes: int64(100 * 1024 * 1024),
|
JSONPatchMaxCopyBytes: int64(3 * 1024 * 1024),
|
||||||
// 10MB is the recommended maximum client request size in bytes
|
// 1.5MB is the recommended client request size in byte
|
||||||
// the etcd server should accept. See
|
// the etcd server should accept. See
|
||||||
// https://github.com/etcd-io/etcd/blob/release-3.3/etcdserver/server.go#L90.
|
// https://github.com/etcd-io/etcd/blob/release-3.4/embed/config.go#L56.
|
||||||
// A request body might be encoded in json, and is converted to
|
// A request body might be encoded in json, and is converted to
|
||||||
// proto when persisted in etcd. Assuming the upper bound of
|
// proto when persisted in etcd, so we allow 2x as the largest request
|
||||||
// the size ratio is 10:1, we set 100MB as the largest request
|
|
||||||
// body size to be accepted and decoded in a write request.
|
// body size to be accepted and decoded in a write request.
|
||||||
MaxRequestBodyBytes: int64(100 * 1024 * 1024),
|
MaxRequestBodyBytes: int64(3 * 1024 * 1024),
|
||||||
|
|
||||||
// Default to treating watch as a long-running operation
|
// Default to treating watch as a long-running operation
|
||||||
// Generic API servers have no inherent long-running subresources
|
// Generic API servers have no inherent long-running subresources
|
||||||
|
|
Loading…
Reference in New Issue