* [PATCH] staging: fbtft: fix unaligned access and txbuf safety issues
[not found] <20260625111602.438761F000E9@smtp.kernel.org>
@ 2026-06-25 11:42 ` suryasaimadhu
2026-06-25 12:00 ` Dan Carpenter
2026-06-25 14:05 ` Andy Shevchenko
0 siblings, 2 replies; 3+ messages in thread
From: suryasaimadhu @ 2026-06-25 11:42 UTC (permalink / raw)
To: andy
Cc: gregkh, dri-devel, linux-fbdev, linux-staging, linux-kernel,
suryasaimadhu
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 <suryasaimadhu369@gmail.com>
---
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
^ permalink raw reply related [flat|nested] 3+ messages in thread