Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.compilers > #1137 > unrolled thread
| Started by | Seima Rao <seimarao@gmail.com> |
|---|---|
| First post | 2014-03-07 21:34 +0530 |
| Last post | 2014-04-16 09:18 -0400 |
| Articles | 7 — 7 participants |
Back to article view | Back to comp.compilers
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
| From | Seima Rao <seimarao@gmail.com> |
|---|---|
| Date | 2014-03-07 21:34 +0530 |
| Subject | Self-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]
| From | Kaz Kylheku <kaz@kylheku.com> |
|---|---|
| Date | 2014-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]
| From | Terrence Enger <tenger@iseries-guru.com> |
|---|---|
| Date | 2014-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]
| From | Martin Ward <martin@gkc.org.uk> |
|---|---|
| Date | 2014-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]
| From | seimarao@gmail.com |
|---|---|
| Date | 2014-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]
| From | federation2005@netzero.com |
|---|---|
| Date | 2014-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]
| From | Stefan Monnier <monnier@iro.umontreal.ca> |
|---|---|
| Date | 2014-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