[Bug Report] drivers/video/fbdev/da8xx-fb.c: undefined behavior when left shifting

Bartlomiej Zolnierkiewicz b.zolnierkie at samsung.com
Tue Jun 9 11:58:01 UTC 2020


[ added TI DaVinci platform Maintainers to Cc: ]

Hi,

On 5/22/20 5:01 AM, Changming Liu wrote:
> Hi Bartlomiej,
> Greetings, it's me again, I sent you a bug report yesterday, I hope that find you well.
> 
> This time I found that in /drivers/video/fbdev/da8xx-fb.c
> function lcd_cfg_vertical_sync, there might be an undefined result by left shifting.
> 
> More specifically, in function lcd_cfg_vertical_sync, line 437. back_porch is a signed integer 
> which might come from user space. And it's logic AND with string literal 0xff. The result is then left shifted by 24 bits.
> 
> The problem is, since the logic AND produce a signed integer and the result of left shifting this signed integer
> (whose lowest 8 bits not cleared) by 24 bits is undefined when its 8th bit is 1. Similar patterns can be found in line 410 as well.
> 
> I wonder if this bug is worth fixing? This can help me understand linux and UB a lot.
> 
> Looking forward to you valuable response.

I assume that lcd_cfg_{horizontal,vertical}_sync() take parameters as
signed integers (and not unsigned ones) in order to special case "0"
value (I suppose that hardware expects all bits sets to represent
the "0" value). Sekhar/Bartosz: could you verify this?

If the above is true to get rid of undefined behaviors in the code
(BTW gcc seems to produce correct results currently, I don't know
about clang) we should add type casts in proper places, i.e:

static void lcd_cfg_horizontal_sync(int back_porch, int pulse_width,
		int front_porch)
{
	u32 reg;

	reg = lcdc_read(LCD_RASTER_TIMING_0_REG) & 0x3ff;
	reg |= (((u32)(back_porch - 1) & 0xff) << 24)
	    | (((u32)(front_porch - 1) & 0xff) << 16)
	    | (((u32)(pulse_width - 1) & 0x3f) << 10);
	lcdc_write(reg, LCD_RASTER_TIMING_0_REG);

	/*
	 * LCDC Version 2 adds some extra bits that increase the allowable
	 * size of the horizontal timing registers.
	 * remember that the registers use 0 to represent 1 so all values
	 * that get set into register need to be decremented by 1
	 */
	if (lcd_revision == LCD_VERSION_2) {
		/* Mask off the bits we want to change */
		reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & ~0x780000ff;
		reg |= ((u32)(front_porch - 1) & 0x300) >> 8;
		reg |= ((u32)(back_porch - 1) & 0x300) >> 4;
		reg |= ((u32)(pulse_width - 1) & 0x3c0) << 21;
		lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
	}
}

static void lcd_cfg_vertical_sync(int back_porch, int pulse_width,
		int front_porch)
{
	u32 reg;

	reg = lcdc_read(LCD_RASTER_TIMING_1_REG) & 0x3ff;
	reg |= (((u32)back_porch & 0xff) << 24)
	    | (((u32)front_porch & 0xff) << 16)
	    | (((u32)(pulse_width - 1) & 0x3f) << 10);
	lcdc_write(reg, LCD_RASTER_TIMING_1_REG);
}

Also it would be helpful to disallow negative values being passed
from user-space in fb_ioctl().

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

> Best regards,
> Changming Liu
> 



More information about the dri-devel mailing list