From 18549d1ad42afc4bc631e030591ce5e178e28f5e Mon Sep 17 00:00:00 2001
From: Quentin Young <qlyoung@cumulusnetworks.com>
Date: Tue, 10 Jan 2017 23:33:50 +0000
Subject: [PATCH] lib: limit size of vty buffer to 4096 bytes

This removes the automatic resizing of the vty input buffer and places a
hard size cap of 4096 bytes. It also fixes a potentially unsafe strcpy.

[Edits by Paul Jakma, paul@jakma.org]
---
 lib/command.c |  2 +-
 lib/vty.c     | 58 ++++++++++++++++++++++++++++++++--------------------------
 lib/vty.h     |  1 -
 vtysh/vtysh.c |  2 +-
 4 files changed, 34 insertions(+), 29 deletions(-)

diff --git a/lib/command.c b/lib/command.c
index 31c067a3..27d2f39a 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -2306,7 +2306,7 @@ config_from_file (struct vty *vty, FILE *fp)
   int ret;
   vector vline;
 
-  while (fgets (vty->buf, VTY_BUFSIZ, fp))
+  while (fgets (vty->buf, vty->max, fp))
     {
       vline = cmd_make_strvec (vty->buf);
 
diff --git a/lib/vty.c b/lib/vty.c
index 30a94e11..094a5ce5 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -39,6 +39,8 @@
 
 #include <arpa/telnet.h>
 
+#define VTY_BUFSIZ 4096
+
 /* Vty events */
 enum event 
 {
@@ -470,17 +472,6 @@ vty_write (struct vty *vty, const char *buf, size_t nbytes)
   buffer_put (vty->obuf, buf, nbytes);
 }
 
-/* Ensure length of input buffer.  Is buffer is short, double it. */
-static void
-vty_ensure (struct vty *vty, int length)
-{
-  if (vty->max <= length)
-    {
-      vty->max *= 2;
-      vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
-    }
-}
-
 /* Basic function to insert character into vty. */
 static void
 vty_self_insert (struct vty *vty, char c)
@@ -488,7 +479,9 @@ vty_self_insert (struct vty *vty, char c)
   int i;
   int length;
 
-  vty_ensure (vty, vty->length + 1);
+  if (vty->length + 1 > VTY_BUFSIZ)
+    return;
+
   length = vty->length - vty->cp;
   memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
   vty->buf[vty->cp] = c;
@@ -505,26 +498,29 @@ vty_self_insert (struct vty *vty, char c)
 static void
 vty_self_insert_overwrite (struct vty *vty, char c)
 {
-  vty_ensure (vty, vty->length + 1);
-  vty->buf[vty->cp++] = c;
-
-  if (vty->cp > vty->length)
-    vty->length++;
-
-  if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
-    return;
+  if (vty->cp == vty->length)
+    {
+      vty_self_insert (vty, c);
+      return;
+    }
 
+  vty->buf[vty->cp++] = c;
   vty_write (vty, &c, 1);
 }
 
-/* Insert a word into vty interface with overwrite mode. */
+/**
+ * Insert a string into vty->buf at the current cursor position.
+ *
+ * If the resultant string would be larger than VTY_BUFSIZ it is
+ * truncated to fit.
+ */
 static void
 vty_insert_word_overwrite (struct vty *vty, char *str)
 {
-  int len = strlen (str);
-  vty_write (vty, str, len);
-  strcpy (&vty->buf[vty->cp], str);
-  vty->cp += len;
+  size_t nwrite = MIN ((int) strlen (str), VTY_BUFSIZ - vty->cp);
+  vty_write (vty, str, nwrite);
+  strncpy (&vty->buf[vty->cp], str, nwrite);
+  vty->cp += nwrite;
   vty->length = vty->cp;
 }
 
@@ -2081,12 +2077,21 @@ vtysh_read (struct thread *thread)
   printf ("line: %.*s\n", nbytes, buf);
 #endif /* VTYSH_DEBUG */
 
+  if (vty->length + nbytes > VTY_BUFSIZ)
+    {
+      /* Clear command line buffer. */
+      vty->cp = vty->length = 0;
+      vty_clear_buf (vty);
+      vty_out (vty, "%% Command is too long.%s", VTY_NEWLINE);
+      goto out;
+    }
+  
   for (p = buf; p < buf+nbytes; p++)
     {
-      vty_ensure(vty, vty->length+1);
       vty->buf[vty->length++] = *p;
       if (*p == '\0')
 	{
+	  
 	  /* Pass this line to parser. */
 	  ret = vty_execute (vty);
 	  /* Note that vty_execute clears the command buffer and resets
@@ -2107,6 +2112,7 @@ vtysh_read (struct thread *thread)
 	}
     }
 
+out:
   vty_event (VTYSH_READ, sock, vty);
 
   return 0;
diff --git a/lib/vty.h b/lib/vty.h
index 7df04b5f..5b9db0f9 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -24,7 +24,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "thread.h"
 #include "log.h"
 
-#define VTY_BUFSIZ 512
 #define VTY_MAXHIST 20
 
 /* VTY struct. */
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 3f189adb..7bffbb41 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -459,7 +459,7 @@ vtysh_config_from_file (struct vty *vty, FILE *fp)
   vector vline;
   struct cmd_element *cmd;
 
-  while (fgets (vty->buf, VTY_BUFSIZ, fp))
+  while (fgets (vty->buf, vty->max, fp))
     {
       if (vty->buf[0] == '!' || vty->buf[1] == '#')
 	continue;
-- 
2.13.6

