From owner-freebsd-questions Tue May 15 22:57: 2 2001 Delivered-To: freebsd-questions@freebsd.org Received: from mx01-a.netapp.com (mx01-a.netapp.com [198.95.226.53]) by hub.freebsd.org (Postfix) with ESMTP id 6320837B423 for ; Tue, 15 May 2001 22:56:40 -0700 (PDT) (envelope-from boshea@netapp.com) Received: from frejya.corp.netapp.com (frejya.corp.netapp.com [10.10.20.91]) by mx01-a.netapp.com (8.11.1/8.11.1/NTAP-1.2) with ESMTP id f4G5tlK22428; Tue, 15 May 2001 22:55:47 -0700 (PDT) Received: from shaolin.hq.netapp.com (localhost [127.0.0.1]) by frejya.corp.netapp.com (8.11.1/8.11.1/NTAP-1.2) with ESMTP id f4G5te400295; Tue, 15 May 2001 22:55:40 -0700 (PDT) Received: (from boshea@localhost) by shaolin.hq.netapp.com (8.9.3/8.9.3) id XAA64016; Tue, 15 May 2001 23:03:54 -0700 (PDT) (envelope-from boshea) Date: Tue, 15 May 2001 23:03:54 -0700 From: "Brian O'Shea" To: Matthew Emmerton Cc: John Indra , freebsd-questions@FreeBSD.ORG, freebsd-current@FreeBSD.ORG Subject: Re: My network is dead because of this program :( Message-ID: <20010515230354.A62767@shaolin.hq.netapp.com> Reply-To: boshea@ricochet.net Mail-Followup-To: Brian O'Shea , Matthew Emmerton , John Indra , freebsd-questions@FreeBSD.ORG, freebsd-current@FreeBSD.ORG References: <20010516092035.A79109@office.naver.co.id> <00b401c0ddb2$23b2c710$1200a8c0@gsicomp.on.ca> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="3uo+9/B/ebqu+fSQ" Content-Disposition: inline User-Agent: Mutt/1.2.4i In-Reply-To: <00b401c0ddb2$23b2c710$1200a8c0@gsicomp.on.ca>; from matt@gsicomp.on.ca on Tue, May 15, 2001 at 10:44:32PM -0400 Sender: owner-freebsd-questions@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG --3uo+9/B/ebqu+fSQ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Tue, May 15, 2001 at 10:44:32PM -0400, Matthew Emmerton wrote: [...] > > After going to single user mode, cause I can't kill the offending > > program once it is running in multiuser mode (even kill -9 won't > > work ... Probably because the program is forking and you can't kill it's children fast enough. > > Can anyone help me trace what the program does? And how can I > > prevent the program to DoS my network interface? Even when the > > program is started by unprivileged user, it works, it DoS my network > > interface. Is this a bug? [...] Unfortunately it looks like the program forks, does it's thing, and then each child forks too. There is a call to sleep probably to introduce a delay so that things don't go completely crazy right away, but processes build up exponentially with each child process forking, so eventually resources get exhausted. Take a look at the attachment for more details. -brian -- Brian O'Shea --3uo+9/B/ebqu+fSQ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="x.disasm" It looks like the program basically does this, in pseudo-code: main() { int pid; while (1) { pid = fork(); if (pid == 0) { /* child process */ socketpair(); /* get two AF_LOCAL sockets */ setsockopt(); /* set receive buffer size on one socket */ setsockopt(); /* set send buffer size on other socket */ fcntl(); /* set non-blocking I/O on both sockets */ fcntl(); write(); /* write some data from one socket to the other */ write(); } /* else we're in the parent, or fork() failed */ sleep(); /* sleep a while */ } return; } (gdb) disassemble main Dump of assembler code for function main: 0x804865c
: push %ebp 0x804865d : mov %esp,%ebp 0x804865f : sub $0x32018,%esp 0x8048665 : nop We're probably in an infinite loop here. 0x8048666 : movl $0x0,0xfffffff4(%ebp) 0x804866d : lea 0x0(%esi),%esi 0x8048670 : cmpl $0x12,0xfffffff4(%ebp) 0x8048674 : jle 0x8048678 0x8048676 : jmp 0x8048690 The first thing we do in the loop is call fork(). 0x8048678 : call 0x80484c0 Then we check its return value. 0x804867d : mov %eax,%eax 0x804867f : test %eax,%eax 0x8048681 : je 0x8048688 0x8048683 : jmp 0x8048690 0x8048685 : lea 0x0(%esi),%esi It looks like the parent calls fork in a loop. The child processes that it creates continue. 0x8048688 : incl 0xfffffff4(%ebp) 0x804868b : jmp 0x8048670 0x804868d : lea 0x0(%esi),%esi 0x8048690 : add $0xfffffff4,%esp Sleep for 5 seconds ... 0x8048693 : push $0x5 0x8048695 : call 0x8048490 0x804869a : add $0x10,%esp 0x804869d : lea 0x0(%esi),%esi 0x80486a0 : jmp 0x80486a8 0x80486a2 : jmp 0x80487ac 0x80486a7 : nop Child calls socketpair with the following arguments: int socketpair(int domain, int type, int protocol, int *sv) int domain = 0x1 (AF_LOCAL) int type = 0x1 (SOCK_STREAM) int protocol = 0x0 (typically 0 for AF_LOCAL) int *sv = address of an array of two file descriptors Push arguments to socketpair onto stack and call socketpair again: 0x80486a8 : lea 0xfffffff8(%ebp),%eax 0x80486ab : push %eax 0x80486ac : push $0x0 0x80486ae : push $0x1 0x80486b0 : push $0x1 0x80486b2 : call 0x80484e0 0x80486b7 : add $0x10,%esp 0x80486ba : mov %eax,%eax Note: It's strange that the address family is AF_LOCAL. I wouldn't think this would cause the problems that you are seeing with the xl0 device, unless AF_LOCAL sockets consume some of the same resources that this driver also consumes, and thus starves it of those resources. I don't know enough about FreeBSD to tell. Looks like we're checking the return value of socketpair. The value 0xffffffff is -1, which is what socketpair returns if it fails. 0x80486bc : cmp $0xffffffff,%eax 0x80486bf : jne 0x80486c8 0x80486c1 : jmp 0x80487ac If it fails, jumps ahead to a call to pause (below at main+336) 0x80486c6 : mov %esi,%esi 0x80486c8 : movl $0x32000,0xfffffff4(%ebp) 0x80486cf : add $0xfffffff4,%esp Push arguments to setsockopt onto stack and call setsockopt: 0x80486d2 : push $0x4 0x80486d4 : lea 0xfffffff4(%ebp),%eax 0x80486d7 : push %eax 0x80486d8 : push $0x1002 0x80486dd : push $0xffff 0x80486e2 : mov 0xfffffff8(%ebp),%eax 0x80486e5 : push %eax 0x80486e6 : call 0x80484b0 int setsockopt( int s, /* socket descriptor */ int level, /* 0xffff (SOL_SOCKET) */ int optname, /* 0x1002 (SO_RCVBUF) */ void *optval, /* pointer to a buffer containing optval */ socklen_t *optlen /* pointer to buffer length */ ) Pop arguments to first setsockopt call off stack. 0x80486eb : add $0x20,%esp 0x80486ee : add $0xfffffff4,%esp Same thing, this time with optname 0x1001 (SO_SNDBUF). 0x80486f1 : push $0x4 0x80486f3 : lea 0xfffffff4(%ebp),%eax 0x80486f6 : push %eax 0x80486f7 : push $0x1001 0x80486fc : push $0xffff 0x8048701 : mov 0xfffffff8(%ebp),%eax 0x8048704 : push %eax 0x8048705 : call 0x80484b0 0x804870a : add $0x20,%esp 0x804870d : add $0xfffffff4,%esp Pop arguments to second setsockopt call off stack. Probably the same call to setsockopt follows, except for the other socket in the socketpair. 0x8048710 : push $0x4 0x8048712 : lea 0xfffffff4(%ebp),%eax 0x8048715 : push %eax 0x8048716 : push $0x1002 0x804871b : push $0xffff 0x8048720 : mov 0xfffffffc(%ebp),%eax 0x8048723 : push %eax 0x8048724 : call 0x80484b0 0x8048729 : add $0x20,%esp 0x804872c : add $0xfffffff4,%esp 0x804872f : push $0x4 0x8048731 : lea 0xfffffff4(%ebp),%eax 0x8048734 : push %eax 0x8048735 : push $0x1001 0x804873a : push $0xffff 0x804873f : mov 0xfffffffc(%ebp),%eax 0x8048742 : push %eax 0x8048743 : call 0x80484b0 0x8048748 : add $0x20,%esp 0x804874b : add $0xfffffffc,%esp 0x804874e : push $0x4 0x8048750 : push $0x4 0x8048752 : mov 0xfffffff8(%ebp),%eax 0x8048755 : push %eax 0x8048756 : call 0x8048500 fcntl( int fd, /* socket descriptor */ int cmd, /* 0x4 (O_NONBLOCK) */ ... ) Puts the socket into non-blocking I/O mode. 0x804875b : add $0x10,%esp 0x804875e : add $0xfffffffc,%esp Pop pop... Same thing for other socket. 0x8048761 : push $0x4 0x8048763 : push $0x4 0x8048765 : mov 0xfffffffc(%ebp),%eax 0x8048768 : push %eax 0x8048769 : call 0x8048500 fcntl( int fd, int cmd, ... ) 0x804876e : add $0x10,%esp 0x8048771 : add $0xfffffffc,%esp Push arguments to write onto stack. 0x8048774 : push $0x32000 0x8048779 : lea 0xfffcdff4(%ebp),%eax 0x804877f : push %eax 0x8048780 : mov 0xfffffff8(%ebp),%eax 0x8048783 : push %eax 0x8048784 : call 0x80484a0 0x8048789 : add $0x10,%esp 0x804878c : add $0xfffffffc,%esp write( int d, /* socket descriptor */ const void *buf, /* buffer to write */ size_t nbytes /* number of bytes to write (204800) */ ) Call write again. 0x804878f : push $0x32000 0x8048794 : lea 0xfffcdff4(%ebp),%eax 0x804879a : push %eax 0x804879b : mov 0xfffffffc(%ebp),%eax 0x804879e : push %eax 0x804879f : call 0x80484a0 0x80487a4 : add $0x10,%esp 0x80487a7 : jmp 0x80486a0 0x80487ac : call 0x8048480 0x80487b1 : xor %eax,%eax 0x80487b3 : jmp 0x80487b8 0x80487b5 : lea 0x0(%esi),%esi 0x80487b8 : leave 0x80487b9 : ret 0x80487ba : nop 0x80487bb : nop End of assembler dump. (gdb) quit --3uo+9/B/ebqu+fSQ-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-questions" in the body of the message