From 02805ed17d98c4cdf55c075f857ea82d12f2b8b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Mon, 28 Mar 2005 22:43:34 +0000 Subject: [PATCH] From FreeBSD: Correct a pair of buffer overflows in the telnet(1) command: (CAN-2005-0468) A heap buffer overflow in env_opt_add() and related functions. (CAN-2005-0469) A global uninitialized data section buffer overflow in slc_add_reply() and related functions. As a result of these vulnerabilities, it may be possible for a malicious telnet server or active network attacker to cause telnet(1) to execute arbitrary code with the privileges of the user running it. Security: CAN-2005-0468, CAN-2005-0469 Security: FreeBSD-SA-05:01.telnet Security: http://www.idefense.com/application/poi/display?id=220&type=vulnerabilities Security: http://www.idefense.com/application/poi/display?id=221&type=vulnerabilities These fixes are based in part on patches Submitted by: Solar Designer git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@14693 ec53bebd-3082-4978-b11e-865c3cabbd6b --- appl/telnet/telnet/telnet.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/appl/telnet/telnet/telnet.c b/appl/telnet/telnet/telnet.c index 5db76bb2d..4ca3f351e 100644 --- a/appl/telnet/telnet/telnet.c +++ b/appl/telnet/telnet/telnet.c @@ -1294,6 +1294,7 @@ slc_check() unsigned char slc_reply[128]; +unsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)]; unsigned char *slc_replyp; void @@ -1309,6 +1310,14 @@ slc_start_reply() void slc_add_reply(unsigned char func, unsigned char flags, cc_t value) { + /* A sequence of up to 6 bytes my be written for this member of the SLC + * suboption list by this function. The end of negotiation command, + * which is written by slc_end_reply(), will require 2 additional + * bytes. Do not proceed unless there is sufficient space for these + * items. + */ + if (&slc_replyp[6+2] > slc_reply_eom) + return; if ((*slc_replyp++ = func) == IAC) *slc_replyp++ = IAC; if ((*slc_replyp++ = flags) == IAC) @@ -1322,6 +1331,9 @@ slc_end_reply() { int len; + /* The end of negotiation command requires 2 bytes. */ + if (&slc_replyp[2] > slc_reply_eom) + return; *slc_replyp++ = IAC; *slc_replyp++ = SE; len = slc_replyp - slc_reply; @@ -1415,7 +1427,7 @@ env_opt(unsigned char *buf, int len) } } -#define OPT_REPLY_SIZE 256 +#define OPT_REPLY_SIZE (2 * SUBBUFSIZE) unsigned char *opt_reply; unsigned char *opt_replyp; unsigned char *opt_replyend; @@ -1475,9 +1487,9 @@ env_opt_add(unsigned char *ep) return; } vp = env_getvalue(ep); - if (opt_replyp + (vp ? strlen((char *)vp) : 0) + - strlen((char *)ep) + 6 > opt_replyend) - { + if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) + + 2 * strlen((char *)ep) + 6 > opt_replyend) + { int len; void *tmp; opt_replyend += OPT_REPLY_SIZE; @@ -1503,6 +1515,8 @@ env_opt_add(unsigned char *ep) *opt_replyp++ = ENV_USERVAR; for (;;) { while ((c = *ep++)) { + if (opt_replyp + (2 + 2) > opt_replyend) + return; switch(c&0xff) { case IAC: *opt_replyp++ = IAC; @@ -1517,6 +1531,8 @@ env_opt_add(unsigned char *ep) *opt_replyp++ = c; } if ((ep = vp)) { + if (opt_replyp + (1 + 2 + 2) > opt_replyend) + return; #ifdef OLD_ENVIRON if (telopt_environ == TELOPT_OLD_ENVIRON) *opt_replyp++ = old_env_value; @@ -1547,7 +1563,9 @@ env_opt_end(int emptyok) { int len; - len = opt_replyp - opt_reply + 2; + if (opt_replyp + 2 > opt_replyend) + return; + len = opt_replyp + 2 - opt_reply; if (emptyok || len > 6) { *opt_replyp++ = IAC; *opt_replyp++ = SE;