]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.11-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Sep 2013 21:00:08 +0000 (14:00 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Sep 2013 21:00:08 +0000 (14:00 -0700)
added patches:
hid-provide-a-helper-for-validating-hid-reports.patch
sched-cputime-do-not-scale-when-utime-0.patch
sched-fair-fix-small-race-where-child-se.parent-cfs_rq-might-point-to-invalid-ones.patch

queue-3.11/hid-provide-a-helper-for-validating-hid-reports.patch [new file with mode: 0644]
queue-3.11/sched-cputime-do-not-scale-when-utime-0.patch [new file with mode: 0644]
queue-3.11/sched-fair-fix-small-race-where-child-se.parent-cfs_rq-might-point-to-invalid-ones.patch [new file with mode: 0644]
queue-3.11/series

diff --git a/queue-3.11/hid-provide-a-helper-for-validating-hid-reports.patch b/queue-3.11/hid-provide-a-helper-for-validating-hid-reports.patch
new file mode 100644 (file)
index 0000000..31265c1
--- /dev/null
@@ -0,0 +1,104 @@
+From 331415ff16a12147d57d5c953f3a961b7ede348b Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Wed, 11 Sep 2013 21:56:50 +0200
+Subject: HID: provide a helper for validating hid reports
+
+From: Kees Cook <keescook@chromium.org>
+
+commit 331415ff16a12147d57d5c953f3a961b7ede348b upstream.
+
+Many drivers need to validate the characteristics of their HID report
+during initialization to avoid misusing the reports. This adds a common
+helper to perform validation of the report exisitng, the field existing,
+and the expected number of values within the field.
+
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/hid/hid-core.c |   58 +++++++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/hid.h    |    4 +++
+ 2 files changed, 62 insertions(+)
+
+--- a/drivers/hid/hid-core.c
++++ b/drivers/hid/hid-core.c
+@@ -759,6 +759,64 @@ int hid_parse_report(struct hid_device *
+ }
+ EXPORT_SYMBOL_GPL(hid_parse_report);
++static const char * const hid_report_names[] = {
++      "HID_INPUT_REPORT",
++      "HID_OUTPUT_REPORT",
++      "HID_FEATURE_REPORT",
++};
++/**
++ * hid_validate_values - validate existing device report's value indexes
++ *
++ * @device: hid device
++ * @type: which report type to examine
++ * @id: which report ID to examine (0 for first)
++ * @field_index: which report field to examine
++ * @report_counts: expected number of values
++ *
++ * Validate the number of values in a given field of a given report, after
++ * parsing.
++ */
++struct hid_report *hid_validate_values(struct hid_device *hid,
++                                     unsigned int type, unsigned int id,
++                                     unsigned int field_index,
++                                     unsigned int report_counts)
++{
++      struct hid_report *report;
++
++      if (type > HID_FEATURE_REPORT) {
++              hid_err(hid, "invalid HID report type %u\n", type);
++              return NULL;
++      }
++
++      if (id >= HID_MAX_IDS) {
++              hid_err(hid, "invalid HID report id %u\n", id);
++              return NULL;
++      }
++
++      /*
++       * Explicitly not using hid_get_report() here since it depends on
++       * ->numbered being checked, which may not always be the case when
++       * drivers go to access report values.
++       */
++      report = hid->report_enum[type].report_id_hash[id];
++      if (!report) {
++              hid_err(hid, "missing %s %u\n", hid_report_names[type], id);
++              return NULL;
++      }
++      if (report->maxfield <= field_index) {
++              hid_err(hid, "not enough fields in %s %u\n",
++                      hid_report_names[type], id);
++              return NULL;
++      }
++      if (report->field[field_index]->report_count < report_counts) {
++              hid_err(hid, "not enough values in %s %u field %u\n",
++                      hid_report_names[type], id, field_index);
++              return NULL;
++      }
++      return report;
++}
++EXPORT_SYMBOL_GPL(hid_validate_values);
++
+ /**
+  * hid_open_report - open a driver-specific device report
+  *
+--- a/include/linux/hid.h
++++ b/include/linux/hid.h
+@@ -749,6 +749,10 @@ void hid_output_report(struct hid_report
+ struct hid_device *hid_allocate_device(void);
+ struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
+ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
++struct hid_report *hid_validate_values(struct hid_device *hid,
++                                     unsigned int type, unsigned int id,
++                                     unsigned int field_index,
++                                     unsigned int report_counts);
+ int hid_open_report(struct hid_device *device);
+ int hid_check_keys_pressed(struct hid_device *hid);
+ int hid_connect(struct hid_device *hid, unsigned int connect_mask);
diff --git a/queue-3.11/sched-cputime-do-not-scale-when-utime-0.patch b/queue-3.11/sched-cputime-do-not-scale-when-utime-0.patch
new file mode 100644 (file)
index 0000000..0c7aced
--- /dev/null
@@ -0,0 +1,92 @@
+From 5a8e01f8fa51f5cbce8f37acc050eb2319d12956 Mon Sep 17 00:00:00 2001
+From: Stanislaw Gruszka <sgruszka@redhat.com>
+Date: Wed, 4 Sep 2013 15:16:03 +0200
+Subject: sched/cputime: Do not scale when utime == 0
+
+From: Stanislaw Gruszka <sgruszka@redhat.com>
+
+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.senozhatsky@gmail.com>
+Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
+Cc: stable@vger.kernel.org
+Cc: Frederic Weisbecker <fweisbec@gmail.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
+Cc: Borislav Petkov <bp@alien8.de>
+Link: http://lkml.kernel.org/r/20130904131602.GC2564@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/sched/cputime.c |   19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+--- a/kernel/sched/cputime.c
++++ b/kernel/sched/cputime.c
+@@ -557,7 +557,7 @@ static void cputime_adjust(struct task_c
+                          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_c
+               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_c
+       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;
+       }
+       /*
diff --git a/queue-3.11/sched-fair-fix-small-race-where-child-se.parent-cfs_rq-might-point-to-invalid-ones.patch b/queue-3.11/sched-fair-fix-small-race-where-child-se.parent-cfs_rq-might-point-to-invalid-ones.patch
new file mode 100644 (file)
index 0000000..818971e
--- /dev/null
@@ -0,0 +1,90 @@
+From 6c9a27f5da9609fca46cb2b183724531b48f71ad Mon Sep 17 00:00:00 2001
+From: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
+Date: Tue, 10 Sep 2013 18:16:36 +0900
+Subject: sched/fair: Fix small race where child->se.parent,cfs_rq might point to invalid ones
+
+From: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
+
+commit 6c9a27f5da9609fca46cb2b183724531b48f71ad upstream.
+
+There is a small race between copy_process() and cgroup_attach_task()
+where child->se.parent,cfs_rq points to invalid (old) ones.
+
+        parent doing fork()      | someone moving the parent to another cgroup
+  -------------------------------+---------------------------------------------
+    copy_process()
+      + dup_task_struct()
+        -> parent->se is copied to child->se.
+           se.parent,cfs_rq of them point to old ones.
+
+                                     cgroup_attach_task()
+                                       + cgroup_task_migrate()
+                                         -> parent->cgroup is updated.
+                                       + cpu_cgroup_attach()
+                                         + sched_move_task()
+                                           + task_move_group_fair()
+                                             +- set_task_rq()
+                                                -> se.parent,cfs_rq of parent
+                                                   are updated.
+
+      + cgroup_fork()
+        -> parent->cgroup is copied to child->cgroup. (*1)
+      + sched_fork()
+        + task_fork_fair()
+          -> se.parent,cfs_rq of child are accessed
+             while they point to old ones. (*2)
+
+In the worst case, this bug can lead to "use-after-free" and cause a panic,
+because it's new cgroup's refcount that is incremented at (*1),
+so the old cgroup(and related data) can be freed before (*2).
+
+In fact, a panic caused by this bug was originally caught in RHEL6.4.
+
+    BUG: unable to handle kernel NULL pointer dereference at (null)
+    IP: [<ffffffff81051e3e>] sched_slice+0x6e/0xa0
+    [...]
+    Call Trace:
+     [<ffffffff81051f25>] place_entity+0x75/0xa0
+     [<ffffffff81056a3a>] task_fork_fair+0xaa/0x160
+     [<ffffffff81063c0b>] sched_fork+0x6b/0x140
+     [<ffffffff8106c3c2>] copy_process+0x5b2/0x1450
+     [<ffffffff81063b49>] ? wake_up_new_task+0xd9/0x130
+     [<ffffffff8106d2f4>] do_fork+0x94/0x460
+     [<ffffffff81072a9e>] ? sys_wait4+0xae/0x100
+     [<ffffffff81009598>] sys_clone+0x28/0x30
+     [<ffffffff8100b393>] stub_clone+0x13/0x20
+     [<ffffffff8100b072>] ? system_call_fastpath+0x16/0x1b
+
+Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
+Signed-off-by: Peter Zijlstra <peterz@infradead.org>
+Link: http://lkml.kernel.org/r/039601ceae06$733d3130$59b79390$@mxp.nes.nec.co.jp
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/sched/fair.c |   14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -5818,11 +5818,15 @@ static void task_fork_fair(struct task_s
+       cfs_rq = task_cfs_rq(current);
+       curr = cfs_rq->curr;
+-      if (unlikely(task_cpu(p) != this_cpu)) {
+-              rcu_read_lock();
+-              __set_task_cpu(p, this_cpu);
+-              rcu_read_unlock();
+-      }
++      /*
++       * Not only the cpu but also the task_group of the parent might have
++       * been changed after parent->se.parent,cfs_rq were copied to
++       * child->se.parent,cfs_rq. So call __set_task_cpu() to make those
++       * of child point to valid ones.
++       */
++      rcu_read_lock();
++      __set_task_cpu(p, this_cpu);
++      rcu_read_unlock();
+       update_curr(cfs_rq);
index 27e4860003b228dfc724ad5389e4391b4912d984..e781314267de4f79f08885704b1375351878b24f 100644 (file)
@@ -6,3 +6,6 @@ bgmac-fix-internal-switch-initialization.patch
 rt2800-change-initialization-sequence-to-fix-system-freeze.patch
 rt2800-fix-wrong-tx-power-compensation.patch
 timekeeping-fix-hrtick-related-deadlock-from-ntp-lock-changes.patch
+sched-cputime-do-not-scale-when-utime-0.patch
+sched-fair-fix-small-race-where-child-se.parent-cfs_rq-might-point-to-invalid-ones.patch
+hid-provide-a-helper-for-validating-hid-reports.patch