Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

SUPERCALL_KSTORAGE_LIST_IDS writes to an unvalidated userspace pointer with a raw memcpy → kernel KE

Đang mở
#308 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 3 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
72/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
android, c, linux

Hướng nghiên cứu

Bắt đầu trong kernel/patch/common/supercall.c và kernel/patch/common/kstorage.c, sau đó kiểm tra đường dẫn tương ứng lkm/supercall/kstorage.c. Truy vết SUPERCALL_KSTORAGE_LIST_IDS từ arg2 đến list_kstorage_ids() và chạy reproducer được cung cấp. Hoàn tất khi đầu ra của userspace được xử lý an toàn trong cả hai đường dẫn bị ảnh hưởng và ngoại lệ kernel do con trỏ không hợp lệ không còn xảy ra.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Summary

SUPERCALL_KSTORAGE_LIST_IDS (0x1043) forwards a userspace-supplied pointer into list_kstorage_ids() with data_is_user = false, so the kernel takes the raw memcpy() path instead of copy_to_user(). There is no access_ok() check anywhere in kstorage.c (verified: grep -c access_ok = 0). A bad or stale ids argument therefore makes the kernel write hashtable data to an arbitrary address in kernel context → data abort / KE.

Hit on a Redmi K50 Pro (MT6983, Android 14, KernelPatch 0.13.8 / 0xd08), reproducible kernel exception:

ZZ_INTERNAL: Kernel (KE),0,0,99,/data/vendor/core/,0,,KE at __memcpy+0x8c/0x180,Sat Sep 12 21:59:23 CST 2026

Root cause

kernel/patch/common/kstorage.c:

int list_kstorage_ids(int gid, long *ids, int idslen, bool data_is_user)
{
    if (gid < 0 || gid >= KSTRORAGE_MAX_GROUP_NUM) return -ENOENT;
    ...
    for (int b = 0; b < KSTORAGE_NBUCKETS; b++) {
        hlist_for_each_entry_rcu(pos, &kstorage_groups[gid][b], hnode)
        {
            if (cnt >= idslen) goto out;

            if (data_is_user) {
                int cplen = compat_copy_to_user(ids + cnt, &pos->did, sizeof(pos->did));
                if (cplen <= 0) { ...; goto out; }
            } else {
                memcpy(ids + cnt, &pos->did, sizeof(pos->did));   // <-- raw kernel write
            }
            cnt++;
        }
    }
    ...
}

kernel/patch/common/supercall.c — the userspace-reachable path passes false:

static long call_list_kstorage_ids(int gid, long *ids, int ids_len)
{
    return list_kstorage_ids(gid, ids, ids_len, false);   // ids is a __user pointer!
}
...
case SUPERCALL_KSTORAGE_LIST_IDS:
    return call_list_kstorage_ids((int)arg1, (long *)arg2, (int)arg3);

arg2 comes straight from the syscall registers, i.e. it is an untrusted userspace value. It is then dereferenced with a plain memcpy() in kernel context, with no access_ok() and no data_is_user flag.

The same pattern exists in the kp_kstorage_list_ids port used by the LKM (lkm/supercall/kstorage.c), so current main is affected too, not just the kernel/patch/common tree.

Reproduction

Minimal reproducer (aarch64, run as a uid in the su allowlist, e.g. root):

/* supercall channel: __NR_supercall == __NR3264_truncate == 45 */
#define SUPERCALL_KSTORAGE_LIST_IDS 0x1043
#define KSTORAGE_EXCLUDE_LIST_GROUP 1

long ver_and_cmd(long cmd) {
    /* MAJOR 0, MINOR 13, PATCH 8 -> 0x0d08 ; magic 0x1158 ; cmd in low 16 bits */
    return ((long)0x0d08 << 32) | (0x1158 << 16) | (cmd & 0xFFFF);
}

long *ids = malloc(sizeof(long) * 512);   /* or an intentionally bad pointer */
syscall(45, "su", ver_and_cmd(SUPERCALL_KSTORAGE_LIST_IDS),
        KSTORAGE_EXCLUDE_LIST_GROUP, ids, 512);

Accidentally passing a non-pointer in the ids slot (e.g. two integers that were meant to be (ids, len)) reproduces the crash deterministically: the kernel memcpys into an address like 0x200 = 512 and faults.

Impact

  • Availability: kernel data abort / KE → device hangs → forced long-press reboot (observed ro.boot.bootreason: reboot_longkey), MTK rebuild + fsck on the next boot.
  • Security: this is effectively a kernel arbitrary-write primitive: an authenticated supercall caller (any uid in the su allowlist / manager uid) controls both the destination address and the written value (pos->did, the stored kstorage key, i.e. attacker-chosen uid values). Writing 8 bytes at a controlled kernel address is directly usable for privilege escalation. The idslen bound only limits the number of writes, not where they land.
  • Any KPM (including third-party ones) that calls the exported list_kstorage_ids("...", ptr, len, false) with a userspace pointer inherits the same fault.

Suggested fix

In call_list_kstorage_ids() the data really is userspace, so either of these works:

  1. Pass data_is_user = true (one-line fix):
static long call_list_kstorage_ids(int gid, long *ids, int ids_len)
{
-   return list_kstorage_ids(gid, ids, ids_len, false);
+   return list_kstorage_ids(gid, ids, ids_len, true);
}
  1. Additionally validate in list_kstorage_ids() before taking the memcpy path, so future callers cannot regress:
if (!data_is_user && !access_ok(ids, (size_t)idslen * sizeof(long)))
    return -EFAULT;

and consider clamping idslen to the group size to also protect the VLA in list_ap_mod_exclude():

int list_ap_mod_exclude(uid_t *uids, int len)
{
    long ids[len];      /* VLA sized by an unvalidated caller argument */
    ...
    for (int i = 0; i < len; i++) uids[i] = (uid_t)ids[i];   /* writes len entries */
}

Environment

Device Redmi K50 Pro (22011211C, MT6983), Android 14
Kernel 5.10.209-android12-9-00019-g4ea09a298bb4-ab12292661
Root APatch, /data/adb/apd version 115032
KernelPatch 0xd08 (0.13.8), compile time 08:03:59 Aug 31 2026, config=android,release
Supercall SUPERCALL_KSTORAGE_LIST_IDS = 0x1043, KSTORAGE_EXCLUDE_LIST_GROUP = 1
Crash KE at __memcpy+0x8c/0x180, 2026-09-12 21:59:23 CST

Notes

  • Not a duplicate of #227 (that one is __sock_create on a Pixel).
  • kernel/patch/common/sucompat.c:481 (list_ap_mod_exclude) passes false too, but with a stack array, so that call site itself is fine — the bug is that the supercall path reuses the same false with an untrusted pointer.
  • I can produce the AEE dump and a disassembly of the faulting list_kstorage_ids frame if useful.
Ngôn ngữ chính
C
Star
1.6k
Fork
393
Merge trung bình
3 ngày 23 giờ
Pull request đã merge (30 ngày)
7

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của bmax121/KernelPatch

Tất cả issue của bmax121/KernelPatch

Issue tương tự

Thêm issue về C

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.