summaryrefslogtreecommitdiffstats
path: root/kernel/itimer.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2006-03-25 03:06:35 -0800
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-25 08:22:49 -0800
commit7d99b7d634d81bb372e03e4561c80430aa4cfac2 (patch)
tree905654bd7cb4940126606cf212c61079eeca722b /kernel/itimer.c
parentc08b8a49100715b20e6f7c997e992428b5e06078 (diff)
downloadlinux-7d99b7d634d81bb372e03e4561c80430aa4cfac2.tar.gz
linux-7d99b7d634d81bb372e03e4561c80430aa4cfac2.tar.bz2
linux-7d99b7d634d81bb372e03e4561c80430aa4cfac2.zip
[PATCH] Validate and sanitze itimer timeval from userspace
According to the specification the timevals must be validated and an errorcode -EINVAL returned in case the timevals are not in canonical form. This check was never done in Linux. The pre 2.6.16 code converted invalid timevals silently. Negative timeouts were converted by the timeval_to_jiffies conversion to the maximum timeout. hrtimers and the ktime_t operations expect timevals in canonical form. Otherwise random results might happen on 32 bits machines due to the optimized ktime_add/sub operations. Negative timeouts are treated as already expired. This might break applications which work on pre 2.6.16. To prevent random behaviour and API breakage the timevals are checked and invalid timevals sanitized in a simliar way as the pre 2.6.16 code did. Invalid timevals are reported with a per boot limited number of kernel messages so applications which use this misfeature can be corrected. After a grace period of one year the sanitizing should be replaced by a correct validation check. This is also documented in Documentation/feature-removal-schedule.txt The validation and sanitizing is done inside do_setitimer so all callers (sys_setitimer, compat_sys_setitimer, osf_setitimer) are catched. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/itimer.c')
-rw-r--r--kernel/itimer.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/kernel/itimer.c b/kernel/itimer.c
index a2dc375927d8..680e6b70c872 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -143,6 +143,60 @@ int it_real_fn(void *data)
return HRTIMER_NORESTART;
}
+/*
+ * We do not care about correctness. We just sanitize the values so
+ * the ktime_t operations which expect normalized values do not
+ * break. This converts negative values to long timeouts similar to
+ * the code in kernel versions < 2.6.16
+ *
+ * Print a limited number of warning messages when an invalid timeval
+ * is detected.
+ */
+static void fixup_timeval(struct timeval *tv, int interval)
+{
+ static int warnlimit = 10;
+ unsigned long tmp;
+
+ if (warnlimit > 0) {
+ warnlimit--;
+ printk(KERN_WARNING
+ "setitimer: %s (pid = %d) provided "
+ "invalid timeval %s: tv_sec = %ld tv_usec = %ld\n",
+ current->comm, current->pid,
+ interval ? "it_interval" : "it_value",
+ tv->tv_sec, (long) tv->tv_usec);
+ }
+
+ tmp = tv->tv_usec;
+ if (tmp >= USEC_PER_SEC) {
+ tv->tv_usec = tmp % USEC_PER_SEC;
+ tv->tv_sec += tmp / USEC_PER_SEC;
+ }
+
+ tmp = tv->tv_sec;
+ if (tmp > LONG_MAX)
+ tv->tv_sec = LONG_MAX;
+}
+
+/*
+ * Returns true if the timeval is in canonical form
+ */
+#define timeval_valid(t) \
+ (((t)->tv_sec >= 0) && (((unsigned long) (t)->tv_usec) < USEC_PER_SEC))
+
+/*
+ * Check for invalid timevals, sanitize them and print a limited
+ * number of warnings.
+ */
+static void check_itimerval(struct itimerval *value) {
+
+ if (unlikely(!timeval_valid(&value->it_value)))
+ fixup_timeval(&value->it_value, 0);
+
+ if (unlikely(!timeval_valid(&value->it_interval)))
+ fixup_timeval(&value->it_interval, 1);
+}
+
int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
{
struct task_struct *tsk = current;
@@ -150,6 +204,18 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
ktime_t expires;
cputime_t cval, cinterval, nval, ninterval;
+ /*
+ * Validate the timevals in value.
+ *
+ * Note: Although the spec requires that invalid values shall
+ * return -EINVAL, we just fixup the value and print a limited
+ * number of warnings in order not to break users of this
+ * historical misfeature.
+ *
+ * Scheduled for replacement in March 2007
+ */
+ check_itimerval(value);
+
switch (which) {
case ITIMER_REAL:
again: