Re: [Q] source code of connect system call
河野真治 @ 琉球大学情報工学です。
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
河野真治 @ 琉球大学工学部情報工学科
Fnews-brouse 1.9(20180406) -- by Mizuno, MWE <mwe@ccsf.jp>
GnuPG Key ID = ECC8A735
GnuPG Key fingerprint = 9BE6 B9E9 55A5 A499 CD51 946E 9BDC 7870 ECC8 A735