additional fbdev fixes & cleanups for 7.2-rc1:

Fixes:
 - fbcon: fix NULL pointer dereference for a console without vc_data [Ian Bridges]
 - fbdev: fix fb_new_modelist to prevent null-ptr-deref in fb_videomode_to_var [Ian Bridges]
 
 Fixes in failure paths:
 - pm2fb: unwind write-cache setting on probe failure [Haoxiang Li]
 - goldfishfb: fail pan display on base-update timeout [Pengpeng Hou]
 - viafb: return error on DMA copy time-out [Pengpeng Hou]
 - fbcon: fix out-of-bounds read in error path of fbcon_do_set_font() [Mingyu Wang]
 - fbdev: fix modelist use-after-free in store_modes() [Ian Bridges]
 
 Code cleanup:
 - vga16fb: clean up platform_device_id table [Uwe Kleine-König]
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCakAKnwAKCRD3ErUQojoP
 X27+AQCPvMJUMScjO1dlGKkPnnIFiOWCU6AW1aM2m6T+qWrCTQEAnNi5CCI3JiLi
 6NCcyPm7/4R6tSXDm+UcWJ5tyzaNvww=
 =EBHb
 -----END PGP SIGNATURE-----

Merge tag 'fbdev-for-7.2-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev

Pull more fbdev updates from Helge Deller:
 "Fixes for generic fbdev & fbcon code for the handling of modelists
  and preventing a potential NULL ptr dereference in the console code.

  Fix missed cleanups in the error path of various fbdev drivers.

  And Uwe Kleine-König contributed a cleanup patch to use named
  initializers in the vga16fb driver"

* tag 'fbdev-for-7.2-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev:
  fbdev: Fix fb_new_modelist to prevent null-ptr-deref in fb_videomode_to_var
  fbcon: fix NULL pointer dereference for a console without vc_data
  fbdev: fix use-after-free in store_modes()
  fbdev: viafb: return an error when DMA copy times out
  fbdev: goldfishfb: fail pan display on base-update timeout
  fbdev: fbcon: fix out-of-bounds read in err_out of fbcon_do_set_font()
  fbdev: pm2fb: unwind WC setup on probe failure
  fbdev: vga16fb: Drop unused assignment of platform_device_id driver data
This commit is contained in:
Linus Torvalds 2026-06-27 12:52:20 -07:00
commit f21df87320
7 changed files with 49 additions and 12 deletions

View File

@ -1273,6 +1273,7 @@ static void fbcon_deinit(struct vc_data *vc)
int idx;
fbcon_free_font(p);
p->mode = NULL;
idx = con2fb_map[vc->vc_num];
if (idx == -1)
@ -1443,14 +1444,14 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
p = &fb_display[unit];
if (var_to_display(p, var, info))
return;
vc = vc_cons[unit].d;
if (!vc)
return;
if (var_to_display(p, var, info))
return;
default_mode = vc->vc_display_fg;
svc = *default_mode;
t = &fb_display[svc->vc_num];
@ -2405,6 +2406,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
int resize, ret, old_width, old_height, old_charcount;
font_data_t *old_fontdata = p->fontdata;
const u8 *old_data = vc->vc_font.data;
unsigned short old_hi_font_mask = vc->vc_hi_font_mask;
font_data_get(data);
@ -2451,6 +2453,12 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
vc->vc_font.height = old_height;
vc->vc_font.charcount = old_charcount;
/* Restore the hi_font state and screen buffer */
if (old_hi_font_mask && !vc->vc_hi_font_mask)
set_vc_hi_font(vc, true);
else if (!old_hi_font_mask && vc->vc_hi_font_mask)
set_vc_hi_font(vc, false);
font_data_put(data);
return ret;

View File

@ -767,6 +767,18 @@ int fb_new_modelist(struct fb_info *info)
if (list_empty(&info->modelist))
return 1;
/*
* The new modelist may not contain the current mode (info->var), and
* fbcon_new_modelist() below only re-points consoles mapped to this
* framebuffer. Add the current mode here so info->var keeps a match
* even when fbcon is unbound.
*/
if (!fb_match_mode(&info->var, &info->modelist)) {
fb_var_to_videomode(&mode, &info->var);
if (fb_add_videomode(&mode, &info->modelist))
return 1;
}
fbcon_new_modelist(info);
return 0;

View File

@ -10,6 +10,7 @@
#include <linux/major.h>
#include "fb_internal.h"
#include "fbcon.h"
static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
{
@ -108,8 +109,15 @@ static ssize_t store_modes(struct device *device,
if (fb_new_modelist(fb_info)) {
fb_destroy_modelist(&fb_info->modelist);
list_splice(&old_list, &fb_info->modelist);
} else
} else {
/*
* fb_display[i].mode and fb_info->mode both point into the old
* list. Clear them before it is freed.
*/
fbcon_delete_modelist(&old_list);
fb_info->mode = NULL;
fb_destroy_modelist(&old_list);
}
unlock_fb_info(fb_info);
console_unlock();

View File

@ -138,10 +138,12 @@ static int goldfish_fb_pan_display(struct fb_var_screeninfo *var,
writel(fb->fb.fix.smem_start + fb->fb.var.xres * 2 * var->yoffset,
fb->reg_base + FB_SET_BASE);
spin_unlock_irqrestore(&fb->lock, irq_flags);
wait_event_timeout(fb->wait,
fb->base_update_count != base_update_count, HZ / 15);
if (fb->base_update_count == base_update_count)
if (!wait_event_timeout(fb->wait,
fb->base_update_count != base_update_count,
HZ / 15)) {
pr_err("%s: timeout waiting for base update\n", __func__);
return -ETIMEDOUT;
}
return 0;
}
@ -251,7 +253,9 @@ static int goldfish_fb_probe(struct platform_device *pdev)
goto err_request_irq_failed;
writel(FB_INT_BASE_UPDATE_DONE, fb->reg_base + FB_INT_ENABLE);
goldfish_fb_pan_display(&fb->fb.var, &fb->fb); /* updates base */
ret = goldfish_fb_pan_display(&fb->fb.var, &fb->fb); /* updates base */
if (ret)
goto err_pan_display_failed;
ret = register_framebuffer(&fb->fb);
if (ret)
@ -259,6 +263,7 @@ static int goldfish_fb_probe(struct platform_device *pdev)
return 0;
err_register_framebuffer_failed:
err_pan_display_failed:
free_irq(fb->irq, fb);
err_request_irq_failed:
err_fb_set_var_failed:

View File

@ -1711,6 +1711,7 @@ static int pm2fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_exit_both:
kfree(info->pixmap.addr);
err_exit_pixmap:
arch_phys_wc_del(default_par->wc_cookie);
iounmap(info->screen_base);
release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
err_exit_mmio:

View File

@ -1421,8 +1421,8 @@ static void vga16fb_remove(struct platform_device *dev)
}
static const struct platform_device_id vga16fb_driver_id_table[] = {
{"ega-framebuffer", 0},
{"vga-framebuffer", 0},
{ .name = "ega-framebuffer" },
{ .name = "vga-framebuffer" },
{ }
};
MODULE_DEVICE_TABLE(platform, vga16fb_driver_id_table);

View File

@ -234,6 +234,7 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg)
dma_addr_t descr_handle;
unsigned long flags;
int i;
int ret = 0;
struct scatterlist *sgentry;
dma_addr_t nextdesc;
@ -290,8 +291,10 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg)
*/
wait_for_completion_timeout(&viafb_dma_completion, 1);
msleep(1);
if ((viafb_mmio_read(VDMA_CSR0)&VDMA_C_DONE) == 0)
if ((viafb_mmio_read(VDMA_CSR0) & VDMA_C_DONE) == 0) {
printk(KERN_ERR "VIA DMA timeout!\n");
ret = -ETIMEDOUT;
}
/*
* Clean up and we're done.
*/
@ -301,7 +304,7 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg)
dma_free_coherent(&global_dev.pdev->dev,
nsg*sizeof(struct viafb_vx855_dma_descr), descrpages,
descr_handle);
return 0;
return ret;
}
EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg);
#endif /* CONFIG_VIDEO_VIA_CAMERA */