Not only is the Internet dead, it's starting to smell really bad.:2014年09月22日分

2014/09/22(Mon)

[NetBSD] debugging dlsym(3) その3

@あらすじ

LD_PRELOAD した場合だけ dlsym(3) がおかしいっぽいね、仕方ないね。

@【教養】 ld.so(1) が呼ばれるまで何が行われるのか? 【時間かせぎ】

今回のバグに無関係なんですが、お嬢様の嗜みとしてね? ld.so(1)が実行されるまでの流れをさらっと説明。

@shell → libc

まず shell は入力された環境変数やコマンドラインそしてオプション及び引数を execve(2) に渡します、以下/bin/shの コード

161 STATIC void
162 tryexec(char *cmd, char **argv, char **envp, int vforked)
163 {
164         int e;
165 #ifndef BSD
166         char *p;
167 #endif
168
169 #ifdef SYSV
170         do {
171                 execve(cmd, argv, envp);
172         } while (errno == EINTR);
173 #else
174         execve(cmd, argv, envp);
175 #endif

@libc → kernel

execve(2) はセクション 2 すなわちシステムコールで libc 側の実装はただの kernel へのプロキシですので、すぐ飛びます。 飛び先は kernel_exec.c の sys_execve()がそれっすね。

518 /*
519  * exec system call
520  */
521 int
522 sys_execve(struct lwp *l, const struct sys_execve_args *uap, register_t *retval)
523 {
...

execve(2)は、コマンドラインで渡されたファイルについていろいろなチェックを行うのですが、今回は実行形式かどうかのチェックについて詳しくみていこうかと。

@NetBSDにおいてサポートされる実行形式は、どのように判別されるのか?

まず NetBSD kernelでは、とある実行形式をサポートするには execsw 構造体というインタフェースを実装したサブクラスを提供する必要があります。

150 struct execsw {
151 	u_int	es_hdrsz;		/* size of header for this format */
152 	exec_makecmds_fcn es_makecmds;	/* function to setup vmcmds */
...
170 };

ネイティブでサポートされる実行形式、そしてサブクラスの実装は

  • a.out形式 ... EXEC_AOUT, exec_aout.c
    9 options 	EXEC_AOUT	# exec a.out binaries
    ...
    
    59 static struct execsw exec_aout_execsw = {
    ...
    
  • ECOFF形式 ... EXEC_COFF, exec_ecoff.c
    12 options 	EXEC_ECOFF	# (native) ECOFF binary support
    ...
    
    60 static struct execsw exec_ecoff_execsw = {
    ...
    
  • ELF(32bit)形式 ... EXEC_ELF32, exec_elf32.c
    10 options 	EXEC_ELF32	# exec ELF binaries
    ...
    
    54 static struct execsw exec_elf32_execsw[] = {
    ...
    
  • ELF(64bit)系形式 ... EXEC_ELF64, exec_elf64.c
    9 options 	EXEC_ELF64	# exec ELF binaries
    ...
    
    54 static struct execsw exec_elf64_execsw[] = {
    ...
    
  • #! スクリプト ...EXEC_SCRIPT, exec_script.c
    11 options 	EXEC_SCRIPT	# exec #! scripts
    ...
    
    59 static struct execsw exec_script_execsw = {
    ...
    

あたりを参照ですやね、EXEC_* だけでなく他にもLinux等の他OSバイナリ実行サポートの COMPAT_* でも いろいろ取り揃えております(動くとはいっていない) *1

こいつらは execsw のサブクラスであるだけでなく、カーネルモジュールでもあるので

  • MODULE() マクロを宣言し、自身をカーネルモジュールとして登録
  • *_modcmd という初期化/終了時/状態取得インタフェースを実装

ちゅーこともしとります。

52 MODULE(MODULE_CLASS_EXEC, exec_elf64, DEP);
...
89 static int
90 exec_elf64_modcmd(modcmd_t cmd, void *arg)
91 {
92 
93 	switch (cmd) {
94 	case MODULE_CMD_INIT:
...

詳しくは module(9) 読んでどうぞ。

@次回

この execsw と module インタフェースがどのように使われていくかを読んでいきます。

*1:ちな昔はDarwin/MACHバイナリを動かす為にMACH-O形式、Windows以下同文PECOFF形式とかのサポートもあったんですが メンテが滞るとの理由でいつものモヒカンが ヒャッハーして削られてます、南無。