Skip to content

Commit

Permalink
Clone value when copy fields in processors to avoid crash (elastic#20500
Browse files Browse the repository at this point in the history
)

Closes elastic#19206

(cherry picked from commit 0940e25)
  • Loading branch information
ianwoolf authored and jsoriano committed Jun 21, 2021
1 parent e4aa68a commit 854acce
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
- Fix incorrect field name appending to `related.hash` in `threatintel.abusechmalware` ingest pipeline. {issue}25151[25151] {pull}25674[25674]
- Add improvements to the azure activitylogs and platformlogs ingest pipelines. {pull}26148[26148]
- Fix `kibana.log` pipeline when `event.duration` calculation becomes a Long. {issue}24556[24556] {pull}25675[25675]
- Clone value when copy fields in processors to avoid crash. {issue}19206[19206] {pull}20500[20500]

*Heartbeat*

Expand Down
23 changes: 22 additions & 1 deletion libbeat/processors/actions/copy_fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func (f *copyFields) copyField(from string, to string, fields common.MapStr) err
return fmt.Errorf("could not fetch value for key: %s, Error: %s", from, err)
}

_, err = fields.Put(to, value)
_, err = fields.Put(to, cloneValue(value))
if err != nil {
return fmt.Errorf("could not copy value to %s: %v, %+v", to, value, err)
}
Expand All @@ -114,3 +114,24 @@ func (f *copyFields) copyField(from string, to string, fields common.MapStr) err
func (f *copyFields) String() string {
return "copy_fields=" + fmt.Sprintf("%+v", f.config.Fields)
}

// cloneValue returns a shallow copy of a map. All other types are passed
// through in the return. This should be used when making straight copies of
// maps without doing any type conversions.
func cloneValue(value interface{}) interface{} {
switch v := value.(type) {
case common.MapStr:
return v.Clone()
case map[string]interface{}:
return common.MapStr(v).Clone()
case []interface{}:
len := len(v)
newArr := make([]interface{}, len)
for idx, val := range v {
newArr[idx] = cloneValue(val)
}
return newArr
default:
return value
}
}
23 changes: 23 additions & 0 deletions libbeat/processors/actions/copy_fields_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,29 @@ func TestCopyFields(t *testing.T) {
"message": 42,
},
},
"copy map from nested key message.original to top level field message_copied": {
FromTo: fromTo{
From: "message.original",
To: "message_copied",
},
Input: common.MapStr{
"message": common.MapStr{
"original": common.MapStr{
"original": "original",
},
},
},
Expected: common.MapStr{
"message": common.MapStr{
"original": common.MapStr{
"original": "original",
},
},
"message_copied": common.MapStr{
"original": "original",
},
},
},
}

for name, test := range tests {
Expand Down

0 comments on commit 854acce

Please sign in to comment.