8

sigaction を使用してページ フォールト例外を処理します。ハンドラー関数は次のように定義されます。

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

そのため、 info->si_addrを読み取ることで、ページ フォールト アドレスを簡単に取得できます。

問題は、この操作がメモリのREADWRITEかを知る方法です。

_contextパラメーターのタイプは、/usr/include/sys/ ucontext.hで定義されているucontext_tであることがわかりました。

mcontext_t にはcr2フィールドが定義されていますが、残念ながらx86_64が定義されていない場合にのみ利用可能であるため、cr2 を使用して読み取り/書き込み操作を識別することができませんでした。

別の方法として、/usr/include/bits/sigcontext.h に定義されているsigcontextという名前の構造体があります。 この構造体には cr2 フィールドが含まれています。しかし、どこで入手できるかわかりません。

4

3 に答える 3

7

ucontext の mcontext 構造体と err レジスタを参照することで、x86_64 でこれを確認できます。

void pf_sighandler(int sig, siginfo_t *info, ucontext_t *ctx) {
    ...
    if (ctx->uc_mcontext.gregs[REG_ERR] & 0x2) {
        // Write fault
    } else {
        // Read fault
    }
    ...
}
于 2014-04-27T20:58:44.623 に答える
6

カーネル関数 からの SIGSEGV の生成はarch/x86/mm/fault.c次のとおりです: http://lxr.missinglinkelectronics.com/linux+v3.12/arch/x86/mm/fault.c#L760__bad_area_nosemaphore()

 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フィールドがあり、その値も定義されていarch/x86/mm/fault.cます: 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};

したがって、アクセス タイプに関する正確な情報は次の場所に保存されthread_struct.error_codeます

私が見るように、error_codeフィールドは構造体にエクスポートされません( http://man7.org/linux/man-pages/man2/sigaction.2.htmlsiginfo_tで定義されてい ます..si_signoを検索してください)。

だからあなたはできる

  • カーネルをハックしてエクスポートします(または、既にエクスポートされているかどうかを確認しますtsk->thread.error_code。たとえば、.ptrace
  • メモリ アドレスを取得し、読み取り/proc/self/maps、解析し、ページのアクセス ビットをチェックします。ページが存在し、読み取り専用である場合、考えられる唯一の障害は書き込みによるものであり、ページが存在しない場合、両方の種類のアクセスが可能であり、もし... 書き込み専用ページがないはずです。
  • また、失敗した命令のアドレスを見つけて、それを読み取って逆アセンブルすることもできます。
于 2014-04-19T00:12:53.200 に答える