diff mbox series

[v3,02/16] cxl/pci: Handle truncated CDAT header

Message ID 7f7030bb14ad7c8e0e051319cf473ab3197da5be.1676043318.git.lukas@wunner.de (mailing list archive)
State Superseded
Delegated to: Bjorn Helgaas
Headers show
Series Collection of DOE material | expand

Commit Message

Lukas Wunner Feb. 10, 2023, 8:25 p.m. UTC
cxl_cdat_get_length() only checks whether the DOE response size is
sufficient for the Table Access response header (1 dword), but not the
succeeding CDAT header (1 dword length plus other fields).

It thus returns whatever uninitialized memory happens to be on the stack
if a truncated DOE response with only 1 dword was received.  Fix it.

Fixes: c97006046c79 ("cxl/port: Read CDAT table")
Reported-by: Ming Li <ming4.li@intel.com>
Tested-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Cc: stable@vger.kernel.org # v6.0+
---
 Changes v2 -> v3:
 * Newly added patch in v3

 drivers/cxl/core/pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Dan Williams Feb. 11, 2023, 12:40 a.m. UTC | #1
Lukas Wunner wrote:
> cxl_cdat_get_length() only checks whether the DOE response size is
> sufficient for the Table Access response header (1 dword), but not the
> succeeding CDAT header (1 dword length plus other fields).
> 
> It thus returns whatever uninitialized memory happens to be on the stack
> if a truncated DOE response with only 1 dword was received.  Fix it.
> 
> Fixes: c97006046c79 ("cxl/port: Read CDAT table")
> Reported-by: Ming Li <ming4.li@intel.com>
> Tested-by: Ira Weiny <ira.weiny@intel.com>
> Signed-off-by: Lukas Wunner <lukas@wunner.de>
> Cc: stable@vger.kernel.org # v6.0+
> ---
>  Changes v2 -> v3:
>  * Newly added patch in v3
> 
>  drivers/cxl/core/pci.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index d3cf1d9d67d4..11a85b3a9a0b 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -528,7 +528,7 @@ static int cxl_cdat_get_length(struct device *dev,
>  		return rc;
>  	}
>  	wait_for_completion(&t.c);
> -	if (t.task.rv < sizeof(u32))
> +	if (t.task.rv < 2 * sizeof(u32))
>  		return -EIO;

Looks good, I wonder since this is standard for all data objects whether
the check should be pushed into the core?

For now this is easier to backport, but a follow-on could push it down a
level.

Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Lukas Wunner Feb. 11, 2023, 9:34 a.m. UTC | #2
On Fri, Feb 10, 2023 at 04:40:15PM -0800, Dan Williams wrote:
> Lukas Wunner wrote:
> > cxl_cdat_get_length() only checks whether the DOE response size is
> > sufficient for the Table Access response header (1 dword), but not the
> > succeeding CDAT header (1 dword length plus other fields).
> > 
> > It thus returns whatever uninitialized memory happens to be on the stack
> > if a truncated DOE response with only 1 dword was received.  Fix it.
[...]
> > --- a/drivers/cxl/core/pci.c
> > +++ b/drivers/cxl/core/pci.c
> > @@ -528,7 +528,7 @@ static int cxl_cdat_get_length(struct device *dev,
> >  		return rc;
> >  	}
> >  	wait_for_completion(&t.c);
> > -	if (t.task.rv < sizeof(u32))
> > +	if (t.task.rv < 2 * sizeof(u32))
> >  		return -EIO;
> 
> Looks good, I wonder since this is standard for all data objects whether
> the check should be pushed into the core?

No, "t.task.rv" contains the payload length in bytes of the response
received via DOE.  It doesn't include the DOE header.

I think it is legal to receive an empty response via DOE, so I cannot
push a length check down into the core.

In this case, the payload contains one dword for the Table Access Response
header (CXL r3.0 sec 8.1.11.1), followed by 3 dwords for the CDAT header:

https://uefi.org/sites/default/files/resources/Coherent%20Device%20Attribute%20Table_1.01.pdf

The CDAT header contains the length of the entire CDAT in the first
dword, hence the above-quoted check only verifies that at least two
dwords were received.  It's harmless if the remainder of the CDAT
header is truncated.

Thanks,

Lukas
Jonathan Cameron Feb. 14, 2023, 11:16 a.m. UTC | #3
On Fri, 10 Feb 2023 21:25:02 +0100
Lukas Wunner <lukas@wunner.de> wrote:

> cxl_cdat_get_length() only checks whether the DOE response size is
> sufficient for the Table Access response header (1 dword), but not the
> succeeding CDAT header (1 dword length plus other fields).
> 
> It thus returns whatever uninitialized memory happens to be on the stack
> if a truncated DOE response with only 1 dword was received.  Fix it.
> 
> Fixes: c97006046c79 ("cxl/port: Read CDAT table")
> Reported-by: Ming Li <ming4.li@intel.com>
> Tested-by: Ira Weiny <ira.weiny@intel.com>
> Signed-off-by: Lukas Wunner <lukas@wunner.de>
> Cc: stable@vger.kernel.org # v6.0+
Oops + thanks for fixing.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

> ---
>  Changes v2 -> v3:
>  * Newly added patch in v3
> 
>  drivers/cxl/core/pci.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index d3cf1d9d67d4..11a85b3a9a0b 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
> @@ -528,7 +528,7 @@ static int cxl_cdat_get_length(struct device *dev,
>  		return rc;
>  	}
>  	wait_for_completion(&t.c);
> -	if (t.task.rv < sizeof(u32))
> +	if (t.task.rv < 2 * sizeof(u32))
>  		return -EIO;
>  
>  	*length = le32_to_cpu(t.response_pl[1]);
Li, Ming Feb. 15, 2023, 1:41 a.m. UTC | #4
On 2/11/2023 4:25 AM, Lukas Wunner wrote:
> cxl_cdat_get_length() only checks whether the DOE response size is
> sufficient for the Table Access response header (1 dword), but not the
> succeeding CDAT header (1 dword length plus other fields).
> 
> It thus returns whatever uninitialized memory happens to be on the stack
> if a truncated DOE response with only 1 dword was received.  Fix it.
> 
> Fixes: c97006046c79 ("cxl/port: Read CDAT table")
> Reported-by: Ming Li <ming4.li@intel.com>
> Tested-by: Ira Weiny <ira.weiny@intel.com>
> Signed-off-by: Lukas Wunner <lukas@wunner.de>

Reviewed-by: Ming Li <ming4.li@intel.com>
diff mbox series

Patch

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index d3cf1d9d67d4..11a85b3a9a0b 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -528,7 +528,7 @@  static int cxl_cdat_get_length(struct device *dev,
 		return rc;
 	}
 	wait_for_completion(&t.c);
-	if (t.task.rv < sizeof(u32))
+	if (t.task.rv < 2 * sizeof(u32))
 		return -EIO;
 
 	*length = le32_to_cpu(t.response_pl[1]);