Skip to content

Commit da21936

Browse files
committed
Merged in branch for new README.md file containing enough instruction for a user to start using Shiva.
1 parent 5ca543f commit da21936

2 files changed

Lines changed: 270 additions & 6 deletions

File tree

Makefile

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ patches:
3636
install:
3737
cp build/shiva /lib/shiva
3838
ln -sf build/shiva shiva
39-
rm shiva-ld
40-
ln -s tools/shiva-ld/shiva-ld shiva-ld
4139
cp build/shiva /usr/bin
4240
cp tools/shiva-ld/shiva-ld /usr/bin
4341
mkdir -p /opt/shiva/modules

README.md

Lines changed: 270 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,270 @@
1-
Shiva is a programmable runtime linker (Program interpreter) for ELF x64/aarch64 Linux --
2-
ELF-microprograms (Shiva modules) are linked into the process address space and given
3-
intricate control over program instrumentation via ShivaTrace API. ShivaTrace is an in-process debugging
4-
and instrumentation API with innovative debugging and hooking features.
1+
# Shiva -- Programmable runtime linking and microcode patching
2+
3+
4+
## Description
5+
6+
Shiva is a programmable runtime linker (Program interpreter) for ELF
7+
x64/aarch64 Linux -- ELF-microprograms (Shiva modules) are linked into the
8+
process address space and given intricate control over program instrumentation
9+
via ShivaTrace API. ShivaTrace is an in-process debugging and instrumentation
10+
API with innovative debugging and hooking features.
11+
12+
Shiva has been custom tailored towards the requirements of the AMP project and
13+
with support for the AArch64 architecture. This fork of the project has created
14+
an abundant set of new microcode patching capabilities, including symbol interposition
15+
on functions (i.e. .text), as well as on global data (i.e. .rodata, .data, .bss).
16+
17+
The original Shiva project can be found at https://github.com/elfmaster/shiva
18+
19+
This README will only cover Shiva as it relates to the AMP project.
20+
21+
Please see ./documentation/shiva_preliminary_design.pdf for a technical description
22+
of Shiva.
23+
24+
## Support
25+
26+
Support is limited to ELF AArch64 ET_DYN binaries. Future support for ET_EXEC will
27+
be added as needed. The cFS software and the patch challenge-10 binaries are
28+
ELF AArch64 ET_DYN binaries, so currently we are meeting the requirements.
29+
30+
## Build
31+
32+
This has been tested on aarch64 ubuntu 18.04 and 22.
33+
Shiva relies on libelfmaster and musl-libc.
34+
35+
## Dependencies
36+
37+
38+
#### libelfmaster (aarch64_support branch)
39+
40+
```
41+
git clone git@github.com:elfmaster/libelfmaster
42+
cd libelfmaster
43+
git --fetch all
44+
git checkout aarch64_support
45+
```
46+
47+
The original build for libelfmaster seems broken and I haven't yet fixed it.
48+
Meanwhile just use the simple build shellscript I made.
49+
50+
```
51+
cd src
52+
sudo make.sh
53+
```
54+
55+
The static library to libelfmaster
56+
```/opt/elfmaster/lib/libelfmaster.a```
57+
58+
The header file to libelfmaster
59+
```/opt/elfmaster/include/elfmaster.h```
60+
61+
62+
#### musl-libc
63+
64+
```
65+
sudo apt-get install musl musl-dev musl-tools
66+
```
67+
68+
## Building Shiva
69+
70+
```
71+
cd ~/git
72+
git clone git@github.com:advanced-microcode-patching/shiva
73+
cd shiva
74+
make
75+
make shiva-ld
76+
make patches
77+
sudo make install
78+
```
79+
80+
Shiva is copied to `"/lib/shiva"` and can be executed directly, but more commonly
81+
indirectly as an interpreter.
82+
83+
The shiva-ld utility is used to modify binaries with the path to the new
84+
program interpreter `"/lib/shiva"`, and the path to the patch module (i.e.
85+
`"/opt/modules/shiva/patch1.o"`).
86+
87+
## Patch testing
88+
89+
We have already compiled and prelinked the patches. Shiva prelinking
90+
refers specifically to the Shiva prelinking applied by the shiva-ld tool.
91+
92+
Take a look at the Makefile for each patch, and you will see how shiva-ld is
93+
used to apply the pre-patch meta-data.
94+
95+
```
96+
shiva-ld -e core-cpu1 -p cfs_patch1.o -i /lib/shiva -s /opt/shiva/modules -o core-cpu1.patched
97+
```
98+
99+
The Shiva make install script installs all of the patch modules into `/opt/shiva/modules`
100+
101+
The patch build environments are stored in `modules/aarch64_patches/` and are as follows:
102+
103+
### CFS Binary patch: cfs_patch1
104+
105+
This is just a simple patch that uses symbol interposition to replace the
106+
STB_GLOBAL/STT_FUNC `OS_printf` that lives within the `core-cpu1` executable.
107+
The patch `cfs_patch1.c` simply rewrites its own version of the function.
108+
109+
The contents of the `./modules/aarch64_patches/cfs_patch1`
110+
111+
```
112+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/cfs_patch1$ ls
113+
cfs_patch1.c cfs_patch1.o core-cpu1 core-cpu1.patched EEPROM.DAT Makefile
114+
```
115+
116+
The program that we are patching is `core-cpu1` and specifically the symbol `OS_printf`
117+
118+
```
119+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/cfs_patch1$ readelf -s core-cpu1 | grep OS_printf
120+
241: 0000000000047d88 456 FUNC GLOBAL DEFAULT 13 OS_printf
121+
```
122+
123+
Our patch contains it's own version of the function `OS_printf` and at runtime Shiva will load
124+
the `/opt/shiva/modules/cfs_patch1.o` handle all of it's own relocations, and then it will externally
125+
re-link `core-cpu1` so that any calls to the old `OS_printf` are patched to call the new `OS_printf`
126+
that lives within the modules runtime environment setup by Shiva.
127+
128+
129+
```
130+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/cfs_patch1$ cat cfs_patch1.c
131+
#include <stdarg.h>
132+
#include <stdlib.h>
133+
#include <stdint.h>
134+
#include <stdio.h>
135+
136+
void OS_printf(const char *string, ...)
137+
{
138+
char msg_buffer[4096];
139+
va_list va;
140+
int sz;
141+
142+
va_start(va, string);
143+
sz = vsnprintf(msg_buffer, sizeof(msg_buffer), string, va);
144+
va_end(va);
145+
msg_buffer[sz] = '\0';
146+
printf("[PATCHED :)]: %s\n", msg_buffer); /* NOTICE THIS LINE */
147+
}
148+
149+
```
150+
151+
A quick look at the `PT_INTERP` segment will reveal that `core-cpu1.patched` has `"/lib/shiva"`
152+
set as the program interpreter.
153+
154+
```
155+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/cfs_patch1$ readelf -l core-cpu1.patched | grep interpreter
156+
[Requesting program interpreter: /lib/shiva]
157+
```
158+
159+
Two custom dynamic segment entries were also added to the binary:
160+
161+
`SHIVA_DT_SEARCH` denotes a dynamic entry containing the address of the module search path,
162+
usually set to `"/opt/shiva/modules/"`.
163+
164+
`SHIVA_DT_NEEDED` denotes a dynamic entry containing the address of the module basename,
165+
i.e. `"cfs_patch1.o"`.
166+
167+
```
168+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/cfs_patch1$ readelf -d core-cpu1.patched | tail -n 3
169+
0x0000000060000018 (Operating System specific: 60000018) 0x1ab200
170+
0x0000000060000017 (Operating System specific: 60000017) 0x1ab213
171+
0x0000000000000000 (NULL) 0x0
172+
```
173+
174+
NOTE: The new dynamic segment lives within a newly created PT_LOAD segment. The new PT_LOAD segment
175+
is the result of a PT_NOTE to PT_LOAD transition.
176+
177+
#### Running core-cpu1.patched
178+
179+
180+
When running the `./core-cpu.patched` we see in the last stdout line our patched
181+
`OS_printf` executes. Notice it prefaces each line of output with the string `"[PATCHED :)]"`
182+
183+
```
184+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/cfs_patch1$ ./core-cpu1.patched
185+
OS_BSP_Initialize():Maximum user msg queue depth = 10
186+
CFE_PSP: Default Reset SubType = 1
187+
CFE_PSP: Default CPU ID = 1
188+
CFE_PSP: Default Spacecraft ID = 66
189+
CFE_PSP: Default CPU Name: cpu1
190+
OS_Posix_GetSchedulerParams():186:Policy 1: available, min-max: 1-99
191+
OS_Posix_GetSchedulerParams():186:Policy 2: available, min-max: 1-99
192+
OS_Posix_TaskAPI_Impl_Init():372:Selected policy 2 for RT tasks, root task = 99
193+
OS_Posix_TaskAPI_Impl_Init():388:Could not setschedparam in main thread: Operation not permitted (1)
194+
CFE_PSP: initializing module 'soft_timebase' with ID 0110ff00
195+
CFE_PSP: Instantiated software timebase 'cFS-Master' running at 10000 usec
196+
CFE_PSP: initializing module 'timebase_posix_clock' with ID 0110ff01
197+
CFE_PSP: Using POSIX monotonic clock as CFE timebase
198+
CFE_PSP: initializing module 'eeprom_mmap_file' with ID 0110ff02
199+
CFE_PSP: Using MMAP simulated EEPROM implementation
200+
[PATCHED :)]: CFE_PSP: EEPROM Range (2) created: Start Address = FFFF84032000, Size = 00080000 Status = 0
201+
```
202+
203+
#### Patching .rodata symbols with Shiva: rodata_interposing patch.
204+
205+
`modules/aarch64_patches/rodata_interposing`
206+
207+
This patch demonstrates how Shiva is able to link new read-only data into place over
208+
existing read-only data symbols. For example
209+
210+
211+
The contents of the `rodata_interposing` directory
212+
213+
```
214+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/rodata_interposing$ ls
215+
Makefile ro_patch.c ro_patch.o test_rodata test_rodata.c test_rodata.patched
216+
```
217+
218+
The original program has a read-only string `const char rodata_string[] = "Arcana Technologies"`
219+
220+
```
221+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/rodata_interposing$ readelf -s test_rodata | grep rodata_string
222+
73: 0000000000000800 20 OBJECT GLOBAL DEFAULT 15 rodata_string
223+
```
224+
225+
This constant string data is stored within the `.rodata section`.
226+
227+
```
228+
objdump -D test_rodata | less
229+
230+
...
231+
232+
0000000000000800 <rodata_string>:
233+
800: 61637241 .word 0x61637241
234+
804: 5420616e .word 0x5420616e
235+
808: 6e686365 .word 0x6e686365
236+
80c: 676f6c6f .word 0x676f6c6f
237+
810: 00736569 .word 0x00736569
238+
```
239+
240+
Our patch aims to change the string from `"Arcana Technologies"` to `"The Great Arcanum"`.
241+
242+
```
243+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/rodata_interposing$ cat ro_patch.c
244+
245+
const char rodata_string[] = "The Great Arcanum";
246+
247+
```
248+
249+
The compiled patch is `ro_patch.o`
250+
251+
At runtime Shiva will load and link the patch with the executable in memory, and all references
252+
to the old `rodata_string[]` will be replaced with the correct offset to the patches version of
253+
`rodata_string[]`. The original string is not being over-written, but is no longer referenced.
254+
255+
256+
#### Running the unpatched and patched test_rodata binary
257+
258+
```
259+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/rodata_interposing$ ./test_rodata
260+
rodata_string: Arcana Technologies
261+
val: 5
262+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/rodata_interposing$ ./test_rodata.patched
263+
rodata_string: The Great Arcanum
264+
val: 5
265+
elfmaster@esoteric-aarch64:~/amp/shiva/modules/aarch64_patches/rodata_interposing$
266+
```
267+
268+
### A work in progress...
269+
270+

0 commit comments

Comments
 (0)