Avoiding Hardware Aliasing
Peter T. Breuer and Jonathan P. Bowen
Birmingham City University
Imagine the Lander is on Mars
●
A cosmic ray tracks through the processor
Arithmetic Logic Unit
– From then on 1+1=3
●
How do we save the mission?
– An answer turns out to be 'reliable' code
Extreme: every
operation 'wrong'
●
Krypto-Processor (KPU)
– Natively encrypted computing
● Instead of 4 - 4 = 0 ...
● 99900 - 99900 = 78763298
– Potential Holy Grail Security Cure-All
● Encryption is 1-to-many
99900(4) + 78763298(0) = 2980(4) Same address (4) accesses
different memory (99900, 2980)
Called
Hardware
Aliasing
●
Two devices/memory live at one address
– E.g. old Windows shared library problem
● All versions load at same address
● Applications get unexpected functionality
– Still around today
● M/S mem-maps library files by basename
➔ different versions of same library in same
directory don't work. Also .net (sub-4)
– Application sees same address access
Different cause, different rescue
●
Don't use processor register with stuck bit
●Pre/post-correct ALU arithmetic
The messed-up arithmetic case
●
Model: Imagine there's a devil
messing with calculations:
● Think: values have invisible extra bits
● 42.1101101
● Represents the many ways of saying '42'
●
Processor ignores and mutates extra bits
● 42.1101101 + 42.1100001 = 84.0110110
●
Memory/peripherals
sensitive to extra bits
Fixing Processor Arithmetic
Clue: processors are
Deterministic
behind the scenes
No matter how haphazard it seems
Solution: deterministic
Krypto-processor (KPU) case
Many different bit-patterns signify same address 'messed-up on purpose'
Data in one of the crypto-equivalent addresses!
1011
(&4)
&99900 &2980
Soln: always calculate same address same way
Example
●
Left program returns
different alias
to caller
SP – 32 + 32, SP equivalent, not identical Different calculation, different result
Subroutine foo:
SP -= 32 # 8 local vars
…code ...
SP += 32 # destroy frame
return
Subroutine foo:
GP = SP
SP -= 32
…code ...
SP = GP
return
Use t
yping
●
Milner typing
– Assign type variables to every register
and local stack position
– Distinguish by type
● Data
● Data address
– Array data address
– String data address
●
A type-correct machine code …
Call stack
●
Variables in the local frame are ...
– Accessed like arrays – Base address + offset
● Base address = bottom of stack
● Every stack change starts fresh frame
●
If
offset < local frame size. there is ...
– Only one way of calculating local address
Heap access
●
Contains both
array
and
string
addresses
– Array … I just did that
– String access: base+1+1+1+1+..+1
Apply typing
●
Type-check machine code as per paper...
– Pass guarantees each address …
● Calculated same way each time
– Deterministic processor
– Implies same bit-pattern results each time
●
Code is safe against hardware aliasing
Interesting Abstract Computer
Science Things
●
Formal logic
of
machine code
●
Each instruction has many interpretations
– addiu r1 r1 4
● Change stack pointer in r1 by 4 ● Add 4 to datum in register r1
– Disambiguated by decompilation
– Self-consistent decompilation is a proof
● Decompiled instructions are proof step names
●
At most 32 possible code decompilations
Interesting Abstract Computer
Science Things
●
Formal logic of machine code
●
Each instruction has many interpretations
– addiu r1 r1 4
● Change stack pointer in r1 by 4 ● Add 4 to datum in register r1
– Disambiguated by decompilation
– Self-consistent decompilation is a proof
● Decompiled instructions are proof step names
●
At most 32 possible code decompilations
Example
●
32B current frame
{ sp=
c
32!10
;
(10)=
x
}
ld gp 10(sp)
[
get 10 gp
]
{sp=
c
32!10
;
(10)=gp=
x
}
●
'
c
32!10
' means 'pointer to 32B that ...
– has already been written to at offset 10'
●
(10)=
x
means stack cell 10 is an
x
-thing
●
Machine code
is '
ld gp 10(sp)
'
– 'load reg gp from offset 10 off stack ptr'
Uninteresting Abstract
Computer Science Things
●
Typing restricts the number of valid codes
– In machine code, normally everything goes – But only well-typed codes will type
● There are effectively NONE in existence
– We can fix existing ones and check the fix
– We can keep checking through maintenance
– Worse, only iterative sequential machine code
● Makes sense to our typing system
– This is not surprising!
●
Typing is theoretically double-exponential
Conclusion
●
Encrypted processing/KPU is what we like
– Secure!
– But it has horrible hardware aliasing
● Same address accesses different memory
●
Solution for class of `damaged' processors
– Resilient machine code that
● Calculates each address same way each time ● Processor arithmetic `error' does not matter