From nobody@FreeBSD.org  Tue Mar  4 16:31:36 2008
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id A3EE41065670
	for <freebsd-gnats-submit@FreeBSD.org>; Tue,  4 Mar 2008 16:31:36 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 95A538FC1F
	for <freebsd-gnats-submit@FreeBSD.org>; Tue,  4 Mar 2008 16:31:36 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.2/8.14.2) with ESMTP id m24GSbRp002095
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 4 Mar 2008 16:28:37 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.2/8.14.1/Submit) id m24GSboX002094;
	Tue, 4 Mar 2008 16:28:37 GMT
	(envelope-from nobody)
Message-Id: <200803041628.m24GSboX002094@www.freebsd.org>
Date: Tue, 4 Mar 2008 16:28:37 GMT
From: sipher <sipherr@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: local stack overflow in ppp
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         121359
>Category:       bin
>Synopsis:       [patch] [security] ppp(8): fix local stack overflow in ppp
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    maxim
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Mar 04 16:40:00 UTC 2008
>Closed-Date:    
>Last-Modified:  Wed Feb 19 20:30:36 CET 2014
>Originator:     sipher
>Release:        FreeBSD 7.0
>Organization:
none
>Environment:
all affected.
>Description:
http://www.securityfocus.com/archive/82/488980/30/0/threaded

Stack based overflow which is confirmed to be exploitable on FreeBSD 7.0.
>How-To-Repeat:
1. Run ppp

2. type the following (or atleat some variation of)

~/~/~/~/~/~/~/~/~/~/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxx

>Fix:
diff --git a/usr.sbin/ppp/systems.c b/usr.sbin/ppp/systems.c
index 77f06a1..0cf01d1 100644
--- a/usr.sbin/ppp/systems.c
+++ b/usr.sbin/ppp/systems.c
@@ -82,6 +82,10 @@ InterpretArg(const char *from, char *to)
from++;

while (*from != '\0') {
+ if (to >= endto) {
+ *endto = '\0';
+ return from;
+ }
switch (*from) {
case '"':
instring = !instring;
@@ -97,6 +101,10 @@ InterpretArg(const char *from, char *to)
*to++ = '\\'; /* Pass the escapes on, maybe skipping \# */
break;
}
+ if (to >= endto) {
+ *endto = '\0';
+ return from;
+ }
*to++ = *from++;
break;
case '$':
@@ -127,6 +135,10 @@ InterpretArg(const char *from, char *to)
*ptr++ = *from;
*ptr = '\0';
}
+ if (to >= endto) {
+ *endto = '\0';
+ return from;
+ }
if (*to == '\0')
*to++ = '$';
else if ((env = getenv(to)) != NULL) {
@@ -142,6 +154,10 @@ InterpretArg(const char *from, char *to)
if (len == 0)
pwd = getpwuid(ID0realuid());
else {
+ if (to + len >= endto) {
+ *to = '\0';
+ return from;
+ }
strncpy(to, from, len);
to[len] = '\0';
pwd = getpwnam(to);



Submitted by Eygene Ryabinkin (rea-sec@codelabs.ru) 

>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-net 
Responsible-Changed-By: brucec 
Responsible-Changed-When: Wed Mar 25 17:15:00 UTC 2009 
Responsible-Changed-Why:  
Over to maintainer(s). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=121359 

From: Maxim Konovalov <maxim.konovalov@gmail.com>
To: bug-followup@freebsd.org
Cc:  
Subject: bin/121359
Date: Fri, 29 Jul 2011 12:53:19 +0400 (MSD)

 Try the following patch (ported from OpenBSD):
 
 Index: systems.c
 ===================================================================
 --- systems.c	(revision 224489)
 +++ systems.c	(working copy)
 @@ -64,9 +64,12 @@
    fclose(fp);
  }
 
 -/* Move string from ``from'' to ``to'', interpreting ``~'' and $.... */
 +/*
 + * Move string from ``from'' to ``to'', interpreting ``~'' and $....
 + * Returns NULL if string expansion failed due to lack of buffer space.
 + */
  const char *
 -InterpretArg(const char *from, char *to)
 +InterpretArg(const char *from, char *to, size_t tosiz)
  {
    char *ptr, *startto, *endto;
    struct passwd *pwd;
 @@ -76,12 +79,14 @@
 
    instring = 0;
    startto = to;
 -  endto = to + LINE_LEN - 1;
 +  endto = to + tosiz - 1;
 
    while(issep(*from))
      from++;
 
    while (*from != '\0') {
 +    if (to >= endto)
 +      return NULL;
      switch (*from) {
        case '"':
          instring = !instring;
 @@ -97,6 +102,8 @@
              *to++ = '\\';	/* Pass the escapes on, maybe skipping \# */
              break;
          }
 +        if (to >= endto)
 +          return NULL;
          *to++ = *from++;
          break;
        case '$':
 @@ -108,7 +115,7 @@
            if (ptr) {
              len = ptr - from - 2;
              if (endto - to < (int)len )
 -              len = endto - to;
 +              return NULL;
              if (len) {
                strncpy(to, from+2, len);
                to[len] = '\0';
 @@ -127,9 +134,13 @@
              *ptr++ = *from;
            *ptr = '\0';
          }
 +        if (to >= endto)
 +          return NULL;
          if (*to == '\0')
            *to++ = '$';
          else if ((env = getenv(to)) != NULL) {
 +          if (endto - to < (int)strlen(env))
 +            return NULL;
            strncpy(to, env, endto - to);
            *endto = '\0';
            to += strlen(to);
 @@ -142,19 +153,24 @@
          if (len == 0)
            pwd = getpwuid(ID0realuid());
          else {
 +          if (endto - to < (int)len)
 +            return NULL;
            strncpy(to, from, len);
            to[len] = '\0';
            pwd = getpwnam(to);
          }
 +        if (to >= endto)
 +          return NULL;
          if (pwd == NULL)
            *to++ = '~';
          else {
 +          if (endto - to < (int)strlen(pwd->pw_dir))
 +            return NULL;
            strncpy(to, pwd->pw_dir, endto - to);
            *endto = '\0';
            to += strlen(to);
            from += len;
          }
 -        endpwent();
          break;
 
        default:
 @@ -179,12 +195,16 @@
  #define CTRL_INCLUDE (1)
 
  static int
 -DecodeCtrlCommand(char *line, char *arg)
 +DecodeCtrlCommand(char *line, char *arg, size_t argsiz)
  {
    const char *end;
 
    if (!strncasecmp(line, "include", 7) && issep(line[7])) {
 -    end = InterpretArg(line+8, arg);
 +    end = InterpretArg(line+8, arg, argsiz);
 +    if (end == NULL) {
 +      log_Printf(LogWARN, "Failed to expand command '%s': too long for the destination buffer\n", line);
 +      return CTRL_UNKNOWN;
 +    }
      if (*end && *end != '#')
        log_Printf(LogWARN, "usage: !include filename\n");
      else
 @@ -218,7 +238,6 @@
          userok = 1;
          break;
        }
 -  endpwent();
 
    return 0;
  }
 @@ -353,7 +372,7 @@
        break;
 
      case '!':
 -      switch (DecodeCtrlCommand(cp+1, arg)) {
 +      switch (DecodeCtrlCommand(cp+1, arg, LINE_LEN)) {
        case CTRL_INCLUDE:
          log_Printf(LogCOMMAND, "%s: Including \"%s\"\n", filename, arg);
          n = ReadSystem(bundle, name, arg, prompt, cx, how);
 Index: systems.h
 ===================================================================
 --- systems.h	(revision 224489)
 +++ systems.h	(working copy)
 @@ -40,4 +40,4 @@
  extern void CloseSecret(FILE *);
  extern int AllowUsers(struct cmdargs const *);
  extern int AllowModes(struct cmdargs const *);
 -extern const char *InterpretArg(const char *, char *);
 +extern const char *InterpretArg(const char *, char *, size_t);
 Index: command.c
 ===================================================================
 --- command.c	(revision 224489)
 +++ command.c	(working copy)
 @@ -1139,7 +1134,11 @@
  {
    char buff2[LINE_LEN-offset];
 
 -  InterpretArg(buff, buff2);
 +  if (InterpretArg(buff, buff2, sizeof buff2) == NULL) {
 +    log_Printf(LogWARN, "Failed to expand command '%s': too long for the destination buffer\n", buff);
 +    return -1;
 +  }
 +
    strncpy(buff, buff2, LINE_LEN - offset - 1);
    buff[LINE_LEN - offset - 1] = '\0';
 
 %%%
 
 -- 
 Maxim Konovalov
Responsible-Changed-From-To: freebsd-net->maxim 
Responsible-Changed-By: brueffer 
Responsible-Changed-When: Wed Feb 19 20:30:04 CET 2014 
Responsible-Changed-Why:  
Maxim has a patch, so assign this to him. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=121359 
>Unformatted:
