Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.compilers > #1137 > unrolled thread

Self-modifying code, Function pointers & { Safety, Security}

Started bySeima Rao <seimarao@gmail.com>
First post2014-03-07 21:34 +0530
Last post2014-04-16 09:18 -0400
Articles 7 — 7 participants

Back to article view | Back to comp.compilers


Contents

  Self-modifying code, Function pointers & { Safety, Security} Seima Rao <seimarao@gmail.com> - 2014-03-07 21:34 +0530
    Re: Self-modifying code, Function pointers & { Safety, Security} Kaz Kylheku <kaz@kylheku.com> - 2014-03-09 20:36 +0000
      Re: Self-modifying code, Function pointers & { Safety, Security} Terrence Enger <tenger@iseries-guru.com> - 2014-03-15 09:29 -0400
    Re: Self-modifying code, Function pointers & { Safety, Security} Martin Ward <martin@gkc.org.uk> - 2014-03-14 14:15 +0000
    Re: Self-modifying code, Function pointers & { Safety, Security} seimarao@gmail.com - 2014-03-20 00:42 -0700
      Re: Self-modifying code, Function pointers & { Safety, Security} federation2005@netzero.com - 2014-04-13 12:41 -0700
        Re: Self-modifying code, Function pointers & { Safety, Security} Stefan Monnier <monnier@iro.umontreal.ca> - 2014-04-16 09:18 -0400

#1137 — Self-modifying code, Function pointers & { Safety, Security}

FromSeima Rao <seimarao@gmail.com>
Date2014-03-07 21:34 +0530
SubjectSelf-modifying code, Function pointers & { Safety, Security}
Message-ID<14-03-015@comp.compilers>
Hi,

    We are used to separation of code from data at the language level.
    However, two features disupt security :

    i) self-modifying code

     i.e. writing to code space

    ii) functions residing in data space

Are there safety & security solutions possible for the above two
safety, security holes ?

Sincerely,
Seima Rao.
[The major reasons for self-modifying code historically were for
address modification for indexing and subroutine returns.  Index
registers and indirect addressing provide instruction modification as
the instruction is executed, making those modifications go away.  For
runtime code generation, there have been a variety of approaches to
controlled addition of code to running programs, which I could dig up
if people care. -John]

[toc] | [next] | [standalone]


#1138

FromKaz Kylheku <kaz@kylheku.com>
Date2014-03-09 20:36 +0000
Message-ID<14-03-016@comp.compilers>
In reply to#1137
On 2014-03-07, Seima Rao <seimarao@gmail.com> wrote:
> Hi,
>
>     We are used to separation of code from data at the language level.

Those "we" who don't use Lisp and related languages.

>     However, two features disupt security :
>
>     i) self-modifying code
>
>      i.e. writing to code space

Note that loading an executable on any operating system constitutes
the above.

The solution for that is supposed to be a web of trust. You load only
code that is trusted somehow.

>     ii) functions residing in data space
>
> Are there safety & security solutions possible for the above two
> safety, security holes ?

You can have a compiler built into our language for dynamically compiling code.
That compiler can "sandbox" dynamic programs into not doing anything "bad": it
can avoid exposing certain functions or operators to them.

E.g. in Lisp we have the compile function, but that provides access to the
full language, including all implementation-specific escape hatches, like
foreign function calling or whatever.

However, we can make a function "my-compile" which accepts only a strictly
sandboxed dialect, translates it to the regular Lisp (or at least the
parts of it that differ, if any) and then hands it to the compile function.

Dynamically compiled regular expressions are an example of this. You can hardly
reformat the proverbial disk out of a regex, unless it has some exploitable
hole not related to the semantics of regex. A regex is a severely sandboxed,
dynamically compiled language which can be translated all the way down to
machine code that can be trusted.

--
Music DIY Mailing List: http://www.kylheku.com/diy
ADA MP-1 Mailing List:  http://www.kylheku.com/mp1

[toc] | [prev] | [next] | [standalone]


#1163

FromTerrence Enger <tenger@iseries-guru.com>
Date2014-03-15 09:29 -0400
Message-ID<14-03-041@comp.compilers>
In reply to#1138
Kaz Kylheku <kaz@kylheku.com> wrote (with blank lines snipped to keep
the email-filter happy):
> On 2014-03-07, Seima Rao <seimarao@gmail.com> wrote:
> > We are used to separation of code from data at the language level.
[snip Kaz's response]
> > However, two features disupt security :
> > i) self-modifying code
> > i.e. writing to code space
> Note that loading an executable on any operating system constitutes
> the above.

I believe that the IBM system/i is an exception to that general rule.
Only the operating system can write to the code space of a program
object.  This *does* contribute to the security of the system.
[Burroughs mainframes have done that since the 1960s.  I wouldn't put
too much faith in the security implications though; I once saw a demo
of hacking computerized voting machines even though all of the code
was in ROM.  They constructed a stack with pointers to bits of
routines that could be exploited, and then just did a return. -John]

[toc] | [prev] | [next] | [standalone]


#1154

FromMartin Ward <martin@gkc.org.uk>
Date2014-03-14 14:15 +0000
Message-ID<14-03-032@comp.compilers>
In reply to#1137
On 07/03/14 16:04, John wrote:
> [The major reasons for self-modifying code historically were for
> address modification for indexing and subroutine returns.  Index
> registers and indirect addressing provide instruction modification as
> the instruction is executed, making those modifications go away.... -John]

The IBM mainframe instruction set includes an "Execute" instruction
(EX) which takes a register and an address. The instruction at the
given address is loaded into memory, part of it is overwritten by the
low byte from the register, and the resulting modified instruction is
executed.

The most common use for Execute is to modify the length field of an
instruction to give a variable length move or compare.

As common with many IBM instructions, the Execute instruction includes
an index register field: so an instruction can be selected for
execution from a table of instructions, depending on the value in the
given index register.

Despite the presence of Execute, and the fact that more recent
mainframes now include variable length move and comare instructions,
self modifying code is still quite common in assembler code which is
currently in production.

One of the most common cases is overwriting a NOP (branch never)
instruction to convert it into a B (unconditional branch) instruction.
This is typically used to set up a "first time through" switch, for
example:

NOPINSTR NOP LAB1
          MVI   NOPINSTR+1,X'F0'
          initialisation code...
LAB1     ...

The first time through, the NOP instruction does not branch, so
control falls through to the MVI instruction (move immediate) which
overwrites part of the NOP instruction, turning it into an
unconditional branch. Subsequent executions will then skip the
initialisation code. The advantage of this approach (over setting and
testing a flag) is that it saves five whole bytes of memory: one byte
for the flag and four more bytes for the compare instruction. It also
saves executing one instruction.

The other common cases for self-modifying code are modifying the
length field (directly in the instruction, rather than indirectly via
an Execute instruction), modifying one or more displacement fields
(i.e. modifying the address of the data that the instruction operates
on) and modifying the data field of an immediate data instruction.

I recently carried out a survey of several million lines of current
production assembler in three organisations.  Self-modifying code
appeared in all code bases, with the amounts varying considerably
between organisations.  The numbers below are per million lines of
executable instructions:

Organisation A:

    24 EXecute instructions
 2,685 modified branch instructions
 3,451 modified length fields
   490 modified immediate data fields
 1,578 modified displacements

Organisation B:

   722 EXecute instructions
 1,236 modified branch instructions
   626 modified length fields
    74 modified immediate data fields
   429 modified displacements

Organisation C:

 1,222 EXecute instructions
    76 modified branch instructions
   107 modified length fields
     0 modified immediate data fields
    90 modified displacements

Any automated assembler analysis or migration tool therefore needs to
be able to detect and handle all these cases of self-modifying code
(as ours does, of course!)

As well as saving memory space, self-modifying code was used to
improve exection speed. Ironically, on modern mainframes,
self-modifying code will dirty the instruction cache: forcing the CPU
to re-load from main memory and killing performance!

I can only think of two cases (out of all the production assembler code
we have ever processed) in which a block of instructions is written
to memory and subsequently executed.

--
			Martin

Dr Martin Ward STRL Principal Lecturer & Reader in Software Engineering
martin@gkc.org.uk  http://www.cse.dmu.ac.uk/~mward/  Erdos number: 4
G.K.Chesterton web site: http://www.cse.dmu.ac.uk/~mward/gkc/
Mirrors:  http://www.gkc.org.uk  and  http://www.gkc.org.uk/gkc

[Thanks, this is quite interesting.  Mainframe sort programs compile
the sort instructions into machine code that does the record editing
and comparison, but they write the code out as an object file on disk,
and then use the link editor or loader to combine it with any user
exit routines and bring it into memory, where the main sort program
can call it. Given the large size of most sort jobs, the extra time for
the linkedit is insignficant. -John]

[toc] | [prev] | [next] | [standalone]


#1174

Fromseimarao@gmail.com
Date2014-03-20 00:42 -0700
Message-ID<14-03-052@comp.compilers>
In reply to#1137
> [The major reasons for self-modifying code historically were for
> address modification for indexing and subroutine returns.  Index
> registers and indirect addressing provide instruction modification as
> the instruction is executed, making those modifications go away.  For
> runtime code generation, there have been a variety of approaches to
> controlled addition of code to running programs, which I could dig up
> if people care. -John]

I was planning to discontinue self-modifying code entirely.
For runtime code generation, I was planning to bank entirely
upon runtime hooks(mapping instructions of an interpreter to
API hooks).

I will proceed on these two premises if only others advised.

Sincerely,
Seima Rao.

[toc] | [prev] | [next] | [standalone]


#1219

Fromfederation2005@netzero.com
Date2014-04-13 12:41 -0700
Message-ID<14-04-012@comp.compilers>
In reply to#1174
On Thursday, March 20, 2014 2:42:20 AM UTC-5, seim...@gmail.com wrote:
> I was planning to discontinue self-modifying code entirely.
> For runtime code generation, I was planning to bank entirely
> upon runtime hooks(mapping instructions of an interpreter to
> API hooks).

I think the brunt of the Halting Problem comes down to this very matter and
can probably be summed up in a simple way that there are no finite number of
fixes that completely account for all the things you may want or *need* to do
with self-modifying code. Instead, you have a set of standard "fixes" that
appear to meet most needs (e.g. the "loader" for run-time loading a program,
the "branch prediction" of some CPU's for handling the "nop" to jump
conversion at run-time, the "relocator" for handling "nop" to op at load time,
etc.). But no finite set of "standard fixes" or "utilities" for the various
special cases (nor even an *infinite* set of such fixes, if they are
recursively enumerable) will exhaust all the things you may want or need to
do.

What I'm not sure of is this question: is there way of actually defining
"no-modifying" algorithms that leads to a *positive* resolution for the
halting problem? I suspect there is and that it may be directly tied to the
formalism for linearly bounded automata (the automata for context-sensitive
languages).

Tha halting problem is solvable for linearly bounded automata.

[toc] | [prev] | [next] | [standalone]


#1221

FromStefan Monnier <monnier@iro.umontreal.ca>
Date2014-04-16 09:18 -0400
Message-ID<14-04-014@comp.compilers>
In reply to#1219
> Tha halting problem is solvable for linearly bounded automata.

The halting problem is also trivially solvable for languages such as
Coq and Agda: in those languages, all functions terminate.  Of course,
they may take centuries to run to completion, so knowing that they
will eventually terminate may not be nearly as useful as one might
think.

        Stefan

[toc] | [prev] | [standalone]


Back to top | Article view | comp.compilers


csiph-web