-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Packet alerts/v3 #6896
Packet alerts/v3 #6896
Conversation
Some unittests used SCMalloc for allocating new Packet the unittests. While this is valid, it leads to segmentation faults when we move to dynamic allocation of the maximum alerts allowed to be triggered by a single packet. This massive patch uses PacketGetFromAlloc, which initializes a Packet in such a way that any dynamic allocated structures within will also be initialized. Related to Task#4207
The maximum of possible alerts triggered by a unique packet was hardcoded to 15. With usage of 'noalert' rules, that limit could be reached somewhat easily. Make that configurable via suricata.yaml. Conf Bug#4941 Task#4207
Plus small clang formatting change.
Codecov Report
@@ Coverage Diff @@
## master #6896 +/- ##
==========================================
- Coverage 77.72% 77.69% -0.04%
==========================================
Files 628 628
Lines 186493 186392 -101
==========================================
- Hits 144959 144813 -146
- Misses 41534 41579 +45
Flags with carried forward coverage won't be shown. Click here to find out more. |
#define PACKET_INITIALIZE(p) \ | ||
{ \ | ||
SCMutexInit(&(p)->tunnel_mutex, NULL); \ | ||
(p)->alerts.alerts = CreatePacketAlert(); \ |
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.
Could/Should we not defer the need for allocation until there truly is one alert ?
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.
Victor has mentioned something similar, actually, iirc. I'll have a look at how to do address that...
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 packets and their alert structures are pooled and reused all the time. We don't free them, only clear them. So allocing this at init makes sense and avoids alloc time overhead at runtime for an already expensive packet (ie an alerting packet)
SCLogDebug("detect->packet_alert_max set to %" PRIdMAX "", max); | ||
packet_alert_max = max; | ||
} else { | ||
packet_alert_max = PACKET_ALERT_MAX; |
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.
is it not redundant with line 77 ?
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, you're right.
{ | ||
intmax_t max = 0; | ||
if (ConfGetInt("packet-alert-max", &max) == 1) { | ||
SCLogDebug("detect->packet_alert_max set to %" PRIdMAX "", max); |
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.
Could have only one debug line for both cases I guess
{ | ||
PacketAlert *pa_array = NULL; | ||
if (RunmodeIsUnittests()) { | ||
pa_array = SCCalloc(PACKET_ALERT_MAX, sizeof(PacketAlert)); |
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.
Do we have any idea what is the performance impact ?
Could/should we use a pool of preallocated buffers ?
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 packets themselves are pooled and reused, so this allocation is a once per packet step.
for (i = pos; i <= p->alerts.cnt - 1; i++) { | ||
memcpy(&p->alerts.alerts[i], &p->alerts.alerts[i + 1], sizeof(PacketAlert)); | ||
const uint16_t after = (p->alerts.cnt - 1) - pos; | ||
if (after) { |
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.
Is p->alerts.alerts
somehow sorted ?
If not, it would be more efficient to just move the last alert to the removed position.
That would be like memmove(p->alerts.alerts + pos, &p->alerts.alerts[p->alerts.cnt - 1], sizeof(PacketAlert)
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 this logic is to have it sorted by Signature::num (the internal id, assigned after sort by sig priority).
const uint16_t target_pos = i + 1; | ||
const uint16_t space_post_target = packet_alert_max - 1 - i; | ||
const uint16_t to_move = MIN(space_post_target, (p->alerts.cnt - i)); | ||
memmove(p->alerts.alerts + target_pos, p->alerts.alerts + i, |
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.
Will this work correctly if to_move == 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.
I'll add a BUG_ON but given the check above it should not ever be 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.
it should not ever be 0
It can be 0 : if space_post_target
is 0 c-which can be the case if you have like packet_alert_max
= 3, you have 3 alerts with num 3,5,7 and you want to add one with num 6
Than no memmove, just replace the last one
Otherwise, all is good :-)
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.
but if we had packet_alert_max=3
in this example, the function would have returned 0 before, so we would not reach this stage, right?
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.
S-V tests failing with BUG_ON(to_move == 0)
atm:
===> http2-bugfixes: FAILED: got exit code -6, expected 0
===> http2-files: FAILED: got exit code -6, expected 0
===> http-sticky-server: FAILED: got exit code -6, expected 0
===> smb2-07-frames: FAILED: got exit code -6, expected 0
===> tls13-draft28-frames: FAILED: got exit code -6, expected 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.
but if we had packet_alert_max=3 in this example, the function would have returned 0 before, so we would not reach this stage, right?
Indeed, but I guess it should not return 0, because we want to insert the highest priority alert
memcpy(&p->alerts.alerts[i + 1], &p->alerts.alerts[i], sizeof(PacketAlert)); | ||
} | ||
/* find position to insert */ | ||
for (i = p->alerts.cnt - 1; i >= 0 && p->alerts.alerts[i].num > s->num; i--) |
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.
There is a duplicate test for p->alerts.alerts[p->alerts.cnt - 1].num < s->num
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.
And
if (p->alerts.cnt == 0 || (p->alerts.cnt > 0 && p->alerts.alerts[p->alerts.cnt - 1].num < s->num)) {
can be simplified to
if (p->alerts.cnt == 0 || p->alerts.alerts[p->alerts.cnt - 1].num < s->num) {
as alerts.cnt is unsigned cf PacketAlerts_
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.
There is a duplicate test for
p->alerts.alerts[p->alerts.cnt - 1].num < s->num
Sorry, I don't think I get this. Can you point out where?
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.
It is tested a first time in the surrounding if. Then in the else clause, it is tested again in the loop
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 think I see it now. Because the surrounding if has it <
while the for checks for >
I didn't realize it before. Thanks :)
It looks dangerous indeed... I left some questions |
ERROR: QA failed on build_asan. Pipeline 6035 |
Because of needed rebase |
Rebased and addressed things related to my changes on #6929 |
Comments addressed with #6999 |
Thanks @jufajardini |
#6895 with an fix/optimization for alert queue removal/insert.
@catenacyber can you help review the
memmove
logic? The relation between array index, array size and array use cnt is easily messed up I think.suricata-verify-pr: 694