Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

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

Aperta
#308 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 3 giorni

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
72/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
android, c, linux

Direzione di ricerca

Inizia da kernel/patch/common/supercall.c e kernel/patch/common/kstorage.c, quindi esamina il percorso corrispondente lkm/supercall/kstorage.c. Segui SUPERCALL_KSTORAGE_LIST_IDS da arg2 fino a list_kstorage_ids() ed esegui il reproducer fornito. Il lavoro è completato quando l’output dello userspace viene gestito in modo sicuro in entrambi i percorsi interessati e l’eccezione del kernel dovuta al puntatore non valido non si verifica più.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

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.
Lingua principale
C
Stelle
1.6k
Fork
393
Merge medio
3g 23h
PR unite (30g)
7

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di bmax121/KernelPatch

Tutte le issue di bmax121/KernelPatch

Issue simili

Altre issue su C

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.