GET /hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello/hello
I compiled and executed the examples from the instructions with address sanitizer to help debug the exact location of the out-of-bounds-read:
Similar to above, I compiled and executed the examples from the instructions with address sanitizer to help debug the exact location of the use-after-free bug:
make && make test && ./output/test/issue5_server 1234
Sending multiple consecutive connections to the server results in a use-after-free bug
After running the script below, wait around ~30-60 seconds and the server will crash.
$ while true; do curl http://localhost:1234/; done
use-after-free-fuzz.mp4
Address Sanitizer Output
==131898==ERROR: AddressSanitizer: heap-use-after-free on address 0x607001a34440 at pc 0x55999cd1a37f bp 0x7f44178fddd0 sp 0x7f44178fddc8
WRITE of size 4 at 0x607001a34440 thread T2
#0 0x55999cd1a37e in read_func(void*) src/epoll_socket.cpp:234
#1 0x55999cd25201 in Task::run() src/threadpool.cpp:19
#2 0x55999cd263cf in ThreadPool::execute_thread() src/threadpool.cpp:159
#3 0x55999cd25534 in ss_start_thread src/threadpool.cpp:48
#4 0x7f441b0a63eb in start_thread nptl/pthread_create.c:444
#5 0x7f441b126a1b in clone3 ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
0x607001a34440 is located 64 bytes inside of 72-byte region [0x607001a34400,0x607001a34448)
freed by thread T3 here:
#0 0x7f441b6da008 in operator delete(void*, unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:164
#1 0x55999cd1dd7c in EpollSocket::close_and_release(epoll_event&) src/epoll_socket.cpp:571
#2 0x55999cd1aa19 in EpollSocket::handle_writeable_event(int&, epoll_event&, EpollSocketWatcher&) src/epoll_socket.cpp:275
#3 0x55999cd189d2 in write_func(void*) src/epoll_socket.cpp:74
#4 0x55999cd25201 in Task::run() src/threadpool.cpp:19
#5 0x55999cd263cf in ThreadPool::execute_thread() src/threadpool.cpp:159
#6 0x55999cd25534 in ss_start_thread src/threadpool.cpp:48
#7 0x7f441b0a63eb in start_thread nptl/pthread_create.c:444
previously allocated by thread T0 here:
#0 0x7f441b6d9108 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:95
#1 0x55999cd19c6b in EpollSocket::create_client(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) src/epoll_socket.cpp:191
#2 0x55999cd19eed in EpollSocket::handle_accept_event(int&, epoll_event&, EpollSocketWatcher&) src/epoll_socket.cpp:209
#3 0x55999cd1bc20 in EpollSocket::handle_event(epoll_event&) src/epoll_socket.cpp:386
#4 0x55999cd1d0cc in EpollSocket::start_event_loop() src/epoll_socket.cpp:491
#5 0x55999cd1d5c7 in EpollSocket::start_epoll() src/epoll_socket.cpp:526
#6 0x55999ccef9fe in HttpServer::start_sync() src/http_server.cpp:132
#7 0x55999cceb270 in main test/issue5/issue5_server.cpp:78
#8 0x7f441b0456c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
Thread T2 created by T0 here:
#0 0x7f441b647c36 in __interceptor_pthread_create ../../../../src/libsanitizer/asan/asan_interceptors.cpp:208
#1 0x55999cd2585e in ThreadPool::start_threadpool() src/threadpool.cpp:70
#2 0x55999cd1c080 in EpollSocket::init_tp() src/epoll_socket.cpp:417
#3 0x55999cd1d37a in EpollSocket::start_epoll() src/epoll_socket.cpp:514
#4 0x55999ccef9fe in HttpServer::start_sync() src/http_server.cpp:132
#5 0x55999cceb270 in main test/issue5/issue5_server.cpp:78
#6 0x7f441b0456c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
SUMMARY: AddressSanitizer: heap-use-after-free src/epoll_socket.cpp:234 in read_func(void*)
Shadow bytes around the buggy address:
0x607001a34180: fd fd fd fd fd fa fa fa fa fa fd fd fd fd fd fd
0x607001a34200: fd fd fd fa fa fa fa fa fd fd fd fd fd fd fd fd
0x607001a34280: fd fa fa fa fa fa fd fd fd fd fd fd fd fd fd fa
0x607001a34300: fa fa fa fa fd fd fd fd fd fd fd fd fd fa fa fa
0x607001a34380: fa fa fd fd fd fd fd fd fd fd fd fa fa fa fa fa
=>0x607001a34400: fd fd fd fd fd fd fd fd[fd]fa fa fa fa fa fd fd
0x607001a34480: fd fd fd fd fd fd fd fa fa fa fa fa fd fd fd fd
0x607001a34500: fd fd fd fd fd fa fa fa fa fa fd fd fd fd fd fd
0x607001a34580: fd fd fd fa fa fa fa fa fd fd fd fd fd fd fd fd
0x607001a34600: fd fa fa fa fa fa fd fd fd fd fd fd fd fd fd fa
0x607001a34680: fa fa fa fa fd fd fd fd fd fd fd fd fd 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
==131898==ABORTING
Potential Fix
A potential fix for this bug would be to set the pointers to NULL once they are freed. I believe the pointer of interest is the following:
int ThreadPool::destroy_threadpool() {
................................................................
m_task_cond_var.broadcast();
int ret = -1;
for (int i = 0; i < m_pool_size; i++) {
void* result;
ret = pthread_join(m_threads[i], &result);
............................................................................
m_task_cond_var.broadcast();
}
................................................................
return m_tasks.size();
@hongliuliao 非常感谢开源这么好的项目,我把编译成功后的ehttp给其他项目使用时cmake编译一直卡在下面(编译环境ubuntu16.04,Threads库在其他项目中运行正常):
/home/suneliw/Downloads/ehttp/output/lib/libehttp.a(http_server.o): In function HttpServer::start_async()': /home/suneliw/Downloads/ehttp/src/http_server.cpp:107: undefined reference to pthread_create'
cmake结果如下:
-- Check for working CXX compiler: /usr/bin/g++-7
-- Check for working CXX compiler: /usr/bin/g++-7 -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
Build type: Release
-- Looking for C++ include pthread.h
-- Looking for C++ include pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - not found
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE
-- Configuring done
-- Generating done
### 测试环境
Win10 + WSL + Ubuntu16.04 x64 + cmake
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
cmake version 3.14.5
CMake suite maintained and supported by Kitware (kitware.com/cmake).