From 9aff57968fdea0b6792a8826d101788f31fdf1a3 Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Mon, 6 May 2024 05:13:34 +1000 Subject: [PATCH] net: fix UB in VM_CL_getstati() and when sending the `items` stat Simplifies the shifting in VM_CL_getstati() to avoid signed integer overflow when the high bits are read with the arguments 23 and 9 (as done in "quake15" and "ad" mods). Refactors VM_CL_getstati() slightly, returns 0 when the index is out of range (instead of whatever happened to be in that memory). Masks off the bits that will overflow when packing the `items` stat for sending (otherwise corruption of the low bits could occur on x86). Signed-off-by: bones_was_here --- clvm_cmds.c | 24 +++++++++++++----------- sv_send.c | 4 +++- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/clvm_cmds.c b/clvm_cmds.c index fac584d4..99f907d4 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -2017,6 +2017,7 @@ static void VM_CL_getstatf (prvm_prog_t *prog) i = (int)PRVM_G_FLOAT(OFS_PARM0); if(i < 0 || i >= MAX_CL_STATS) { + PRVM_G_FLOAT(OFS_RETURN) = 0; VM_Warning(prog, "VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n"); return; } @@ -2027,12 +2028,18 @@ static void VM_CL_getstatf (prvm_prog_t *prog) //#331 float(float stnum) getstati (EXT_CSQC) static void VM_CL_getstati (prvm_prog_t *prog) { - int i, index; - int firstbit, bitcount; + int index, firstbit, bitcount; VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getstati); index = (int)PRVM_G_FLOAT(OFS_PARM0); + if(index < 0 || index >= MAX_CL_STATS) + { + PRVM_G_FLOAT(OFS_RETURN) = 0; + VM_Warning(prog, "VM_CL_getstati: index>=MAX_CL_STATS or index<0\n"); + return; + } + if (prog->argc > 1) { firstbit = (int)PRVM_G_FLOAT(OFS_PARM1); @@ -2047,15 +2054,10 @@ static void VM_CL_getstati (prvm_prog_t *prog) bitcount = 32; } - if(index < 0 || index >= MAX_CL_STATS) - { - VM_Warning(prog, "VM_CL_getstati: index>=MAX_CL_STATS or index<0\n"); - return; - } - i = cl.stats[index]; - if (bitcount != 32) //32 causes the mask to overflow, so there's nothing to subtract from. - i = (((unsigned int)i)&(((1<>firstbit; - PRVM_G_FLOAT(OFS_RETURN) = i; + if (bitcount < 32) //32 causes the mask to overflow, so there's nothing to subtract from. + PRVM_G_FLOAT(OFS_RETURN) = cl.stats[index]>>firstbit & ((1<