[22/99] fbdev/fsl-diu-fb: Duplicate video-mode option string

Message ID 20230306160016.4459-23-tzimmermann@suse.de
State New
Headers
Series fbdev: Fix memory leak in option parsing |

Commit Message

Thomas Zimmermann March 6, 2023, 3:58 p.m. UTC
  Assume that the driver does not own the option string or its substrings
and hence duplicate the option string for the video mode. The driver only
parses the option string once as part of module initialization, so use
a static buffer to store the duplicated mode option. Linux automatically
frees the memory upon releasing the module.

Done in preparation of switching the driver to struct option_iter and
constifying the option string.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/video/fbdev/fsl-diu-fb.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)
  

Comments

Timur Tabi March 6, 2023, 8:04 p.m. UTC | #1
On Mon, Mar 6, 2023 at 10:01 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
>
> Assume that the driver does not own the option string or its substrings
> and hence duplicate the option string for the video mode. The driver only
> parses the option string once as part of module initialization, so use
> a static buffer to store the duplicated mode option. Linux automatically
> frees the memory upon releasing the module.

So after module_init is finished, mode_option_buf[] no longer exists?

> +                       static char mode_option_buf[256];
> +                       int ret;
> +
> +                       ret = snprintf(mode_option_buf, sizeof(mode_option_buf), "%s", opt);
> +                       if (WARN(ret < 0, "fsl-diu-fb: ignoring invalid option, ret=%d\n", ret))
> +                               continue;
> +                       if (WARN(ret >= sizeof(mode_option_buf), "fsl-diu-fb: option too long\n"))
> +                               continue;
> +                       fb_mode = mode_option_buf;

If so, then I'm not sure that's going to work.  fb_mode is used after
module_init, in install_fb(), which is called by fsl_diu_probe().
  
Thomas Zimmermann March 7, 2023, 8:28 a.m. UTC | #2
Hi

Am 06.03.23 um 21:04 schrieb Timur Tabi:
> On Mon, Mar 6, 2023 at 10:01 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
>>
>> Assume that the driver does not own the option string or its substrings
>> and hence duplicate the option string for the video mode. The driver only
>> parses the option string once as part of module initialization, so use
>> a static buffer to store the duplicated mode option. Linux automatically
>> frees the memory upon releasing the module.
> 
> So after module_init is finished, mode_option_buf[] no longer exists?

Does the __init attribute on a function affect the static variables in 
that function?

Best regards
Thomas

> 
>> +                       static char mode_option_buf[256];
>> +                       int ret;
>> +
>> +                       ret = snprintf(mode_option_buf, sizeof(mode_option_buf), "%s", opt);
>> +                       if (WARN(ret < 0, "fsl-diu-fb: ignoring invalid option, ret=%d\n", ret))
>> +                               continue;
>> +                       if (WARN(ret >= sizeof(mode_option_buf), "fsl-diu-fb: option too long\n"))
>> +                               continue;
>> +                       fb_mode = mode_option_buf;
> 
> If so, then I'm not sure that's going to work.  fb_mode is used after
> module_init, in install_fb(), which is called by fsl_diu_probe().

-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev
  
Timur Tabi March 8, 2023, 4:26 p.m. UTC | #3
On Tue, Mar 7, 2023 at 2:28 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
> > So after module_init is finished, mode_option_buf[] no longer exists?
>
> Does the __init attribute on a function affect the static variables in
> that function?

That is an excellent question.

https://stackoverflow.com/questions/64558614/what-happens-to-local-static-identifiers-in-init-function

I don't think the compiler is naturally aware of whatever section a
variable or function is placed in, so it can't really know that
mode_option_buf[] is suppose to have a limited lifetime.

Either way, the code seems wrong.  If mode_option_buf[] is marked as
__initdata, then it will disappear before the probe() function is
called.

If mode_option_buf[] remains resident, then we are wasting 256 bytes.
  
Thomas Zimmermann March 9, 2023, 12:15 p.m. UTC | #4
Hi

Am 08.03.23 um 17:26 schrieb Timur Tabi:
> On Tue, Mar 7, 2023 at 2:28 AM Thomas Zimmermann <tzimmermann@suse.de> wrote:
>>> So after module_init is finished, mode_option_buf[] no longer exists?
>>
>> Does the __init attribute on a function affect the static variables in
>> that function?
> 
> That is an excellent question.
> 
> https://stackoverflow.com/questions/64558614/what-happens-to-local-static-identifiers-in-init-function
> 
> I don't think the compiler is naturally aware of whatever section a
> variable or function is placed in, so it can't really know that
> mode_option_buf[] is suppose to have a limited lifetime.
> 
> Either way, the code seems wrong.  If mode_option_buf[] is marked as
> __initdata, then it will disappear before the probe() function is
> called.
> 
> If mode_option_buf[] remains resident, then we are wasting 256 bytes.

I'm preparing an update to this series. The string will be allocated and 
freed with kstrdup() and kfree(). So these issues should be resolved then.

Best regards
Thomas


-- 
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev
  

Patch

diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c
index e332017c6af6..e01281959062 100644
--- a/drivers/video/fbdev/fsl-diu-fb.c
+++ b/drivers/video/fbdev/fsl-diu-fb.c
@@ -1858,8 +1858,17 @@  static int __init fsl_diu_setup(char *options)
 		} else if (!strncmp(opt, "bpp=", 4)) {
 			if (!kstrtoul(opt + 4, 10, &val))
 				default_bpp = val;
-		} else
-			fb_mode = opt;
+		} else {
+			static char mode_option_buf[256];
+			int ret;
+
+			ret = snprintf(mode_option_buf, sizeof(mode_option_buf), "%s", opt);
+			if (WARN(ret < 0, "fsl-diu-fb: ignoring invalid option, ret=%d\n", ret))
+				continue;
+			if (WARN(ret >= sizeof(mode_option_buf), "fsl-diu-fb: option too long\n"))
+				continue;
+			fb_mode = mode_option_buf;
+		}
 	}
 
 	return 0;