Dears, Hello everyone, I have found a potential vulnerability. The specific description is as follows. Please help me check whether this is a real vulnerability.
1. Description This code demonstrates the CWE-190 (Integer Overflow or Wraparound) vulnerability in the `video_splash_align_axis()` function, which fails to properly handle unsigned-to-signed integer conversions and arithmetic operations. https://github.com/u-boot/u-boot/blob/70dfd674782adb47a641288925484d6edc8df963/drivers/video/video_bmp.c#L229\ The current main branch also has this vulnerability. 2. Vulnerability Details Integer Overflow Mechanism: The function subtracts two `unsigned long` values (`panel_size` and `picture_size`), storing the result in a `long` variable. When `panel_size < picture_size`, the unsigned subtraction yields a large positive value (e.g., `ULONG_MAX - delta`), which converts to a **negative signed value** due to undefined behavior. Subsequent division by 2 and casting to `int` can cause truncation or sign reversal, leading to unexpected coordinate values. 3. Exploit An attacker could exploit this vulnerability by: (1) Forcing `panel_size < picture_size`: Supply crafted values (e.g., `panel_size = 100`, `picture_size = ULONG_MAX - 100`) to trigger a large unsigned result. (2) Triggering Signed Conversion: The unsigned result converts to a negative signed value, which is then divided and cast to `int`. (3) Causing Unintended Behavior: The final `int` value (e.g., `-10` instead of the expected `1000000000`) can crash the application if the coordinate is used as a memory offset. Or bypass security checks by creating out-of-bounds conditions. 4. Proof of Concept (PoC) The provided code demonstrates the vulnerability by: - Setting `panel_size = ULONG_MAX - 10` and `picture_size = 10`. - The subtraction results in `ULONG_MAX - 20`, which converts to `-21` when cast to `long`. - Division by 2 yields `-10`, which is assigned to `axis`, causing unexpected alignment. ```c #include <stdio.h> #include <stdlib.h> #include <limits.h> #define BMP_ALIGN_CENTER 0x7fff static void video_splash_align_axis(int *axis, unsigned long panel_size, unsigned long picture_size) { unsigned long panel_picture_delta = panel_size - picture_size; long axis_alignment; printf("Before calculation: panel_size = %lu, picture_size = %lu\n", panel_size, picture_size); printf("panel_size - picture_size = %lu (unsigned)\n", panel_picture_delta); // Force conversion to signed long, may cause sign error long signed_delta = (long)panel_picture_delta; printf("Converted to signed: %ld\n", signed_delta); if (*axis == BMP_ALIGN_CENTER) axis_alignment = signed_delta / 2; else if (*axis < 0) axis_alignment = signed_delta + *axis + 1; else return; printf("axis_alignment = %ld\n", axis_alignment); printf("int range before conversion: INT_MIN=%d, INT_MAX=%d\n", INT_MIN, INT_MAX); // Check for 64-bit overflow condition if (axis_alignment > LONG_MAX || axis_alignment < LONG_MIN) { printf("Warning: Calculation result exceeds long range! (%ld)\n", axis_alignment); } *axis = (int)axis_alignment; printf("Converted to int: %d (binary: 0x%08x)\n", *axis, *axis); } int main() { // Use values close to ULONG_MAX to ensure overflow unsigned long panel_size = ULONG_MAX - 10; // 2^64 - 11 unsigned long picture_size = 10; int axis = BMP_ALIGN_CENTER; printf("Before call: axis = %d, panel_size = %lu, picture_size = %lu\n", axis, panel_size, picture_size); video_splash_align_axis(&axis, panel_size, picture_size); printf("After call: axis = %d (Expected positive value, but overflowed to negative)\n", axis); return 0; } ``` output: ``` Before call: axis = 32767, panel_size = 18446744073709551605, picture_size = 10 Before calculation: panel_size = 18446744073709551605, picture_size = 10 panel_size - picture_size = 18446744073709551595 (unsigned) Converted to signed: -21 axis_alignment = -10 int range before conversion: INT_MIN=-2147483648, INT_MAX=2147483647 Converted to int: -10 (binary: 0xfffffff6) After call: axis = -10 (Expected positive value, but overflowed to negative) ``` Best Regards, ybdesire