mode_string() uses snprintf() which can return a value larger than the
remaining buffer space. show_modes() accumulates the return value into i
without checking whether i has reached PAGE_SIZE, causing the offset to
advance past the sysfs buffer if the modelist is long enough.

Add a size parameter to mode_string() and use scnprintf() to return
only the bytes actually written. Add an early return when offset
already exceeds the buffer. In show_modes(), stop accumulating once
the buffer is full.

Cc: [email protected]
Signed-off-by: Melbin K Mathew <[email protected]>
---
 drivers/video/fbdev/core/fbsysfs.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/video/fbdev/core/fbsysfs.c 
b/drivers/video/fbdev/core/fbsysfs.c
index ea196603c7..af21dc5052 100644
--- a/drivers/video/fbdev/core/fbsysfs.c
+++ b/drivers/video/fbdev/core/fbsysfs.c
@@ -27,12 +27,15 @@ static int activate(struct fb_info *fb_info, struct 
fb_var_screeninfo *var)
        return 0;
 }
 
-static int mode_string(char *buf, unsigned int offset,
+static int mode_string(char *buf, size_t size, unsigned int offset,
                       const struct fb_videomode *mode)
 {
        char m = 'U';
        char v = 'p';
 
+       if (offset >= size)
+               return 0;
+
        if (mode->flag & FB_MODE_IS_DETAILED)
                m = 'D';
        if (mode->flag & FB_MODE_IS_VESA)
@@ -45,7 +48,7 @@ static int mode_string(char *buf, unsigned int offset,
        if (mode->vmode & FB_VMODE_DOUBLE)
                v = 'd';
 
-       return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d%c-%d\n",
+       return scnprintf(&buf[offset], size - offset, "%c:%dx%d%c-%d\n",
                        m, mode->xres, mode->yres, v, mode->refresh);
 }
 
@@ -64,7 +67,7 @@ static ssize_t store_mode(struct device *device, struct 
device_attribute *attr,
 
        list_for_each_entry(modelist, &fb_info->modelist, list) {
                mode = &modelist->mode;
-               i = mode_string(mstr, 0, mode);
+               i = mode_string(mstr, sizeof(mstr), 0, mode);
                if (strncmp(mstr, buf, max(count, i)) == 0) {
 
                        var = fb_info->var;
@@ -86,7 +89,7 @@ static ssize_t show_mode(struct device *device, struct 
device_attribute *attr,
        if (!fb_info->mode)
                return 0;
 
-       return mode_string(buf, 0, fb_info->mode);
+       return mode_string(buf, PAGE_SIZE, 0, fb_info->mode);
 }
 
 static ssize_t store_modes(struct device *device,
@@ -136,7 +139,9 @@ static ssize_t show_modes(struct device *device, struct 
device_attribute *attr,
        i = 0;
        list_for_each_entry(modelist, &fb_info->modelist, list) {
                mode = &modelist->mode;
-               i += mode_string(buf, i, mode);
+               i += mode_string(buf, PAGE_SIZE, i, mode);
+               if (i >= PAGE_SIZE - 1)
+                       break;
        }
        return i;
 }
-- 
2.39.5

Reply via email to