From: Matthew Dillon (dillon@apollo.backplane.com)
Date: Mon Feb 08 1999 - 16:00:57 EST
:>
:> I don't understand your statement about
:> "But once you've executed something in it you cannot write to it again."
:> Of course you can write into it and execute it again.
:>
:
:I just realized that saying "you can write into it and execute it again"
:does not refute your statement.
:
:What I mean is that you can write to the data segment and execute code
:in it arbitrarily.
:
: - Godmar
Most modern processors have a separate instruction cache. Typically,
writes to memory are only cached in the data cache, not the instruction
cache. Thus if you have executed a piece of code ( causing it to be
brought into the instruction cache ), and then attempt to change
that code by writing to the memory where said code resides, then execute
it again, the processor may execute stale instructions from the
instruction cache instead of the new instructions you wrote into the
memory.
So, the rule of thumb is: You can write instructions to newly allocated
memory but once you've executed them, you can't modify that memory.
UNIX systems have the notion of three protection bits:
PROT_READ, PROT_WRITE, and PROT_EXECUTE. Many of today's processor's
MMU's can only deal with PROT_READ and PROT_WRITE and ignore
PROT_EXECUTE. Thus, on many of today's processors you can run code
out of memory that was allocated R+W rather then R+W+X. This leads to
rather sloppy memory allocation practices in regards to dynamically
loaded code or JIT code.
The only way to be absolutely sure is to use mmap(), which allows you
to properly specify PROT_EXECUTE. If you use sbrk() you do not necessarily
know what access flags the OS is applying to the memory, and you might
still be able to run code in it *even* if the OS only mapped the memory
R+W ( due to limitations with the hardware MMU for the processor in
question ). Prior to mmap() coming into existance, sbrk() was used
to allocate memory to hold dynamically loaded code, so the use of
sbrk() has become a kind of defacto standard. Given the choice,
though, it is better to use mmap() on systems that support anonymous
or /dev/zero mmaping.
The IA32 architecture ( aka intel ) has no notion of execute permissions
in the MMU proper. It does have a notion of execute permissions in
the code segment register, but apart from a few hacks one sees here and
there the code segment register is not useful in a paged memory
environment and so cannot typically be used to enforce PROT_EXECUTE.
-Matt
Matthew Dillon
<dillon@backplane.com>
This archive was generated by hypermail 2b29 : Sat Sep 23 2000 - 19:58:02 EDT