Linux sys コールを傍受するにはどうすればよいですか?

LD_PRELOAD トリックを使用できない/使用したくないのはなぜですか?

コード例:

/*
 * File: soft_atimes.c
 * Author: D.J. Capelis
 *
 * Compile:
 * gcc -fPIC -c -o soft_atimes.o soft_atimes.c
 * gcc -shared -o soft_atimes.so soft_atimes.o -ldl
 *
 * Use:
 * LD_PRELOAD="./soft_atimes.so" command
 *
 * Copyright 2007 Regents of the University of California
 */

#define _GNU_SOURCE
#include <dlfcn.h>
#define _FCNTL_H
#include <sys/types.h>
#include <bits/fcntl.h>
#include <stddef.h>

extern int errorno;

int __thread (*_open)(const char * pathname, int flags, ...) = NULL;
int __thread (*_open64)(const char * pathname, int flags, ...) = NULL;

int open(const char * pathname, int flags, mode_t mode)
{
    if (NULL == _open) {
        _open = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open");
    }
    if(flags & O_CREAT)
        return _open(pathname, flags | O_NOATIME, mode);
    else
        return _open(pathname, flags | O_NOATIME, 0);
}

int open64(const char * pathname, int flags, mode_t mode)
{
    if (NULL == _open64) {
        _open64 = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open64");
    }
    if(flags & O_CREAT)
        return _open64(pathname, flags | O_NOATIME, mode);
    else
        return _open64(pathname, flags | O_NOATIME, 0);
}

私が理解していることから...それはほとんどLD_PRELOADトリックまたはカーネルモジュールです。関数をトラップできるエミュレーターで実行したり、実際のバイナリでコードを書き直して関数をトラップしたりしない限り、妥協点はあまりありません。

プログラムを変更できず、カーネルを変更できない (または変更したくない) と仮定すると、アプリケーションがかなり標準的であり、実際には悪意を持って通り抜けようとしているアプリケーションではない場合、LD_PRELOAD アプローチが最適です。あなたの傍受。 (その場合、他のテクニックのいずれかが必要になります。)


Valgrind を使用して、関数呼び出しをインターセプトできます。完成した製品でシステム コールをインターセプトする必要がある場合、これは役に立ちません。ただし、開発中に傍受しようとする場合は、非常に便利です。私はこの手法を頻繁に使用してハッシュ関数をインターセプトし、返されたハッシュをテスト目的で制御できるようにしました。

ご存じないかもしれませんが、Valgrind は主にメモリ リークやその他のメモリ関連のエラーを検出するために使用されます。しかし、基盤となるテクノロジーは基本的に x86 エミュレーターです。プログラムをエミュレートし、malloc/free などの呼び出しをインターセプトします。良いことに、使用するために再コンパイルする必要はありません。

Valgrind には、関数ラッピングと呼ばれる機能があります。 、関数の傍受を制御するために使用されます。詳細については、Valgrind マニュアルのセクション 3.2 を参照してください。好きな関数の関数ラッピングを設定できます。呼び出しがインターセプトされると、指定した代替関数が呼び出されます。


一部のアプリケーションは strace/ptrace をだまして実行しないようにすることができるため、私が持っていた唯一の現実的なオプションは systemtap を使用することです

Systemtap は、ワイルドカード マッチングが原因で必要に応じて一連のシステム コールをインターセプトできます。 Systemtap は C ではなく、別の言語です。基本モードでは、systemtap は愚かなことをしないようにする必要がありますが、必要に応じて開発者が C を使用できるようにする「エキスパート モード」で実行することもできます。

カーネルにパッチを適用する必要はありません (または、少なくともパッチを適用する必要はありません)。モジュールがコンパイルされたら、テスト/開発ボックスからコピーして、(insmod を介して) 運用システムに挿入できます。

systemtap に引っかかるのを回避/回避する方法を見つけた Linux アプリケーションをまだ見つけていません。