Nmap Development mailing list archives

Re: Ncat with ssl using 100% cpu (PATCH)


From: David Fifield <david () bamsoftware com>
Date: Fri, 3 Jul 2009 14:28:37 -0600

On Fri, Jun 19, 2009 at 12:00:59PM -0600, David Fifield wrote:
On Thu, Jun 04, 2009 at 05:30:46PM -0600, David Fifield wrote:
On Tue, May 19, 2009 at 04:30:32PM -0300, el draco wrote:
Hi everyone, i was testing ncat a little bit and found that under
certain conditions it uses all of my cpu.

I'm using:
Kubuntu 8.10
Kernel 2.6.27-14-generic SMP
openssl 0.9.8g-10
libssl0.9.8
libssl-dev 0.9.8g-10
Nmap 4.85BETA9, svn rev. 13330

Test case 1:

a) ncat -l 8000 --ssl
b) ncat localhost 8000 --ssl

So far so good, and now we type anything on the CLIENT like 'test'

Now ncat client is using 100% of cpu.

Thanks. I can reproduce this. There used to be a similar problem for
non-SSL connections, but it was fixed in Ncat. From some investigation,
it appears that this problem is inside Nsock. Somehow select is always
returning true in some situations.

The problem is this code:

    /* Decrement the count of waiting writes on this IOD. When it hits 0 we
       remove it from the descriptor lists. */
    iod->writesd_count--;
    assert(iod->writesd_count >= 0);
    if (!iod->ssl && iod->writesd_count == 0) {
      FD_CLR(iod->sd, &ms->mioi.fds_master_w);
      FD_CLR(iod->sd, &ms->mioi.fds_results_w);
    } else if (iod->ssl && iod->events_pending <= 1) {
    /* Exception: If this is an SSL socket and there is another
       pending event (such as a read), it might actually be waiting
       on a write so we can't clear in that case */
      FD_CLR(iod->sd, &ms->mioi.fds_master_r);
      FD_CLR(iod->sd, &ms->mioi.fds_results_r);
      FD_CLR(iod->sd, &ms->mioi.fds_master_w);
      FD_CLR(iod->sd, &ms->mioi.fds_results_w);
    }

When the write is finished, Nsock normally checks if there are any other
writes pending, and if not, it removes the descriptor from the set of
descriptors it is watching. If we were to keep watching the descriptor
it would always be ready to write and use up all the CPU, being
repeatedly selected but not handled.

In the SSL case, it is possible that a read event can require a network
write, because of how the protocol works. The code correctly notes this
and avoids clearing the descriptor bit if a read is pending. However, it
should be more careful and only clearing the bit when a read event
actually requires a network write at that moment. Ncat in client mode
always has a pending read event from the network, so write bits never
get cleared. (The exception is immediately after a successful network
read, when the count of reads momentarily drops to zero before the next
read is scheduled. Then it's possible to clear the write bit, and that's
why it stopped using 100% CPU after reading from the server.)

I attached a patch that works for me but I want others to review it. It
provides functions (socket_count_*) that automatically keep the file
descriptor sets in sync with the number of pending reads and writes.
They make sure that when a count is zero the bit is unset, and when a
count is nonzero the corresponding bit is set. When an SSL read requires
a write, the read count is decremented and the write count is
incremented.
       socket_count_read_dec(iod, ms);
       socket_count_write_inc(iod, ms);
But when the write count is zero, the corresponding socket descriptor is
removed from the select set so it won't be repeatedly selected.

I committed this in r14022.

David Fifield

_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org


Current thread: