From viro@math.psu.edu  Sat Nov 21 18:28:47 1998
Received: from math.psu.edu (leibniz.math.psu.edu [146.186.130.2])
          by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id SAA18350
          for <FreeBSD-gnats-submit@freebsd.org>; Sat, 21 Nov 1998 18:28:45 -0800 (PST)
          (envelope-from viro@math.psu.edu)
Received: from weyl.math.psu.edu (weyl.math.psu.edu [146.186.130.226]) by math.psu.edu (8.8.5/8.7.3) with ESMTP id VAA28743 for <FreeBSD-gnats-submit@freebsd.org>; Sat, 21 Nov 1998 21:28:08 -0500 (EST)
Received: (viro@localhost) by weyl.math.psu.edu (8.8.8/8.6.9) id VAA04320 for FreeBSD-gnats-submit@freebsd.org; Sat, 21 Nov 1998 21:28:07 -0500 (EST)
Message-Id: <199811220228.VAA04320@weyl.math.psu.edu>
Date: Sat, 21 Nov 1998 21:28:07 -0500 (EST)
From: viro@math.psu.edu
Reply-To: viro@math.psu.edu
To: FreeBSD-gnats-submit@freebsd.org
Subject: [PATCH] Buffer overrun in nvi-1.79.
X-Send-Pr-Version: 3.2

>Number:         8790
>Category:       bin
>Synopsis:       [PATCH] Buffer overrun in nvi-1.79 (exploitable)
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Nov 21 18:30:00 PST 1998
>Closed-Date:    Sun Jul 25 18:36:44 PDT 1999
>Last-Modified:  Sun Jul 25 18:37:14 PDT 1999
>Originator:     Al Viro
>Release:        FreeBSD 2.2.7 i586
>Organization:
-ENOENT
>Environment:

	Any compiler having char==signed char. E.g. gcc ;-/

>Description:

[It's a copy of bug report sent to Keith Bostic and to Debian project.
I've set Priority: high 'cause the same vulnerability may occur in
other packages using Spencer's regex. No, I don't know which ones do ;-<]


	Regex used in nvi is vulnerable to the following exploit:
if we are trying to compile an expression contining characters with
the 8th bit set we'll force p_bre() to stomp on the core. Details:
p_simp_re() incorrectly handles high half of ASCII.
	a) suppose we got the following: '\\',x where (x&0x80)==0x80.
We'll get c==256|(unsigned char)x. I.e. something in range 0x180--0x1ff.
We'll go to default: and there ordinary(c&~256) will happen. That is,
argument of ordinary() will be in range 0x80--0xff. Now, ordinary()
will do correct EMIT() and will try to set p->g->categories[c&~256].
Since ->categories points into the middle of g->catspace we'll hit the
area g->catspace+256 -- g->catspace+383, i.e. point outside of malloc()ed
block.
	b) suppose we got x where (x&0x80)==0x80 (and no backslashes around). 
Since char is signed we'll have c == (unsigned char)x - 256. Now, when we'll
get to default: ordinary() will get (c &~ 256), i.e. (unsigned char)x - 512.
That is, something in range -384 -- -257. As the result we'll hit the area
g->catspace-256 -- g->catspace-127. Again, we've stomped the core.
	Moreover, look at the ordinary() shows that we can easily control
what and where we'll write. Details of full-scale exploit depend on OS,
library and compiler, but crufting a pattern that resets 'secure' on Debian
(gcc-2.7.2.3 / glibc-2.0.7u) took 10 minutes ;-/
	I'm sending this report to you and to Debian and FreeBSD projects.
I'm not sure that security issues in nvi are that serious, but I don't know
what other packages may contain that version of regex ;-<

>How-To-Repeat:

	See above and below.

>Fix:
	Patch follows:

*** regex/regcomp.c	Sat Mar 19 11:21:28 1994
--- regex/regcomp.c	Sat Nov 21 13:18:11 1998
***************
*** 609,615 ****
  		REQUIRE(starordinary, REG_BADRPT);
  		/* FALLTHROUGH */
  	default:
! 		ordinary(p, c &~ BACKSL);
  		break;
  	}
  
--- 609,615 ----
  		REQUIRE(starordinary, REG_BADRPT);
  		/* FALLTHROUGH */
  	default:
! 		ordinary(p, (char)c); 
  		break;
  	}

						Down, not across!
								Al

>Release-Note:
>Audit-Trail:

From: David Greenman <dg@root.com>
To: viro@math.psu.edu
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: bin/8790: [PATCH] Buffer overrun in nvi-1.79. 
Date: Sat, 21 Nov 1998 20:39:19 -0800

 >	Regex used in nvi is vulnerable to the following exploit:
 
    I'm wondering what you mean by "exploitable buffer overrun"...? You make
 this sound like a security problem, but nvi isn't installed suid/sgid.
 
 -DG
 
 David Greenman
 Co-founder/Principal Architect, The FreeBSD Project

From: Alexander Viro <viro@math.psu.edu>
To: David Greenman <dg@root.com>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: bin/8790: [PATCH] Buffer overrun in nvi-1.79. 
Date: Sun, 22 Nov 1998 15:13:38 -0500 (EST)

 On Sat, 21 Nov 1998, David Greenman wrote:
 
 > >	Regex used in nvi is vulnerable to the following exploit:
 	^^^^^
 > 
 >    I'm wondering what you mean by "exploitable buffer overrun"...? You make
 > this sound like a security problem, but nvi isn't installed suid/sgid.
 
 	Erm... First of all, there is 'secure' flag. IIRC it isn't
 supposed to be removable. I'm _not_ saying that it has real security
 implications for vi (albeit it is possible in really weird setups).
 But:
 	a) It is bug (SIGSEGVing vi by search for right pattern isn't
 nice ;-/)
 	b) It is exploitable bug in regex. And regex is used in suid
 beasts. Since GNU regex is GPLed... I suspect that Spencer's one is used
 in most cases. So, yes, I'm afraid that it can be security problem. If
 there is a regular way to submit bug reports against things like regex
 (i.e. piece of code used in many packages) - my apologies for lack of
 clues ;-(
 							Al
 #include <language_disclaimer.h>
 -- 
 There are no "civil aviation for dummies" books out there and most of
 you would probably be scared and spend a lot of your time looking up
 if there was one. :-)			  Jordan Hubbard in c.u.b.f.m
 

From: Alexander Viro <viro@math.psu.edu>
To: David Greenman <dg@root.com>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: bin/8790: [PATCH] Buffer overrun in nvi-1.79. 
Date: Tue, 24 Nov 1998 13:55:29 -0500 (EST)

 Sorry for followup to myself, but:
 
 *** lib/libc/regex/regcomp.c.old	Tue Nov 24 13:45:54 1998
 --- lib/libc/regex/regcomp.c	Tue Nov 24 13:47:16 1998
 ***************
 *** 613,619 ****
   		(void)REQUIRE(starordinary, REG_BADRPT);
   		/* FALLTHROUGH */
   	default:
 ! 		ordinary(p, c &~ BACKSL);
   		break;
   	}
   
 --- 613,619 ----
   		(void)REQUIRE(starordinary, REG_BADRPT);
   		/* FALLTHROUGH */
   	default:
 ! 		ordinary(p, (char)c);
   		break;
   	}
 
 That is, regex in libc has the same vulnerability. And libc _is_ used in
 suid programs.
 

From: Nick Hibma <nick.hibma@jrc.it>
To: freebsd-gnats-submit@freebsd.org, viro@math.psu.edu
Cc:  
Subject: Re: bin/8790: [PATCH] Buffer overrun in nvi-1.79 (exploitable)
Date: Sat, 24 Jul 1999 14:07:16 +0200

 The problem is probably in ordinary():
 
 static void
 ordinary(p, ch)
 register struct parse *p; 
 register int ch;
 {
         register cat_t *cap = p->g->categories;
  
         if ((p->g->cflags&REG_ICASE) && isalpha((unsigned char)ch) &&
 othercase(ch) != ch)
                 bothcases(p, ch);
         else {
                 EMIT(OCHAR, (unsigned char)ch);
                 if (cap[ch] == 0)
                         cap[ch] = p->g->ncategories++;
         }
 }
 
 
 p->g->categories is NC*sizeof(cat_t) big, which is 256 bytes. With
 BACKSL being 1<<8 you end up beyond that limit. Me thinks. Possible
 patch (to src/lib/libc/regex/regcomp.c, rev.1.12):
 
 --- regcomp.c   Wed Sep 16 10:13:00 1998
 +++ /tmp/regcomp.c      Sat Jul 24 14:02:42 1999
 @@ -1043,8 +1043,8 @@
                 bothcases(p, ch);
         else {
                 EMIT(OCHAR, (unsigned char)ch);
 -               if (cap[ch] == 0)
 -                       cap[ch] = p->g->ncategories++;
 +               if (cap[(unsigned char) ch] == 0)
 +                       cap[(unsigned char) ch] = p->g->ncategories++;
         }
  }
  
 
 Nick
 -- 
 ISIS/STA, T.P.270, Joint Research Centre, 21020 Ispra, Italy
 

From: Alexander Viro <viro@math.psu.edu>
To: Nick Hibma <nick.hibma@jrc.it>
Cc: freebsd-gnats-submit@freebsd.org
Subject: Re: bin/8790: [PATCH] Buffer overrun in nvi-1.79 (exploitable)
Date: Sat, 24 Jul 1999 11:08:43 -0400 (EDT)

 On Sat, 24 Jul 1999, Nick Hibma wrote:
 
 > p->g->categories is NC*sizeof(cat_t) big, which is 256 bytes. With
 > BACKSL being 1<<8 you end up beyond that limit. Me thinks. Possible
 > patch (to src/lib/libc/regex/regcomp.c, rev.1.12):
 > 
 > --- regcomp.c   Wed Sep 16 10:13:00 1998
 > +++ /tmp/regcomp.c      Sat Jul 24 14:02:42 1999
 > @@ -1043,8 +1043,8 @@
 >                 bothcases(p, ch);
 >         else {
 >                 EMIT(OCHAR, (unsigned char)ch);
 > -               if (cap[ch] == 0)
 > -                       cap[ch] = p->g->ncategories++;
 > +               if (cap[(unsigned char) ch] == 0)
 > +                       cap[(unsigned char) ch] = p->g->ncategories++;
 >         }
 >  }
 >  
 > 
 > Nick
 	Nope. Note where the cap points to. Your fix will break
 everything for characters with 7th bit set. Look: g->categories is
 initialized in line 241:
 	g->categories = &g->catspace[-(CHAR_MIN)];
 You need casting to char, not unsigned char here. With that modification
 your patch will work, but if you will look at the places where we call
 ordinary() you'll see that ch may fall out of the char range only in one
 place. Cheaper to cast it there... That's exactly what the patch I've
 proposed does.
 	BTW, last time I checked this bug was in libc too ;-< The same
 patch applies - they simply share the code.
 								Al
 
 
State-Changed-From-To: open->closed 
State-Changed-By: ache 
State-Changed-When: Sun Jul 25 18:36:44 PDT 1999 
State-Changed-Why:  
Fix applied to libc's regcomp 
>Unformatted:
