linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: sbelmon2@paola.ucsd.edu (Stephane Belmon)
To: linux-kernel@vger.rutgers.edu
Cc: marcs@znep.com, tkorvola@grumpy.hut.fi
Subject: Timeout overflow in select()
Date: Sun, 22 Nov 1998 02:17:21 -0800 (PST)	[thread overview]
Message-ID: <m0zhWa1-00764fC@paola.ucsd.edu> (raw)

I think there is an overflow in the timeout computation in select().

It is at least in 2.0.34 and 2.1.128-9, and likely in just about any
kernel around. Here's the problem, as was reported by Timo Korvola
<tkorvola@grumpy.hut.fi> on comp.os.linux.development.system:

> It seems that calling select with a very long timeout causes an
> arithmetic overflow in the kernel code and messages like this begin to
> appear:
> schedule_timeout: wrong timeout value bbf81e00 from c0133e15
> I am running 2.1.128.  Admittedly triggering this bug requires rather
> strange use of select but CGoban (1.9.2) actually does it by using a
> timeout of one year instead of just passing a null pointer.

(Thanks, Timo) The cause is easy enough to find:
fs/select.c, sys_select(), in 2.1.129:

222		timeout = ROUND_UP(usec, 1000000/HZ);
223		timeout += sec * (unsigned long) HZ;

Line 223 will cause "timeout" (a long) to overflow when the struct
timeval passed has a large enough "tv_sec" member (a year
qualifies). Depending on the exact value passed, you can get a loong
sleep (but not as looong as intended) or an immediate wakeup.
schedule_timeout() (kernel/sched.c) has enough sanity checks to make
this show up, as above; in 2.0.34, the overflow goes unnoticed.

In any case, this doesn't look proper to me. I guess this is a general
problem when converting from a struct timeval to the internal format;
I must say that I'm still rather unsure this is a real problem, as
this section of code has been posted on this list a couple of times.

Implications: this will break some poorly written code (people who
don't use NULL as the timeout parameter, but instead "a year", to mean
"forever"). Besides that, you could imagine some cron-like daemons
which need to sleep (and still watch some FDs) for a looong time. That
could happen because of the configuration through the "cron-like
tab". The daemon could be woken up immediately, and would probably
start busy looping around the select() call. Not very good.

Security implications: here I'm not sure. 2.1.129's schedule_timeout()
is paranoid enough; nothing bad should happen. The test line 482 in
kernel/sched.c, and the "goto out" a few lines below, prevent
it. However, this might be just a lucky state of affairs. Potentially,
the scheduler could trust the timeout computation, and set a timer in
the past. If this goes off and puts the process in front of the queue
(as should happen in the 2.1.129 scheduler), other processes might not
get a chance to run. In 2.0, I think the process is put last in the
queue.

Proposed solutions: We can't refuse to serve long timeouts: if it fits
in a struct timeval, we have to do it. We could have a loop around the
do_select() call, each time with a timeout value that fits. But that's
messy, error-prone, and will almost never be exercised. Marc Slemko
<marcs@znep.com> found that:

> it is correct to place an upper limit on the timeout.
> From the single unix spec
> (http://www.opengroup.org/publications/catalog/t912.htm):
>  Implementations may place limitations on the maximum timeout interval
>  supported. On all implementations, the maximum timeout interval
>  supported will be at least 31 days. If the timeout argument specifies
>  a timeout interval greater than the implementation-dependent maximum
>  value, the maximum value will be used as the actual timeout value.
>  Implementations may also place limitations on the granularity of
>  timeout intervals. If the requested timeout interval requires a
>  finer granularity than the implementation supports, the actual
>  timeout interval will be rounded up to the next supported value.

(Thanks, Marc) This makes sense: struct timeval is too general
anyway. So it should be enough to insert a few lines to check the
tv_sec value. I propose the following:

--- linux-2.1.129/fs/select.c   Sat Nov 21 01:13:02 1998
+++ linux/fs/select.c   Sun Nov 22 01:23:09 1998
@@ -217,6 +217,10 @@
                    || (ret = __get_user(sec, &tvp->tv_sec))
                    || (ret = __get_user(usec, &tvp->tv_usec)))
                        goto out_nofds;
+               
+               if (sec<0) sec = 0;
+               if (sec>MAX_SCHEDULE_TIMEOUT/2/HZ) 
+                       sec = MAX_SCHEDULE_TIMEOUT/2/HZ; 
 
                timeout = ROUND_UP(usec, 1000000/HZ);
                timeout += sec * (unsigned long) HZ;


BTW, you need it for another reason: if a process uses
MAX_SCHEDULE_TIMEOUT/HZ as its tv_sec, it will _never_ be awaken (see
the scheduler code again); for all we know, maybe it meant "sometime
in the distant future" (granted, it's unlikely).

The patch works fine with me. I haven't seen any undesirable side
effects so far; but I haven't done extensive testing (just your
average desktop: X, Netscape, ...). I don't see how it could go wrong,
though.

--
Stephane Belmon <sbelmon@cs.ucsd.edu>

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/

             reply	other threads:[~1998-11-22 11:18 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1998-11-22 10:17 Stephane Belmon [this message]
1998-11-23  1:34 Timeout overflow in select() Colin Plumb
1998-11-25  2:01 ` Stephane Belmon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=m0zhWa1-00764fC@paola.ucsd.edu \
    --to=sbelmon2@paola.ucsd.edu \
    --cc=linux-kernel@vger.rutgers.edu \
    --cc=marcs@znep.com \
    --cc=sbelmon@cs.ucsd.edu \
    --cc=tkorvola@grumpy.hut.fi \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).