Skip to content

Commit

Permalink
efi-stdio: Fix out of bounds error in puts
Browse files Browse the repository at this point in the history
In efi_console_puts we use 'nbytes' as counter to break out of iterating
over the input string. An escape sequence consumes more than 1 input
character, still nbytes is only decremented by one. This results in
iterating past the end of the input string once an escape sequence is
in the buffer.
This patch introduces efi_console_add_char() to write a character in the
buffer and efi_console_flush() to print out the current buffer. This
fixes the issue and also allows us to prevent writing past the end of
the internal output buffer.

Signed-off-by: Sascha Hauer <[email protected]>
  • Loading branch information
saschahauer committed Dec 13, 2021
1 parent e4a8037 commit 008af16
Showing 1 changed file with 39 additions and 21 deletions.
60 changes: 39 additions & 21 deletions drivers/serial/efi-stdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ struct efi_console_priv {
struct efi_simple_text_input_ex_protocol *inex;
struct console_device cdev;
int lastkey;
u16 efi_console_buffer[CONFIG_CBSIZE];
u16 efi_console_buffer[CONFIG_CBSIZE + 1];
int pos;

unsigned long columns, rows;

Expand Down Expand Up @@ -256,34 +257,51 @@ static int efi_process_escape(struct efi_console_priv *priv, const char *inp)
return 1;
}

static void efi_console_add_char(struct efi_console_priv *priv, int c)
{
if (priv->pos >= CONFIG_CBSIZE)
return;

priv->efi_console_buffer[priv->pos] = c;
priv->pos++;
}

static void efi_console_flush(struct efi_console_priv *priv)
{
priv->efi_console_buffer[priv->pos] = 0;

priv->out->output_string(priv->out, priv->efi_console_buffer);

priv->pos = 0;
}

static int efi_console_puts(struct console_device *cdev, const char *s,
size_t nbytes)
{
struct efi_console_priv *priv = to_efi(cdev);
int n = 0;

while (nbytes--) {
if (*s == 27) {
priv->efi_console_buffer[n] = 0;
priv->out->output_string(priv->out,
priv->efi_console_buffer);
n = 0;
s += efi_process_escape(priv, s);
continue;
}
int pos = 0;

if (*s == '\n')
priv->efi_console_buffer[n++] = '\r';
priv->efi_console_buffer[n] = *s;
s++;
n++;
while (pos < nbytes) {
switch (s[pos]) {
case 27:
efi_console_flush(priv);
pos += efi_process_escape(priv, s + pos);
break;
case '\n':
efi_console_add_char(priv, '\r');
efi_console_add_char(priv, '\n');
pos++;
break;
default:
efi_console_add_char(priv, s[pos]);
pos++;
break;
}
}

priv->efi_console_buffer[n] = 0;

priv->out->output_string(priv->out, priv->efi_console_buffer);
efi_console_flush(priv);

return n;
return nbytes;
}

static int efi_console_tstc(struct console_device *cdev)
Expand Down

0 comments on commit 008af16

Please sign in to comment.