[comp.lang.c] Insecure hardware

lvc@cbnews.ATT.COM (Lawrence V. Cipriani) (11/26/88)

In article <288@ispi.UUCP> jbayer@ispi.UUCP (Jonathan Bayer) writes:
>gets is different in that the input is undefined.  If gets is used in a
>program in which data is piped to, and it is part of a secure system, and
>unsecured data can be piped to it, then it is possible to break it.

(Not picking on you Mr. Bayer!)

All the discussion I have seen so far about recent virus has focused on
software.  To what extent can hardware be at fault?  Was the one of the
reasons the two processor types were attacked because they would allow
code to be executed in data space?  Is this what happened?  Some other
machines will produce a core dump if you pull this.  What else can be done
in hardware to enhance the security of the UNIX(r) operating system?

	Larry Cipriani
--
UNIX was a trademark of Western Electric, Western Electric is a trademark
of AT&T, UNIX is a registered trademark of AT&T

dhesi@bsu-cs.UUCP (Rahul Dhesi) (11/27/88)

In article <2330@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani)
writes:
>Was the one of the
>reasons the two processor types were attacked because they would allow
>code to be executed in data space?

The fingerd bug was that sending a long line to it via gets() allowed
you to push anything you wanted on the stack.  Since the stack contains
both data and return addresses, keeping code space and data space
separate would probably not have helped.  (I don't know if hardware
separation of code and data inhibited the worm but it would still leave
the same loophole there for exploitation in some other way.)

However, it is rumored that there are machines that maintain a tag
value with each word.  On such a machine, a return address on the stack
would be tagged as a 'code address'.  Overwriting it with the data read
by gets() would remove the 'code address' tag and replace it with a
'character data' tag, preventing a return to that address.  Such a
machine would not permit you to change a 'data' tag to a 'code address'
tag without either doing a system call or executing a "jump to
subroutine" instruction that would automatically push an address with a
'code address' tag on the stack.

Unfortunately, this might seriously hinder the assembly-language
programmer who wishes to play around with return addresses for code
optimization.
-- 
Rahul Dhesi         UUCP:  <backbones>!{iuvax,pur-ee}!bsu-cs!dhesi

chris@mimsy.UUCP (Chris Torek) (11/28/88)

>In article <2330@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani)
>asks:
>>Was the one of the reasons the two processor types were attacked
>>because they would allow code to be executed in data space?

(It is worth noting that the fingerd attack was applied only to VAXen.)

In article <4869@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
>The fingerd bug was that sending a long line to it via gets() allowed
>you to push anything you wanted on the stack.  Since the stack contains
>both data and return addresses, keeping code space and data space
>separate would probably not have helped.  (I don't know if hardware
>separation of code and data inhibited the worm but it would still leave
>the same loophole there for exploitation in some other way.)

It would indeed have helped, although it might not have made a similar
attack impossible.

The attack consisted of sending a 536-byte `line' (with embedded NULs,
so it was not a C string) which contained 400 control-As, some VAX
machine code, numerous NULs, and finally a hand-crafted stack frame
that caused fingerd's return from main()---fingerd did not use
exit()---to return somewhere into the 512-byte buffer (to 0x7fffe9fc,
actually).  I have not gone so far as to analyse the stack of a normal
(inetd-spawned) 4.3BSD or 4.3BSD-tahoe fingerd, but the obvious
probability is that the ^As were used to allow for some slop in
addressing:  ^A, or ASCII 01, is a VAX NOP instruction.

The stack of a 4BSD VAX Unix process looks like this:

	8000 0000	System space
	7fff ec00	u. area + red zone + kernel stack (UPAGES=0t10)
	7fff xxxx	environment variables
	7fff yyyy	argv strings
	7fff zzzz	stack frame for return from main()
	7fff wwww	local variables for main()

xxxx depends on the number and length of environment variables, and
would typically be ebxx (<256 bytes of environment, e.g., just HOME and
PATH).  yyyy depends on xxxx and on the number and length of the argv
strings; zzzz depends on yyyy and on the number of registers used in
main().  Apparently, for fingerd, wwww is around (7fff)cabc.

The 400 ^As would allow for up to 400 bytes of error in the worm's
assumption for the value of wwww above.  If you had made changes to
/etc/rc.local and/or inetd and/or fingerd, but had not pushed the
address far enough away from the `usual' location, the worm could write
a frame that would still look reasonable and would skip over its NOPs
and execute the code it sent after the NOPs.  That code essentially did
an execve("/bin/sh"), but cleverly avoided anything but stack-relative
addressing.

Now, if the VAX hardware had refused to execute data pages---perhaps
by refusing to execute any pages with user-write permission enabled---
the worm could not have run code off the stack.  It could still replace
the old stack frame, and change the argv and environment strings.  I
will not speculate on possible ways to break in using this ability.
I will, however, note that any number of local changes might have
moved the address `wwww' far enough to foil the attack.  One could
argue that, perhaps, each process should have a different view of its
own address space.  It would certainly be easy enough to have the
c startup code move the stack down by a pseudo-random amount....
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

brian@ucsd.EDU (Brian Kantor) (11/28/88)

In article <4869@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
>However, it is rumored that there are machines that maintain a tag
>value with each word.  On such a machine, a return address on the stack
>would be tagged as a 'code address'.  Overwriting it with the data read
>by gets() would remove the 'code address' tag and replace it with a
>'character data' tag, preventing a return to that address.  

Such machines do exist; we have one of them here - a ancient beast
known as a Burroughs 7800.  Since the architecture of such a machine
dates from the middle SIXTIES, one wonders why more such equipment
isn't being made, especially in these days of cheap (well,
not-as-cheap-as-two-years-ago) memory.

The Burro uses a three-bit tag on each of its 48 data-bit words to
signal whether a word is code, data, array descriptor, pointer,
stack control word, etc.  It also does array bounds checking in
hardware as part of the index calculation, and allocates arrays in
virtual space (segmented, if necessary) with a descriptor on the
stack instead of the whole array on the stack, and has special
stack control words so the firmware can cut the stack back on
procedure exit, etc, etc, etc.  Oh, and the program counter stack
is separate from the data stack, so there is NOTHING you can do that
will bugger the return addresses.

Ah well, make something ahead of its time, and nobody remembers....

	Brian Kantor	UCSD Office of Academic Computing
			Academic Network Operations Group  
			UCSD B-028, La Jolla, CA 92093 USA
			brian@ucsd.edu ucsd!brian BRIAN@UCSD

gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/28/88)

In article <4869@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
>In article <2330@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani) writes:
>>Was the one of the reasons the two processor types were attacked
>>because they would allow code to be executed in data space?

I think one of the reasons was that those machines just happened to be
AVAILABLE for compilation of the source to produce the objects that
were shipped around.  However, the particular form that the fingerd
attack took would not work on a system that supported only split-I&D
spaces.

>The fingerd bug was that sending a long line to it via gets() allowed
>you to push anything you wanted on the stack.  Since the stack contains
>both data and return addresses, keeping code space and data space
>separate would probably not have helped.

No, this is wrong.  On a split-I&D machine, return addresses are in
D space but instructions are in I space.  Therefore, the code being
returned to would have had to have been placed in I space, which is
not normally something an unprivileged process can accomplish (other
than by one of a limited class of system calls, e.g. exec on UNIX).

Tags are not required for split-I&D implementations; just consider
the PDP-11 for an example.  Tagged architectures and other uncommon
architectures could also pose barriers, but split-I&D would have
been sufficient to block that particular virus/work attak path.
However, there were (and probably are) still plenty of exploitable
security holes for such viruses to enter.

Note that most common systems that support split I&D spaces do
not REQUIRE their use; the space separation would have to be
ENFORCED to serve as a practical security barrier.  There are
also a lot of subtle details that would have to be gotten right;
I have never in my decades of working with computers seen an
absolutely secure architectural implementation (not even Multics
was 100% secure).

rang@cpsin3.cps.msu.edu (Anton Rang) (11/28/88)

One quick note here...

Chris Torek (chris@mimsy.UUCP), in article 14733@mimsy.UUCP, writes:
>>In article <2330@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani)
>>asks:
>>>Was the one of the reasons the two processor types were attacked
>>>because they would allow code to be executed in data space?

>(It is worth noting that the fingerd attack was applied only to VAXen.)

> [ stuff deleted ]

>Now, if the VAX hardware had refused to execute data pages---perhaps
>by refusing to execute any pages with user-write permission enabled---
>the worm could not have run code off the stack.

  VAX processors do have separate bits for read, write, and execute on
each page (I seem to vaguely recall one more).  The problem lies with
the implementation of BSD and Ultrix, which leave the stack
executable; I can't see any reason for this offhand.

+---------------------------+------------------------+----------------------+
| Anton Rang (grad student) | "UNIX: Just Say No!"   | "Do worry...be SAD!" |
| Michigan State University | rang@cpswh.cps.msu.edu |                      |
+---------------------------+------------------------+----------------------+

chase@Ozona.orc.olivetti.com (David Chase) (11/29/88)

In article <1189@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang) writes:
>  The problem lies with
>the implementation of BSD and Ultrix, which leave the stack
>executable; I can't see any reason for this offhand.

Well, I'm told that there's signal handling code that writes on the
stack and then executes it.  It's also a handy trick for implementing
partial application, which can in turn be used to implement lexical
binding of variables in nested functions for languages that aren't C
but wish to remain compatible with it.  This is VERY useful if your
intermediate/portability language IS C (no, I can't use a global
variable to simulate a lexical or display pointer, because we'll be
using threads.  Yes, I'm aware that C structure-returning conventions
are often non-reentrant, and we've dealt with that.)  Some Lisp
systems may generate code onto the stack in certain situations.

Some new machines have separate instruction and data busses and/or
caches, and this is sometimes given as a good reason for keeping
instruction and data spaces separate (protect us from undefined
results, I assume).  I'd prefer otherwise, since it isn't too hard to
write code to do the right thing (somewhat efficiently, even) if there
is a system call that allows page-by-page changing of protection or
copying of a page of data into I-space.

David

henry@utzoo.uucp (Henry Spencer) (11/29/88)

In article <2330@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani) writes:
>... To what extent can hardware be at fault?  Was the one of the
>reasons the two processor types were attacked because they would allow
>code to be executed in data space?  Is this what happened?  Some other
>machines will produce a core dump if you pull this...

One should remember that dynamic code generation (necessarily into the
data space) followed by execution of the resulting code can be a very
valuable technique for things like interpreters.  One can finesse that
with a "change data to code" system call, but the system-call overhead
can hurt badly.
-- 
SunOSish, adj:  requiring      |     Henry Spencer at U of Toronto Zoology
32-bit bug numbers.            | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

gregg@ihlpb.ATT.COM (Wonderly) (11/29/88)

From article <8995@smoke.BRL.MIL>, by gwyn@smoke.BRL.MIL (Doug Gwyn ):
> In article <4869@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
>>In article <2330@cbnews.ATT.COM> lvc@cbnews.ATT.COM (Lawrence V. Cipriani) writes:
>>>Was the one of the reasons the two processor types were attacked
>>>because they would allow code to be executed in data space?
> 
> ...
>
> However, there were (and probably are) still plenty of exploitable
> security holes for such viruses to enter.

Just to demonstrate how vunerable we can make ourselves,

Consider my naive implementation of fingerd which, on most architectures
with a decending address, local variable stack allocation stratedgy
can be compromised, after a little investigation.

main ()
{
	char vec[10];
	int vecp = 1;
	char buf[512];

	vec[0] = "/usr/ucb/finger";
	if (gets(buf) != NULL)
		vec[vecp++] = buf;

	vec[vecp++] = NULL

	execvp (vec[0], vec);
	perror (vec[0]);
}

One only needs to write the appropriate strings, a value for vecp,
and a value for vec[0-?] to the programs standard input to force
execution of your choice of programs.  Naturally, there is less
freedom (actually none) of the values one might write into the 
array of pointers, but all it takes is the source and a wee bit of
knowledge about the STANDARD environment that sooooo many turnkey
UN*X boxes have these days, and you are in.

This is just one method of many...


-- 
It isn't the DREAM that NASA's missing...  DOMAIN: gregg@ihlpb.att.com
It's a direction!                          UUCP:   att!ihlpb!gregg

cmf@cisunx.UUCP (Carl M. Fongheiser) (11/29/88)

In article <1189@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang) writes:
>  VAX processors do have separate bits for read, write, and execute on
>each page (I seem to vaguely recall one more).  The problem lies with
>the implementation of BSD and Ultrix, which leave the stack
>executable; I can't see any reason for this offhand.

Oh really?  Are you sure you're talking about a VAX? :-)

The only permissions that can be specified in a VAX PTE are read & write.
And they aren't really encoded in separate bits; instead, you have
values which specify the outermost mode which can write (and read) the
given page.  Note also, there's no such thing as a write-only page.
If you can write the page, you can also read it.

				Carl Fongheiser
				University of Pittsburgh
				...!pitt!cisunx!cmf
				cmf@unix.cis.pittsburgh.edu

gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/29/88)

In article <9119@ihlpb.ATT.COM> gregg@ihlpb.ATT.COM (Wonderly) writes:
>Just to demonstrate how vunerable we can make ourselves, ...

Your example is the same as what started the whole gets() discussion!

terryl@tekcrl.CRL.TEK.COM (11/30/88)

In article <1189@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang) writes:
>One quick note here...
>
>Chris Torek (chris@mimsy.UUCP), in article 14733@mimsy.UUCP, writes:
>>Now, if the VAX hardware had refused to execute data pages---perhaps
>>by refusing to execute any pages with user-write permission enabled---
>>the worm could not have run code off the stack.
>
>  VAX processors do have separate bits for read, write, and execute on
>each page (I seem to vaguely recall one more).  The problem lies with
>the implementation of BSD and Ultrix, which leave the stack
>executable; I can't see any reason for this offhand.


     BBBBUUUUUZZZZ!!!!! Wrong answer...

     The VAX only has read/write permissions per page, but it does have
4 different access modes per page (kernel, executive, supervisor, & user),
with each access mode having its own independent permissions per page...


Boy
Do
I
Hate
Inews
!!!!
!!!!

PS:
	Don't tell me about the various different ways around the infamous
"rn" included line count problem; I know all of them. I just like to complain
about fascist software!!!! (-:

chris@mimsy.UUCP (Chris Torek) (11/30/88)

Someone else mentioned the correct answer, but I suppose I had best do
it again.  I have redirected followups to comp.unix.wizards only.

>In article <1189@cps3xx.UUCP> rang@cpswh.cps.msu.edu (Anton Rang)
`corrects' me:
>>VAX processors do have separate bits for read, write, and execute on
>>each page (I seem to vaguely recall one more). ...

In article <3335@tekcrl.CRL.TEK.COM> terryl@tekcrl.CRL.TEK.COM writes:
>     BBBBUUUUUZZZZ!!!!! Wrong answer...

So far so good....

>     The VAX only has read/write permissions per page, but it does have
>4 different access modes per page (kernel, executive, supervisor, & user),
>with each access mode having its own independent permissions per page...

Not so.  There is a four bit field for `access control'.  With four CPU
modes (K E S & U as above) and two permissions (R & W), there are only
half as many bits as needed for fully independent permissions.
Instead, the VAX designers made the assumption that if the user can
write the page, all the more privileged modes should also be able to
write; if the user can only read, more bits might allow other modes to
write.  Whatever permissions a less-privileged mode has, a more-
privileged mode has at least those permissions.

4BSD VAX Unix makes use of only the following modes:

#define	PG_NOACC	0
#define	PG_KW		0x10000000
#define	PG_KR		0x18000000
#define	PG_UW		0x20000000
#define	PG_URKW		0x70000000
#define	PG_URKR		0x78000000

Execute permission is implied by read permission.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

levy@ttrdc.UUCP (Daniel R. Levy) (12/02/88)

In article <14733@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> I will, however, note that any number of local changes might have
> moved the address `wwww' far enough to foil the attack.  One could
> argue that, perhaps, each process should have a different view of its
> own address space.  It would certainly be easy enough to have the
> c startup code move the stack down by a pseudo-random amount....

Couldn't this cause problems in using a debugger?  With the stack location
differing from invocation to invocation, pointer values which refer to stack
locations would also differ between otherwise identical runs of a program.

-- 
|------------Dan Levy------------|  THE OPINIONS EXPRESSED HEREIN ARE MINE ONLY
| Bell Labs Area 61 (R.I.P., TTY)|  AND ARE NOT TO BE IMPUTED TO AT&T.
|        Skokie, Illinois        | 
|-----Path:  att!ttbcad!levy-----|

stuart@bms-at.UUCP (Stuart Gathman) (12/03/88)

Although the code space can't be modified, a virus can selectively
execute portions of the code space in any desired sequence by modifying
the stack in a split I&D process.  It doesn't take much imagination
to see what might be done with the library code included with a
typical program.  exec() is only one possibility.
-- 
Stuart D. Gathman	<stuart@bms-at.uucp>
			<..!{vrdxhq|daitc}!bms-at!stuart>

allbery@ncoast.UUCP (Brandon S. Allbery) (12/04/88)

As quoted from <14733@mimsy.UUCP> by chris@mimsy.UUCP (Chris Torek):
+---------------
| (It is worth noting that the fingerd attack was applied only to VAXen.)
| 
> (deleted; "wwww" is the "worm address" where the worm had to run)
|
| I will, however, note that any number of local changes might have
| moved the address `wwww' far enough to foil the attack.  One could
+---------------

From what I've read, the fingerd attack was applied to Suns as well -- but
the "wwww" address *was* sufficiently wrong, so an infected fingerd simply
dumped core.

++Brandon
-- 
Brandon S. Allbery, comp.sources.misc moderator and one admin of ncoast PA UN*X
uunet!hal.cwru.edu!ncoast!allbery  <PREFERRED!>	    ncoast!allbery@hal.cwru.edu
allberyb@skybridge.sdi.cwru.edu	      <ALSO>		   allbery@uunet.uu.net
comp.sources.misc is moving off ncoast -- please do NOT send submissions direct
      Send comp.sources.misc submissions to comp-sources-misc@<backbone>.

jik@athena.mit.edu (Jonathan I. Kamens) (12/05/88)

In article <13203@ncoast.UUCP> allbery@ncoast.UUCP (Brandon S. Allbery) writes:

>From what I've read, the fingerd attack was applied to Suns as well -- but
>the "wwww" address *was* sufficiently wrong, so an infected fingerd simply
>dumped core.

This is not correct.  I just checked with the one of the members of
the team who disassembled the code here at MIT.  He says that the
problem with the Sun version of the worm was that it was trying to use
the same hex instructions as the VAX code.  This obviously wouldn't
work, since the Sun instruction set is just slightly different from
the VAX's :-).

If the author(s) of the code had bothered to figure out the stack
frame dimensions on the Sun, I'm sure he/she/they would have also
figured out the necessary Sun instructions to make it work, and vice
versa.

  Jonathan Kamens
  MIT Project Athena

barmar@think.COM (Barry Margolin) (12/06/88)

In article <8308@bloom-beacon.MIT.EDU> jik@athena.mit.edu (Jonathan I. Kamens) writes:
[Regarding the fingerd worm:]
>If the author(s) of the code had bothered to figure out the stack
>frame dimensions on the Sun, I'm sure he/she/they would have also
>figured out the necessary Sun instructions to make it work, and vice
>versa.

I don't think so.  I don't think the worm knows the hardware of the
system it is trying to propogate to.  If it's propogating using
machine language instructions, it needs to know the hardware.  The
sendmail worm could go to either system because it transmitted a shell
script that runs on both Suns and Vaxes, which was able to look around
and determine which kind it was running on (in order to transfer and
link the correct stuff).

Barry Margolin
Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar