From: Greg Kroah-Hartman Date: Fri, 27 Sep 2013 21:00:08 +0000 (-0700) Subject: 3.11-stable patches X-Git-Tag: v3.0.98~37 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bb61374e005643f26152dd75ca58a4ef27ddff8a;p=thirdparty%2Fkernel%2Fstable-queue.git 3.11-stable patches 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 --- 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 index 00000000000..31265c15ed8 --- /dev/null +++ b/queue-3.11/hid-provide-a-helper-for-validating-hid-reports.patch @@ -0,0 +1,104 @@ +From 331415ff16a12147d57d5c953f3a961b7ede348b Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Wed, 11 Sep 2013 21:56:50 +0200 +Subject: HID: provide a helper for validating hid reports + +From: Kees Cook + +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 +Reviewed-by: Benjamin Tissoires +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..0c7acedfe23 --- /dev/null +++ b/queue-3.11/sched-cputime-do-not-scale-when-utime-0.patch @@ -0,0 +1,92 @@ +From 5a8e01f8fa51f5cbce8f37acc050eb2319d12956 Mon Sep 17 00:00:00 2001 +From: Stanislaw Gruszka +Date: Wed, 4 Sep 2013 15:16:03 +0200 +Subject: sched/cputime: Do not scale when utime == 0 + +From: Stanislaw Gruszka + +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 +Signed-off-by: Stanislaw Gruszka +Cc: stable@vger.kernel.org +Cc: Frederic Weisbecker +Cc: Peter Zijlstra +Cc: Paul E. McKenney +Cc: Borislav Petkov +Link: http://lkml.kernel.org/r/20130904131602.GC2564@redhat.com +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..818971e57b6 --- /dev/null +++ b/queue-3.11/sched-fair-fix-small-race-where-child-se.parent-cfs_rq-might-point-to-invalid-ones.patch @@ -0,0 +1,90 @@ +From 6c9a27f5da9609fca46cb2b183724531b48f71ad Mon Sep 17 00:00:00 2001 +From: Daisuke Nishimura +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 + +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: [] sched_slice+0x6e/0xa0 + [...] + Call Trace: + [] place_entity+0x75/0xa0 + [] task_fork_fair+0xaa/0x160 + [] sched_fork+0x6b/0x140 + [] copy_process+0x5b2/0x1450 + [] ? wake_up_new_task+0xd9/0x130 + [] do_fork+0x94/0x460 + [] ? sys_wait4+0xae/0x100 + [] sys_clone+0x28/0x30 + [] stub_clone+0x13/0x20 + [] ? system_call_fastpath+0x16/0x1b + +Signed-off-by: Daisuke Nishimura +Signed-off-by: Peter Zijlstra +Link: http://lkml.kernel.org/r/039601ceae06$733d3130$59b79390$@mxp.nes.nec.co.jp +Signed-off-by: Ingo Molnar +Signed-off-by: Greg Kroah-Hartman + +--- + 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); + diff --git a/queue-3.11/series b/queue-3.11/series index 27e4860003b..e781314267d 100644 --- a/queue-3.11/series +++ b/queue-3.11/series @@ -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