mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 12:15:52 +00:00
Merge pull request #38525 from juanvallejo/jvallejo/fix-panic-on-invalid-json-syntax
Automatic merge from submit-queue (batch tested with PRs 38525, 38977) Prevent json decoder panic on invalid input Related downstream issue: https://github.com/openshift/origin/issues/12132 ``` # Can be replicated on kubectl with: $ cat panic.json { "kind": "Pod", "apiVersion": "v1", "metadata": { "name": "", "labels": { "name": "" }, "generateName": "", "namespace": "", "annotations": [] }, "spec": {} }, $ kubectl create -f panic.json --validate=false ``` **Release note**: ```release-note release-note-none ``` This patch handles cases where `ioutil.ReadAll` will return a single character output on an invalid json input, causing the `Decode` method to panic when it tries to calculate the line number for the syntax error. The example below would cause a panic due to the trailing comma at the end: ``` { "kind": "Pod", "apiVersion": "v1", "metadata": { "name": "", "labels": { "name": "" }, "generateName": "", "namespace": "", "annotations": [] }, "spec": {} }, ``` @kubernetes/cli-review @fabianofranz
This commit is contained in:
commit
36c20d1f5e
@ -194,7 +194,7 @@ func (s *Serializer) RecognizesData(peek io.Reader) (ok, unknown bool, err error
|
||||
// we could potentially look for '---'
|
||||
return false, true, nil
|
||||
}
|
||||
_, ok = utilyaml.GuessJSONStream(peek, 2048)
|
||||
_, _, ok = utilyaml.GuessJSONStream(peek, 2048)
|
||||
return ok, false, nil
|
||||
}
|
||||
|
||||
|
@ -181,6 +181,7 @@ type YAMLOrJSONDecoder struct {
|
||||
bufferSize int
|
||||
|
||||
decoder decoder
|
||||
rawData []byte
|
||||
}
|
||||
|
||||
// NewYAMLOrJSONDecoder returns a decoder that will process YAML documents
|
||||
@ -198,10 +199,11 @@ func NewYAMLOrJSONDecoder(r io.Reader, bufferSize int) *YAMLOrJSONDecoder {
|
||||
// provide object, or returns an error.
|
||||
func (d *YAMLOrJSONDecoder) Decode(into interface{}) error {
|
||||
if d.decoder == nil {
|
||||
buffer, isJSON := GuessJSONStream(d.r, d.bufferSize)
|
||||
buffer, origData, isJSON := GuessJSONStream(d.r, d.bufferSize)
|
||||
if isJSON {
|
||||
glog.V(4).Infof("decoding stream as JSON")
|
||||
d.decoder = json.NewDecoder(buffer)
|
||||
d.rawData = origData
|
||||
} else {
|
||||
glog.V(4).Infof("decoding stream as YAML")
|
||||
d.decoder = NewYAMLToJSONDecoder(buffer)
|
||||
@ -215,6 +217,13 @@ func (d *YAMLOrJSONDecoder) Decode(into interface{}) error {
|
||||
glog.V(4).Infof("reading stream failed: %v", readErr)
|
||||
}
|
||||
js := string(data)
|
||||
|
||||
// if contents from io.Reader are not complete,
|
||||
// use the original raw data to prevent panic
|
||||
if int64(len(js)) <= syntax.Offset {
|
||||
js = string(d.rawData)
|
||||
}
|
||||
|
||||
start := strings.LastIndex(js[:syntax.Offset], "\n") + 1
|
||||
line := strings.Count(js[:start], "\n")
|
||||
return fmt.Errorf("json: line %d: %s", line, syntax.Error())
|
||||
@ -296,10 +305,10 @@ func (r *LineReader) Read() ([]byte, error) {
|
||||
// GuessJSONStream scans the provided reader up to size, looking
|
||||
// for an open brace indicating this is JSON. It will return the
|
||||
// bufio.Reader it creates for the consumer.
|
||||
func GuessJSONStream(r io.Reader, size int) (io.Reader, bool) {
|
||||
func GuessJSONStream(r io.Reader, size int) (io.Reader, []byte, bool) {
|
||||
buffer := bufio.NewReaderSize(r, size)
|
||||
b, _ := buffer.Peek(size)
|
||||
return buffer, hasJSONPrefix(b)
|
||||
return buffer, b, hasJSONPrefix(b)
|
||||
}
|
||||
|
||||
var jsonPrefix = []byte("{")
|
||||
|
@ -65,7 +65,7 @@ func TestSplitYAMLDocument(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGuessJSON(t *testing.T) {
|
||||
if r, isJSON := GuessJSONStream(bytes.NewReader([]byte(" \n{}")), 100); !isJSON {
|
||||
if r, _, isJSON := GuessJSONStream(bytes.NewReader([]byte(" \n{}")), 100); !isJSON {
|
||||
t.Fatalf("expected stream to be JSON")
|
||||
} else {
|
||||
b := make([]byte, 30)
|
||||
|
Loading…
Reference in New Issue
Block a user