Nessus plugins often run this kind of code:
blah = recv(socket: soc, length:4096);
The NASL recv() function calls the stream_read_connection() C function
which returns when:
- "length" bytes have been read
- the peer closed the connection (aka EOF)
- a timeout expired. By default, 20 s
If the peer does not close the connection, recv will return after
the timeout. And whatever the value is, it will always be too big
(slow) or too small (timeout on a slow network)
To have quick tests and avoid losing data, we have to find the right
value for plugins_read_timeout in nessusd.conf
That was the behaviour in version <= 1.2.4
In the "true life", especially telecommunications or real time
software, when you speak sme kind of protocol on whatever serial
medium (even some cases of broadcast), you read "messages" and you
have some "end of message" mark, whatever it is:
1. A token in the data flow says that you reached a message limit.
2. You read a well defined number of bytes, that you got from a header
or that you know from elsewhere (e.g., the messages have all the same
fixed size)
3. Hardware signal, or any other side channel
4. timeout (if your network delay cannot be longer than a known value,
whatver the situtation is, to avoid the "Three Miles Island syndrom")
5. etc. etc.
Our problem is that we want to have a generic read function.
We cannot code a function for every protocol: there are too many of
them.
For many clear text communication, we have the end of line as a
message separator. recv_line may reach a timeout too, but only if the
peer is really slow; in normal operation, this function returns as
soon as it got a full text line.
We might write a clean function for HTTP because it is so common --
but we have to beware of buggy web servers that would not respect the
protocol.
In many cases, we will get a EOF/EPIPE when the peer process
closes its connection. But this does not work for protocols like HTTPS
because the SSL connection is kept open (for performance reasons)
A clean solution would be that plugins do the real work as they
know the protocol. But we don't want our plugins or includes to become
as big as a novel from Dostoievsky
So we really need a "smart" read function, that will ease plugin
writing, speed up the tests and... work well in normal situations
(i.e. if the network is not overloaded)
Renaud tried this hack (in CVS, post 1.2.4): when reading starts,
loop while there is still data waiting on the socket and ends ASAP.
Unfortunately, the function sometimes returned too early (on Linux
2.4 at least), the buffer was truncated and some vulnerability missed.
I propose this:
1. Add a "min" parameter in recv()
If it is set, recv() will read at most "max" bytes, and will return
when the timeout occurs or when "min" bytes have been received
2. Implement a "smart" default for lazy people :-)
recv() starts reading and will time out after 20 s. However, if it
received at least one byte, it will retry reading with a 2 s timeout.
(my current code is rather brain damaged and use two 1 s timeout in
fact)
This is implemented in the CVS version. Feel free to play with this.
Keep in mind that the "min" parameter will be ignored by Nessus <=
1.2.4
We'd appreciate comments on this. If anybody has seen this problem
before and has a silver bullet, he is welcome.
--
mailto:arboi@bigfoot.com
GPG Public keys: http://michel.arboi.free.fr/pubkey.txt
http://michel.arboi.free.fr/ http://arboi.da.ru/
FAQNOPI de fr.comp.securite : http://faqnopi.da.ru/
blah = recv(socket: soc, length:4096);
The NASL recv() function calls the stream_read_connection() C function
which returns when:
- "length" bytes have been read
- the peer closed the connection (aka EOF)
- a timeout expired. By default, 20 s
If the peer does not close the connection, recv will return after
the timeout. And whatever the value is, it will always be too big
(slow) or too small (timeout on a slow network)
To have quick tests and avoid losing data, we have to find the right
value for plugins_read_timeout in nessusd.conf
That was the behaviour in version <= 1.2.4
In the "true life", especially telecommunications or real time
software, when you speak sme kind of protocol on whatever serial
medium (even some cases of broadcast), you read "messages" and you
have some "end of message" mark, whatever it is:
1. A token in the data flow says that you reached a message limit.
2. You read a well defined number of bytes, that you got from a header
or that you know from elsewhere (e.g., the messages have all the same
fixed size)
3. Hardware signal, or any other side channel
4. timeout (if your network delay cannot be longer than a known value,
whatver the situtation is, to avoid the "Three Miles Island syndrom")
5. etc. etc.
Our problem is that we want to have a generic read function.
We cannot code a function for every protocol: there are too many of
them.
For many clear text communication, we have the end of line as a
message separator. recv_line may reach a timeout too, but only if the
peer is really slow; in normal operation, this function returns as
soon as it got a full text line.
We might write a clean function for HTTP because it is so common --
but we have to beware of buggy web servers that would not respect the
protocol.
In many cases, we will get a EOF/EPIPE when the peer process
closes its connection. But this does not work for protocols like HTTPS
because the SSL connection is kept open (for performance reasons)
A clean solution would be that plugins do the real work as they
know the protocol. But we don't want our plugins or includes to become
as big as a novel from Dostoievsky
So we really need a "smart" read function, that will ease plugin
writing, speed up the tests and... work well in normal situations
(i.e. if the network is not overloaded)
Renaud tried this hack (in CVS, post 1.2.4): when reading starts,
loop while there is still data waiting on the socket and ends ASAP.
Unfortunately, the function sometimes returned too early (on Linux
2.4 at least), the buffer was truncated and some vulnerability missed.
I propose this:
1. Add a "min" parameter in recv()
If it is set, recv() will read at most "max" bytes, and will return
when the timeout occurs or when "min" bytes have been received
2. Implement a "smart" default for lazy people :-)
recv() starts reading and will time out after 20 s. However, if it
received at least one byte, it will retry reading with a 2 s timeout.
(my current code is rather brain damaged and use two 1 s timeout in
fact)
This is implemented in the CVS version. Feel free to play with this.
Keep in mind that the "min" parameter will be ignored by Nessus <=
1.2.4
We'd appreciate comments on this. If anybody has seen this problem
before and has a silver bullet, he is welcome.
--
mailto:arboi@bigfoot.com
GPG Public keys: http://michel.arboi.free.fr/pubkey.txt
http://michel.arboi.free.fr/ http://arboi.da.ru/
FAQNOPI de fr.comp.securite : http://faqnopi.da.ru/