Bug 121359 - [patch] [security] ppp(8): fix local stack overflow in ppp
Summary: [patch] [security] ppp(8): fix local stack overflow in ppp
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs mailing list
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-03-04 16:40 UTC by sipher
Modified: 2017-12-31 22:27 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description sipher 2008-03-04 16:40:00 UTC
http://www.securityfocus.com/archive/82/488980/30/0/threaded

Stack based overflow which is confirmed to be exploitable on FreeBSD 7.0.

Fix: 

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)--oGfy3gwDPofJxGxjgqjEpS7KzQKLTajKfAzDJhZ2Vw7AuxMg
Content-Type: text/plain; name="file.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="file.diff"

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++;
How-To-Repeat: 1. Run ppp

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

~/~/~/~/~/~/~/~/~/~/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxx
Comment 1 Bruce Cran freebsd_committer 2009-03-25 17:15:00 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-net

Over to maintainer(s).
Comment 2 Maxim Konovalov 2011-07-29 09:53:19 UTC
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
Comment 3 Christian Brueffer freebsd_committer 2014-02-19 19:30:04 UTC
Responsible Changed
From-To: freebsd-net->maxim

Maxim has a patch, so assign this to him.
Comment 4 Eitan Adler freebsd_committer freebsd_triage 2017-12-31 08:00:33 UTC
For bugs matching the following criteria:

Status: In Progress Changed: (is less than) 2014-06-01

Reset to default assignee and clear in-progress tags.

Mail being skipped