Potential null pointer fixes / checks#4132
Potential null pointer fixes / checks#4132OverOrion wants to merge 6 commits intosyslog-ng:masterfrom
Conversation
|
No news file has been detected. Please write one, if applicable. |
|
Build FAILURE |
| log_pipe_notify(self->control, notify_code, self); | ||
| } | ||
| if (self->super.super.flags & PIF_INITIALIZED) | ||
| if ((self->super.super.flags & PIF_INITIALIZED) && self->proto) |
There was a problem hiding this comment.
this should rather be an assert in the body of the if.
self->proto should never be a NULL in this case (we had a bug in this path a while back in case of threaded(no)), and I reviewed that we have it covered. The bug at that time was caused by use-after-free.
So, I would rather get an abort in case self->proto is NULL here.
There was a problem hiding this comment.
We concluded that self->proto being NULL here is allowed, as a pending_close can NULL it out a few lines above.
There was a problem hiding this comment.
This was a rather naive approach, I blindly copied what I had found in LogWriter, thanks for catching it!
I do remember now, yes, self->proto can be NULL here.
lib/control/control-command-thread.c
Outdated
| self->thread_finished.cookie = control_command_thread_ref(self); | ||
| iv_event_register(&self->thread_finished); | ||
|
|
||
| g_assert(self->connection); |
There was a problem hiding this comment.
I don't see how this could occur. self->connection is initialized in the constructor by taking a ref from a constructor argument. The only call-site that calls control_command_thread_new() is control-connection which passes "self" to that argument.
I wouldn't want to spray unneeded asserts everywhere. If we want to add this anywhere, it should be in the constructor I think, but I don't think there's too much pressure doing it even there.
There was a problem hiding this comment.
Indeed, it was a false positive, thanks once again for the catch!
lib/logwriter.c
Outdated
| { | ||
| g_free(self->line_buffer->str); | ||
| g_string_free(self->line_buffer, TRUE); | ||
| log_writer_realloc_line_buffer(self); |
There was a problem hiding this comment.
this doubles the number of allocations as it will allocate both the GString struct and its "str" member. The aim was to optimize away this case.
A better alternative would be to use scratch-buffers for this purpose, or maybe wrap this ugly trick into a nicer looking function (aka g_string_steal).
Also, this seems to be a use-after-free, you are freeing self->line_buffer and then calling g_string_set_size() on it.
There was a problem hiding this comment.
I gave it a second thought and refactored the function to take a ownership_transferred boolean which decides whether the old buffer should be freed or not. I think it helps with readability as the freeing would happen inside the function instead of the call side.
I am more than happy to revert it, because it does not contribute much to the spirit of the PR either.
| affile_dw_set_owner(writer, self); | ||
| if (!log_pipe_init(&writer->super)) | ||
| { | ||
| affile_dw_set_owner(writer, NULL); |
There was a problem hiding this comment.
I think removing this would cause a leak through the circular reference through the AFFileDestWriter->owner member.
There was a problem hiding this comment.
I agree, affile_dw_set_owner() is necessary here, but its implementation needs to be fixed in order not to dereference NULL pointers. This is a real issue, we've reproduced the crash.
affile_dw_unset_owner() would be even cleaner.
There was a problem hiding this comment.
Thanks once again, affile_dw_set_owner got fixed, it should take care of the possible NULL owner now.
bazsi
left a comment
There was a problem hiding this comment.
I've filed a few comments that should change before this can be merged.
|
@OverOrion Do you have plans to finish this PR? |
Fix a potential null pointer dereference Signed-off-by: Szilárd Parrag <[email protected]>
Signed-off-by: Szilárd Parrag <[email protected]>
Refactored this function to have it decied whether the old buffer should be freed or not. Signed-off-by: Szilárd Parrag <[email protected]>
bc13c3a to
834fd74
Compare
|
Thanks for fixing these. I've reproduced one of the crashes, will review the PR tomorrow. |
834fd74 to
62f5e81
Compare
2f77d1f to
1a139a1
Compare
|
|
||
| if (consumed) | ||
| log_writer_realloc_line_buffer(self); | ||
| log_writer_realloc_line_buffer(self, consumed); |
There was a problem hiding this comment.
This does not look like an equivalent transformation to me.
What's the idea behind this patch?
There was a problem hiding this comment.
The idea was that the freeing was outside the other buffer manipulations and I wanted them to be close to each other (on the call site -> inside the function).
The consumed boolean is responsible for deciding whether a specific buffer has been passed yet or not. If it has been passed, then it should not be freed, because the reference is needed (there is something that refers to it).
If it has not been passed (nothing else refers to it), then the old buffer must be freed.
Basically I moved the g_free call into the function body.
modules/affile/affile-dest.c
Outdated
| affile_dw_set_owner(AFFileDestWriter *self, AFFileDestDriver *owner) | ||
| { | ||
| GlobalConfig *cfg = log_pipe_get_config(&owner->super.super.super); | ||
| log_pipe_set_config(&self->super, cfg); |
There was a problem hiding this comment.
This does not fix the NULL pointer deref issue as log_pipe_get_config dereferences owner.
There was a problem hiding this comment.
You are right, I messed it up during the rebase 🤦 .
| { | ||
| if (self->owner) | ||
| log_pipe_unref(&self->owner->super.super.super); | ||
| self->owner = NULL; |
There was a problem hiding this comment.
Probably we should do something with self->super.expr_node too.
There was a problem hiding this comment.
Upon a closer look it seems that the expr_node setting is done without freeing the old one in other places as well.
Should I fix it in this PR or in a separate one?
In very rare (and unrealistic) cases syslog-ng could crash if it was reloaded and it was unable to reuse it's file writers. Signed-off-by: Szilárd Parrag <[email protected]>
Signed-off-by: Szilard Parrag <[email protected]>
Signed-off-by: Szilárd Parrag <[email protected]>
1a139a1 to
1107829
Compare
In #4123 the fix was to check the return value of a failable function.
With the help of Infer I was able to find similar cases and fix them.