perf: don't leave group_entry on sibling list(use-after-free)
John Dias [Mon, 16 Jan 2017 08:22:04 +0000 (13:22 +0530)]
When perf_group_detach is called on a group leader,
it should empty its sibling list. Otherwise, when
a sibling is later deallocated, list_del_event()
removes the sibling's group_entry from its current
list, which can be the now-deallocated group leader's
sibling list (use-after-free bug).

Bug: 32402548

CVE-2017-0403 (A-32402548)
Bug 1849492

Change-Id: I99f6bc97c8518df1cb0035814368012ba72ab1f1
Signed-off-by: John Dias <joaodias@google.com>
Signed-off-by: Gagan Grover <ggrover@nvidia.com>
Reviewed-on: http://git-master/r/1285800
(cherry picked from commit a5dc2d079ba88bba5dc78484d4820842af65d656)
Reviewed-on: http://git-master/r/1299508
(cherry picked from commit 8dae5d362123d37d29552b5a9ed89c7dbfe3dd55)
Reviewed-on: http://git-master/r/1311419
GVS: Gerrit_Virtual_Submit
Reviewed-by: Vinayak Pane <vpane@nvidia.com>

kernel/events/core.c

index 09fb6c7..626c335 100644 (file)
@@ -1313,10 +1313,17 @@ static void perf_group_detach(struct perf_event *event)
         * If this was a group event with sibling events then
         * upgrade the siblings to singleton events by adding them
         * to whatever list we are on.
+        * If this isn't on a list, make sure we still remove the sibling's
+        * group_entry from this sibling_list; otherwise, when that sibling
+        * is later deallocated, it will try to remove itself from this
+        * sibling_list, which may well have been deallocated already,
+        * resulting in a use-after-free.
         */
        list_for_each_entry_safe(sibling, tmp, &event->sibling_list, group_entry) {
                if (list)
                        list_move_tail(&sibling->group_entry, list);
+               else
+                       list_del_init(&sibling->group_entry);
                sibling->group_leader = sibling;
 
                /* Inherit group flags from the previous leader */