SUPERCALL_KSTORAGE_LIST_IDS writes to an unvalidated userspace pointer with a raw memcpy → kernel KE
Los mantenedores suelen responder en 3 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 72/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- android, c, linux
- Área
- operating-systems, security
Línea de trabajo
Comienza en kernel/patch/common/supercall.c y kernel/patch/common/kstorage.c, y después inspecciona la ruta correspondiente lkm/supercall/kstorage.c. Sigue SUPERCALL_KSTORAGE_LIST_IDS desde arg2 hasta list_kstorage_ids() y ejecuta el reproducer proporcionado. El trabajo estará terminado cuando la salida de userspace se gestione de forma segura en ambas rutas afectadas y ya no se produzca la excepción del kernel por el puntero incorrecto.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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.
- Lenguaje dominante
- C
- Estrellas
- 1.6k
- Forks
- 393
- Merge medio
- 3 d 23 h
- PR fusionados (30 d)
- 7
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de bmax121/KernelPatch
-
official LineageOS on nicepool: APpatch patching fails but only if done via recovery sideloadPosiblemente ocupada @bmax121 la tomó hace 9 días. Abierto
bmax121/KernelPatch#332 · 1 asignado ·
Los mantenedores suelen responder en 3 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
bmax121/KernelPatch#329 · 1 comentario ·
Los mantenedores suelen responder en 3 días
-
kernel stack overflow: handle_supercmd 与 supercmd_echo 各持 4KB 栈缓冲区嵌套,event 上报改写 argv 时栈耗尽 panicAbierto
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
bmax121/KernelPatch#323 ·
Los mantenedores suelen responder en 3 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
bmax121/KernelPatch#319 · 9 comentarios ·
Los mantenedores suelen responder en 3 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 35/100
bmax121/KernelPatch#306 ·
Los mantenedores suelen responder en 3 días
Todos los issues de bmax121/KernelPatch
Issues similares
-
[mimalloc] update to 3.6.0Abiertocategory:port-update
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
Los mantenedores suelen responder en 2 días
-
emerge failure MARK mark-unstable media-kit
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
macaroni-os/mark-issues#834 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 93/100
webarkit/WebARKitLib#107 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día