Date: Tue, 15 May 2001 23:03:54 -0700 From: "Brian O'Shea" <boshea@ricochet.net> To: Matthew Emmerton <matt@gsicomp.on.ca> Cc: John Indra <john@office.naver.co.id>, 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> In-Reply-To: <00b401c0ddb2$23b2c710$1200a8c0@gsicomp.on.ca>; from matt@gsicomp.on.ca on Tue, May 15, 2001 at 10:44:32PM -0400 References: <20010516092035.A79109@office.naver.co.id> <00b401c0ddb2$23b2c710$1200a8c0@gsicomp.on.ca>
next in thread | previous in thread | raw e-mail | index | archive | help
--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 <boshea@ricochet.net> --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 <main>: push %ebp 0x804865d <main+1>: mov %esp,%ebp 0x804865f <main+3>: sub $0x32018,%esp 0x8048665 <main+9>: nop We're probably in an infinite loop here. 0x8048666 <main+10>: movl $0x0,0xfffffff4(%ebp) 0x804866d <main+17>: lea 0x0(%esi),%esi 0x8048670 <main+20>: cmpl $0x12,0xfffffff4(%ebp) 0x8048674 <main+24>: jle 0x8048678 <main+28> 0x8048676 <main+26>: jmp 0x8048690 <main+52> The first thing we do in the loop is call fork(). 0x8048678 <main+28>: call 0x80484c0 <fork> Then we check its return value. 0x804867d <main+33>: mov %eax,%eax 0x804867f <main+35>: test %eax,%eax 0x8048681 <main+37>: je 0x8048688 <main+44> 0x8048683 <main+39>: jmp 0x8048690 <main+52> 0x8048685 <main+41>: lea 0x0(%esi),%esi It looks like the parent calls fork in a loop. The child processes that it creates continue. 0x8048688 <main+44>: incl 0xfffffff4(%ebp) 0x804868b <main+47>: jmp 0x8048670 <main+20> 0x804868d <main+49>: lea 0x0(%esi),%esi 0x8048690 <main+52>: add $0xfffffff4,%esp Sleep for 5 seconds ... 0x8048693 <main+55>: push $0x5 0x8048695 <main+57>: call 0x8048490 <sleep> 0x804869a <main+62>: add $0x10,%esp 0x804869d <main+65>: lea 0x0(%esi),%esi 0x80486a0 <main+68>: jmp 0x80486a8 <main+76> 0x80486a2 <main+70>: jmp 0x80487ac <main+336> 0x80486a7 <main+75>: 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 <main+76>: lea 0xfffffff8(%ebp),%eax 0x80486ab <main+79>: push %eax 0x80486ac <main+80>: push $0x0 0x80486ae <main+82>: push $0x1 0x80486b0 <main+84>: push $0x1 0x80486b2 <main+86>: call 0x80484e0 <socketpair> 0x80486b7 <main+91>: add $0x10,%esp 0x80486ba <main+94>: 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 <main+96>: cmp $0xffffffff,%eax 0x80486bf <main+99>: jne 0x80486c8 <main+108> 0x80486c1 <main+101>: jmp 0x80487ac <main+336> If it fails, jumps ahead to a call to pause (below at main+336) 0x80486c6 <main+106>: mov %esi,%esi 0x80486c8 <main+108>: movl $0x32000,0xfffffff4(%ebp) 0x80486cf <main+115>: add $0xfffffff4,%esp Push arguments to setsockopt onto stack and call setsockopt: 0x80486d2 <main+118>: push $0x4 0x80486d4 <main+120>: lea 0xfffffff4(%ebp),%eax 0x80486d7 <main+123>: push %eax 0x80486d8 <main+124>: push $0x1002 0x80486dd <main+129>: push $0xffff 0x80486e2 <main+134>: mov 0xfffffff8(%ebp),%eax 0x80486e5 <main+137>: push %eax 0x80486e6 <main+138>: call 0x80484b0 <setsockopt> 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 <main+143>: add $0x20,%esp 0x80486ee <main+146>: add $0xfffffff4,%esp Same thing, this time with optname 0x1001 (SO_SNDBUF). 0x80486f1 <main+149>: push $0x4 0x80486f3 <main+151>: lea 0xfffffff4(%ebp),%eax 0x80486f6 <main+154>: push %eax 0x80486f7 <main+155>: push $0x1001 0x80486fc <main+160>: push $0xffff 0x8048701 <main+165>: mov 0xfffffff8(%ebp),%eax 0x8048704 <main+168>: push %eax 0x8048705 <main+169>: call 0x80484b0 <setsockopt> 0x804870a <main+174>: add $0x20,%esp 0x804870d <main+177>: 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 <main+180>: push $0x4 0x8048712 <main+182>: lea 0xfffffff4(%ebp),%eax 0x8048715 <main+185>: push %eax 0x8048716 <main+186>: push $0x1002 0x804871b <main+191>: push $0xffff 0x8048720 <main+196>: mov 0xfffffffc(%ebp),%eax 0x8048723 <main+199>: push %eax 0x8048724 <main+200>: call 0x80484b0 <setsockopt> 0x8048729 <main+205>: add $0x20,%esp 0x804872c <main+208>: add $0xfffffff4,%esp 0x804872f <main+211>: push $0x4 0x8048731 <main+213>: lea 0xfffffff4(%ebp),%eax 0x8048734 <main+216>: push %eax 0x8048735 <main+217>: push $0x1001 0x804873a <main+222>: push $0xffff 0x804873f <main+227>: mov 0xfffffffc(%ebp),%eax 0x8048742 <main+230>: push %eax 0x8048743 <main+231>: call 0x80484b0 <setsockopt> 0x8048748 <main+236>: add $0x20,%esp 0x804874b <main+239>: add $0xfffffffc,%esp 0x804874e <main+242>: push $0x4 0x8048750 <main+244>: push $0x4 0x8048752 <main+246>: mov 0xfffffff8(%ebp),%eax 0x8048755 <main+249>: push %eax 0x8048756 <main+250>: call 0x8048500 <fcntl> fcntl( int fd, /* socket descriptor */ int cmd, /* 0x4 (O_NONBLOCK) */ ... ) Puts the socket into non-blocking I/O mode. 0x804875b <main+255>: add $0x10,%esp 0x804875e <main+258>: add $0xfffffffc,%esp Pop pop... Same thing for other socket. 0x8048761 <main+261>: push $0x4 0x8048763 <main+263>: push $0x4 0x8048765 <main+265>: mov 0xfffffffc(%ebp),%eax 0x8048768 <main+268>: push %eax 0x8048769 <main+269>: call 0x8048500 <fcntl> fcntl( int fd, int cmd, ... ) 0x804876e <main+274>: add $0x10,%esp 0x8048771 <main+277>: add $0xfffffffc,%esp Push arguments to write onto stack. 0x8048774 <main+280>: push $0x32000 0x8048779 <main+285>: lea 0xfffcdff4(%ebp),%eax 0x804877f <main+291>: push %eax 0x8048780 <main+292>: mov 0xfffffff8(%ebp),%eax 0x8048783 <main+295>: push %eax 0x8048784 <main+296>: call 0x80484a0 <write> 0x8048789 <main+301>: add $0x10,%esp 0x804878c <main+304>: 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 <main+307>: push $0x32000 0x8048794 <main+312>: lea 0xfffcdff4(%ebp),%eax 0x804879a <main+318>: push %eax 0x804879b <main+319>: mov 0xfffffffc(%ebp),%eax 0x804879e <main+322>: push %eax 0x804879f <main+323>: call 0x80484a0 <write> 0x80487a4 <main+328>: add $0x10,%esp 0x80487a7 <main+331>: jmp 0x80486a0 <main+68> 0x80487ac <main+336>: call 0x8048480 <pause> 0x80487b1 <main+341>: xor %eax,%eax 0x80487b3 <main+343>: jmp 0x80487b8 <main+348> 0x80487b5 <main+345>: lea 0x0(%esi),%esi 0x80487b8 <main+348>: leave 0x80487b9 <main+349>: ret 0x80487ba <main+350>: nop 0x80487bb <main+351>: nop End of assembler dump. (gdb) quit --3uo+9/B/ebqu+fSQ-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010515230354.A62767>