SUPERCALL_KSTORAGE_LIST_IDS writes to an unvalidated userspace pointer with a raw memcpy → kernel KE
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
- Ambito
- operating-systems, security
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. Theidslenbound 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:
- 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);
}
- Additionally validate in
list_kstorage_ids()before taking thememcpypath, 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_createon a Pixel). kernel/patch/common/sucompat.c:481(list_ap_mod_exclude) passesfalsetoo, but with a stack array, so that call site itself is fine — the bug is that the supercall path reuses the samefalsewith an untrusted pointer.- I can produce the AEE dump and a disassembly of the faulting
list_kstorage_idsframe 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
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di bmax121/KernelPatch
-
official LineageOS on nicepool: APpatch patching fails but only if done via recovery sideloadForse già presa @bmax121 l’ha presa 9 giorni fa. Aperta
bmax121/KernelPatch#332 · 1 assegnatario ·
I maintainer di solito rispondono entro 3 giorni
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
bmax121/KernelPatch#329 · 1 commento ·
I maintainer di solito rispondono entro 3 giorni
-
kernel stack overflow: handle_supercmd 与 supercmd_echo 各持 4KB 栈缓冲区嵌套,event 上报改写 argv 时栈耗尽 panicAperta
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
bmax121/KernelPatch#323 ·
I maintainer di solito rispondono entro 3 giorni
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
bmax121/KernelPatch#319 · 9 commenti ·
I maintainer di solito rispondono entro 3 giorni
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
bmax121/KernelPatch#306 ·
I maintainer di solito rispondono entro 3 giorni
Tutte le issue di bmax121/KernelPatch
Issue simili
-
[mimalloc] update to 3.6.0Apertacategory:port-update
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
I maintainer di solito rispondono entro 2 giorni
-
emerge failure MARK mark-unstable media-kit
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
macaroni-os/mark-issues#834 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
NVIDIA/open-gpu-kernel-modules#1479 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 93/100
webarkit/WebARKitLib#107 ·
I maintainer di solito rispondono entro 1 giorno