-
Notifications
You must be signed in to change notification settings - Fork 174
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
Fix a buffer overflow in compose handling #2297
Conversation
I believe this has no security impact but it is making my valgrind sad. Thanks to Omni for the help in finding the root cause of this. Test case (a full repro with hacks to get valgrind on the ibus-engine-simple process is available at https://github.com/lf-/ibus/tree/repro): ~/.XCompose is: ``` <Multi_key> <g> <h> : "η" <Multi_key> <g> <v> <t> <h> : "ϑ" <Multi_key> <g> <h> : "ɣ" ``` Errors (from include-directive branch before applying this patch): ``` Invalid read of size 4 at 0x48A6378: ibus_compose_data_compare (ibuscomposetable.c:509) by 0x4B64A38: ??? (in /usr/lib/libglib-2.0.so.0.6600.4) by 0x4B649DE: ??? (in /usr/lib/libglib-2.0.so.0.6600.4) by 0x48A8485: ibus_compose_table_new_with_file (ibuscomposetable.c:1108) by 0x48A871E: ibus_compose_table_list_add_file (ibuscomposetable.c:1204) by 0x48C087A: ibus_engine_simple_add_compose_file (ibusenginesimple.c:1863) by 0x48C0A8D: ibus_engine_simple_add_table_by_locale (ibusenginesimple.c:1788) by 0x109404: __lambda6_ (main.c:230) by 0x1094DE: ___lambda6__gsource_func (main.c:280) by 0x4B75A83: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.6600.4) by 0x4BC99B0: ??? (in /usr/lib/libglib-2.0.so.0.6600.4) by 0x4B74FD2: g_main_loop_run (in /usr/lib/libglib-2.0.so.0.6600.4) Address 0x52926b0 is 0 bytes after a block of size 16 alloc'd at 0x483CD7B: realloc (vg_replace_malloc.c:834) by 0x4B748F8: g_realloc (in /usr/lib/libglib-2.0.so.0.6600.4) by 0x48A72BA: parse_compose_sequence (ibuscomposetable.c:208) by 0x48A77F2: parse_compose_line (ibuscomposetable.c:344) by 0x48A79CF: ibus_compose_list_parse_file (ibuscomposetable.c:392) by 0x48A79E1: ibus_compose_list_parse_file (ibuscomposetable.c:394) by 0x48A83EE: ibus_compose_table_new_with_file (ibuscomposetable.c:1098) by 0x48A871E: ibus_compose_table_list_add_file (ibuscomposetable.c:1204) by 0x48C087A: ibus_engine_simple_add_compose_file (ibusenginesimple.c:1863) by 0x48C0A8D: ibus_engine_simple_add_table_by_locale (ibusenginesimple.c:1788) by 0x109404: __lambda6_ (main.c:230) by 0x1094DE: ___lambda6__gsource_func (main.c:280) Invalid read of size 4 at 0x48A637D: ibus_compose_data_compare (ibuscomposetable.c:510) by 0x4B64A38: ??? (in /usr/lib/libglib-2.0.so.0.6600.4) by 0x4B649DE: ??? (in /usr/lib/libglib-2.0.so.0.6600.4) by 0x48A8485: ibus_compose_table_new_with_file (ibuscomposetable.c:1108) by 0x48A871E: ibus_compose_table_list_add_file (ibuscomposetable.c:1204) by 0x48C087A: ibus_engine_simple_add_compose_file (ibusenginesimple.c:1863) by 0x48C0A8D: ibus_engine_simple_add_table_by_locale (ibusenginesimple.c:1788) by 0x109404: __lambda6_ (main.c:230) by 0x1094DE: ___lambda6__gsource_func (main.c:280) by 0x4B75A83: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.6600.4) by 0x4BC99B0: ??? (in /usr/lib/libglib-2.0.so.0.6600.4) by 0x4B74FD2: g_main_loop_run (in /usr/lib/libglib-2.0.so.0.6600.4) Address 0x534a860 is 0 bytes after a block of size 16 alloc'd at 0x483CD7B: realloc (vg_replace_malloc.c:834) by 0x4B748F8: g_realloc (in /usr/lib/libglib-2.0.so.0.6600.4) by 0x48A72BA: parse_compose_sequence (ibuscomposetable.c:208) by 0x48A77F2: parse_compose_line (ibuscomposetable.c:344) by 0x48A79CF: ibus_compose_list_parse_file (ibuscomposetable.c:392) by 0x48A83EE: ibus_compose_table_new_with_file (ibuscomposetable.c:1098) by 0x48A871E: ibus_compose_table_list_add_file (ibuscomposetable.c:1204) by 0x48C087A: ibus_engine_simple_add_compose_file (ibusenginesimple.c:1863) by 0x48C0A8D: ibus_engine_simple_add_table_by_locale (ibusenginesimple.c:1788) by 0x109404: __lambda6_ (main.c:230) by 0x1094DE: ___lambda6__gsource_func (main.c:280) by 0x4B75A83: g_main_context_dispatch (in /usr/lib/libglib-2.0.so.0.6600.4) ```
Probably I don't think your patch is not needed.
max_compose_len is 5 in your case and it will return 0 because |
Hm. I agree that the input is not a reasonable/valid one, but it was equally accidental: it came from an xcompose file someone else wrote and I was using, and an invalid compose file causing a memory access violation is definitely a bug in my view. I've read carefully through the code again, and this is what's happening: The space allocated for the first compose sequence is 4 gunichars (size 16; 3 chars and a null). If the sequences match up to and including the null terminator and max_compose_len is greater than the length of allocation for the sequence in question, we will read right over the null terminator into unallocated memory:
The point of this patch is to catch this condition with the identical compose sequences by checking if it's reading the null terminator on both and stop. Finally, the reason we aren't seeing this with non identical compose sequences is that if they mismatch before the null, we leave; if we read a character from one and a null from the other, we leave. So it can only happen on identical strings such as are found in the repro above. |
I think the "out of bounds read" should not happen. |
Well, it's reading 4 items past the start of an allocation of length 4, that's an out of bounds read. In order to not do an out of bounds read here, we either need to check for the null terminator, or allow reading past the null terminator but not into uninitialized memory by making the allocations all the same length. The reason it's an out of bounds read here is because the if statement does not make the loop stop as every character in the string and the null terminator are equal. Further, the loop bounds I believe that the original intent of the limit on the for loop is to prevent this out of bounds read, but it doesn't work as designed, because the allocations are different lengths and thus it doesn't stop reading out of bounds of a compose sequence of shorter length. Because our allocations are not the same length as the maximum length, we need to introduce a null check to guard against reading past the end of strings that are shorter than the maximum length. |
I mean the length of compose_data_a->sequence should be greater than max_compose_len and your buffer overflow could not happen. |
This is not what the allocation code does, unfortunately, and that's what the Valgrind report is saying: it's allocated based on the input sequence length in So my patch doesn't change that and it instead chooses to change the comparison, which does also solve the problem. The current design is sound assuming null terminators are appropriately checked for, which they seem to be elsewhere based on nothing else causing Valgrind errors. I could further change it to remove |
I believe this has no security impact but it is making my Valgrind sad. Thanks to Omni for the help in finding the root cause of this. ~/.XCompose is: ``` <Multi_key> <g> <h> : "η" <Multi_key> <g> <v> <t> <h> : "ϑ" <Multi_key> <g> <h> : "ɣ" ``` BUG=#2297
Sorry max_compose_len does not work as I assumed in that function and I can reproduce your issue with Valgrind. |
I believe this has no security impact as the XCompose parser is operating on specifically user-configured data, but it is making my valgrind sad.
Thanks to Omni for the help in finding the root cause of this.
Test case (a full repro with hacks to get valgrind on the
ibus-engine-simple process is available at
https://github.com/lf-/ibus/tree/repro):
~/.XCompose is:
Errors (from include-directive branch before applying this patch):