diff options
| author | Mark Brown <broonie@kernel.org> | 2026-07-26 22:25:20 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-07-26 22:25:22 +0100 |
| commit | 9ab15e8ae6199ec96ee1909824c27cddf356c1c0 (patch) | |
| tree | 7c4e71d8e590159d5226d2ffa4075da6576973dc | |
| parent | dfdb2e2c135bb9b27c48987f458bcee195def03f (diff) | |
| parent | d3143d4b1537e707f5a131735f336b69199464d3 (diff) | |
| download | linux-next-9ab15e8ae6199ec96ee1909824c27cddf356c1c0.tar.gz linux-next-9ab15e8ae6199ec96ee1909824c27cddf356c1c0.zip | |
Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev.git
| -rw-r--r-- | drivers/gpu/drm/hyperv/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/video/fbdev/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/video/fbdev/core/fb_io_fops.c | 24 | ||||
| -rw-r--r-- | drivers/video/fbdev/core/fb_sys_fops.c | 16 | ||||
| -rw-r--r-- | drivers/video/fbdev/core/fbmem.c | 5 | ||||
| -rw-r--r-- | drivers/video/fbdev/core/fbsysfs.c | 59 | ||||
| -rw-r--r-- | drivers/video/fbdev/kyro/fbdev.c | 24 | ||||
| -rw-r--r-- | drivers/video/fbdev/mmp/hw/mmp_ctrl.c | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/omap2/omapfb/dss/dsi.c | 9 | ||||
| -rw-r--r-- | drivers/video/fbdev/pvr2fb.c | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/pxa168fb.c | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/pxa3xx-gcu.c | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/pxafb.c | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/s3c-fb.c | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/sa1100fb.c | 4 | ||||
| -rw-r--r-- | drivers/video/fbdev/sstfb.c | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/tdfxfb.c | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/udlfb.c | 22 | ||||
| -rw-r--r-- | drivers/video/fbdev/uvesafb.c | 2 | ||||
| -rw-r--r-- | include/linux/font.h | 4 |
21 files changed, 146 insertions, 52 deletions
diff --git a/drivers/gpu/drm/hyperv/Kconfig b/drivers/gpu/drm/hyperv/Kconfig index 86234f6a73f2..e48e35fb7f8b 100644 --- a/drivers/gpu/drm/hyperv/Kconfig +++ b/drivers/gpu/drm/hyperv/Kconfig @@ -8,7 +8,6 @@ config DRM_HYPERV help This is a KMS driver for Hyper-V synthetic video device. Choose this option if you would like to enable drm driver for Hyper-V virtual - machine. Unselect Hyper-V framebuffer driver (CONFIG_FB_HYPERV) so - that DRM driver is used by default. + machine. If M is selected the module will be called hyperv_drm. diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 085d3a202148..e8cd8cb76874 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1717,8 +1717,7 @@ config FB_MB862XX_PCI_GDC config FB_MB862XX_LIME bool "Lime GDC" depends on OF && PPC - select FB_FOREIGN_ENDIAN - select FB_LITTLE_ENDIAN + depends on FB_LITTLE_ENDIAN || FB_BOTH_ENDIAN help Framebuffer support for Fujitsu Lime GDC on host CPU bus. diff --git a/drivers/video/fbdev/core/fb_io_fops.c b/drivers/video/fbdev/core/fb_io_fops.c index 6d0a8c8e141a..545886cb3eeb 100644 --- a/drivers/video/fbdev/core/fb_io_fops.c +++ b/drivers/video/fbdev/core/fb_io_fops.c @@ -24,6 +24,14 @@ ssize_t fb_io_read(struct fb_info *info, char __user *buf, size_t count, loff_t if (total_size == 0) total_size = info->fix.smem_len; + /* + * Security Hardening: Defend against buggy legacy drivers that may + * calculate a malformed screen_size. Clamp total_size to the actual + * hardware mapped memory limit (smem_len) to prevent OOB access. + */ + if (info->fix.smem_len && total_size > info->fix.smem_len) + total_size = info->fix.smem_len; + if (p >= total_size) return 0; @@ -61,6 +69,14 @@ ssize_t fb_io_read(struct fb_info *info, char __user *buf, size_t count, loff_t buf += c; cnt += c; count -= c; + + /* + * If there was a partial copy, the user buffer is faulty. + * Break out to avoid over-advancing the src pointer and + * reading out of bounds in the next iteration. + */ + if (trailing) + break; } kfree(buffer); @@ -88,6 +104,14 @@ ssize_t fb_io_write(struct fb_info *info, const char __user *buf, size_t count, if (total_size == 0) total_size = info->fix.smem_len; + /* + * Security Hardening: Defend against buggy legacy drivers that may + * calculate a malformed screen_size. Clamp total_size to the actual + * hardware mapped memory limit (smem_len) to prevent OOB access. + */ + if (info->fix.smem_len && total_size > info->fix.smem_len) + total_size = info->fix.smem_len; + if (p > total_size) return -EFBIG; diff --git a/drivers/video/fbdev/core/fb_sys_fops.c b/drivers/video/fbdev/core/fb_sys_fops.c index be96b3b3942e..e97cf02f7c70 100644 --- a/drivers/video/fbdev/core/fb_sys_fops.c +++ b/drivers/video/fbdev/core/fb_sys_fops.c @@ -35,6 +35,14 @@ ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count, if (total_size == 0) total_size = info->fix.smem_len; + /* + * Security Hardening: Defend against buggy legacy drivers that may + * calculate a malformed screen_size. Clamp total_size to the actual + * hardware mapped memory limit (smem_len) to prevent OOB access. + */ + if (info->fix.smem_len && total_size > info->fix.smem_len) + total_size = info->fix.smem_len; + if (p >= total_size) return 0; @@ -80,6 +88,14 @@ ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, if (total_size == 0) total_size = info->fix.smem_len; + /* + * Security Hardening: Defend against buggy legacy drivers that may + * calculate a malformed screen_size. Clamp total_size to the actual + * hardware mapped memory limit (smem_len) to prevent OOB access. + */ + if (info->fix.smem_len && total_size > info->fix.smem_len) + total_size = info->fix.smem_len; + if (p > total_size) return -EFBIG; diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 2f1c56e5a7a2..c8aa163b0ecf 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -246,8 +246,11 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) ret = fb_mode_is_equal(&mode1, &mode2); if (!ret) { ret = fbcon_mode_deleted(info, &mode1); - if (!ret) + if (!ret) { + if (info->mode && fb_mode_is_equal(info->mode, &mode1)) + info->mode = NULL; fb_delete_videomode(&mode1, &info->modelist); + } } return ret ? -EINVAL : 0; diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c index ea196603c7a8..d3d60c555bb8 100644 --- a/drivers/video/fbdev/core/fbsysfs.c +++ b/drivers/video/fbdev/core/fbsysfs.c @@ -12,27 +12,35 @@ #include "fb_internal.h" #include "fbcon.h" +static int activate_locked(struct fb_info *fb_info, + struct fb_var_screeninfo *var) +{ + var->activate |= FB_ACTIVATE_FORCE; + return fb_set_var_from_user(fb_info, var); +} + static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var) { int err; - var->activate |= FB_ACTIVATE_FORCE; console_lock(); lock_fb_info(fb_info); - err = fb_set_var_from_user(fb_info, var); + err = activate_locked(fb_info, var); unlock_fb_info(fb_info); console_unlock(); - if (err) - return err; - return 0; + + return err; } -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 +53,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); } @@ -62,19 +70,32 @@ static ssize_t store_mode(struct device *device, struct device_attribute *attr, memset(&var, 0, sizeof(var)); + console_lock(); + lock_fb_info(fb_info); + 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; fb_videomode_to_var(&var, mode); - if ((err = activate(fb_info, &var))) + err = activate_locked(fb_info, &var); + if (err) { + unlock_fb_info(fb_info); + console_unlock(); return err; + } fb_info->mode = mode; + unlock_fb_info(fb_info); + console_unlock(); return count; } } + + unlock_fb_info(fb_info); + console_unlock(); + return -EINVAL; } @@ -82,11 +103,20 @@ static ssize_t show_mode(struct device *device, struct device_attribute *attr, char *buf) { struct fb_info *fb_info = dev_get_drvdata(device); + struct fb_videomode mode; + bool have_mode = false; + + lock_fb_info(fb_info); + if (fb_info->mode) { + mode = *fb_info->mode; + have_mode = true; + } + unlock_fb_info(fb_info); - if (!fb_info->mode) + if (!have_mode) return 0; - return mode_string(buf, 0, fb_info->mode); + return mode_string(buf, PAGE_SIZE, 0, &mode); } static ssize_t store_modes(struct device *device, @@ -134,10 +164,15 @@ static ssize_t show_modes(struct device *device, struct device_attribute *attr, const struct fb_videomode *mode; i = 0; + lock_fb_info(fb_info); 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; } + unlock_fb_info(fb_info); + return i; } diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c index d756b3603fa6..c23738988822 100644 --- a/drivers/video/fbdev/kyro/fbdev.c +++ b/drivers/video/fbdev/kyro/fbdev.c @@ -369,6 +369,9 @@ static int kyro_dev_overlay_create(u32 ulWidth, static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight) { + u32 right; + u32 bottom; + if (deviceInfo.ulOverlayOffset == 0) /* probably haven't called CreateOverlay yet */ return -EINVAL; @@ -378,11 +381,30 @@ static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight (x < 2 && ulWidth + 2 == 0)) return -EINVAL; + /* + * SetOverlayViewPort() adjusts X coordinates by +2 (left) and +1 + * (right) before packing them into 16-bit register fields. + */ + if (x > U16_MAX - 2 || y > U16_MAX) + return -EINVAL; + + right = x + ulWidth; + bottom = y + ulHeight; + + if (right < x || bottom < y) + return -EINVAL; + + right--; + bottom--; + + if (right > U16_MAX - 1 || bottom > U16_MAX) + return -EINVAL; + /* Stop Ramdac Output */ DisableRamdacOutput(deviceInfo.pSTGReg); SetOverlayViewPort(deviceInfo.pSTGReg, - x, y, x + ulWidth - 1, y + ulHeight - 1); + x, y, right, bottom); EnableOverlayPlane(deviceInfo.pSTGReg); /* Start Ramdac Output */ diff --git a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c index 75bbdc0b4aa6..2c457da67a9f 100644 --- a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c +++ b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c @@ -505,8 +505,6 @@ static int mmphw_probe(struct platform_device *pdev) ret = devm_request_irq(ctrl->dev, ctrl->irq, ctrl_handle_irq, IRQF_SHARED, "lcd_controller", ctrl); if (ret < 0) { - dev_err(ctrl->dev, "%s unable to request IRQ %d\n", - __func__, ctrl->irq); ret = -ENXIO; goto failed; } diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c index 5e7963b4aa93..7c3463ee02ef 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c @@ -1185,10 +1185,8 @@ static int dsicm_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING, "taal vsync", ddata); - if (r) { - dev_err(dev, "IRQ request failed\n"); + if (r) return r; - } INIT_DEFERRABLE_WORK(&ddata->te_timeout_work, dsicm_te_timeout_work_callback); diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dsi.c b/drivers/video/fbdev/omap2/omapfb/dss/dsi.c index 330d9fb7d2b0..d98db01fdd39 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dsi.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dsi.c @@ -326,8 +326,6 @@ struct dsi_data { spinlock_t irq_lock; struct dsi_isr_tables isr_tables; - /* space for a copy used by the interrupt handler */ - struct dsi_isr_tables isr_tables_copy; int update_channel; #ifdef DSI_PERF_MEASURE @@ -838,15 +836,10 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) timer_delete(&dsi->te_timer); #endif - /* make a copy and unlock, so that isrs can unregister - * themselves */ - memcpy(&dsi->isr_tables_copy, &dsi->isr_tables, - sizeof(dsi->isr_tables)); + dsi_handle_isrs(&dsi->isr_tables, irqstatus, vcstatus, ciostatus); spin_unlock(&dsi->irq_lock); - dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus); - dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus); dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus); diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c index 9428716e2dc4..a6e7abca7a06 100644 --- a/drivers/video/fbdev/pvr2fb.c +++ b/drivers/video/fbdev/pvr2fb.c @@ -639,7 +639,7 @@ static irqreturn_t __maybe_unused pvr2fb_interrupt(int irq, void *dev_id) } #ifdef CONFIG_PVR2_DMA -static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, +static ssize_t pvr2fb_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos) { unsigned long dst, start, end, len; @@ -1077,7 +1077,7 @@ static struct pvr2_board { #ifdef CONFIG_PCI { pvr2fb_pci_init, pvr2fb_pci_exit, "PCI PVR2" }, #endif - { 0, }, + { }, }; static int __init pvr2fb_init(void) diff --git a/drivers/video/fbdev/pxa168fb.c b/drivers/video/fbdev/pxa168fb.c index 6784888d93c9..ce8a823d7128 100644 --- a/drivers/video/fbdev/pxa168fb.c +++ b/drivers/video/fbdev/pxa168fb.c @@ -725,7 +725,6 @@ static int pxa168fb_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, pxa168fb_handle_irq, IRQF_SHARED, info->fix.id, fbi); if (ret < 0) { - dev_err(&pdev->dev, "unable to request IRQ\n"); ret = -ENXIO; goto failed_free_cmap; } diff --git a/drivers/video/fbdev/pxa3xx-gcu.c b/drivers/video/fbdev/pxa3xx-gcu.c index a2320e2fb8f2..fc5bd7e7aae6 100644 --- a/drivers/video/fbdev/pxa3xx-gcu.c +++ b/drivers/video/fbdev/pxa3xx-gcu.c @@ -615,10 +615,8 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, pxa3xx_gcu_handle_irq, 0, DRV_NAME, priv); - if (ret < 0) { - dev_err(dev, "request_irq failed\n"); + if (ret < 0) return ret; - } /* allocate dma memory */ priv->shared = dma_alloc_coherent(dev, SHARED_SIZE, diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c index e418eee825fb..1682345fb9b0 100644 --- a/drivers/video/fbdev/pxafb.c +++ b/drivers/video/fbdev/pxafb.c @@ -2312,7 +2312,6 @@ static int pxafb_probe(struct platform_device *dev) ret = devm_request_irq(&dev->dev, irq, pxafb_handle_irq, 0, "LCD", fbi); if (ret) { - dev_err(&dev->dev, "request_irq failed: %d\n", ret); ret = -EBUSY; goto failed_free_mem; } diff --git a/drivers/video/fbdev/s3c-fb.c b/drivers/video/fbdev/s3c-fb.c index 2f4d707e2e09..82a3bc9de433 100644 --- a/drivers/video/fbdev/s3c-fb.c +++ b/drivers/video/fbdev/s3c-fb.c @@ -1421,10 +1421,8 @@ static int s3c_fb_probe(struct platform_device *pdev) ret = devm_request_irq(dev, sfb->irq_no, s3c_fb_irq, 0, "s3c_fb", sfb); - if (ret) { - dev_err(dev, "irq request failed\n"); + if (ret) goto err_lcd_clk; - } dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs); diff --git a/drivers/video/fbdev/sa1100fb.c b/drivers/video/fbdev/sa1100fb.c index 0d362d2bf0e3..fea0172c45b5 100644 --- a/drivers/video/fbdev/sa1100fb.c +++ b/drivers/video/fbdev/sa1100fb.c @@ -1167,10 +1167,8 @@ static int sa1100fb_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, sa1100fb_handle_irq, 0, "LCD", fbi); - if (ret) { - dev_err(&pdev->dev, "request_irq failed: %d\n", ret); + if (ret) return ret; - } fbi->shannon_lcden = gpiod_get_optional(&pdev->dev, "shannon-lcden", GPIOD_OUT_LOW); diff --git a/drivers/video/fbdev/sstfb.c b/drivers/video/fbdev/sstfb.c index 2ea947f57efb..2745557822f7 100644 --- a/drivers/video/fbdev/sstfb.c +++ b/drivers/video/fbdev/sstfb.c @@ -1492,6 +1492,7 @@ static const struct pci_device_id sstfb_id_tbl[] = { .driver_data = ID_VOODOO2, }, { 0 }, }; +MODULE_DEVICE_TABLE(pci, sstfb_id_tbl); static struct pci_driver sstfb_driver = { .name = "sstfb", diff --git a/drivers/video/fbdev/tdfxfb.c b/drivers/video/fbdev/tdfxfb.c index cc6a074f3165..9a06cef75699 100644 --- a/drivers/video/fbdev/tdfxfb.c +++ b/drivers/video/fbdev/tdfxfb.c @@ -1385,7 +1385,7 @@ static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) return err; - err = pci_enable_device(pdev); + err = pcim_enable_device(pdev); if (err) { printk(KERN_ERR "tdfxfb: Can't enable pdev: %d\n", err); return err; diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index fdbb8671a810..e78d6f95c9c5 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -1586,19 +1586,29 @@ static int dlfb_parse_vendor_descriptor(struct dlfb_data *dlfb, desc += 5; /* the fixed header we've already parsed */ while (desc < desc_end) { + char *value; u8 length; u16 key; - key = *desc++; - key |= (u16)*desc++ << 8; + if (desc_end - desc < sizeof(key) + sizeof(length)) + goto unrecognized; + + key = get_unaligned_le16(desc); + desc += sizeof(key); length = *desc++; + if (length > desc_end - desc) + goto unrecognized; + + value = desc; switch (key) { case 0x0200: { /* max_area */ - u32 max_area = *desc++; - max_area |= (u32)*desc++ << 8; - max_area |= (u32)*desc++ << 16; - max_area |= (u32)*desc++ << 24; + u32 max_area; + + if (length < sizeof(max_area)) + goto unrecognized; + + max_area = get_unaligned_le32(value); dev_warn(&intf->dev, "DL chip limited to %d pixel modes\n", max_area); diff --git a/drivers/video/fbdev/uvesafb.c b/drivers/video/fbdev/uvesafb.c index 9d82326c744f..ccc9dbc25813 100644 --- a/drivers/video/fbdev/uvesafb.c +++ b/drivers/video/fbdev/uvesafb.c @@ -1907,6 +1907,8 @@ static int uvesafb_init(void) err = 0; } } + if (err) + cn_del_callback(&uvesafb_cn_id); return err; } diff --git a/include/linux/font.h b/include/linux/font.h index ea23b727388b..5e1cf9830084 100644 --- a/include/linux/font.h +++ b/include/linux/font.h @@ -49,6 +49,8 @@ static inline unsigned int font_glyph_pitch(unsigned int width) * scanlines, which is usually the glyph's height in scanlines. Fonts * coming from user space can sometimes have a different vertical pitch * with empty scanlines between two adjacent glyphs. + * + * Returns: the number of bytes per glyph */ static inline unsigned int font_glyph_size(unsigned int width, unsigned int vpitch) { @@ -60,7 +62,7 @@ static inline unsigned int font_glyph_size(unsigned int width, unsigned int vpit */ /** - * font_data_t - Raw font data + * typedef font_data_t - Raw font data * * Values of type font_data_t store a pointer to raw font data. The format * is monochrome. Each bit sets a pixel of a stored glyph. Font data does |
