commit 5a8e01f8fa51f5cbce8f37acc050eb2319d12956 upstream.

scale_stime() silently assumes that stime < rtime, otherwise
when stime == rtime and both values are big enough (operations
on them do not fit in 32 bits), the resulting scaling stime can
be bigger than rtime. In consequence utime = rtime - stime
results in negative value.

User space visible symptoms of the bug are overflowed TIME
values on ps/top, for example:

 $ ps aux | grep rcu
 root         8  0.0  0.0      0     0 ?        S    12:42   0:00 [rcuc/0]
 root         9  0.0  0.0      0     0 ?        S    12:42   0:00 [rcub/0]
 root        10 62422329  0.0  0     0 ?        R    12:42 21114581:37 
[rcu_preempt]
 root        11  0.1  0.0      0     0 ?        S    12:42   0:02 [rcuop/0]
 root        12 62422329  0.0  0     0 ?        S    12:42 21114581:35 [rcuop/1]
 root        10 62422329  0.0  0     0 ?        R    12:42 21114581:37 
[rcu_preempt]

or overflowed utime values read directly from /proc/$PID/stat

Reference:

  https://lkml.org/lkml/2013/8/20/259

Reported-and-tested-by: Sergey Senozhatsky <sergey.senozhat...@gmail.com>
Signed-off-by: Stanislaw Gruszka <sgrus...@redhat.com>
Cc: stable@vger.kernel.org
Cc: Frederic Weisbecker <fweis...@gmail.com>
Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Paul E. McKenney <paul...@linux.vnet.ibm.com>
Cc: Borislav Petkov <b...@alien8.de>
Link: http://lkml.kernel.org/r/20130904131602.gc2...@redhat.com
Signed-off-by: Ingo Molnar <mi...@kernel.org>
---

 kernel/sched/cputime.c | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index a7959e0..25cc35d 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -557,7 +557,7 @@ static void cputime_adjust(struct task_cputime *curr,
                           struct cputime *prev,
                           cputime_t *ut, cputime_t *st)
 {
-       cputime_t rtime, stime, utime, total;
+       cputime_t rtime, stime, utime;
 
        if (vtime_accounting_enabled()) {
                *ut = curr->utime;
@@ -565,9 +565,6 @@ static void cputime_adjust(struct task_cputime *curr,
                return;
        }
 
-       stime = curr->stime;
-       total = stime + curr->utime;
-
        /*
         * Tick based cputime accounting depend on random scheduling
         * timeslices of a task to be interrupted or not by the timer.
@@ -588,13 +585,19 @@ static void cputime_adjust(struct task_cputime *curr,
        if (prev->stime + prev->utime >= rtime)
                goto out;
 
-       if (total) {
+       stime = curr->stime;
+       utime = curr->utime;
+
+       if (utime == 0) {
+               stime = rtime;
+       } else if (stime == 0) {
+               utime = rtime;
+       } else {
+               cputime_t total = stime + utime;
+
                stime = scale_stime((__force u64)stime,
                                    (__force u64)rtime, (__force u64)total);
                utime = rtime - stime;
-       } else {
-               stime = rtime;
-               utime = 0;
        }
 
        /*

--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to