lib: ensure vty buf is nul terminated and wrap puts to it with checks
* vty.c: Fix str* overruns in previous commit, which I reported to the
author. Add bit more checking of updates to vty buffer.
Swap VTY_BUFSIZ over to vty->max, as that should be the external API.
* vty.c: (vty_buf_assert) conditions that should always be assertable for
vty buffer.
(vty_buf_put) little wrapper to check char puts to vty input buffer,
and unconditionally write nul at very end of buffer as guard.
Won't always work, as some places use mem* to manipulate.
(vty_self_insert{,_overwrite}) Length check needs to leave room for nul.
Use vty_buf_put.
(vty_insert_word_overwrite) Length check needs to leave room for nul.
(*) Add vty_buf_assert calls.
Merging in fixes from Quentin Young <qlyoung@cumulusnetworks.com>
diff --git a/lib/vty.c b/lib/vty.c
index 6d64797..afaf2b0 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -94,6 +94,23 @@
static int do_log_commands = 0;
+static void
+vty_buf_assert (struct vty *vty)
+{
+ assert (vty->cp <= vty->length);
+ assert (vty->length < vty->max);
+ assert (vty->buf[vty->length] == '\0');
+}
+
+/* Sanity/safety wrappers around access to vty->buf */
+static void
+vty_buf_put (struct vty *vty, char c)
+{
+ vty_buf_assert (vty);
+ vty->buf[vty->cp] = c;
+ vty->buf[vty->max - 1] = '\0';
+}
+
/* VTY standard output function. */
int
vty_out (struct vty *vty, const char *format, ...)
@@ -515,33 +532,46 @@
{
int i;
int length;
-
- if (vty->length + 1 > VTY_BUFSIZ)
+
+ vty_buf_assert (vty);
+
+ /* length is sans nul, max is with */
+ if (vty->length + 1 >= vty->max)
return;
length = vty->length - vty->cp;
memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
- vty->buf[vty->cp] = c;
+ vty->length++;
+ vty->buf[vty->length] = '\0';
+
+ vty_buf_put (vty, c);
vty_write (vty, &vty->buf[vty->cp], length + 1);
for (i = 0; i < length; i++)
vty_write (vty, &telnet_backward_char, 1);
vty->cp++;
- vty->length++;
+
+ vty_buf_assert (vty);
}
/* Self insert character 'c' in overwrite mode. */
static void
vty_self_insert_overwrite (struct vty *vty, char c)
{
+ vty_buf_assert (vty);
+
if (vty->cp == vty->length)
{
vty_self_insert (vty, c);
return;
}
- vty->buf[vty->cp++] = c;
+ vty_buf_put (vty, c);
+ vty->cp++;
+
+ vty_buf_assert (vty);
+
vty_write (vty, &c, 1);
}
@@ -554,33 +584,46 @@
static void
vty_insert_word_overwrite (struct vty *vty, char *str)
{
- size_t nwrite = MIN ((int) strlen (str), VTY_BUFSIZ - vty->cp);
- vty_write (vty, str, nwrite);
- strncpy (&vty->buf[vty->cp], str, nwrite);
+ vty_buf_assert (vty);
+
+ size_t nwrite = MIN ((int) strlen (str), vty->max - vty->cp - 1);
+ memcpy (&vty->buf[vty->cp], str, nwrite);
vty->cp += nwrite;
vty->length = vty->cp;
+ vty->buf[vty->length] = '\0';
+ vty_buf_assert (vty);
+
+ vty_write (vty, str, nwrite);
}
/* Forward character. */
static void
vty_forward_char (struct vty *vty)
{
+ vty_buf_assert (vty);
+
if (vty->cp < vty->length)
{
vty_write (vty, &vty->buf[vty->cp], 1);
vty->cp++;
}
+
+ vty_buf_assert (vty);
}
/* Backward character. */
static void
vty_backward_char (struct vty *vty)
{
+ vty_buf_assert (vty);
+
if (vty->cp > 0)
{
vty->cp--;
vty_write (vty, &telnet_backward_char, 1);
}
+
+ vty_buf_assert (vty);
}
/* Move to the beginning of the line. */
@@ -615,7 +658,9 @@
length = strlen (vty->hist[vty->hp]);
memcpy (vty->buf, vty->hist[vty->hp], length);
vty->cp = vty->length = length;
-
+ vty->buf[vty->length] = '\0';
+ vty_buf_assert (vty);
+
/* Redraw current line */
vty_redraw_line (vty);
}
@@ -671,6 +716,8 @@
{
vty_write (vty, vty->buf, vty->length);
vty->cp = vty->length;
+
+ vty_buf_assert (vty);
}
/* Forward word. */
@@ -775,10 +822,12 @@
vty_down_level (vty);
return;
}
-
+
if (vty->cp == vty->length)
return; /* completion need here? */
+ vty_buf_assert (vty);
+
size = vty->length - vty->cp;
vty->length--;
@@ -825,6 +874,7 @@
memset (&vty->buf[vty->cp], 0, size);
vty->length = vty->cp;
+ vty_buf_assert (vty);
}
/* Kill line from the beginning. */
@@ -2194,7 +2244,7 @@
printf ("line: %.*s\n", nbytes, buf);
#endif /* VTYSH_DEBUG */
- if (vty->length + nbytes > VTY_BUFSIZ)
+ if (vty->length + nbytes >= vty->max)
{
/* Clear command line buffer. */
vty->cp = vty->length = 0;