]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fbdev: bound mode sysfs output to the sysfs buffer
authorMelbin K Mathew <mlbnkm1@gmail.com>
Wed, 1 Jul 2026 23:42:46 +0000 (01:42 +0200)
committerHelge Deller <deller@gmx.de>
Sat, 8 Aug 2026 06:08:58 +0000 (08:08 +0200)
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: stable@vger.kernel.org # v7.1+
Signed-off-by: Melbin K Mathew <mlbnkm1@gmail.com>
Signed-off-by: Helge Deller <deller@gmx.de>
drivers/video/fbdev/core/fbsysfs.c

index ea196603c7a87b8fb01879c45322e49a9f3bc903..af21dc5052df37825d5ff858c02cfd47a7b13dce 100644 (file)
@@ -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;
 }