* [PATCH] misc: xilinx_sdfec: validate LDPC code register offsets
@ 2026-06-24 19:08 Yousef Alhouseen
2026-06-29 8:14 ` Cvetic, Dragan
0 siblings, 1 reply; 2+ messages in thread
From: Yousef Alhouseen @ 2026-06-24 19:08 UTC (permalink / raw)
To: Derek Kiernan, Dragan Cvetic
Cc: Arnd Bergmann, Greg Kroah-Hartman, Michal Simek,
linux-arm-kernel, linux-kernel, Yousef Alhouseen
The LDPC code register helpers check the target MMIO address after adding
code_id * XSDFEC_LDPC_REG_JUMP to the register base. code_id is supplied
through the ioctl path, so the multiplication and addition can wrap before
the bounds check.
Validate the code_id against the register window size before computing
the final address, then write using the checked address.
Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
---
drivers/misc/xilinx_sdfec.c | 72 +++++++++++++++++--------------------
1 file changed, 32 insertions(+), 40 deletions(-)
diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
index 3135ba3a5..63f0eb2bd 100644
--- a/drivers/misc/xilinx_sdfec.c
+++ b/drivers/misc/xilinx_sdfec.c
@@ -456,10 +456,23 @@ static int xsdfec_get_turbo(struct xsdfec_dev *xsdfec, void __user *arg)
return err;
}
+static int xsdfec_ldpc_reg_addr(struct xsdfec_dev *xsdfec, u32 base, u32 high,
+ u32 offset, u32 *addr)
+{
+ if (offset > (high - base) / XSDFEC_LDPC_REG_JUMP) {
+ dev_dbg(xsdfec->dev, "Writing outside of LDPC register space");
+ return -EINVAL;
+ }
+
+ *addr = base + offset * XSDFEC_LDPC_REG_JUMP;
+ return 0;
+}
+
static int xsdfec_reg0_write(struct xsdfec_dev *xsdfec, u32 n, u32 k, u32 psize,
u32 offset)
{
u32 wdata;
+ u32 addr;
if (n < XSDFEC_REG0_N_MIN || n > XSDFEC_REG0_N_MAX || psize == 0 ||
(n > XSDFEC_REG0_N_MUL_P * psize) || n <= k || ((n % psize) != 0)) {
@@ -476,17 +489,11 @@ static int xsdfec_reg0_write(struct xsdfec_dev *xsdfec, u32 n, u32 k, u32 psize,
k = k << XSDFEC_REG0_K_LSB;
wdata = k | n;
- if (XSDFEC_LDPC_CODE_REG0_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP) >
- XSDFEC_LDPC_CODE_REG0_ADDR_HIGH) {
- dev_dbg(xsdfec->dev, "Writing outside of LDPC reg0 space 0x%x",
- XSDFEC_LDPC_CODE_REG0_ADDR_BASE +
- (offset * XSDFEC_LDPC_REG_JUMP));
+ if (xsdfec_ldpc_reg_addr(xsdfec, XSDFEC_LDPC_CODE_REG0_ADDR_BASE,
+ XSDFEC_LDPC_CODE_REG0_ADDR_HIGH, offset,
+ &addr))
return -EINVAL;
- }
- xsdfec_regwrite(xsdfec,
- XSDFEC_LDPC_CODE_REG0_ADDR_BASE +
- (offset * XSDFEC_LDPC_REG_JUMP),
- wdata);
+ xsdfec_regwrite(xsdfec, addr, wdata);
return 0;
}
@@ -494,6 +501,7 @@ static int xsdfec_reg1_write(struct xsdfec_dev *xsdfec, u32 psize,
u32 no_packing, u32 nm, u32 offset)
{
u32 wdata;
+ u32 addr;
if (psize < XSDFEC_REG1_PSIZE_MIN || psize > XSDFEC_REG1_PSIZE_MAX) {
dev_dbg(xsdfec->dev, "Psize is not in range");
@@ -510,17 +518,11 @@ static int xsdfec_reg1_write(struct xsdfec_dev *xsdfec, u32 psize,
nm = (nm << XSDFEC_REG1_NM_LSB) & XSDFEC_REG1_NM_MASK;
wdata = nm | no_packing | psize;
- if (XSDFEC_LDPC_CODE_REG1_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP) >
- XSDFEC_LDPC_CODE_REG1_ADDR_HIGH) {
- dev_dbg(xsdfec->dev, "Writing outside of LDPC reg1 space 0x%x",
- XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
- (offset * XSDFEC_LDPC_REG_JUMP));
+ if (xsdfec_ldpc_reg_addr(xsdfec, XSDFEC_LDPC_CODE_REG1_ADDR_BASE,
+ XSDFEC_LDPC_CODE_REG1_ADDR_HIGH, offset,
+ &addr))
return -EINVAL;
- }
- xsdfec_regwrite(xsdfec,
- XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
- (offset * XSDFEC_LDPC_REG_JUMP),
- wdata);
+ xsdfec_regwrite(xsdfec, addr, wdata);
return 0;
}
@@ -529,6 +531,7 @@ static int xsdfec_reg2_write(struct xsdfec_dev *xsdfec, u32 nlayers, u32 nmqc,
u32 max_schedule, u32 offset)
{
u32 wdata;
+ u32 addr;
if (nlayers < XSDFEC_REG2_NLAYERS_MIN ||
nlayers > XSDFEC_REG2_NLAYERS_MAX) {
@@ -563,17 +566,11 @@ static int xsdfec_reg2_write(struct xsdfec_dev *xsdfec, u32 nlayers, u32 nmqc,
wdata = (max_schedule | no_final_parity | special_qc | norm_type |
nmqc | nlayers);
- if (XSDFEC_LDPC_CODE_REG2_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP) >
- XSDFEC_LDPC_CODE_REG2_ADDR_HIGH) {
- dev_dbg(xsdfec->dev, "Writing outside of LDPC reg2 space 0x%x",
- XSDFEC_LDPC_CODE_REG2_ADDR_BASE +
- (offset * XSDFEC_LDPC_REG_JUMP));
+ if (xsdfec_ldpc_reg_addr(xsdfec, XSDFEC_LDPC_CODE_REG2_ADDR_BASE,
+ XSDFEC_LDPC_CODE_REG2_ADDR_HIGH, offset,
+ &addr))
return -EINVAL;
- }
- xsdfec_regwrite(xsdfec,
- XSDFEC_LDPC_CODE_REG2_ADDR_BASE +
- (offset * XSDFEC_LDPC_REG_JUMP),
- wdata);
+ xsdfec_regwrite(xsdfec, addr, wdata);
return 0;
}
@@ -581,20 +578,15 @@ static int xsdfec_reg3_write(struct xsdfec_dev *xsdfec, u8 sc_off, u8 la_off,
u16 qc_off, u32 offset)
{
u32 wdata;
+ u32 addr;
wdata = ((qc_off << XSDFEC_REG3_QC_OFF_LSB) |
(la_off << XSDFEC_REG3_LA_OFF_LSB) | sc_off);
- if (XSDFEC_LDPC_CODE_REG3_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP) >
- XSDFEC_LDPC_CODE_REG3_ADDR_HIGH) {
- dev_dbg(xsdfec->dev, "Writing outside of LDPC reg3 space 0x%x",
- XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
- (offset * XSDFEC_LDPC_REG_JUMP));
+ if (xsdfec_ldpc_reg_addr(xsdfec, XSDFEC_LDPC_CODE_REG3_ADDR_BASE,
+ XSDFEC_LDPC_CODE_REG3_ADDR_HIGH, offset,
+ &addr))
return -EINVAL;
- }
- xsdfec_regwrite(xsdfec,
- XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
- (offset * XSDFEC_LDPC_REG_JUMP),
- wdata);
+ xsdfec_regwrite(xsdfec, addr, wdata);
return 0;
}
--
2.54.0
^ permalink raw reply [flat|nested] 2+ messages in thread
* RE: [PATCH] misc: xilinx_sdfec: validate LDPC code register offsets
2026-06-24 19:08 [PATCH] misc: xilinx_sdfec: validate LDPC code register offsets Yousef Alhouseen
@ 2026-06-29 8:14 ` Cvetic, Dragan
0 siblings, 0 replies; 2+ messages in thread
From: Cvetic, Dragan @ 2026-06-29 8:14 UTC (permalink / raw)
To: Yousef Alhouseen, Kiernan, Derek
Cc: Arnd Bergmann, Greg Kroah-Hartman, Simek, Michal,
linux-arm-kernel, linux-kernel
AMD General
> -----Original Message-----
> From: Yousef Alhouseen <alhouseenyousef@gmail.com>
> Sent: Wednesday 24 June 2026 20:08
> To: Kiernan, Derek <derek.kiernan@amd.com>; Cvetic, Dragan
> <dragan.cvetic@amd.com>
> Cc: Arnd Bergmann <arnd@arndb.de>; Greg Kroah-Hartman
> <gregkh@linuxfoundation.org>; Simek, Michal <michal.simek@amd.com>;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; Yousef
> Alhouseen <alhouseenyousef@gmail.com>
> Subject: [PATCH] misc: xilinx_sdfec: validate LDPC code register offsets
>
> The LDPC code register helpers check the target MMIO address after adding
> code_id * XSDFEC_LDPC_REG_JUMP to the register base. code_id is supplied
> through the ioctl path, so the multiplication and addition can wrap before
> the bounds check.
>
> Validate the code_id against the register window size before computing
> the final address, then write using the checked address.
>
> Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
> ---
> drivers/misc/xilinx_sdfec.c | 72 +++++++++++++++++--------------------
> 1 file changed, 32 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
> index 3135ba3a5..63f0eb2bd 100644
> --- a/drivers/misc/xilinx_sdfec.c
> +++ b/drivers/misc/xilinx_sdfec.c
> @@ -456,10 +456,23 @@ static int xsdfec_get_turbo(struct xsdfec_dev
> *xsdfec, void __user *arg)
> return err;
> }
>
> +static int xsdfec_ldpc_reg_addr(struct xsdfec_dev *xsdfec, u32 base, u32
> high,
> + u32 offset, u32 *addr)
> +{
> + if (offset > (high - base) / XSDFEC_LDPC_REG_JUMP) {
If someone accidentally passes swapped high, base constants in the future, this underflows because they're unsigned.
Check if (high-base) >=0
> + dev_dbg(xsdfec->dev, "Writing outside of LDPC register
> space");
> + return -EINVAL;
> + }
> +
> + *addr = base + offset * XSDFEC_LDPC_REG_JUMP;
> + return 0;
> +}
> +
> static int xsdfec_reg0_write(struct xsdfec_dev *xsdfec, u32 n, u32 k, u32
> psize,
> u32 offset)
> {
> u32 wdata;
> + u32 addr;
>
> if (n < XSDFEC_REG0_N_MIN || n > XSDFEC_REG0_N_MAX || psize ==
> 0 ||
> (n > XSDFEC_REG0_N_MUL_P * psize) || n <= k || ((n % psize) != 0))
> {
> @@ -476,17 +489,11 @@ static int xsdfec_reg0_write(struct xsdfec_dev
> *xsdfec, u32 n, u32 k, u32 psize,
> k = k << XSDFEC_REG0_K_LSB;
> wdata = k | n;
>
> - if (XSDFEC_LDPC_CODE_REG0_ADDR_BASE + (offset *
> XSDFEC_LDPC_REG_JUMP) >
> - XSDFEC_LDPC_CODE_REG0_ADDR_HIGH) {
> - dev_dbg(xsdfec->dev, "Writing outside of LDPC reg0 space
> 0x%x",
> - XSDFEC_LDPC_CODE_REG0_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP));
> + if (xsdfec_ldpc_reg_addr(xsdfec,
> XSDFEC_LDPC_CODE_REG0_ADDR_BASE,
> + XSDFEC_LDPC_CODE_REG0_ADDR_HIGH,
> offset,
> + &addr))
Put debug message, previous code had debug message.
> return -EINVAL;
> - }
> - xsdfec_regwrite(xsdfec,
> - XSDFEC_LDPC_CODE_REG0_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP),
> - wdata);
> + xsdfec_regwrite(xsdfec, addr, wdata);
> return 0;
> }
>
> @@ -494,6 +501,7 @@ static int xsdfec_reg1_write(struct xsdfec_dev
> *xsdfec, u32 psize,
> u32 no_packing, u32 nm, u32 offset)
> {
> u32 wdata;
> + u32 addr;
>
> if (psize < XSDFEC_REG1_PSIZE_MIN || psize >
> XSDFEC_REG1_PSIZE_MAX) {
> dev_dbg(xsdfec->dev, "Psize is not in range");
> @@ -510,17 +518,11 @@ static int xsdfec_reg1_write(struct xsdfec_dev
> *xsdfec, u32 psize,
> nm = (nm << XSDFEC_REG1_NM_LSB) & XSDFEC_REG1_NM_MASK;
>
> wdata = nm | no_packing | psize;
> - if (XSDFEC_LDPC_CODE_REG1_ADDR_BASE + (offset *
> XSDFEC_LDPC_REG_JUMP) >
> - XSDFEC_LDPC_CODE_REG1_ADDR_HIGH) {
> - dev_dbg(xsdfec->dev, "Writing outside of LDPC reg1 space
> 0x%x",
> - XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP));
> + if (xsdfec_ldpc_reg_addr(xsdfec,
> XSDFEC_LDPC_CODE_REG1_ADDR_BASE,
> + XSDFEC_LDPC_CODE_REG1_ADDR_HIGH,
> offset,
> + &addr))
Put debug message, previous code had debug message.
> return -EINVAL;
> - }
> - xsdfec_regwrite(xsdfec,
> - XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP),
> - wdata);
> + xsdfec_regwrite(xsdfec, addr, wdata);
> return 0;
> }
>
> @@ -529,6 +531,7 @@ static int xsdfec_reg2_write(struct xsdfec_dev
> *xsdfec, u32 nlayers, u32 nmqc,
> u32 max_schedule, u32 offset)
> {
> u32 wdata;
> + u32 addr;
>
> if (nlayers < XSDFEC_REG2_NLAYERS_MIN ||
> nlayers > XSDFEC_REG2_NLAYERS_MAX) {
> @@ -563,17 +566,11 @@ static int xsdfec_reg2_write(struct xsdfec_dev
> *xsdfec, u32 nlayers, u32 nmqc,
> wdata = (max_schedule | no_final_parity | special_qc | norm_type |
> nmqc | nlayers);
>
> - if (XSDFEC_LDPC_CODE_REG2_ADDR_BASE + (offset *
> XSDFEC_LDPC_REG_JUMP) >
> - XSDFEC_LDPC_CODE_REG2_ADDR_HIGH) {
> - dev_dbg(xsdfec->dev, "Writing outside of LDPC reg2 space
> 0x%x",
> - XSDFEC_LDPC_CODE_REG2_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP));
> + if (xsdfec_ldpc_reg_addr(xsdfec,
> XSDFEC_LDPC_CODE_REG2_ADDR_BASE,
> + XSDFEC_LDPC_CODE_REG2_ADDR_HIGH,
> offset,
> + &addr))
Put debug message, previous code had debug message.
> return -EINVAL;
> - }
> - xsdfec_regwrite(xsdfec,
> - XSDFEC_LDPC_CODE_REG2_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP),
> - wdata);
> + xsdfec_regwrite(xsdfec, addr, wdata);
> return 0;
> }
>
> @@ -581,20 +578,15 @@ static int xsdfec_reg3_write(struct xsdfec_dev
> *xsdfec, u8 sc_off, u8 la_off,
> u16 qc_off, u32 offset)
> {
> u32 wdata;
> + u32 addr;
>
> wdata = ((qc_off << XSDFEC_REG3_QC_OFF_LSB) |
> (la_off << XSDFEC_REG3_LA_OFF_LSB) | sc_off);
> - if (XSDFEC_LDPC_CODE_REG3_ADDR_BASE + (offset *
> XSDFEC_LDPC_REG_JUMP) >
> - XSDFEC_LDPC_CODE_REG3_ADDR_HIGH) {
> - dev_dbg(xsdfec->dev, "Writing outside of LDPC reg3 space
> 0x%x",
> - XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP));
> + if (xsdfec_ldpc_reg_addr(xsdfec,
> XSDFEC_LDPC_CODE_REG3_ADDR_BASE,
> + XSDFEC_LDPC_CODE_REG3_ADDR_HIGH,
> offset,
> + &addr))
Put debug message, previous code had debug message.
> return -EINVAL;
> - }
> - xsdfec_regwrite(xsdfec,
> - XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP),
> - wdata);
> + xsdfec_regwrite(xsdfec, addr, wdata);
> return 0;
> }
>
> --
> 2.54.0
Dragan
Regards
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-06-29 8:14 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-24 19:08 [PATCH] misc: xilinx_sdfec: validate LDPC code register offsets Yousef Alhouseen
2026-06-29 8:14 ` Cvetic, Dragan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®