[PATCH] staging: fbtft: fix unaligned access and txbuf safety issues
From: suryasaimadhu <hidden>
Date: 2026-06-25 11:42:32
Also in:
dri-devel, linux-staging, lkml
Subsystem:
fbtft framebuffer drivers, staging subsystem, the rest · Maintainers:
Andy Shevchenko, Greg Kroah-Hartman, Linus Torvalds
This patch addresses several pre-existing issues in the fbtft driver: 1. define_fbtft_write_reg(): when par->startbyte is set, buf is advanced by one byte creating a misaligned pointer for 16-bit types. Use put_unaligned() for register writes and fix the SPI transfer size from len * (sizeof(data_type) + offset) to len * sizeof(data_type) + offset. 2. fbtft_write_vmem16_bus8() and fb_ra8875 write_vmem16_bus8(): same unaligned 16-bit stores when txbuf is byte-offset for a start prefix. Use put_unaligned() for pixel data copies. 3. tx_array_size underflow: both vmem helpers subtract 2 from tx_array_size when a startbyte prefix is used. A small txbuflen device property causes unsigned underflow and out-of-bounds heap writes. Fall back to the non-buffered write path when the buffer is too small. 4. fb_ra8875 write_vmem16_bus8(): missing NULL check for par->txbuf.buf, which remains NULL on big-endian when txbuflen is 0 because the PAGE_SIZE fallback is little-endian only. Fall back to direct write when the buffer is missing. Also replace empty modifier arguments in define_fbtft_write_reg() with a no-op macro to fix checkpatch warnings. Signed-off-by: suryasaimadhu <redacted> --- drivers/staging/fbtft/fb_ra8875.c | 10 +++++++++- drivers/staging/fbtft/fbtft-bus.c | 25 +++++++++++++++++-------- 2 files changed, 26 insertions(+), 9 deletions(-)
diff --git a/drivers/staging/fbtft/fb_ra8875.c b/drivers/staging/fbtft/fb_ra8875.c
index 0ab1de664..06f650aac 100644
--- a/drivers/staging/fbtft/fb_ra8875.c
+++ b/drivers/staging/fbtft/fb_ra8875.c@@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/gpio/consumer.h> +#include <linux/unaligned.h> #include "fbtft.h" #define DRVNAME "fb_ra8875"
@@ -250,7 +251,14 @@ static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len) remain = len / 2; vmem16 = (u16 *)(par->info->screen_buffer + offset); + + if (!par->txbuf.buf) + return par->fbtftops.write(par, vmem16, len); + tx_array_size = par->txbuf.len / 2; + if (tx_array_size <= 2) + return par->fbtftops.write(par, vmem16, len); + txbuf16 = par->txbuf.buf + 1; tx_array_size -= 2; *(u8 *)(par->txbuf.buf) = 0x00;
@@ -262,7 +270,7 @@ static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len) to_copy, remain - to_copy); for (i = 0; i < to_copy; i++) - txbuf16[i] = cpu_to_be16(vmem16[i]); + put_unaligned(cpu_to_be16(vmem16[i]), &txbuf16[i]); vmem16 = vmem16 + to_copy; ret = par->fbtftops.write(par, par->txbuf.buf,
diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c
index 30e436ff1..52a0c5c0c 100644
--- a/drivers/staging/fbtft/fbtft-bus.c
+++ b/drivers/staging/fbtft/fbtft-bus.c@@ -4,6 +4,7 @@ #include <linux/gpio/consumer.h> #include <linux/spi/spi.h> #include "fbtft.h" +#include <linux/unaligned.h> /***************************************************************************** *
@@ -11,6 +12,7 @@ * *****************************************************************************/ +#define fbtft_write_reg_no_modifier(x) (x) #define define_fbtft_write_reg(func, buffer_type, data_type, modifier) \ void func(struct fbtft_par *par, int len, ...) \ { \
@@ -39,7 +41,7 @@ void func(struct fbtft_par *par, int len, ...) \ offset = 1; \ } \ \ - *buf = modifier((data_type)va_arg(args, unsigned int)); \ + put_unaligned(modifier((data_type)va_arg(args, unsigned int)), buf); \ ret = fbtft_write_buf_dc(par, par->buf, sizeof(data_type) + offset, \ 0); \ if (ret < 0) \
@@ -51,20 +53,22 @@ void func(struct fbtft_par *par, int len, ...) \ \ if (len) { \ i = len; \ - while (i--) \ - *buf++ = modifier((data_type)va_arg(args, \ - unsigned int)); \ + while (i--) { \ + put_unaligned(modifier((data_type)va_arg(args, \ + unsigned int)), buf); \ + buf++; \ + } \ fbtft_write_buf_dc(par, par->buf, \ - len * (sizeof(data_type) + offset), 1); \ + len * sizeof(data_type) + offset, 1); \ } \ out: \ va_end(args); \ } \ EXPORT_SYMBOL(func); -define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, u8, ) +define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, u8, fbtft_write_reg_no_modifier) define_fbtft_write_reg(fbtft_write_reg16_bus8, __be16, u16, cpu_to_be16) -define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, u16, ) +define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, u16, fbtft_write_reg_no_modifier) void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...) {
@@ -142,19 +146,24 @@ int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len) tx_array_size = par->txbuf.len / 2; if (par->startbyte) { + if (tx_array_size <= 2) + return par->fbtftops.write(par, vmem16, len); txbuf16 = par->txbuf.buf + 1; tx_array_size -= 2; *(u8 *)(par->txbuf.buf) = par->startbyte | 0x2; startbyte_size = 1; } + if (!tx_array_size) + return par->fbtftops.write(par, vmem16, len); + while (remain) { to_copy = min(tx_array_size, remain); dev_dbg(par->info->device, "to_copy=%zu, remain=%zu\n", to_copy, remain - to_copy); for (i = 0; i < to_copy; i++) - txbuf16[i] = cpu_to_be16(vmem16[i]); + put_unaligned(cpu_to_be16(vmem16[i]), &txbuf16[i]); vmem16 = vmem16 + to_copy; ret = par->fbtftops.write(par, par->txbuf.buf,
--
2.47.3