Subject: [alpine-aports] [PATCH 3.2-stable] main/putty: fix CVE-2015-5309

From: Christian Kampka <[email-masked]>
Date: Wed, 2 Dec 2015 19:35:24 +0100

fixes #4910
---
 main/putty/APKBUILD            |  16 ++-
 main/putty/CVE-2015-5309.patch | 250 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 260 insertions(+), 6 deletions(-)
 create mode 100644 main/putty/CVE-2015-5309.patch

diff --git a/main/putty/APKBUILD b/main/putty/APKBUILD
index ba3d455..cb8c2c0 100644
--- a/main/putty/APKBUILD
+++ b/main/putty/APKBUILD
@@ -1,7 +1,7 @@
 # Maintainer: Jeff Bilyk <[email-masked]>
 pkgname=putty
 pkgver=0.64
-pkgrel=1
+pkgrel=2
 pkgdesc="SSH and telnet client"
 url="http://www.chiark.greenend.org.uk/~sgtatham/putty/"
 arch="all"
@@ -11,7 +11,9 @@ depends_dev=
 makedepends="$depends_dev"
 install=""
 subpackages="$pkgname-doc"
-source="http://the.earth.li/~sgtatham/putty/latest/putty-$pkgver.tar.gz"
+source="http://the.earth.li/~sgtatham/putty/$pkgver/putty-$pkgver.tar.gz
+	CVE-2015-5309.patch
+	"
 
 _builddir="$srcdir"/putty-$pkgver
 prepare() {
@@ -38,7 +40,9 @@ package() {
 	cd "$_builddir"
 	make DESTDIR="$pkgdir" install || return 1
 }
-
-md5sums="75ff711e8b7cc9e0073bc511e1c1c14a  putty-0.64.tar.gz"
-sha256sums="2a46c97a184144e3ec2392aca9acc64d062317a3a38b9a5f623a147eda5f3821  putty-0.64.tar.gz"
-sha512sums="ba4d4086b8edcb6388924bf3d9b018841be36a9dbf298271c9d2ed063aae9854093e9ff6808bd1f65669d78369548639eb3c95fdec5e3f0daee4b1c7bb603051  putty-0.64.tar.gz"
+md5sums="75ff711e8b7cc9e0073bc511e1c1c14a  putty-0.64.tar.gz
+dfdc6d6f52e33811ce72f6f1614f71e8  CVE-2015-5309.patch"
+sha256sums="2a46c97a184144e3ec2392aca9acc64d062317a3a38b9a5f623a147eda5f3821  putty-0.64.tar.gz
+b49a26d0ad2578acbe7e106fad010d333ca09ce5272774e4e2ce3805f37f9780  CVE-2015-5309.patch"
+sha512sums="ba4d4086b8edcb6388924bf3d9b018841be36a9dbf298271c9d2ed063aae9854093e9ff6808bd1f65669d78369548639eb3c95fdec5e3f0daee4b1c7bb603051  putty-0.64.tar.gz
+692f06ed53b8d4a6b3d041ece83d0d36601d0fcaa0b7a207b52ed57be0dea108681785466f65599ab85f4b8d164b0849c7d0b3f0f54999517390f06547163e5a  CVE-2015-5309.patch"
diff --git a/main/putty/CVE-2015-5309.patch b/main/putty/CVE-2015-5309.patch
new file mode 100644
index 0000000..2225b2c
--- /dev/null
+++ b/main/putty/CVE-2015-5309.patch
@@ -0,0 +1,250 @@
+From 6056396f77cafc7e40da4d09f1d6212408dcb065 Mon Sep 17 00:00:00 2001
+From: Ben Harris <[email-masked]>
+Date: Wed, 7 Oct 2015 23:54:39 +0100
+Subject: [PATCH] More robust control sequence parameter handling.
+
+Parameters are now accumulated in unsigned integers and carefully checked
+for overflow (which is turned into saturation).  Things that consume them
+now have explicit range checks (again, saturating) to ensure that their
+inputs are sane.  This should make it much harder to cause overflow by
+supplying ludicrously large numbers.
+
+Fixes two bugs found with the help of afl-fuzz.  One of them may be
+exploitable and is CVE-2015-5309.
+---
+ terminal.c |   49 +++++++++++++++++++++++++++++++++++++++++++------
+ terminal.h |    2 +-
+ 2 files changed, 44 insertions(+), 7 deletions(-)
+
+diff --git a/terminal.c b/terminal.c
+index d8d0ea0..c7e2647 100644
+--- a/terminal.c
++++ b/terminal.c
+@@ -5,6 +5,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <ctype.h>
++#include <limits.h>
+ 
+ #include <time.h>
+ #include <assert.h>
+@@ -3493,8 +3494,15 @@ static void term_out(Terminal *term)
+ 		    if (term->esc_nargs <= ARGS_MAX) {
+ 			if (term->esc_args[term->esc_nargs - 1] == ARG_DEFAULT)
+ 			    term->esc_args[term->esc_nargs - 1] = 0;
+-			term->esc_args[term->esc_nargs - 1] =
+-			    10 * term->esc_args[term->esc_nargs - 1] + c - '0';
++			if (term->esc_args[term->esc_nargs - 1] <=
++			    UINT_MAX / 10 &&
++			    term->esc_args[term->esc_nargs - 1] * 10 <=
++			    UINT_MAX - c - '0')
++			    term->esc_args[term->esc_nargs - 1] =
++			        10 * term->esc_args[term->esc_nargs - 1] +
++			        c - '0';
++			else
++			    term->esc_args[term->esc_nargs - 1] = UINT_MAX;
+ 		    }
+ 		    term->termstate = SEEN_CSI;
+ 		} else if (c == ';') {
+@@ -3510,8 +3518,10 @@ static void term_out(Terminal *term)
+ 			term->esc_query = c;
+ 		    term->termstate = SEEN_CSI;
+ 		} else
++#define CLAMP(arg, lim) ((arg) = ((arg) > (lim)) ? (lim) : (arg))
+ 		    switch (ANSI(c, term->esc_query)) {
+ 		      case 'A':       /* CUU: move up N lines */
++			CLAMP(term->esc_args[0], term->rows);
+ 			move(term, term->curs.x,
+ 			     term->curs.y - def(term->esc_args[0], 1), 1);
+ 			seen_disp_event(term);
+@@ -3520,6 +3530,7 @@ static void term_out(Terminal *term)
+ 			compatibility(ANSI);
+ 			/* FALLTHROUGH */
+ 		      case 'B':		/* CUD: Cursor down */
++			CLAMP(term->esc_args[0], term->rows);
+ 			move(term, term->curs.x,
+ 			     term->curs.y + def(term->esc_args[0], 1), 1);
+ 			seen_disp_event(term);
+@@ -3535,23 +3546,27 @@ static void term_out(Terminal *term)
+ 			compatibility(ANSI);
+ 			/* FALLTHROUGH */
+ 		      case 'C':		/* CUF: Cursor right */ 
++			CLAMP(term->esc_args[0], term->cols);
+ 			move(term, term->curs.x + def(term->esc_args[0], 1),
+ 			     term->curs.y, 1);
+ 			seen_disp_event(term);
+ 			break;
+ 		      case 'D':       /* CUB: move left N cols */
++			CLAMP(term->esc_args[0], term->cols);
+ 			move(term, term->curs.x - def(term->esc_args[0], 1),
+ 			     term->curs.y, 1);
+ 			seen_disp_event(term);
+ 			break;
+ 		      case 'E':       /* CNL: move down N lines and CR */
+ 			compatibility(ANSI);
++			CLAMP(term->esc_args[0], term->rows);
+ 			move(term, 0,
+ 			     term->curs.y + def(term->esc_args[0], 1), 1);
+ 			seen_disp_event(term);
+ 			break;
+ 		      case 'F':       /* CPL: move up N lines and CR */
+ 			compatibility(ANSI);
++			CLAMP(term->esc_args[0], term->rows);
+ 			move(term, 0,
+ 			     term->curs.y - def(term->esc_args[0], 1), 1);
+ 			seen_disp_event(term);
+@@ -3559,12 +3574,14 @@ static void term_out(Terminal *term)
+ 		      case 'G':	      /* CHA */
+ 		      case '`':       /* HPA: set horizontal posn */
+ 			compatibility(ANSI);
++			CLAMP(term->esc_args[0], term->cols);
+ 			move(term, def(term->esc_args[0], 1) - 1,
+ 			     term->curs.y, 0);
+ 			seen_disp_event(term);
+ 			break;
+ 		      case 'd':       /* VPA: set vertical posn */
+ 			compatibility(ANSI);
++			CLAMP(term->esc_args[0], term->rows);
+ 			move(term, term->curs.x,
+ 			     ((term->dec_om ? term->marg_t : 0) +
+ 			      def(term->esc_args[0], 1) - 1),
+@@ -3575,6 +3592,8 @@ static void term_out(Terminal *term)
+ 		      case 'f':      /* HVP: set horz and vert posns at once */
+ 			if (term->esc_nargs < 2)
+ 			    term->esc_args[1] = ARG_DEFAULT;
++			CLAMP(term->esc_args[0], term->rows);
++			CLAMP(term->esc_args[1], term->cols);
+ 			move(term, def(term->esc_args[1], 1) - 1,
+ 			     ((term->dec_om ? term->marg_t : 0) +
+ 			      def(term->esc_args[0], 1) - 1),
+@@ -3610,6 +3629,7 @@ static void term_out(Terminal *term)
+ 			break;
+ 		      case 'L':       /* IL: insert lines */
+ 			compatibility(VT102);
++			CLAMP(term->esc_args[0], term->rows);
+ 			if (term->curs.y <= term->marg_b)
+ 			    scroll(term, term->curs.y, term->marg_b,
+ 				   -def(term->esc_args[0], 1), FALSE);
+@@ -3617,6 +3637,7 @@ static void term_out(Terminal *term)
+ 			break;
+ 		      case 'M':       /* DL: delete lines */
+ 			compatibility(VT102);
++			CLAMP(term->esc_args[0], term->rows);
+ 			if (term->curs.y <= term->marg_b)
+ 			    scroll(term, term->curs.y, term->marg_b,
+ 				   def(term->esc_args[0], 1),
+@@ -3626,11 +3647,13 @@ static void term_out(Terminal *term)
+ 		      case '@':       /* ICH: insert chars */
+ 			/* XXX VTTEST says this is vt220, vt510 manual says vt102 */
+ 			compatibility(VT102);
++			CLAMP(term->esc_args[0], term->cols);
+ 			insch(term, def(term->esc_args[0], 1));
+ 			seen_disp_event(term);
+ 			break;
+ 		      case 'P':       /* DCH: delete chars */
+ 			compatibility(VT102);
++			CLAMP(term->esc_args[0], term->cols);
+ 			insch(term, -def(term->esc_args[0], 1));
+ 			seen_disp_event(term);
+ 			break;
+@@ -3708,6 +3731,8 @@ static void term_out(Terminal *term)
+ 			compatibility(VT100);
+ 			if (term->esc_nargs <= 2) {
+ 			    int top, bot;
++			    CLAMP(term->esc_args[0], term->rows);
++			    CLAMP(term->esc_args[1], term->rows);
+ 			    top = def(term->esc_args[0], 1) - 1;
+ 			    bot = (term->esc_nargs <= 1
+ 				   || term->esc_args[1] == 0 ?
+@@ -4062,6 +4087,7 @@ static void term_out(Terminal *term)
+ 			}
+ 			break;
+ 		      case 'S':		/* SU: Scroll up */
++			CLAMP(term->esc_args[0], term->rows);
+ 			compatibility(SCOANSI);
+ 			scroll(term, term->marg_t, term->marg_b,
+ 			       def(term->esc_args[0], 1), TRUE);
+@@ -4069,6 +4095,7 @@ static void term_out(Terminal *term)
+ 			seen_disp_event(term);
+ 			break;
+ 		      case 'T':		/* SD: Scroll down */
++			CLAMP(term->esc_args[0], term->rows);
+ 			compatibility(SCOANSI);
+ 			scroll(term, term->marg_t, term->marg_b,
+ 			       -def(term->esc_args[0], 1), TRUE);
+@@ -4111,6 +4138,7 @@ static void term_out(Terminal *term)
+ 			/* XXX VTTEST says this is vt220, vt510 manual
+ 			 * says vt100 */
+ 			compatibility(ANSIMIN);
++			CLAMP(term->esc_args[0], term->cols);
+ 			{
+ 			    int n = def(term->esc_args[0], 1);
+ 			    pos cursplus;
+@@ -4144,6 +4172,7 @@ static void term_out(Terminal *term)
+ 			break;
+ 		      case 'Z':		/* CBT */
+ 			compatibility(OTHER);
++			CLAMP(term->esc_args[0], term->cols);
+ 			{
+ 			    int i = def(term->esc_args[0], 1);
+ 			    pos old_curs = term->curs;
+@@ -4204,7 +4233,7 @@ static void term_out(Terminal *term)
+ 			break;
+ 		      case ANSI('F', '='):      /* set normal foreground */
+ 			compatibility(SCOANSI);
+-			if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) {
++			if (term->esc_args[0] < 16) {
+ 			    long colour =
+  				(sco2ansicolour[term->esc_args[0] & 0x7] |
+ 				 (term->esc_args[0] & 0x8)) <<
+@@ -4218,7 +4247,7 @@ static void term_out(Terminal *term)
+ 			break;
+ 		      case ANSI('G', '='):      /* set normal background */
+ 			compatibility(SCOANSI);
+-			if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) {
++			if (term->esc_args[0] < 16) {
+ 			    long colour =
+  				(sco2ansicolour[term->esc_args[0] & 0x7] |
+ 				 (term->esc_args[0] & 0x8)) <<
+@@ -4342,7 +4371,11 @@ static void term_out(Terminal *term)
+ 		  case '7':
+ 		  case '8':
+ 		  case '9':
+-		    term->esc_args[0] = 10 * term->esc_args[0] + c - '0';
++		    if (term->esc_args[0] <= UINT_MAX / 10 &&
++			term->esc_args[0] * 10 <= UINT_MAX - c - '0')
++			term->esc_args[0] = 10 * term->esc_args[0] + c - '0';
++		    else
++			term->esc_args[0] = UINT_MAX;
+ 		    break;
+ 		  case 'L':
+ 		    /*
+@@ -4424,7 +4457,11 @@ static void term_out(Terminal *term)
+ 		  case '7':
+ 		  case '8':
+ 		  case '9':
+-		    term->esc_args[0] = 10 * term->esc_args[0] + c - '0';
++		    if (term->esc_args[0] <= UINT_MAX / 10 &&
++			term->esc_args[0] * 10 <= UINT_MAX - c - '0')
++			term->esc_args[0] = 10 * term->esc_args[0] + c - '0';
++		    else
++			term->esc_args[0] = UINT_MAX;
+ 		    break;
+ 		  default:
+ 		    term->termstate = OSC_STRING;
+diff --git a/terminal.h b/terminal.h
+index 135ef45..01d5f57 100644
+--- a/terminal.h
++++ b/terminal.h
+@@ -172,7 +172,7 @@ struct terminal_tag {
+ #define ARGS_MAX 32		       /* max # of esc sequence arguments */
+ #define ARG_DEFAULT 0		       /* if an arg isn't specified */
+ #define def(a,d) ( (a) == ARG_DEFAULT ? (d) : (a) )
+-    int esc_args[ARGS_MAX];
++    unsigned esc_args[ARGS_MAX];
+     int esc_nargs;
+     int esc_query;
+ #define ANSI(x,y)	((x)+((y)<<8))
+-- 
+1.7.10.4
+
-- 
2.6.2

---
Unsubscribe:  [email-masked]
Help:         [email-masked]
---