From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:51446) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1as65s-0004fM-Aw for qemu-devel@nongnu.org; Mon, 18 Apr 2016 06:07:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1as65n-00011D-VW for qemu-devel@nongnu.org; Mon, 18 Apr 2016 06:07:48 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57809) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1as65n-00010l-Ql for qemu-devel@nongnu.org; Mon, 18 Apr 2016 06:07:43 -0400 Date: Mon, 18 Apr 2016 13:07:35 +0300 From: "Michael S. Tsirkin" Message-ID: <20160418100735.GA517@redhat.com> References: <143C0AFC63FC204CB0C55BB88F3A8ABBE31B34@EX01.corp.qihoo.net> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: <143C0AFC63FC204CB0C55BB88F3A8ABBE31B34@EX01.corp.qihoo.net> Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH] cadence_uart: bounds check write offset List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Peter Maydell , qemu-devel@nongnu.org Cc: =?utf-8?B?5p2O5by6?= , "pmatouse@redhat.com" , "sstabellini@kernel.org" , "secalert@redhat.com" , "mdroth@linux.vnet.ibm.com" , g-sec-cloud cadence_uart_init() initializes an I/O memory region of size 0x1000 bytes. However in uart_write(), the 'offset' parameter (offset within region) is divided by 4 and then used to index the array 'r' of size CADENCE_UART_R_MAX which is much smaller: (0x48/4). If 'offset>>=3D2' exceeds CADENCE_UART_R_MAX, this will cause an out-of-bounds memory write where the offset and the value are controlled by guest. This will corrupt QEMU memory, in most situations this causes the vm to crash. Fix by checking the offset against the array size. Reported-by: =E6=9D=8E=E5=BC=BA Signed-off-by: Michael S. Tsirkin --- diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 486591b..7977878 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -375,6 +375,9 @@ static void uart_write(void *opaque, hwaddr offset, =20 DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value= ); offset >>=3D 2; + if (offset >=3D CADENCE_UART_R_MAX) { + return; + } switch (offset) { case R_IER: /* ier (wts imr) */ s->r[R_IMR] |=3D value;