From: <ag...@us...> - 2013-04-09 18:30:03
|
Revision: 2743 http://nagios.svn.sourceforge.net/nagios/?rev=2743&view=rev Author: ageric Date: 2013-04-09 18:29:56 +0000 (Tue, 09 Apr 2013) Log Message: ----------- lib/squeue: Protect against insane input If a user would want to schedule things beyond the unix millenium, which ends 2038-01-19 03:14:07 UTC (apparently a tuesday, according to reliable sources), they would previously end up in one of two unpleasant codepaths. If they were on 32-bit systems, the time would silently wrap around into negative time, which would be interpreted as "now" or pretty much anytime inside the 68 years that encompass the unix millenium, depending on how much they wrapped around. Most of the time it would be "now" though, since we discard times in the past inside the squeue library. If, however, they were on 64-bit systems, the situation could get a bit more serious, since we would then try to cram 16 bytes of data into 8 bytes. We would succeed (after a fashion), but we would lose the top 32 bits of the seconds value for the purpose of priority queue comparisons, but we would retain them for the sake of the caller and use it when someone requested it from us (via squeue_event_runtime()). Since the erroneous event went to the head of the queue but was in reality scheduled to happen X thousand years into the future, Nagios wouldn't run it, but would instead go and sulk in a corner. Not very nice. This patch fixes it, and as a nice bonus protects against broken gettimeofday() implementations (are there any?), by masking off the bottom 21 bits for the microsecond value and the 43 topmost bits for the tv_sec value we actually store for the timeval struct. That means the Nagios millenium will end with the unix millenium for 32 bit systems and sometime in the year 141166 for 64-bit systems. We don't support scheduling things beyond those years on the given architectures. Doing so will cause undefined behaviour, and we can't protect against it due to type restrictions enforced on us by the compiler. Users who try will see their events being run inappropriately early. We will, however, not *stop* running events now, but merrily carry on with our other scheduled tasks after we've run the poorly scheduled event (at the wrong time). Reported-by: Ton Voon <ton...@op...> Signed-off-by: Andreas Ericsson <ae...@op...> Modified Paths: -------------- nagioscore/trunk/lib/squeue.c Modified: nagioscore/trunk/lib/squeue.c =================================================================== --- nagioscore/trunk/lib/squeue.c 2013-04-09 18:29:36 UTC (rev 2742) +++ nagioscore/trunk/lib/squeue.c 2013-04-09 18:29:56 UTC (rev 2743) @@ -28,7 +28,16 @@ void *data; }; - +/* + * 21 bits has enough data for systems that can have the usec + * field of a struct timeval move into the 1-second range, but + * not enough to let them to (far) beyond 2. If the system libs + * are too buggy, we really can't save it. + * This little twiddling operation lets us use dates beyond + * 2038 on 64-bit systems, while retaining the fast priority + * comparisons. + */ +#define SQ_BITS 21 static pqueue_pri_t evt_compute_pri(struct timeval *tv) { pqueue_pri_t ret; @@ -39,8 +48,8 @@ ret += !!tv->tv_usec; } else { ret = tv->tv_sec; - ret <<= 32; - ret |= tv->tv_usec; + ret <<= SQ_BITS; + ret |= tv->tv_usec & ((1 << SQ_BITS) - 1); } return ret; @@ -108,6 +117,15 @@ if (tv->tv_sec < time(NULL)) tv->tv_sec = time(NULL); evt->when.tv_sec = tv->tv_sec; + if (sizeof(evt->when.tv_sec) > 4) { + /* + * Only use bottom sizeof(pqueue_pri_t)-SQ_BITS bits on + * 64-bit systems, or we may get entries at the head + * of the queue are actually scheduled to run several + * hundred thousand years from now. + */ + evt->when.tv_sec &= (1ULL << ((sizeof(pqueue_pri_t) * 8) - SQ_BITS)) - 1; + } evt->when.tv_usec = tv->tv_usec; evt->data = data; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |