Edge-Triggered epoll and starvation - Unix
This is a discussion on Edge-Triggered epoll and starvation - Unix ; Hello gurus!
I have a question about epoll and possible starvation.
As epoll(4) says, when epoll is used in Edge-Triggered mode
it's very important to read all the data available in the
buffer.
Otherwise next epoll_wait call may block forever ...
-
Edge-Triggered epoll and starvation
Hello gurus!
I have a question about epoll and possible starvation.
As epoll(4) says, when epoll is used in Edge-Triggered mode
it's very important to read all the data available in the
buffer.
Otherwise next epoll_wait call may block forever (if there
are no changes on monitored file descriptor).
Lets suppose, that epoll_wait detected new events on three
file descriptors 5, 6 and 7.
So, we should handle I/O on all of them.
Read handling loop may be implemented as follows:
void handle_read_event(int fd)
{
while(1)
{
int r = read(fd, buf, size);
if(r==-1)
{
if(errno == EINTR) continue;
if(errno == EAGAIN) break;
handle_read_error();
}
else
{
use_data(buf, r);
}
}
}
We are reading as much data as possible (since epoll-ET is used).
Lets now suppose that peer is much more faster and we are unable
to read data at the same rate (fast producer, slow consumer).
In such a case the loop presented above may be potentially
infinite.
So, this leads to starvation and DoS.
Really, we are unable to handle new events as well as I/O on already
ready descriptors (6 and 7 in the example).
Are my conclusions correct?
Have anyone seen something similar to this scenario in real life?
Thank you beforehand!
-
Re: Edge-Triggered epoll and starvation
On May 30, 11:02*pm, Krivenok Dmitry
wrote:
> Read handling loop may be implemented as follows:
>
> void handle_read_event(int fd)
> {
> * while(1)
> * * {
> * * * int r = read(fd, buf, size);
> * * * if(r==-1)
> * * * * {
> * * * * * if(errno == EINTR) continue;
> * * * * * if(errno == EAGAIN) break;
> * * * * * handle_read_error();
> * * * * }
> * * * else
> * * * * {
> * * * * * use_data(buf, r);
> * * * * }
> * * }
>
> }
>
> We are reading as much data as possible (since epoll-ET is used).
> Lets now suppose that peer is much more faster and we are unable
> to read data at the same rate (fast producer, slow consumer).
> In such a case the loop presented above may be potentially
> infinite.
> So, this leads to starvation and DoS.
> Really, we are unable to handle new events as well as I/O on already
> ready descriptors (6 and 7 in the example).
>
> Are my conclusions correct?
> Have anyone seen something similar to this scenario in real life?
I don't think anyone would write code this bad, but yes, if you were
willing to do an unlimited amount of work on a single connection, your
code would break this way. There are many more sensible things you
could do:
1) You could simply *stop* calling 'read'. There will be no problem
because you know the socket is still ready, so you should call 'read'
later when you're willing to do work, not 'epoll'.
2) You could close the connection as soon as you are reasonably sure
it is an attack.
DS