この前のYLUGで日立の平松氏が以下のような発表をしていた. 彼は今kpatchに注目している.
http://www.slideshare.net/mhiramat/ylug-110th-reading-kpatch
kpatchはftraceの機能を使っている. kpatchは「関数を, 修正済関数に実行時に置き換える」機能を提供する.
完全に理解したわけではないが, 理解を適当に列挙する.
- ftrace_opsのフラグになんちゃらREGSを設定すると, 「pt_regsを使うコールバックにジャンプせよ」ということになる.
FTRACE_REGS_ADDR
にこのアドレスが入っている. アドレスには,ftrace_regs_caller
という関数がある. - 以下のコードは, x86のものであり, 何をしているのかどこで呼ばれるのかも分からないが, コメントだけは役に立つので抜粋した. 共通部のコードでは, __ftrace_replace_codeの中で, REGSが指定されているかどうかで
ftrace_modify_call
を呼ぶアドレスを決定している.
|
|
- たぶん, ftrace_opsっていうのは, mcountから飛んだ先で呼ばれるftraceの共通部の処理であろう.
- kpatchは, ftrace_opsのfunc部分で, pt_regsに新しいアドレスを保存する. これがkpatch_ftrace_handler
- ftrace_regs_callerでまずpt_regsがレジスタに保存され, ftrace_regs_callが呼ばれる. ここでpt_regsに格納されている新しいアドレスを使ってスタック上に戻り番地を上書きする(古い関数は二度と呼ばないようにするため).
まとめ
- mcountからftraceの世界にジャンプする.
- そこでftrace_opsの情報に応じて関数単位の書換を行う.
- kpatchは, REGSを指定してftraceの「pt_regsを使ったアドレス書換処理」を利用することによって, ftraceの世界を抜けたあとに新しい関数に飛ぶ.
- (ちなみに)(たぶん)通常はftrace_callが呼ばれて, トレース収集が行われる. こちらは戻り番地書換でなくて, call命令(kpatchを当てたわけではなくて, 今ある関数に戻らないといけない).
ftrace_callerとftrace_callの実装はこんな感じ(x86/kernel/entry_64.S)
|
|
ということでftrace/kpatchマスターとなった.