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

tty: evh_bytechan: Fix out of bounds accesses

ev_byte_channel_send() assumes that its third argument is a 16 byte
array. Some places where it is called it may not be (or we can't
easily tell if it is). Newer compilers have started producing warnings
about this, so make sure we actually pass a 16 byte array.

There may be more elegant solutions to this, but the driver is quite
old and hasn't been updated in many years.

The warnings (from a powerpc allyesconfig build) are:

In file included from include/linux/byteorder/big_endian.h:5,
from arch/powerpc/include/uapi/asm/byteorder.h:14,
from include/asm-generic/bitops/le.h:6,
from arch/powerpc/include/asm/bitops.h:250,
from include/linux/bitops.h:29,
from include/linux/kernel.h:12,
from include/asm-generic/bug.h:19,
from arch/powerpc/include/asm/bug.h:109,
from include/linux/bug.h:5,
from include/linux/mmdebug.h:5,
from include/linux/gfp.h:5,
from include/linux/slab.h:15,
from drivers/tty/ehv_bytechan.c:24:
drivers/tty/ehv_bytechan.c: In function ‘ehv_bc_udbg_putc’:
arch/powerpc/include/asm/epapr_hcalls.h:298:20: warning: array subscript 1 is outside array bounds of ‘const char[1]’ [-Warray-bounds]
298 | r6 = be32_to_cpu(p[1]);
include/uapi/linux/byteorder/big_endian.h:40:51: note: in definition of macro ‘__be32_to_cpu’
40 | #define __be32_to_cpu(x) ((__force __u32)(__be32)(x))
| ^
arch/powerpc/include/asm/epapr_hcalls.h:298:7: note: in expansion of macro ‘be32_to_cpu’
298 | r6 = be32_to_cpu(p[1]);
| ^~~~~~~~~~~
drivers/tty/ehv_bytechan.c:166:13: note: while referencing ‘data’
166 | static void ehv_bc_udbg_putc(char c)
| ^~~~~~~~~~~~~~~~

Fixes: dcd83aaff1c8 ("tty/powerpc: introduce the ePAPR embedded hypervisor byte channel driver")
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Tested-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
[mpe: Trim warnings from change log]
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20200109183912.5fcb52aa@canb.auug.org.au

authored by

Stephen Rothwell and committed by
Michael Ellerman
3670664b 966c08de

+18 -3
+18 -3
drivers/tty/ehv_bytechan.c
··· 136 136 return 1; 137 137 } 138 138 139 + static unsigned int local_ev_byte_channel_send(unsigned int handle, 140 + unsigned int *count, 141 + const char *p) 142 + { 143 + char buffer[EV_BYTE_CHANNEL_MAX_BYTES]; 144 + unsigned int c = *count; 145 + 146 + if (c < sizeof(buffer)) { 147 + memcpy(buffer, p, c); 148 + memset(&buffer[c], 0, sizeof(buffer) - c); 149 + p = buffer; 150 + } 151 + return ev_byte_channel_send(handle, count, p); 152 + } 153 + 139 154 /*************************** EARLY CONSOLE DRIVER ***************************/ 140 155 141 156 #ifdef CONFIG_PPC_EARLY_DEBUG_EHV_BC ··· 169 154 170 155 do { 171 156 count = 1; 172 - ret = ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE, 157 + ret = local_ev_byte_channel_send(CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE, 173 158 &count, &data); 174 159 } while (ret == EV_EAGAIN); 175 160 } ··· 236 221 while (count) { 237 222 len = min_t(unsigned int, count, EV_BYTE_CHANNEL_MAX_BYTES); 238 223 do { 239 - ret = ev_byte_channel_send(handle, &len, s); 224 + ret = local_ev_byte_channel_send(handle, &len, s); 240 225 } while (ret == EV_EAGAIN); 241 226 count -= len; 242 227 s += len; ··· 416 401 CIRC_CNT_TO_END(bc->head, bc->tail, BUF_SIZE), 417 402 EV_BYTE_CHANNEL_MAX_BYTES); 418 403 419 - ret = ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail); 404 + ret = local_ev_byte_channel_send(bc->handle, &len, bc->buf + bc->tail); 420 405 421 406 /* 'len' is valid only if the return code is 0 or EV_EAGAIN */ 422 407 if (!ret || (ret == EV_EAGAIN))