drm: nv04: Fix out of bounds access

[ Upstream commit cf92bb778eda7830e79452c6917efa8474a30c1e ]

When Output Resource (dcb->or) value is assigned in
fabricate_dcb_output(), there may be out of bounds access to
dac_users array in case dcb->or is zero because ffs(dcb->or) is
used as index there.
The 'or' argument of fabricate_dcb_output() must be interpreted as a
number of bit to set, not value.

Utilize macros from 'enum nouveau_or' in calls instead of hardcoding.

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

Fixes: 2e5702aff3 ("drm/nouveau: fabricate DCB encoder table for iMac G4")
Fixes: 670820c0e6 ("drm/nouveau: Workaround incorrect DCB entry on a GeForce3 Ti 200.")
Signed-off-by: Mikhail Kobuk <m.kobuk@ispras.ru>
Signed-off-by: Danilo Krummrich <dakr@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240411110854.16701-1-m.kobuk@ispras.ru
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Mikhail Kobuk
2024-04-11 14:08:52 +03:00
committed by Greg Kroah-Hartman
parent 5ebbbeb295
commit 097c7918fc

View File

@@ -23,6 +23,7 @@
*/ */
#include "nouveau_drv.h" #include "nouveau_drv.h"
#include "nouveau_bios.h"
#include "nouveau_reg.h" #include "nouveau_reg.h"
#include "dispnv04/hw.h" #include "dispnv04/hw.h"
#include "nouveau_encoder.h" #include "nouveau_encoder.h"
@@ -1672,7 +1673,7 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf)
*/ */
if (nv_match_device(dev, 0x0201, 0x1462, 0x8851)) { if (nv_match_device(dev, 0x0201, 0x1462, 0x8851)) {
if (*conn == 0xf2005014 && *conf == 0xffffffff) { if (*conn == 0xf2005014 && *conf == 0xffffffff) {
fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, 1, 1, 1); fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, 1, 1, DCB_OUTPUT_B);
return false; return false;
} }
} }
@@ -1758,26 +1759,26 @@ fabricate_dcb_encoder_table(struct drm_device *dev, struct nvbios *bios)
#ifdef __powerpc__ #ifdef __powerpc__
/* Apple iMac G4 NV17 */ /* Apple iMac G4 NV17 */
if (of_machine_is_compatible("PowerMac4,5")) { if (of_machine_is_compatible("PowerMac4,5")) {
fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, 0, all_heads, 1); fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, 0, all_heads, DCB_OUTPUT_B);
fabricate_dcb_output(dcb, DCB_OUTPUT_ANALOG, 1, all_heads, 2); fabricate_dcb_output(dcb, DCB_OUTPUT_ANALOG, 1, all_heads, DCB_OUTPUT_C);
return; return;
} }
#endif #endif
/* Make up some sane defaults */ /* Make up some sane defaults */
fabricate_dcb_output(dcb, DCB_OUTPUT_ANALOG, fabricate_dcb_output(dcb, DCB_OUTPUT_ANALOG,
bios->legacy.i2c_indices.crt, 1, 1); bios->legacy.i2c_indices.crt, 1, DCB_OUTPUT_B);
if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0) if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0)
fabricate_dcb_output(dcb, DCB_OUTPUT_TV, fabricate_dcb_output(dcb, DCB_OUTPUT_TV,
bios->legacy.i2c_indices.tv, bios->legacy.i2c_indices.tv,
all_heads, 0); all_heads, DCB_OUTPUT_A);
else if (bios->tmds.output0_script_ptr || else if (bios->tmds.output0_script_ptr ||
bios->tmds.output1_script_ptr) bios->tmds.output1_script_ptr)
fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS, fabricate_dcb_output(dcb, DCB_OUTPUT_TMDS,
bios->legacy.i2c_indices.panel, bios->legacy.i2c_indices.panel,
all_heads, 1); all_heads, DCB_OUTPUT_B);
} }
static int static int