Signal Handling and Reentrancy

C で書かれた昔のプログラムをデバッグ中に 「シグナルハンドラー内で syslog や printf はご法度」というようなコメントに出くわす。引き継ぎ時に知ったかぶりで説明できるように調査。


まずはキーワード「リエントラント(再入可能)」の定義から(wikipedia より)

In computing, a computer program or subroutine is called reentrant if it can be interrupted in the middle of its execution and then safely called again (“re-entered“) before its previous invocations complete executing. The interruption could be caused by an internal action such as a jump or call or by an external action such as a hardware interrupt or signal. Once the reentered invocation completes, the previous invocations will resume correct execution.

signal handling and non-reentrancy

そのものズバリの現象が “Common Weakness Enumeration (CWE)-479: Signal Handler Use of a Non-reentrant Function” で紹介されていた。

syslog のように実行時にメモリを確保する(scratch space = space on the hard disk drive that is dedicated for only temporary storage)関数がハンドラー経由で同時に呼ばれると、メモリのメタデータを破壊してしまい、 undefined で 場合によっては exploitable な状態になる。

glibc のマニュアルでは Signal Handling -> Defining Handlers -> Signal Handling and Nonreentrant Functions に記載がある。

OpenBSD ではこの問題を防ぐために syslog の reentrant バージョンの syslog_r というのが存在する。

recommended programming practices
IBM DeveloperWorks では問題の起きる2例(Signals and non-reentrant functions & Non-reentrant functions and static variables)とsuggested practice が紹介されている。

Use reentrant functions for safer signal handling — How and when to employ reentrancy to keep your code bug free @ IBM DeveloperWorks

なお、DeveloperWorks  の解説記事 “Signals and non-reentrant functions” の Listing 1 の次のプログラムを実行したところ


struct two_int { int a, b; } data;

void signal_handler(int signum){
  printf ("%d, %d\n", data.a, data.b);
  alarm (1);

int main (void){
  static struct two_int zeros = { 0, 0 }, ones = { 1, 1 };
  signal (SIGALRM, signal_handler);
  data = zeros;
  alarm (1);

  while (1)
    {data = zeros; data = ones;}

Kernel 2.6.9-5 & GLIBC 2.3.4 では data = zeros または data = ones の変数操作が複数ステップで行われているらしく、期待通りの問題が起きたが、Kernel 2.6.32-24 & GLIBC 2.11.1 では割り込み無しに1ステップで(=アトミックに)行われているらしく、問題が発生しなかった。(glibc のバージョンは $ ldd –version で調べられる)



ながらく積ん読状態だった 冨永 和人権藤 克彦 著の「例解UNIXプログラミング教室」(2007, ピアソンエデュケーション)の §9.11「競合状態:シグナル処理が難しい理由」(pp.300-312)に関連する記述がある。

著:冨永 和人、権藤 克彦

Tagged with: , , ,
Posted in linux

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: