2013-07-16 16 views
5

tôi sử dụng sigaction để xử lý ngoại lệ lỗi trang, và các chức năng xử lý là defind như thế này:Làm thế nào để xác định đọc hoặc viết hoạt động của lỗi trang khi sử dụng bộ xử lý sigaction trên SIGSEGV (LINUX)

void sigaction_handler(int signum, siginfo_t *info, void *_context) 

Vì vậy, nó là dễ dàng nhận được địa chỉ lỗi trang bằng cách đọc thông tin-> si_addr.

Câu hỏi đặt ra là, làm thế nào để biết liệu hoạt động này là bộ nhớ ĐỌC hoặc VIẾT?

tôi thấy loại _context tham số là ucontext_t quy định tại/usr/include/sys/ucontext.h

Có một lĩnh vực CR2 quy định tại mcontext_t, nhưng Unforunately, nó chỉ là sẵn khi x86_64 không được xác định, vì vậy tôi không thể sử dụng cr2 để xác định các hoạt động đọc/ghi.

On anotherway, có một struct tên sigcontext quy định tại/usr/include/bit/sigcontext.h struct này chứa CR2 lĩnh vực. Nhưng tôi không biết phải lấy đâu.

Trả lời

6

Đây là thế hệ của SIGSEGV từ kernel arch/x86/mm/fault.c, __bad_area_nosemaphore() chức năng: http://lxr.missinglinkelectronics.com/linux+v3.12/arch/x86/mm/fault.c#L760

760    tsk->thread.cr2   = address; 
761    tsk->thread.error_code = error_code; 
762    tsk->thread.trap_nr  = X86_TRAP_PF; 
763 
764    force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0); 

error_code lĩnh vực, và nó giá trị được định nghĩa trong arch/x86/mm/fault.c quá: http://lxr.missinglinkelectronics.com/linux+v3.12/arch/x86/mm/fault.c#L23

23/* 
    24 * Page fault error code bits: 
    25 * 
    26 * bit 0 == 0: no page found  1: protection fault 
    27 * bit 1 == 0: read access   1: write access 
    28 * bit 2 == 0: kernel-mode access 1: user-mode access 
    29 * bit 3 ==       1: use of reserved bit detected 
    30 * bit 4 ==       1: fault was an instruction fetch 
    31 */ 
    32enum x86_pf_error_code { 
    33 
    34  PF_PROT   =    1 << 0, 
    35  PF_WRITE  =    1 << 1, 
    36  PF_USER   =    1 << 2, 
    37  PF_RSVD   =    1 << 3, 
    38  PF_INSTR  =    1 << 4, 
    39}; 

Vì vậy, thông tin chính xác về loại truy cập được lưu trữ trong thread_struct.error_code: http://lxr.missinglinkelectronics.com/linux+v3.12/arch/x86/include/asm/processor.h#L470

Trường error_code không được xuất khẩu vào siginfo_t struct như tôi thấy (nó được định nghĩa trong http://man7.org/linux/man-pages/man2/sigaction.2.html .. tìm kiếm si_signo).

Vì vậy, bạn có thể

  • Hack hạt nhân để xuất khẩu tsk->thread.error_code (hoặc kiểm tra, là nó xuất khẩu đã hay không, ví dụ như trong ptrace)
  • Lấy địa chỉ bộ nhớ, đọc /proc/self/maps, phân tích chúng và kiểm tra các bit truy cập trên trang. Nếu trang có mặt và chỉ đọc, lỗi duy nhất có thể là từ việc viết, nếu trang không có mặt cả hai loại quyền truy cập là có thể, và nếu ... không nên có các trang chỉ ghi.
  • Ngoài ra, bạn có thể thử tìm địa chỉ của hướng dẫn không thành công, đọc nó và tháo rời.
+2

Thông tin error_code có thể được truy cập thông qua: ((ucontext_t *) ngữ cảnh) -> uc_mcontext.gregs [REG_ERR]. Nó được thông qua bởi phần cứng trên ngăn xếp, sau đó được truyền tới bộ xử lý tín hiệu bởi hạt nhân, vì hạt nhân truyền toàn bộ 'khung '. –

+0

M. Alaggan, phần cứng nào? – osgx

+0

Tôi đã thử trên x86-64. –

3

Bạn có thể kiểm tra điều này trong x86_64 bằng cách tham khảo struct mcontext của ucontext và đăng ký err:

void pf_sighandler(int sig, siginfo_t *info, ucontext_t *ctx) { 
    ... 
    if (ctx->uc_mcontext.gregs[REG_ERR] & 0x2) { 
     // Write fault 
    } else { 
     // Read fault 
    } 
    ... 
} 
4

Thông tin error_code có thể được truy cập thông qua:

err = ((ucontext_t*)context)->uc_mcontext.gregs[REG_ERR] 

Nó được thông qua phần cứng trên ngăn xếp, sau đó được truyền tới bộ xử lý tín hiệu bởi hạt nhân, vì hạt nhân truyền toàn bộ `khung '. Sau đó,

bool write_fault = !(err & 0x2); 

sẽ đúng nếu truy cập là quyền truy cập ghi và sai cách khác.

Các vấn đề liên quan