Samsung QuramDng Out-Of-Bounds Write
Samsung QuramDng Out-Of-Bounds Write
The Samsung QuramDng Out-Of-Bounds (OOB) Write is a critical vulnerability The Samsung QuramDng Out-Of-Bounds (OOB) Write is a critical vulnerability found in a Samsung kernel driver. It allows an attacker to write data beyond a memory buffer's intended boundaries. This usually stems from insufficient input validation or incorrect size calculations when processing user-supplied data.

Such a flaw enables corruption of adjacent memory regions. In severe cases, it can lead to arbitrary code execution (ACE) and local privilege escalation (LPE), permitting a malicious application to gain root or system-level control on the device.

Exploitation typically involves a specially crafted application interacting with the vulnerable driver. The vulnerability poses a significant risk, potentially compromising the entire device. Samsung released security patches to fix this, highlighting the need for timely updates.

BACKGROUND

Samsung Android uses an internal DNG decoding library, QuramDng in libimagecodec.quram.so, to decode images in com.samsung.ipservice and com.samsung.gallery3d. Samsung Gallery will decode and render DNG images in content://media/external/file with QuramDng. com.samsung.ipservice will decode DNG images in content://media/external/file shortly after the MEDIA_SCANNER_SCAN_FILE broadcast intent is sent with QuramDng.

VULNERABILITY DETAILS

planes = mainIfd->fSamplesPerPixel; /*** 1 ***/
PixelType = QuramDngIFD::getPixelType(mainIfd);
image = QuramDngImage::initialize(dng_image, &tileArea, planes, PixelType); /*** 2 ***/
QuramDngIFD::readImage(mainIfd, stream, image)

The SamplesPerPixel metadata in the TIFF header indicates the number of planes (color components), and the QuramDngPixelBuffer is allocated with the size width x height x planes.

do {
dst_pixel = (_BYTE *)(row_base_addr + pixel_buffer->fPlanes * col);
*dst_pixel = *(src_pixel - 2); /*** 3 ***/
dst_pixel[1] = *(src_pixel - 1);
dst_pixel[2] = *src_pixel;
src_data += 4;
} while (col < tile_r - tile_l)

QuramDngReadImage::decodeLossyJpeg checks to ensure the embedded jpeg's width and height match, but assumes there is enough room for 3 planes. When a SamplesPerPixel value of less than 3 is provided, it leads to an out-of-bounds write.

Note: This bug is very similar to CVE-2025-43300 in Apple's RawImage DNG decoder.
VERSION

Samsung Galaxy S24 Ultra One UI Version: 7.0 Android version: 15 Versions: S928BOXM4BYH1

Tested on updated S22-S24 and Z Fold/Flip 4

Dates back to at least One UI 6 (Oct 2023). Tested with Samsung Auto Blocker enabled (note the images are not decoded within the messengers, so the hwui.so doDecode modification doesn't do the decoding).

REPRODUCTION CASE

adb push poc.jpeg file:///storage/emulated/0/Android/media/com.whatsapp/WhatsApp/Media/WhatsApp\ Images
am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file:///storage/emulated/0/Android/media/com.whatsapp/WhatsApp/Media/WhatsApp%20Images/poc.jpeg
Wait roughly ~5 minutes for com.android.ipservice to decode poc.jpeg with QuramDng and crash on write

F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
F DEBUG : Build fingerprint: 'samsung/e3qxxx/e3q:15/AP3A.240905.015.A2/S928BXXS4BYH1:user/release-keys'
F DEBUG : Revision: '13'
F DEBUG : ABI: 'arm64'
F DEBUG : Processor: '5'
F DEBUG : Process uptime: 12s
F DEBUG : Cmdline: com.samsung.ipservice
F DEBUG : pid: 20709, tid: 20866, name: pool-4-thread-2 >>> com.samsung.ipservice <<<
F DEBUG : uid: 5004
F DEBUG : tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
F DEBUG : pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY)
F DEBUG : signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0xb400007339620000
F DEBUG : x0 0000000000000001 x1 0000000000000001 x2 0000000000000001 x3 0000000000000000
F DEBUG : x4 0000000000000438 x5 0000000000000000 x6 0000000000000000 x7 0000000000000080
F DEBUG : x8 b400007486e28180 x9 000000000000fffc x10 0000000000003fff x11 b4000072e961d002
F DEBUG : x12 0000000000003fff x13 b40000733961fffe x14 000000000000003f x15 b40000733961c000
F DEBUG : x16 b40000732961cffe x17 0000000000004000 x18 00000073c40d4000 x19 00000073c54528a8
F DEBUG : x20 b4000072e961d000 x21 b4000075f6d95890 x22 00000000000002da x23 00000073c5452860
F DEBUG : x24 0000000040000000 x25 00000073c5455940 x26 0000000000004000 x27 0000000000004000
F DEBUG : x28 00000073c5452858 x29 00000073c5452620
F DEBUG : lr 00000073c0ec066c sp 00000073c5452600 pc 00000073c0ec0768 pst 0000000080001000
F DEBUG : 33 total frames
F DEBUG : backtrace:
F DEBUG : #00 pc 0000000000257768 /system/lib64/libimagecodec.quram.so (QuramDngReadImage::decodeLossyJPEG(QuramDngImage&, QuramDngRect&, unsigned int, unsigned int, unsigned int, unsigned int, std::__1::unique_ptr<char [], std::__1::default_delete<char []>>&, bool)+528) (BuildId: 616cea8390d023e14fa3852e064cde4d60748e97)
F DEBUG : #01 pc 0000000000255f6c /system/lib64/libimagecodec.quram.so (QuramDngReadImage::readTile(QuramDngIFD&, QuramDngStream&, QuramDngImage&, QuramDngRect&, unsigned int, unsigned int, unsigned int, std::__1::unique_ptr<char [], std::__1::default_delete<char []>>&, unsigned int, std::__1::unique_ptr<char [], std::__1::default_delete<char []>>&, unsigned int, std::__1::unique_ptr<char [], std::__1::default_delete<char []>>&, unsigned int, bool)+324) (BuildId: 616cea8390d023e14fa3852e064cde4d60748e97)
F DEBUG : #02 pc 0000000000255b5c /system/lib64/libimagecodec.quram.so (QuramDngReadImage::read(QuramDngIFD&, QuramDngStream&, QuramDngImage&)+2168) (BuildId: 616cea8390d023e14fa3852e064cde4d60748e97)
F DEBUG : #03 pc 0000000000242fc0 /system/lib64/libimagecodec.quram.so (QuramDngIFD::readImage(QuramDngStream&, QuramDngImage&)+68) (BuildId: 616cea8390d023e14fa3852e064cde4d60748e97)
F DEBUG : #04 pc 0000000000238100 /system/lib64/libimagecodec.quram.so (QuramDngDecoder::readStage1Image()+224) (BuildId: 616cea8390d023e14fa3852e064cde4d60748e97)
F DEBUG : #05 pc 0000000000236570 /system/lib64/libimagecodec.quram.so (QuramDngDecoder::decode(decInfo*)+288) (BuildId: 616cea8390d023e14fa3852e064cde4d60748e97)
F DEBUG : #06 pc 0000000000236108 /system/lib64/libimagecodec.quram.so (QuramDngDecoder::decode(unsigned char*, decInfo*)+100) (BuildId: 616cea8390d023e14fa3852e064cde4d60748e97)
F DEBUG : #07 pc 00000000002259c4 /system/lib64/libimagecodec.quram.so (decodeDNGImageBuffer+96) (BuildId: 616cea8390d023e14fa3852e064cde4d60748e97)
F DEBUG : #08 pc 00000000000c36b4 /system/lib64/libimagecodec.quram.so (Java_com_quramsoft_images_QuramDngBitmap_DecodeDNGImageBufferJNI+1216) (BuildId: 616cea8390d023e14fa3852e064cde4d60748e97)
F DEBUG : #09 pc 0000000000344500 /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 80d2ab18f9d259d8e546c1e6bae752b1)
F DEBUG : #10 pc 00000000006899d8 /apex/com.android.art/lib64/libart.so (nterp_helper+2152) (BuildId: 80d2ab18f9d259d8e546c1e6bae752b1)
F DEBUG : #11 pc 0000000000086ea8 /system/priv-app/IPService/IPService.apk (com.quramsoft.images.QuramDngBitmap.decodeFile+320)
F DEBUG : #12 pc 0000000000689208 /apex/com.android.art/lib64/libart.so (nterp_helper+152) (BuildId: 80d2ab18f9d259d8e546c1e6bae752b1)
F DEBUG : #13 pc 000000000008449a /system/priv-app/IPService/IPService.apk (com.quramsoft.images.QrBitmapFactory.decodeFile+38)
F DEBUG : #14 pc 00000000006891a4 /apex/com.android.art/lib64/libart.so (nterp_helper+52) (BuildId: 80d2ab18f9d259d8e546c1e6bae752b1)
F DEBUG : #15 pc 00000000000ef34c /system/priv-app/IPService/IPService.apk (com.samsung.ipservice.common.h.a+220)
F DEBUG : #16 pc 000000000068a0c4 /apex/com.android.art/lib64/libart.so (nterp_helper+3924) (BuildId: 80d2ab18f9d259d8e546c1e6bae752b1)
F DEBUG : #17 pc 000000000006d664 /system/priv-app/IPService/IPService.apk (c0.d.j+516)
F DEBUG : #18 pc 000000000068a0c4 /apex/com.android.art/lib64/libart.so (nterp_helper+3924) (BuildId: 80d2ab18f9d259d8e546c1e6bae752b1)
F DEBUG : #19 pc 000000000006de6c /system/priv-app/IPService/IPService.apk (c0.d.d+184)
F DEBUG : #20 pc 000000000068a0c4 /apex/com.android.art/lib64/libart.so (nterp_helper+3924) (BuildId: 80d2ab18f9d259d8e546c1e6bae752b1)
F DEBUG : #21 pc 0000000000056d00 /system/priv-app/IPService/IPService.apk (Y.a.run+48)
F DEBUG : #22 pc 00000000004a2ddc /data/misc/apexdata/com.android.art/dalvik-cache/arm64/boot.oat (java.util.concurrent.Executors$RunnableAdapter.call+60)
F DEBUG : #23 pc 00000000004a1e54 /data/misc/apexdata/com.android.art/dalvik-cache/arm64/boot.oat (java.util.concurrent.FutureTask.run+164)
F DEBUG : #24 pc 00000000004acd04 /data/misc/apexdata/com.android.art/dalvik-cache/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor.runWorker+676)
F DEBUG : #25 pc 00000000004b0ca8 /data/misc/apexdata/com.android.art/dalvik-cache/arm64/boot.oat (java.util.concurrent.ThreadPoolExecutor$Worker.run+56)
F DEBUG : #26 pc 00000000003414f0 /data/misc/apexdata/com.android.art/dalvik-cache/arm64/boot.oat (java.lang.Thread.run+64)
F DEBUG : #27 pc 000000000032d194 /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+612) (BuildId: 80d2ab18f9d259d8e546c1e6bae752b1)
F DEBUG : #28 pc 00000000002de270 /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+216) (BuildId: 80d2ab18f9d259d8e546c1e6bae752b1)
F DEBUG : #29 pc 00000000004bfcf4 /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallback(void*)+932) (BuildId: 80d2ab18f9d259d8e546c1e6bae752b1)
F DEBUG : #30 pc 00000000004bf940 /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallbackWithUffdGc(void*)+8) (BuildId: 80d2ab18f9d259d8e546c1e6bae752b1)
F DEBUG : #31 pc 0000000000071ae8 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+196) (BuildId: a7d3435cebd777f0dc1a07c5e7386036)
F DEBUG : #32 pc 0000000000063be0 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+68) (BuildId: a7d3435cebd777f0dc1a07c5e7386036)

CREDIT INFORMATION

Brendon Tiszka of Google Project Zero

This bug is subject to a 90-day disclosure deadline. If a fix for this issue is made available to users before the end of the 90-day deadline, this bug report will become public 30 days after the fix was made available. Otherwise, this bug report will become public at the deadline. The scheduled deadline is 2025-12-10.
Social Media Share
About Contact Terms of Use Privacy Policy
© Khalil Shreateh — Cybersecurity Researcher & White-Hat Hacker — Palestine 🇵🇸
All content is for educational purposes only. Unauthorized use of any information on this site is strictly prohibited.