* [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access
@ 2023-07-25 6:40 Chunyan Zhang
2023-07-25 6:40 ` [PATCH V3 2/2] serial: sprd: Fix DMA buffer leak issue Chunyan Zhang
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Chunyan Zhang @ 2023-07-25 6:40 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: linux-serial, Baolin Wang, Orson Zhai, Chunyan Zhang,
Chunyan Zhang, LKML
The global pointer 'sprd_port' may not zero when sprd_probe returns
failure, that is a risk for sprd_port to be accessed afterward, and
may lead to unexpected errors.
For example:
There are two UART ports, UART1 is used for console and configured in
kernel command line, i.e. "console=";
The UART1 probe failed and the memory allocated to sprd_port[1] was
released, but sprd_port[1] was not set to NULL;
In UART2 probe, the same virtual address was allocated to sprd_port[2],
and UART2 probe process finally will go into sprd_console_setup() to
register UART1 as console since it is configured as preferred console
(filled to console_cmdline[]), but the console parameters (sprd_port[1])
belong to UART2.
So move the sprd_port[] assignment to where the port already initialized
can avoid the above issue.
Fixes: b7396a38fb28 ("tty/serial: Add Spreadtrum sc9836-uart driver support")
Signed-off-by: Chunyan Zhang <chunyan.zhang@unisoc.com>
---
V3:
- Call uart_unregister_driver() only when the 'sprd_ports_num' decreases to 0;
- Add calling sprd_rx_free_buf() instread of sprd_remove() under clean_up lable.
V2:
- Leave sprd_remove() to keep the unrelated code logic the same.
---
drivers/tty/serial/sprd_serial.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index b58f51296ace..fc1377029021 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -1106,7 +1106,7 @@ static bool sprd_uart_is_console(struct uart_port *uport)
static int sprd_clk_init(struct uart_port *uport)
{
struct clk *clk_uart, *clk_parent;
- struct sprd_uart_port *u = sprd_port[uport->line];
+ struct sprd_uart_port *u = container_of(uport, struct sprd_uart_port, port);
clk_uart = devm_clk_get(uport->dev, "uart");
if (IS_ERR(clk_uart)) {
@@ -1149,22 +1149,22 @@ static int sprd_probe(struct platform_device *pdev)
{
struct resource *res;
struct uart_port *up;
+ struct sprd_uart_port *sport;
int irq;
int index;
int ret;
index = of_alias_get_id(pdev->dev.of_node, "serial");
- if (index < 0 || index >= ARRAY_SIZE(sprd_port)) {
+ if (index < 0 || index >= UART_NR_MAX) {
dev_err(&pdev->dev, "got a wrong serial alias id %d\n", index);
return -EINVAL;
}
- sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]),
- GFP_KERNEL);
- if (!sprd_port[index])
+ sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
+ if (!sport)
return -ENOMEM;
- up = &sprd_port[index]->port;
+ up = &sport->port;
up->dev = &pdev->dev;
up->line = index;
up->type = PORT_SPRD;
@@ -1195,7 +1195,7 @@ static int sprd_probe(struct platform_device *pdev)
* Allocate one dma buffer to prepare for receive transfer, in case
* memory allocation failure at runtime.
*/
- ret = sprd_rx_alloc_buf(sprd_port[index]);
+ ret = sprd_rx_alloc_buf(sport);
if (ret)
return ret;
@@ -1206,14 +1206,23 @@ static int sprd_probe(struct platform_device *pdev)
return ret;
}
}
+
sprd_ports_num++;
+ sprd_port[index] = sport;
ret = uart_add_one_port(&sprd_uart_driver, up);
if (ret)
- sprd_remove(pdev);
+ goto clean_port;
platform_set_drvdata(pdev, up);
+ return 0;
+
+clean_port:
+ sprd_port[index] = NULL;
+ if (--sprd_ports_num == 0)
+ uart_unregister_driver(&sprd_uart_driver);
+ sprd_rx_free_buf(sport);
return ret;
}
--
2.41.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH V3 2/2] serial: sprd: Fix DMA buffer leak issue
2023-07-25 6:40 [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access Chunyan Zhang
@ 2023-07-25 6:40 ` Chunyan Zhang
2023-07-25 6:50 ` [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access Greg Kroah-Hartman
2023-07-31 3:55 ` Baolin Wang
2 siblings, 0 replies; 6+ messages in thread
From: Chunyan Zhang @ 2023-07-25 6:40 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: linux-serial, Baolin Wang, Orson Zhai, Chunyan Zhang,
Chunyan Zhang, LKML
Release DMA buffer when _probe() returns failure to avoid memory leak.
Fixes: f4487db58eb7 ("serial: sprd: Add DMA mode support")
Signed-off-by: Chunyan Zhang <chunyan.zhang@unisoc.com>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
---
V3:
- Corresponding changes based on patch-1.
V2:
- Added Baolin's Reviewed-by;
- Add setting rx_dma.virt to NULL after being freed.
---
drivers/tty/serial/sprd_serial.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index fc1377029021..99da964e8bd4 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -364,7 +364,7 @@ static void sprd_rx_free_buf(struct sprd_uart_port *sp)
if (sp->rx_dma.virt)
dma_free_coherent(sp->port.dev, SPRD_UART_RX_SIZE,
sp->rx_dma.virt, sp->rx_dma.phys_addr);
-
+ sp->rx_dma.virt = NULL;
}
static int sprd_rx_dma_config(struct uart_port *port, u32 burst)
@@ -1203,7 +1203,7 @@ static int sprd_probe(struct platform_device *pdev)
ret = uart_register_driver(&sprd_uart_driver);
if (ret < 0) {
pr_err("Failed to register SPRD-UART driver\n");
- return ret;
+ goto free_rx_buf;
}
}
@@ -1222,6 +1222,7 @@ static int sprd_probe(struct platform_device *pdev)
sprd_port[index] = NULL;
if (--sprd_ports_num == 0)
uart_unregister_driver(&sprd_uart_driver);
+free_rx_buf:
sprd_rx_free_buf(sport);
return ret;
}
--
2.41.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access
2023-07-25 6:40 [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access Chunyan Zhang
2023-07-25 6:40 ` [PATCH V3 2/2] serial: sprd: Fix DMA buffer leak issue Chunyan Zhang
@ 2023-07-25 6:50 ` Greg Kroah-Hartman
2023-07-25 7:49 ` Chunyan Zhang
2023-07-31 3:55 ` Baolin Wang
2 siblings, 1 reply; 6+ messages in thread
From: Greg Kroah-Hartman @ 2023-07-25 6:50 UTC (permalink / raw)
To: Chunyan Zhang
Cc: Jiri Slaby, linux-serial, Baolin Wang, Orson Zhai, Chunyan Zhang,
LKML
On Tue, Jul 25, 2023 at 02:40:52PM +0800, Chunyan Zhang wrote:
> The global pointer 'sprd_port' may not zero when sprd_probe returns
> failure, that is a risk for sprd_port to be accessed afterward, and
> may lead to unexpected errors.
>
> For example:
>
> There are two UART ports, UART1 is used for console and configured in
> kernel command line, i.e. "console=";
>
> The UART1 probe failed and the memory allocated to sprd_port[1] was
> released, but sprd_port[1] was not set to NULL;
>
> In UART2 probe, the same virtual address was allocated to sprd_port[2],
> and UART2 probe process finally will go into sprd_console_setup() to
> register UART1 as console since it is configured as preferred console
> (filled to console_cmdline[]), but the console parameters (sprd_port[1])
> belong to UART2.
>
> So move the sprd_port[] assignment to where the port already initialized
> can avoid the above issue.
>
> Fixes: b7396a38fb28 ("tty/serial: Add Spreadtrum sc9836-uart driver support")
> Signed-off-by: Chunyan Zhang <chunyan.zhang@unisoc.com>
> ---
> V3:
> - Call uart_unregister_driver() only when the 'sprd_ports_num' decreases to 0;
> - Add calling sprd_rx_free_buf() instread of sprd_remove() under clean_up lable.
>
> V2:
> - Leave sprd_remove() to keep the unrelated code logic the same.
> ---
> drivers/tty/serial/sprd_serial.c | 25 +++++++++++++++++--------
> 1 file changed, 17 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
> index b58f51296ace..fc1377029021 100644
> --- a/drivers/tty/serial/sprd_serial.c
> +++ b/drivers/tty/serial/sprd_serial.c
> @@ -1106,7 +1106,7 @@ static bool sprd_uart_is_console(struct uart_port *uport)
> static int sprd_clk_init(struct uart_port *uport)
> {
> struct clk *clk_uart, *clk_parent;
> - struct sprd_uart_port *u = sprd_port[uport->line];
> + struct sprd_uart_port *u = container_of(uport, struct sprd_uart_port, port);
Now that you are not allocaing the sprd_port[] pointers, shouldn't you
also remove that variable entirely?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access
2023-07-25 6:50 ` [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access Greg Kroah-Hartman
@ 2023-07-25 7:49 ` Chunyan Zhang
2023-07-25 17:33 ` Greg Kroah-Hartman
0 siblings, 1 reply; 6+ messages in thread
From: Chunyan Zhang @ 2023-07-25 7:49 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Chunyan Zhang, Jiri Slaby, linux-serial, Baolin Wang, Orson Zhai,
LKML
On Tue, 25 Jul 2023 at 14:50, Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> On Tue, Jul 25, 2023 at 02:40:52PM +0800, Chunyan Zhang wrote:
> > The global pointer 'sprd_port' may not zero when sprd_probe returns
> > failure, that is a risk for sprd_port to be accessed afterward, and
> > may lead to unexpected errors.
> >
> > For example:
> >
> > There are two UART ports, UART1 is used for console and configured in
> > kernel command line, i.e. "console=";
> >
> > The UART1 probe failed and the memory allocated to sprd_port[1] was
> > released, but sprd_port[1] was not set to NULL;
> >
> > In UART2 probe, the same virtual address was allocated to sprd_port[2],
> > and UART2 probe process finally will go into sprd_console_setup() to
> > register UART1 as console since it is configured as preferred console
> > (filled to console_cmdline[]), but the console parameters (sprd_port[1])
> > belong to UART2.
> >
> > So move the sprd_port[] assignment to where the port already initialized
> > can avoid the above issue.
> >
> > Fixes: b7396a38fb28 ("tty/serial: Add Spreadtrum sc9836-uart driver support")
> > Signed-off-by: Chunyan Zhang <chunyan.zhang@unisoc.com>
> > ---
> > V3:
> > - Call uart_unregister_driver() only when the 'sprd_ports_num' decreases to 0;
> > - Add calling sprd_rx_free_buf() instread of sprd_remove() under clean_up lable.
> >
> > V2:
> > - Leave sprd_remove() to keep the unrelated code logic the same.
> > ---
> > drivers/tty/serial/sprd_serial.c | 25 +++++++++++++++++--------
> > 1 file changed, 17 insertions(+), 8 deletions(-)
> >
> > diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
> > index b58f51296ace..fc1377029021 100644
> > --- a/drivers/tty/serial/sprd_serial.c
> > +++ b/drivers/tty/serial/sprd_serial.c
> > @@ -1106,7 +1106,7 @@ static bool sprd_uart_is_console(struct uart_port *uport)
> > static int sprd_clk_init(struct uart_port *uport)
> > {
> > struct clk *clk_uart, *clk_parent;
> > - struct sprd_uart_port *u = sprd_port[uport->line];
> > + struct sprd_uart_port *u = container_of(uport, struct sprd_uart_port, port);
>
> Now that you are not allocaing the sprd_port[] pointers, shouldn't you
> also remove that variable entirely?
sprd_console_write() and sprd_console_setup() [1] also need sprd_port[].
So, this driver still needs to allocate the buffer for sprd_port[],
the change is using a local variable instead of allocating directly to
the global pointer.
[1] https://elixir.bootlin.com/linux/v6.5-rc1/source/drivers/tty/serial/sprd_serial.c#L1000
Thanks,
Chunyan
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access
2023-07-25 7:49 ` Chunyan Zhang
@ 2023-07-25 17:33 ` Greg Kroah-Hartman
0 siblings, 0 replies; 6+ messages in thread
From: Greg Kroah-Hartman @ 2023-07-25 17:33 UTC (permalink / raw)
To: Chunyan Zhang
Cc: Chunyan Zhang, Jiri Slaby, linux-serial, Baolin Wang, Orson Zhai,
LKML
On Tue, Jul 25, 2023 at 03:49:15PM +0800, Chunyan Zhang wrote:
> On Tue, 25 Jul 2023 at 14:50, Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
> >
> > On Tue, Jul 25, 2023 at 02:40:52PM +0800, Chunyan Zhang wrote:
> > > The global pointer 'sprd_port' may not zero when sprd_probe returns
> > > failure, that is a risk for sprd_port to be accessed afterward, and
> > > may lead to unexpected errors.
> > >
> > > For example:
> > >
> > > There are two UART ports, UART1 is used for console and configured in
> > > kernel command line, i.e. "console=";
> > >
> > > The UART1 probe failed and the memory allocated to sprd_port[1] was
> > > released, but sprd_port[1] was not set to NULL;
> > >
> > > In UART2 probe, the same virtual address was allocated to sprd_port[2],
> > > and UART2 probe process finally will go into sprd_console_setup() to
> > > register UART1 as console since it is configured as preferred console
> > > (filled to console_cmdline[]), but the console parameters (sprd_port[1])
> > > belong to UART2.
> > >
> > > So move the sprd_port[] assignment to where the port already initialized
> > > can avoid the above issue.
> > >
> > > Fixes: b7396a38fb28 ("tty/serial: Add Spreadtrum sc9836-uart driver support")
> > > Signed-off-by: Chunyan Zhang <chunyan.zhang@unisoc.com>
> > > ---
> > > V3:
> > > - Call uart_unregister_driver() only when the 'sprd_ports_num' decreases to 0;
> > > - Add calling sprd_rx_free_buf() instread of sprd_remove() under clean_up lable.
> > >
> > > V2:
> > > - Leave sprd_remove() to keep the unrelated code logic the same.
> > > ---
> > > drivers/tty/serial/sprd_serial.c | 25 +++++++++++++++++--------
> > > 1 file changed, 17 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
> > > index b58f51296ace..fc1377029021 100644
> > > --- a/drivers/tty/serial/sprd_serial.c
> > > +++ b/drivers/tty/serial/sprd_serial.c
> > > @@ -1106,7 +1106,7 @@ static bool sprd_uart_is_console(struct uart_port *uport)
> > > static int sprd_clk_init(struct uart_port *uport)
> > > {
> > > struct clk *clk_uart, *clk_parent;
> > > - struct sprd_uart_port *u = sprd_port[uport->line];
> > > + struct sprd_uart_port *u = container_of(uport, struct sprd_uart_port, port);
> >
> > Now that you are not allocaing the sprd_port[] pointers, shouldn't you
> > also remove that variable entirely?
>
> sprd_console_write() and sprd_console_setup() [1] also need sprd_port[].
Why? Can't they also use the structure passed to them instead?
> So, this driver still needs to allocate the buffer for sprd_port[],
> the change is using a local variable instead of allocating directly to
> the global pointer.
Ah, I missed that you were saving the pointer off.
I think it would be better if you could just remove the static array
entirely, that's a sign of a very old driver that should be fixed up.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access
2023-07-25 6:40 [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access Chunyan Zhang
2023-07-25 6:40 ` [PATCH V3 2/2] serial: sprd: Fix DMA buffer leak issue Chunyan Zhang
2023-07-25 6:50 ` [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access Greg Kroah-Hartman
@ 2023-07-31 3:55 ` Baolin Wang
2 siblings, 0 replies; 6+ messages in thread
From: Baolin Wang @ 2023-07-31 3:55 UTC (permalink / raw)
To: Chunyan Zhang, Greg Kroah-Hartman, Jiri Slaby
Cc: linux-serial, Orson Zhai, Chunyan Zhang, LKML
On 7/25/2023 2:40 PM, Chunyan Zhang wrote:
> The global pointer 'sprd_port' may not zero when sprd_probe returns
> failure, that is a risk for sprd_port to be accessed afterward, and
> may lead to unexpected errors.
>
> For example:
>
> There are two UART ports, UART1 is used for console and configured in
> kernel command line, i.e. "console=";
>
> The UART1 probe failed and the memory allocated to sprd_port[1] was
> released, but sprd_port[1] was not set to NULL;
>
> In UART2 probe, the same virtual address was allocated to sprd_port[2],
> and UART2 probe process finally will go into sprd_console_setup() to
> register UART1 as console since it is configured as preferred console
> (filled to console_cmdline[]), but the console parameters (sprd_port[1])
> belong to UART2.
>
> So move the sprd_port[] assignment to where the port already initialized
> can avoid the above issue.
>
> Fixes: b7396a38fb28 ("tty/serial: Add Spreadtrum sc9836-uart driver support")
> Signed-off-by: Chunyan Zhang <chunyan.zhang@unisoc.com>
LGTM.
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
> ---
> V3:
> - Call uart_unregister_driver() only when the 'sprd_ports_num' decreases to 0;
> - Add calling sprd_rx_free_buf() instread of sprd_remove() under clean_up lable.
>
> V2:
> - Leave sprd_remove() to keep the unrelated code logic the same.
> ---
> drivers/tty/serial/sprd_serial.c | 25 +++++++++++++++++--------
> 1 file changed, 17 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
> index b58f51296ace..fc1377029021 100644
> --- a/drivers/tty/serial/sprd_serial.c
> +++ b/drivers/tty/serial/sprd_serial.c
> @@ -1106,7 +1106,7 @@ static bool sprd_uart_is_console(struct uart_port *uport)
> static int sprd_clk_init(struct uart_port *uport)
> {
> struct clk *clk_uart, *clk_parent;
> - struct sprd_uart_port *u = sprd_port[uport->line];
> + struct sprd_uart_port *u = container_of(uport, struct sprd_uart_port, port);
>
> clk_uart = devm_clk_get(uport->dev, "uart");
> if (IS_ERR(clk_uart)) {
> @@ -1149,22 +1149,22 @@ static int sprd_probe(struct platform_device *pdev)
> {
> struct resource *res;
> struct uart_port *up;
> + struct sprd_uart_port *sport;
> int irq;
> int index;
> int ret;
>
> index = of_alias_get_id(pdev->dev.of_node, "serial");
> - if (index < 0 || index >= ARRAY_SIZE(sprd_port)) {
> + if (index < 0 || index >= UART_NR_MAX) {
> dev_err(&pdev->dev, "got a wrong serial alias id %d\n", index);
> return -EINVAL;
> }
>
> - sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]),
> - GFP_KERNEL);
> - if (!sprd_port[index])
> + sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
> + if (!sport)
> return -ENOMEM;
>
> - up = &sprd_port[index]->port;
> + up = &sport->port;
> up->dev = &pdev->dev;
> up->line = index;
> up->type = PORT_SPRD;
> @@ -1195,7 +1195,7 @@ static int sprd_probe(struct platform_device *pdev)
> * Allocate one dma buffer to prepare for receive transfer, in case
> * memory allocation failure at runtime.
> */
> - ret = sprd_rx_alloc_buf(sprd_port[index]);
> + ret = sprd_rx_alloc_buf(sport);
> if (ret)
> return ret;
>
> @@ -1206,14 +1206,23 @@ static int sprd_probe(struct platform_device *pdev)
> return ret;
> }
> }
> +
> sprd_ports_num++;
> + sprd_port[index] = sport;
>
> ret = uart_add_one_port(&sprd_uart_driver, up);
> if (ret)
> - sprd_remove(pdev);
> + goto clean_port;
>
> platform_set_drvdata(pdev, up);
>
> + return 0;
> +
> +clean_port:
> + sprd_port[index] = NULL;
> + if (--sprd_ports_num == 0)
> + uart_unregister_driver(&sprd_uart_driver);
> + sprd_rx_free_buf(sport);
> return ret;
> }
>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2023-07-31 3:55 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-07-25 6:40 [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access Chunyan Zhang
2023-07-25 6:40 ` [PATCH V3 2/2] serial: sprd: Fix DMA buffer leak issue Chunyan Zhang
2023-07-25 6:50 ` [PATCH V3 1/2] serial: sprd: Assign sprd_port after initialized to avoid wrong access Greg Kroah-Hartman
2023-07-25 7:49 ` Chunyan Zhang
2023-07-25 17:33 ` Greg Kroah-Hartman
2023-07-31 3:55 ` Baolin Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox