Skip to content
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

Use after free when requesting any xspf file #464

Open
tatokis opened this issue Nov 17, 2024 · 0 comments
Open

Use after free when requesting any xspf file #464

tatokis opened this issue Nov 17, 2024 · 0 comments

Comments

@tatokis
Copy link

tatokis commented Nov 17, 2024

When requesting any .xspf file, AddressSanitizer reports the following:

==19579==ERROR: AddressSanitizer: heap-use-after-free on address 0x6020000252d0 at pc 0x7fbf8fc925b3 bp 0x7fbf887f9dd0 sp 0x7fbf887f9578
READ of size 1 at 0x6020000252d0 thread T5
[2024-11-17  18:22:29] INFO xslt/xslt_apply_sheet loaded stylesheet /home/tasos/icecastinst/share/icecast/admin/xspf.xsl
    #0 0x7fbf8fc925b2 in __interceptor_strcmp ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:466
    #1 0x55b878c187c7 in compare_mounts /home/tasos/icecast-kh/src/cfgfile.c:818
    #2 0x55b878cfd3a6 in avl_get_by_key /home/tasos/icecast-kh/src/avl/avl.c:332
    #3 0x55b878c2c858 in config_find_mount /home/tasos/icecast-kh/src/cfgfile.c:1967
    #4 0x55b878c894b0 in ice_http_setup_flags /home/tasos/icecast-kh/src/params.c:434
    #5 0x55b878c8d14e in xslt_prepare_response /home/tasos/icecast-kh/src/xslt.c:522
    #6 0x55b878c8d85c in xslt_update /home/tasos/icecast-kh/src/xslt.c:587
    #7 0x55b878cefab0 in _start_routine /home/tasos/icecast-kh/src/thread/thread.c:768
    #8 0x7fbf8f094ac2 in start_thread nptl/pthread_create.c:442
    #9 0x7fbf8f12684f  (/lib/x86_64-linux-gnu/libc.so.6+0x12684f)

0x6020000252d0 is located 0 bytes inside of 12-byte region [0x6020000252d0,0x6020000252dc)
freed by thread T2 here:
    #0 0x7fbf8fcb4537 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:127
    #1 0x55b878c3c254 in _handle_get_request /home/tasos/icecast-kh/src/connection.c:1900
    #2 0x55b878c3a28e in http_client_request /home/tasos/icecast-kh/src/connection.c:1502
    #3 0x55b878c838be in worker /home/tasos/icecast-kh/src/client.c:876
    #4 0x55b878cefab0 in _start_routine /home/tasos/icecast-kh/src/thread/thread.c:768
    #5 0x7fbf8f094ac2 in start_thread nptl/pthread_create.c:442

previously allocated by thread T2 here:
    #0 0x7fbf8fcb4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
    #1 0x55b878c3f3b7 in util_url_unescape /home/tasos/icecast-kh/src/util.c:304
    #2 0x55b878c3f65c in util_normalise_uri /home/tasos/icecast-kh/src/util.c:340
    #3 0x55b878c3bc86 in _handle_get_request /home/tasos/icecast-kh/src/connection.c:1839
    #4 0x55b878c3a28e in http_client_request /home/tasos/icecast-kh/src/connection.c:1502
    #5 0x55b878c838be in worker /home/tasos/icecast-kh/src/client.c:876
    #6 0x55b878cefab0 in _start_routine /home/tasos/icecast-kh/src/thread/thread.c:768
    #7 0x7fbf8f094ac2 in start_thread nptl/pthread_create.c:442

Thread T5 created by T2 here:
    #0 0x7fbf8fc58685 in __interceptor_pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cpp:216
    #1 0x55b878cee776 in thread_create_c /home/tasos/icecast-kh/src/thread/thread.c:342
    #2 0x55b878c8dc8a in xslt_client /home/tasos/icecast-kh/src/xslt.c:635
    #3 0x55b878c8e079 in _xslt_transform /home/tasos/icecast-kh/src/xslt.c:664
    #4 0x55b878c8e0e6 in xslt_transform_admin /home/tasos/icecast-kh/src/xslt.c:676
    #5 0x55b878c9aaac in admin_send_response /home/tasos/icecast-kh/src/admin.c:242
    #6 0x55b878c921d9 in fserve_client_create /home/tasos/icecast-kh/src/fserve.c:556
    #7 0x55b878cbd12a in add_authenticated_listener /home/tasos/icecast-kh/src/auth.c:551
    #8 0x55b878cbe8f8 in auth_add_listener /home/tasos/icecast-kh/src/auth.c:741
    #9 0x55b878c3c245 in _handle_get_request /home/tasos/icecast-kh/src/connection.c:1898
    #10 0x55b878c3a28e in http_client_request /home/tasos/icecast-kh/src/connection.c:1502
    #11 0x55b878c838be in worker /home/tasos/icecast-kh/src/client.c:876
    #12 0x55b878cefab0 in _start_routine /home/tasos/icecast-kh/src/thread/thread.c:768
    #13 0x7fbf8f094ac2 in start_thread nptl/pthread_create.c:442

Thread T2 created by T0 here:
    #0 0x7fbf8fc58685 in __interceptor_pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cpp:216
    #1 0x55b878cee776 in thread_create_c /home/tasos/icecast-kh/src/thread/thread.c:342
    #2 0x55b878c84189 in worker_start /home/tasos/icecast-kh/src/client.c:957
    #3 0x55b878c84818 in workers_adjust /home/tasos/icecast-kh/src/client.c:1030
    #4 0x55b878c4cdd1 in slave_startup /home/tasos/icecast-kh/src/slave.c:1261
    #5 0x55b878c4ceeb in _slave_thread /home/tasos/icecast-kh/src/slave.c:1272
    #6 0x55b878c44c21 in slave_initialize /home/tasos/icecast-kh/src/slave.c:256
    #7 0x55b878c2d7fb in server_process /home/tasos/icecast-kh/src/main.c:236
    #8 0x55b878c2e6dd in main /home/tasos/icecast-kh/src/main.c:435
    #9 0x7fbf8f029d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

SUMMARY: AddressSanitizer: heap-use-after-free ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:466 in __interceptor_strcmp
Shadow bytes around the buggy address:
  0x0c047fffca00: fa fa 00 04 fa fa 00 00 fa fa 00 03 fa fa 05 fa
  0x0c047fffca10: fa fa 00 00 fa fa 00 02 fa fa 04 fa fa fa 00 00
  0x0c047fffca20: fa fa 00 03 fa fa 04 fa fa fa 00 00 fa fa 06 fa
  0x0c047fffca30: fa fa 00 04 fa fa 00 00 fa fa 05 fa fa fa 00 07
  0x0c047fffca40: fa fa 00 00 fa fa 00 03 fa fa 00 04 fa fa 00 00
=>0x0c047fffca50: fa fa 07 fa fa fa 04 fa fa fa[fd]fd fa fa fd fd
  0x0c047fffca60: fa fa fd fa fa fa fd fd fa fa 00 04 fa fa fa fa
  0x0c047fffca70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffca80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffca90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fffcaa0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==19579==ABORTING

Steps to reproduce:

  1. run icecast-kh with a default config
  2. curl http://localhost:8000/whatever.xspf

Having looked into it, this occurs because uri is passed to add_authenticated_listener() (via auth_add_listener()) and then freed immediately.

icecast-kh/src/connection.c

Lines 1893 to 1901 in ea3554b

{
/* drop non-admin GET requests here if clients limit reached */
if (client_limit_reached)
ret = client_send_403 (client, "Too many clients connected");
else
ret = auth_add_listener (uri, client);
}
free (uri);
return ret;

This is an issue because add_authenticated_listener() simply copies the mount pointer to the client_t, before eventually spawning a thread (through fserve_client_create() → admin_send_response() → xslt_transform_admin() → _xslt_transform() → xslt_client()) that uses it.

icecast-kh/src/auth.c

Lines 542 to 552 in ea3554b

if (ret == -2)
{
if (mountinfo && mountinfo->file_seekable == 0)
{
DEBUG1 ("disable seek on file matching %s", mountinfo->mountname);
httpp_deletevar (client->parser, "range");
client->flags |= CLIENT_NO_CONTENT_LENGTH;
}
client->mount = mount;
ret = fserve_client_create (client, mount);
}

The xslt thread then proceeds to use the deallocated memory section.

I have not been been able to come up with a proper solution, so I created a temporary hack (which is likely not upstreamable) to work around this issue and continue debugging the random crashes that occur.

tatokis@a9f9891

This effectively always strdups the mount field before spawning the thread, and then the thread frees it when it's finished with it, ensuring its lifetime.

Essentially the issue is finding a way to free the memory when done with it, and only when we know we allocated it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant