河野真治 @ 琉球大学情報工学です。

In article <40A4D03A.3B299CDA@ht.sakura.ne.jp>, IIJIMA Hiromitsu <delmonta@ht.sakura.ne.jp> writes
> 本題は解決の方向に向かっているとして、問題部分はまず libc にあるはずです。

「まず」としては正解なんだけど....

> x86 Linux の場合、アセンブラレベルでのシステムコールの呼び出しには、
> レジスタに値をセットして int 0xNN 命令を使うと記憶しています。
> バッファ・オーバーフローの exploit code ではこの直接呼び出しが一般的です。

それを見たいんだったら、gdb で、一回connect を呼び出してから、
x/20i connect で disassemeble するのが簡単です。何故一回呼び出すか
というと、dynamic link されているから...

で、
0x400ff2f0 <__libc_connect>:    mov    %ebx,%edx
0x400ff2f2 <__libc_connect+2>:  mov    $0x66,%eax
0x400ff2f7 <__libc_connect+7>:  mov    $0x3,%ebx
0x400ff2fc <__libc_connect+12>: lea    0x4(%esp,1),%ecx
0x400ff300 <__libc_connect+16>: int    $0x80
0x400ff302 <__libc_connect+18>: mov    %edx,%ebx
0x400ff304 <__libc_connect+20>: cmp    $0xffffff83,%eax
0x400ff307 <__libc_connect+23>: jae    0x400ff30a <__libc_connect+26>
みたいなのが見れるので... 0x66 = 102 がシステムコール番号
だってのがわかります。

libc のソース見てもいいんだけどさ。

> #アセンブラソースも grep しました?>>柏崎さん

これもかなり正解に近いんですが、cpp を通るので、.s でなくて、.S 
だったりします。Linux には、システムコールの番号は、libc と
entry.S に分離して記述されているんです。BSDだと、このあたりは
config がやるんですが...
    linux-2.6.5/arch/i386/kernel/entry.S


> で、それを確認したら今度はカーネルソースをあたる、と。

で、そこを見ても connect というのはなくて... 102 という番号を頼りに、

        .long sys_fstatfs       /* 100 */
        .long sys_ioperm
        .long sys_socketcall
        .long sys_syslog

とかいうのがあるので、sys_socketcall だってのがわかるわけですね。
で、そいつは、socket.c にあって、
    linux-2.6.5/net/socket.c

        switch(call) 
        {
                case SYS_SOCKET:
                        err = sys_socket(a0,a1,a[2]);
                        break;
                case SYS_BIND:
                        err = sys_bind(a0,(struct sockaddr __user *)a1, a[2]);
                        break;
                case SYS_CONNECT:
                        err = sys_connect(a0, (struct sockaddr __user *)a1, a[2])
;
                        break;
ってなっているので、ようやっと、sys_connect にいるとわかる。
最初から別なシステムコールにしなかったのは、拡張性を考えてかな。

でも、それでも、行きつけない。何故なら、

        err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen,
                                 sock->file->f_flags);

となっていて、実は、indirect call だから。そりゃそうなんで、connect
といっても、TCPとは限らない。decnet (ふる〜) かも知れないし。
もちろん、sock はファイルディスクリプタテーブルを指していて、ops
は、そこに入っている関数へのポインタの表です。

この表は、デバイスとプロトコルに分散しているので... このindirect
callがどこを指しているかを見付けるのは、割と楽しい作業です...
この構造体に代入しているところを見付けるのは大変なので。

で、ソースを追わずに、remote debug するのが直接的でよろしい。
kernel をgdbでのぞいても良いですが... Virtual PC でやりたい
んだけど、まだ、やってないです。

結果的には、

struct proto_ops inet_stream_ops = {
    .....
        .connect =      inet_stream_connect,

とかいうのがあって、(だんだんめんどくさくなってきた...)
あと何段かindirectがあって、

 In /Users/kono/src/linux/linux-2.6.5/net/ipv4/tcp_ipv4.c
2623:   .name           =       "TCP",
2624:   .close          =       tcp_close,
2625:   .connect        =       tcp_v4_connect,
2626:   .disconnect     =       tcp_disconnect,
2627:   .accept         =       tcp_accept,

ってのがあるから、

 In /Users/kono/src/linux/linux-2.6.5/net/ipv4/tcp_ipv4.c
753:/* This will initiate an outgoing connection. */
754:int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
755:{
756:    struct inet_opt *inet = inet_sk(sk);

だってのがわかりますね。

---
Shinji KONO @ Information Engineering, University of the Ryukyus
河野真治 @ 琉球大学工学部情報工学科