-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
x-pack/filebeat/processors/decode_cef/cef: allow (*Event).Unpack to attempt to recover extensions #30938
Conversation
Pinging @elastic/security-external-integrations (Team:Security-External Integrations) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the reorganization. Had one question.
t.Run("truncatedHeader", func(t *testing.T) { | ||
var e Event | ||
err := e.Unpack(truncatedHeader) | ||
assert.Equal(t, errUnexpectedEndOfEvent, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to make this error more descriptive based on the machine state? Like have the error indicate that the header is incomplete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added a second error in the case that there is a failure on the first round and there are no extensions.
Added an action into the first pass since it gives greater control. Also added a test in the decode_cef package to show what the events end up looking like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Before merging, can you please run the decode_cef/cef/fuzz on the changes for a few minutes if you haven't already.
This pull request is now in conflicts. Could you fix it? 🙏
|
…ttempt to recover extensions This adds a second pass at parsing messages if the original parse operation fails and there are no extensions found by relaxing the requirements on header syntax. Because header values may include syntax that looks like the extension key/value pair syntax, the parsers are separated and under control of the host language.
This will need some addition logic there are a bunch of crashers. |
@andrewkroh It's worth taking another look at the ragel since I've needed to make some reasonably large changes (by ragel standards) to the actions, but it's been fuzzing after the fixes for 30 minutes without a crasher. |
This reverts commit 7c9acf5.
state.key = data[mark:p] | ||
} | ||
action extension_value_start { | ||
if len(state.escapes) != 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this condition based on the number of escapes? Can't we have extensions without escapes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue here that if we have got to this point we have a syntax that is not expected and so may have escapes that have not been consumed. So if there are some to consume, this makes sure we do.
The original was
action extension_value_start {
state.valueStart = p;
state.valueEnd = p
}
Without this, what happens is that we can end up with negative indices into the data handed to the unescaper because we have moved on from the fragment being handled without being signaled by the syntax to unescape it so our offset is greater than the span described by each of the escapes. This happens with the fuzz test cases added here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point is that there may be an "extension" that needs to be consumed which does not contain any escapes. That's why I am questioning the condition being based on len(escapes) rather than something like len(key) && something with the value start/end. Does that make sense or do I have a misunderstanding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those won't be affected by this. This is purely to cope with the cases where things have been set up and not used. I the first pass of the parse, this condition is never triggered because the header state machine prevents this from ever happening, but in the salvage pass, the guarantees don't hold, but also we can't guarantee sensible results, we are just trying to capture as much as possible.
Put another way, if the escape were well formed, it would have been handled by extension_eof
which is those cases that you describe, guarded by len(state.key) != 0 && state.valueStart < state.valueEnd
. So this just picks up cases that that failed to identify because they were syntactically broken and did not satisfy the machine before the next extension start.
Does that clarify?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that’s clear. Thanks. Can you add a short comment there.
/test |
1 similar comment
/test |
The coverage tool appears to be choking on this. It shouldn't. |
The issue looks like golang/go#35781 and that we just did not hit it with the exact number of lines that we had. The options are to:
(I think the issue is that the line directive allows the coverage tool to believe that there are identical lines that have different coverage because the same ragel line ends up in more than one place. Why this only presents itself when the comment is in that action block, I don't know). I have moved the comment into a section of the file that won't end up in the Go code with an explanation and instructions to move it back when the issue in cover is resolved). |
…ttempt to recover extensions (#30938) This adds a second pass at parsing messages if the original parse operation fails and there are no extensions found by relaxing the requirements on header syntax. Because header values may include syntax that looks like the extension key/value pair syntax, the parsers are separated and under control of the host language. (cherry picked from commit c193dde) # Conflicts: # x-pack/filebeat/processors/decode_cef/cef/cef_test.go
…ow (*Event).Unpack to attempt to recover extensions (#31036) * x-pack/filebeat/processors/decode_cef/cef: allow (*Event).Unpack to attempt to recover extensions (#30938) This adds a second pass at parsing messages if the original parse operation fails and there are no extensions found by relaxing the requirements on header syntax. Because header values may include syntax that looks like the extension key/value pair syntax, the parsers are separated and under control of the host language. (cherry picked from commit c193dde) # Conflicts: # x-pack/filebeat/processors/decode_cef/cef/cef_test.go * fix conflict Co-authored-by: Dan Kortschak <90160302+efd6@users.noreply.github.com> Co-authored-by: Dan Kortschak <dan.kortschak@elastic.co>
…ttempt to recover extensions (elastic#30938) This adds a second pass at parsing messages if the original parse operation fails and there are no extensions found by relaxing the requirements on header syntax. Because header values may include syntax that looks like the extension key/value pair syntax, the parsers are separated and under control of the host language.
…ttempt to recover extensions (elastic#30938) This adds a second pass at parsing messages if the original parse operation fails and there are no extensions found by relaxing the requirements on header syntax. Because header values may include syntax that looks like the extension key/value pair syntax, the parsers are separated and under control of the host language.
…ttempt to recover extensions (#30938) This adds a second pass at parsing messages if the original parse operation fails and there are no extensions found by relaxing the requirements on header syntax. Because header values may include syntax that looks like the extension key/value pair syntax, the parsers are separated and under control of the host language.
What does this PR do?
This adds a second pass at parsing messages if the original parse operation fails
and there are no extensions found by relaxing the requirements on header syntax.
Because header values may include syntax that looks like the extension key/value
pair syntax, the parsers are separated and under control of the host language.
Why is it important?
Fixes a bug.
Checklist
- [ ] I have made corresponding changes to the documentation- [ ] I have made corresponding change to the default configuration filesCHANGELOG.next.asciidoc
orCHANGELOG-developer.next.asciidoc
.Author's Checklist
How to test this PR locally
Related issues
Use cases
Screenshots
Logs