From: Greg Kroah-Hartman Date: Fri, 27 Sep 2013 21:06:50 +0000 (-0700) Subject: 3.4-stable patches X-Git-Tag: v3.0.98~35 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9b70bbe26e44ad34bbf1461b541404f6c7d2aa2e;p=thirdparty%2Fkernel%2Fstable-queue.git 3.4-stable patches added patches: hid-provide-a-helper-for-validating-hid-reports.patch sched-fair-fix-small-race-where-child-se.parent-cfs_rq-might-point-to-invalid-ones.patch --- diff --git a/queue-3.4/hid-provide-a-helper-for-validating-hid-reports.patch b/queue-3.4/hid-provide-a-helper-for-validating-hid-reports.patch new file mode 100644 index 00000000000..22d536476d9 --- /dev/null +++ b/queue-3.4/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 +@@ -821,6 +821,64 @@ static int search(__s32 *array, __s32 va + return -1; + } + ++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_match_report - check if driver's raw_event should be called + * +--- a/include/linux/hid.h ++++ b/include/linux/hid.h +@@ -737,6 +737,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_check_keys_pressed(struct hid_device *hid); + int hid_connect(struct hid_device *hid, unsigned int connect_mask); + void hid_disconnect(struct hid_device *hid); diff --git a/queue-3.4/sched-fair-fix-small-race-where-child-se.parent-cfs_rq-might-point-to-invalid-ones.patch b/queue-3.4/sched-fair-fix-small-race-where-child-se.parent-cfs_rq-might-point-to-invalid-ones.patch new file mode 100644 index 00000000000..150d1b79d6d --- /dev/null +++ b/queue-3.4/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 +@@ -5190,11 +5190,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.4/series b/queue-3.4/series index 521cbcc1dd8..b10b0bd7226 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -1,3 +1,5 @@ revert-sctp-fix-call-to-sctp_cmd_process_sack-in.patch net-usb-cdc_ether-use-wwan-interface-for-telit-modules.patch rt2800-fix-wrong-tx-power-compensation.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