From f7ff4ac9a35fa7a4f2e8c35766dc8fd929c5f04f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mauricio=20Alexander=20Fl=C3=B3rez=20Pati=C3=B1o?= Date: Mon, 9 Nov 2026 22:50:33 -0500 Subject: [PATCH] Fix out-of-range LED writes on split keyboards in rgblight (#26481) rgblight_led_index() subtracts the clipping start position and returns a uint8_t, so on the half whose clipping range does not start at 0 the LEDs of the other half wrap around to indices like 252..255. Those reached rgblight_driver.set_color() unchecked and, with the RP2040 vendor WS2812 driver, overwrote RAM past the LED buffer (the emulated EEPROM cache). Skip indices outside the clipping range in setrgb() and route the direct set_color() calls through it. Fixes #26480 --- quantum/rgblight/rgblight.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/quantum/rgblight/rgblight.c b/quantum/rgblight/rgblight.c index 3c4a05844d9..03ff8b9417c 100644 --- a/quantum/rgblight/rgblight.c +++ b/quantum/rgblight/rgblight.c @@ -147,7 +147,14 @@ uint8_t rgblight_led_index(uint8_t index) { } void setrgb(uint8_t r, uint8_t g, uint8_t b, int index) { - rgblight_driver.set_color(rgblight_led_index(index), r, g, b); + uint8_t led_index = rgblight_led_index(index); + // On split keyboards each half only drives the LEDs in its clipping range. The index of an + // LED on the other half wraps around in rgblight_led_index() and must not reach the driver, + // which does not bounds-check it. + if (led_index >= rgblight_ranges.clipping_num_leds) { + return; + } + rgblight_driver.set_color(led_index, r, g, b); } void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, int index) { @@ -628,7 +635,7 @@ void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) { } for (uint8_t i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { - rgblight_driver.set_color(rgblight_led_index(i), r, g, b); + setrgb(r, g, b, i); } rgblight_set(); } @@ -638,7 +645,7 @@ void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index) { return; } - rgblight_driver.set_color(rgblight_led_index(index), r, g, b); + setrgb(r, g, b, index); rgblight_set(); } @@ -669,7 +676,7 @@ void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8 } for (uint8_t i = start; i < end; i++) { - rgblight_driver.set_color(rgblight_led_index(i), r, g, b); + setrgb(r, g, b, i); } rgblight_set(); } @@ -861,7 +868,7 @@ void rgblight_wakeup(void) { void rgblight_set(void) { if (!rgblight_config.enable) { for (uint8_t i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { - rgblight_driver.set_color(rgblight_led_index(i), 0, 0, 0); + setrgb(0, 0, 0, i); } } @@ -1198,7 +1205,7 @@ void rgblight_effect_snake(animation_status_t *anim) { # endif for (i = 0; i < rgblight_ranges.effect_num_leds; i++) { - rgblight_driver.set_color(rgblight_led_index(i + rgblight_ranges.effect_start_pos), 0, 0, 0); + setrgb(0, 0, 0, i + rgblight_ranges.effect_start_pos); for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) { k = pos + j * increment; @@ -1254,7 +1261,7 @@ void rgblight_effect_knight(animation_status_t *anim) { # endif // Set all the LEDs to 0 for (i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { - rgblight_driver.set_color(rgblight_led_index(i), 0, 0, 0); + setrgb(0, 0, 0, i); } // Determine which LEDs should be lit up for (i = 0; i < RGBLIGHT_EFFECT_KNIGHT_LED_NUM; i++) { @@ -1263,7 +1270,7 @@ void rgblight_effect_knight(animation_status_t *anim) { if (i >= low_bound && i <= high_bound) { sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, cur); } else { - rgblight_driver.set_color(rgblight_led_index(cur), 0, 0, 0); + setrgb(0, 0, 0, cur); } } rgblight_set();