Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/radeon/evergreen_cs: fix int overflow errors in cs track offsets

Several cs track offsets (such as 'track->db_s_read_offset')
either are initialized with or plainly take big enough values that,
once shifted 8 bits left, may be hit with integer overflow if the
resulting values end up going over u32 limit.

Same goes for a few instances of 'surf.layer_size * mslice'
multiplications that are added to 'offset' variable - they may
potentially overflow as well and need to be validated properly.

While some debug prints in this code section take possible overflow
issues into account, simply casting to (unsigned long) may be
erroneous in its own way, as depending on CPU architecture one is
liable to get different results.

Fix said problems by:
- casting 'offset' to fixed u64 data type instead of
ambiguous unsigned long.
- casting one of the operands in vulnerable to integer
overflow cases to u64.
- adjust format specifiers in debug prints to properly
represent 'offset' values.

Found by Linux Verification Center (linuxtesting.org) with static
analysis tool SVACE.

Fixes: 285484e2d55e ("drm/radeon: add support for evergreen/ni tiling informations v11")
Signed-off-by: Nikita Zhandarovich <n.zhandarovich@fintech.ru>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Nikita Zhandarovich and committed by
Alex Deucher
3fbaf475 89ec85d1

+31 -31
+31 -31
drivers/gpu/drm/radeon/evergreen_cs.c
··· 395 395 struct evergreen_cs_track *track = p->track; 396 396 struct eg_surface surf; 397 397 unsigned pitch, slice, mslice; 398 - unsigned long offset; 398 + u64 offset; 399 399 int r; 400 400 401 401 mslice = G_028C6C_SLICE_MAX(track->cb_color_view[id]) + 1; ··· 433 433 return r; 434 434 } 435 435 436 - offset = track->cb_color_bo_offset[id] << 8; 436 + offset = (u64)track->cb_color_bo_offset[id] << 8; 437 437 if (offset & (surf.base_align - 1)) { 438 - dev_warn(p->dev, "%s:%d cb[%d] bo base %ld not aligned with %ld\n", 438 + dev_warn(p->dev, "%s:%d cb[%d] bo base %llu not aligned with %ld\n", 439 439 __func__, __LINE__, id, offset, surf.base_align); 440 440 return -EINVAL; 441 441 } 442 442 443 - offset += surf.layer_size * mslice; 443 + offset += (u64)surf.layer_size * mslice; 444 444 if (offset > radeon_bo_size(track->cb_color_bo[id])) { 445 445 /* old ddx are broken they allocate bo with w*h*bpp but 446 446 * program slice with ALIGN(h, 8), catch this and patch ··· 448 448 */ 449 449 if (!surf.mode) { 450 450 uint32_t *ib = p->ib.ptr; 451 - unsigned long tmp, nby, bsize, size, min = 0; 451 + u64 tmp, nby, bsize, size, min = 0; 452 452 453 453 /* find the height the ddx wants */ 454 454 if (surf.nby > 8) { 455 455 min = surf.nby - 8; 456 456 } 457 457 bsize = radeon_bo_size(track->cb_color_bo[id]); 458 - tmp = track->cb_color_bo_offset[id] << 8; 458 + tmp = (u64)track->cb_color_bo_offset[id] << 8; 459 459 for (nby = surf.nby; nby > min; nby--) { 460 460 size = nby * surf.nbx * surf.bpe * surf.nsamples; 461 461 if ((tmp + size * mslice) <= bsize) { ··· 467 467 slice = ((nby * surf.nbx) / 64) - 1; 468 468 if (!evergreen_surface_check(p, &surf, "cb")) { 469 469 /* check if this one works */ 470 - tmp += surf.layer_size * mslice; 470 + tmp += (u64)surf.layer_size * mslice; 471 471 if (tmp <= bsize) { 472 472 ib[track->cb_color_slice_idx[id]] = slice; 473 473 goto old_ddx_ok; ··· 476 476 } 477 477 } 478 478 dev_warn(p->dev, "%s:%d cb[%d] bo too small (layer size %d, " 479 - "offset %d, max layer %d, bo size %ld, slice %d)\n", 479 + "offset %llu, max layer %d, bo size %ld, slice %d)\n", 480 480 __func__, __LINE__, id, surf.layer_size, 481 - track->cb_color_bo_offset[id] << 8, mslice, 481 + (u64)track->cb_color_bo_offset[id] << 8, mslice, 482 482 radeon_bo_size(track->cb_color_bo[id]), slice); 483 483 dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n", 484 484 __func__, __LINE__, surf.nbx, surf.nby, ··· 562 562 struct evergreen_cs_track *track = p->track; 563 563 struct eg_surface surf; 564 564 unsigned pitch, slice, mslice; 565 - unsigned long offset; 565 + u64 offset; 566 566 int r; 567 567 568 568 mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1; ··· 608 608 return r; 609 609 } 610 610 611 - offset = track->db_s_read_offset << 8; 611 + offset = (u64)track->db_s_read_offset << 8; 612 612 if (offset & (surf.base_align - 1)) { 613 - dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n", 613 + dev_warn(p->dev, "%s:%d stencil read bo base %llu not aligned with %ld\n", 614 614 __func__, __LINE__, offset, surf.base_align); 615 615 return -EINVAL; 616 616 } 617 - offset += surf.layer_size * mslice; 617 + offset += (u64)surf.layer_size * mslice; 618 618 if (offset > radeon_bo_size(track->db_s_read_bo)) { 619 619 dev_warn(p->dev, "%s:%d stencil read bo too small (layer size %d, " 620 - "offset %ld, max layer %d, bo size %ld)\n", 620 + "offset %llu, max layer %d, bo size %ld)\n", 621 621 __func__, __LINE__, surf.layer_size, 622 - (unsigned long)track->db_s_read_offset << 8, mslice, 622 + (u64)track->db_s_read_offset << 8, mslice, 623 623 radeon_bo_size(track->db_s_read_bo)); 624 624 dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n", 625 625 __func__, __LINE__, track->db_depth_size, ··· 627 627 return -EINVAL; 628 628 } 629 629 630 - offset = track->db_s_write_offset << 8; 630 + offset = (u64)track->db_s_write_offset << 8; 631 631 if (offset & (surf.base_align - 1)) { 632 - dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n", 632 + dev_warn(p->dev, "%s:%d stencil write bo base %llu not aligned with %ld\n", 633 633 __func__, __LINE__, offset, surf.base_align); 634 634 return -EINVAL; 635 635 } 636 - offset += surf.layer_size * mslice; 636 + offset += (u64)surf.layer_size * mslice; 637 637 if (offset > radeon_bo_size(track->db_s_write_bo)) { 638 638 dev_warn(p->dev, "%s:%d stencil write bo too small (layer size %d, " 639 - "offset %ld, max layer %d, bo size %ld)\n", 639 + "offset %llu, max layer %d, bo size %ld)\n", 640 640 __func__, __LINE__, surf.layer_size, 641 - (unsigned long)track->db_s_write_offset << 8, mslice, 641 + (u64)track->db_s_write_offset << 8, mslice, 642 642 radeon_bo_size(track->db_s_write_bo)); 643 643 return -EINVAL; 644 644 } ··· 659 659 struct evergreen_cs_track *track = p->track; 660 660 struct eg_surface surf; 661 661 unsigned pitch, slice, mslice; 662 - unsigned long offset; 662 + u64 offset; 663 663 int r; 664 664 665 665 mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1; ··· 706 706 return r; 707 707 } 708 708 709 - offset = track->db_z_read_offset << 8; 709 + offset = (u64)track->db_z_read_offset << 8; 710 710 if (offset & (surf.base_align - 1)) { 711 - dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n", 711 + dev_warn(p->dev, "%s:%d stencil read bo base %llu not aligned with %ld\n", 712 712 __func__, __LINE__, offset, surf.base_align); 713 713 return -EINVAL; 714 714 } 715 - offset += surf.layer_size * mslice; 715 + offset += (u64)surf.layer_size * mslice; 716 716 if (offset > radeon_bo_size(track->db_z_read_bo)) { 717 717 dev_warn(p->dev, "%s:%d depth read bo too small (layer size %d, " 718 - "offset %ld, max layer %d, bo size %ld)\n", 718 + "offset %llu, max layer %d, bo size %ld)\n", 719 719 __func__, __LINE__, surf.layer_size, 720 - (unsigned long)track->db_z_read_offset << 8, mslice, 720 + (u64)track->db_z_read_offset << 8, mslice, 721 721 radeon_bo_size(track->db_z_read_bo)); 722 722 return -EINVAL; 723 723 } 724 724 725 - offset = track->db_z_write_offset << 8; 725 + offset = (u64)track->db_z_write_offset << 8; 726 726 if (offset & (surf.base_align - 1)) { 727 - dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n", 727 + dev_warn(p->dev, "%s:%d stencil write bo base %llu not aligned with %ld\n", 728 728 __func__, __LINE__, offset, surf.base_align); 729 729 return -EINVAL; 730 730 } 731 - offset += surf.layer_size * mslice; 731 + offset += (u64)surf.layer_size * mslice; 732 732 if (offset > radeon_bo_size(track->db_z_write_bo)) { 733 733 dev_warn(p->dev, "%s:%d depth write bo too small (layer size %d, " 734 - "offset %ld, max layer %d, bo size %ld)\n", 734 + "offset %llu, max layer %d, bo size %ld)\n", 735 735 __func__, __LINE__, surf.layer_size, 736 - (unsigned long)track->db_z_write_offset << 8, mslice, 736 + (u64)track->db_z_write_offset << 8, mslice, 737 737 radeon_bo_size(track->db_z_write_bo)); 738 738 return -EINVAL; 739 739 }