2017-09-18 7 views
2

clang manual의 -ftrap-function 플래그를 사용하여 사용자 지정 처리기에서 CFI (call frame information) 오류를 catch하려고합니다. 이 예는 최적화하지 않고 빌드 할 때clang-linux : 충돌없이 CFI 오류를보고합니다. ftrap-function 및 -O2

-ftrap-function=CatchCfi -fsanitize=cfi-vcall -fvisibility=hidden -fsanitize=cfi-derived-cast -fsanitize=cfi-unrelated-cast -flto=thin 

그것은 내가 원하는대로 작동합니다

#include <stdio.h> 
#include <stdlib.h> 

__attribute__((used)) extern "C" void CatchCfi() { 
    printf("catched\n"); 
} 

struct Foo { 
    Foo(const char* s) : command(s) {} 
    virtual ~Foo() {} 

    void fooStuff() { printf("fooStuff\n"); } 

    const char* command; 
}; 

struct Bar { 
    Bar(const char* s) : name(s) {} 
    virtual ~Bar() {} 

    void barStuff() { printf("barStuff\n"); } 

    const char* name; 
}; 

enum class WhichObject { FooObject, BarObject }; 

static void* allocator(WhichObject w, const char* arg) { 
    switch (w) { 
    case WhichObject::FooObject: 
     return new Foo(arg); 
    case WhichObject::BarObject: 
     return new Bar(arg); 
    } 
} 

int main(int argc, const char* argv[]) { 
    void* ptr = nullptr; 
    (void)(argc); 
    (void)(argv); 

    ptr = allocator(WhichObject::BarObject, "system(\"/bin/sh\")"); 

    Foo* fooptr = static_cast<Foo*>(ptr); 
    fooptr->fooStuff(); 

    printf("not printed when compiled with -O2\n"); 
    return 0; 
} 

내가이 CFI 관련 연타 옵션을 구축 : 여기

는 CFI 오류를 생성하는 기본적인 예입니다 . 출력 :

catched 
fooStuff 
not printed when compiled with -O2 

문제는 내가 -O2 옵션을 빌드 할 때 나타납니다

catched 
Trace/breakpoint trap (core dumped) 

GDB CatchCfi 반환 직후 프로그램이 SIGTRAP을 받고 있음을 보여줍니다

(gdb) r 
Starting program: /home/romex/browser/src/out/debug/hello_cfi 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 
catched 

Program received signal SIGTRAP, Trace/breakpoint trap. 
0x000000000020118a in ??() 
(gdb) bt 
#0 0x000000000020118a in ??() 
#1 0x00000000002010f0 in frame_dummy() 
#2 0x00007ffff748e830 in __libc_start_main (main=0x201180 <main(int, char const**)>, argc=1, argv=0x7fffffffde18, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, 
    stack_end=0x7fffffffde08) at ../csu/libc-start.c:291 
#3 0x0000000000201029 in _start() 
Warning: the current language does not match this frame. 
(gdb) 

방법 고쳐? 누군가가 ftrap-function 플래그를 다루는 성공 사례가 있는지 궁금합니다. 이 오류를 수정하는 특정 최적화 플래그가있을 수 있습니까? 감사합니다. . ptr 이후

답변

0

Foo* fooptr = static_cast<Foo*>(ptr); 
fooptr->fooStuff(); 

이 정의되지 않은 동작이며, 컴파일러는 당신이 그를가 예상대로 작동 할 필요가 없을 것입니다하는 Bar에 대한 포인터입니다.

+0

나는 의도적으로 CFI 살균제를 작동시키기 위해이 작업을 수행했습니다. – rkuksin

+0

@rkuksin 미안하지만 C++에는 더 이상 말할 것도 없습니다. 일단 규칙을 위반하면 의도적으로 또는하지 않으면 [정의되지 않은 동작] (http://en.cppreference.com/w/cpp/language/ub)을 호출하면 아무 것도 보장되지 않습니다. 프로그램이 충돌하거나 [비강 악마] (http://www.catb.org/jargon/html/N/nasal-demons.html)가 나타날 수 있습니다. 그리고 할 수있는 일은 없습니다. – YSC

0

코드가 예상대로 작동하도록 업데이트했습니다. 내 환경이 SIGTRAP을 키우지 않아서 __builtin_trap() 콜을 삽입했습니다. @YSC에 언급 된 바와 같이 그것은 UB입니다. 트랩 기능이 반환 된 후에 프로그램을 계속할 수 없으면 SIGTRAP이 발생하기 전에 프로그램을 잘 알려진 양호한 상태로 복원해야합니다.

#include <setjmp.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

jmp_buf env; 

__attribute__((used)) extern "C" void CatchCfi() { 
    printf("catched\n"); 
    longjmp(env, 1); 
} 

struct Foo { 
    Foo(const char* s) : command(s) {} 
    virtual ~Foo() {} 

    void fooStuff() { printf("fooStuff\n"); } 

    const char* command; 
}; 

struct Bar { 
    Bar(const char* s) : name(s) {} 
    virtual ~Bar() {} 

    void barStuff() { printf("barStuff\n"); } 

    const char* name; 
}; 

enum class WhichObject { FooObject, BarObject }; 

static void* allocator(WhichObject w, const char* arg) { 
    switch (w) { 
    case WhichObject::FooObject: 
     return new Foo(arg); 
    case WhichObject::BarObject: 
     return new Bar(arg); 
    } 
} 

int main(int argc, const char* argv[]) { 
    void* ptr = nullptr; 
    (void)(argc); 
    (void)(argv); 

    ptr = allocator(WhichObject::BarObject, "system(\"/bin/sh\")"); 

    int val = setjmp(env); 

    if (!val) { 
    Foo* fooptr = static_cast<Foo*>(ptr); 
    fooptr->fooStuff(); 
    __builtin_trap(); 
    } 

    printf("not printed when compiled with -O2\n"); 
    return 0; 
}