Commit 4e4832dd72 for qemu.org

commit 4e4832dd72db59cf9348a5cb787fe65b738d7601
Author: Nguyen Dinh Phi <phind.uet@gmail.com>
Date:   Mon Apr 6 13:04:54 2026 +0800

    util/readline: Fix out-of-bounds access in readline_insert_char().

    Currently, the readline_insert_char() function is guarded by the cursor
    position (cmd_buf_index) rather than the actual buffer fill level(cmd_buf_size).
    The current check is:
            if (rs->cmd_buf_index < READLINE_CMD_BUF_SIZE)

    This logic is flawed because if the command buffer is full and a user moves the
    cursor backward (e.g. by sending left arrow key), cmd_buf_index can be
    decreased without descreasing of buffer size.
    This allow subsequent insertions to increase cmd_buf_size past its maximum
    limit of rs->cmd_buf.

    Because in the ReadLineState struct, cmd_buf[READLINE_CMD_BUF_SIZE + 1] is
    immediately followed by the cmd_buf_index integer, once the buffer size is
    sufficiently inflated, the memmove() operation inside readline_insert_char()
    can write past the end of cmd_buf[] and overwrites cmd_buf_index itself.

    The subsequent line:
            rs->cmd_buf[rs->cmd_buf_index] = ch;

    then writes the input character to an address determined by the now-corrupted
    index.

    By providing a specifically crafted input sequence via HMP, this flaw can be
    used to redirect the write operation to overwrite any field within the
    ReadLineState structure, which can lead to unpredictable behavior or
    application crashes.

    Fix this by adding the guard to check for buffer fullness.

    Cc: qemu-stable@nongnu.org
    Signed-off-by: Nguyen Dinh Phi <phind.uet@gmail.com>
    Message-id: 20260406050454.284873-2-phind.uet@gmail.com
    Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
    Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

diff --git a/util/readline.c b/util/readline.c
index 0f19674f52..e2664e48ca 100644
--- a/util/readline.c
+++ b/util/readline.c
@@ -84,7 +84,9 @@ static void readline_update(ReadLineState *rs)

 static void readline_insert_char(ReadLineState *rs, int ch)
 {
-    if (rs->cmd_buf_index < READLINE_CMD_BUF_SIZE) {
+    assert(rs->cmd_buf_index <= rs->cmd_buf_size);
+
+    if (rs->cmd_buf_size < READLINE_CMD_BUF_SIZE) {
         memmove(rs->cmd_buf + rs->cmd_buf_index + 1,
                 rs->cmd_buf + rs->cmd_buf_index,
                 rs->cmd_buf_size - rs->cmd_buf_index);