Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for pointer authentication on load and store instructions with ARM's PAC #1

Draft
wants to merge 33 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2712cf0
First draft of adding PAC to llvm
fritzrehde Jun 18, 2023
fdaec8c
Small bug fix, incorrect variable name in load
fritzrehde Jun 18, 2023
8a6bab3
Fixed wrong usage of load and store operands
fritzrehde Jun 21, 2023
a56666f
Fixed recursive referencing of loads after replacing
fritzrehde Jun 22, 2023
fbfb35b
Added demo for pac testing
fritzrehde Jun 27, 2023
50c1ce7
Added separate WIP pointer authentication function pass
fritzrehde Jun 29, 2023
b1fe159
Some progress
fritzrehde Jun 30, 2023
81602ca
More progress
fritzrehde Jul 5, 2023
8101587
Split pointer auth into seperate function and module passes
fritzrehde Jul 8, 2023
26a8609
Added unit tests for valueComesFromElsewhere
fritzrehde Jul 9, 2023
a1d7b6d
Added another unit test for argv
fritzrehde Jul 9, 2023
e1a0148
Added condition for value coming from elsewhere
fritzrehde Jul 9, 2023
2cb3bf1
Temporary fix for encountering loops when checking for PA for loads
fritzrehde Jul 10, 2023
b21b374
Fixed some analysis
fritzrehde Jul 10, 2023
180b1cf
Fixed small bug that allowed pointers stored in global values to be s…
fritzrehde Jul 11, 2023
6809e58
Added a real attack that PAC should prevent
fritzrehde Jul 11, 2023
a5d062e
Removed some debugging print statements from function pass
fritzrehde Jul 12, 2023
12f8075
Added all test files
fritzrehde Jul 15, 2023
f54676a
Updated module pass
fritzrehde Jul 19, 2023
2bd0b70
Work on module pass
fritzrehde Jul 20, 2023
92bcc76
Fixed a few bugs related to the module pass analysis
fritzrehde Jul 21, 2023
bcfb6bf
Added notes on a potential optimization
fritzrehde Aug 1, 2023
e49e78d
Removed some debugging prints
fritzrehde Aug 9, 2023
5e14ffb
Infer function attributes before checking alloc kind
martin-fink Jul 17, 2023
6f83d99
Add missing header
martin-fink Jul 18, 2023
6bb99b8
Only enable mte for now
fritzrehde Aug 9, 2023
d9c5b98
Some additions to PAC analysis
fritzrehde Sep 6, 2023
13065aa
Added basics for LTO pass
fritzrehde Sep 11, 2023
5065a01
Fixed rtlib directory
fritzrehde Sep 11, 2023
cfc8d6a
LTO pass is the same as module pass
fritzrehde Sep 14, 2023
6e43852
Switched back to module pass
fritzrehde Sep 16, 2023
a57470b
pac benchmarking
fritzrehde Sep 17, 2023
0da63bc
Added documentation on how to test PAC
fritzrehde Feb 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@
"-resource-dir",
"./build/lib/clang/17",
"-isysroot",
"../wasi-libc/sysroot",
"/scratch/martin/src/wasm/wasi-libc/sysroot",
"-internal-isystem",
"./build/lib/clang/17/include",
"-internal-isystem",
"../wasi-libc/sysroot/include/wasm64-wasi",
"/scratch/martin/src/wasm/wasi-libc/sysroot/include/wasm64-wasi",
"-internal-isystem",
"../wasi-libc/sysroot/include",
"/scratch/martin/src/wasm/wasi-libc/sysroot/include",
"-Os",
"-ferror-limit",
"19",
Expand Down Expand Up @@ -135,7 +135,7 @@
"command": "extension.commandvariable.file.pickFile",
"args": {
"fromFolder": {
"fixed": "/scratch/martin/src/wasm/hello-world"
"fixed": "/scratch/fritz/src/safe-wasm/llvm-project/demo"
},
"include": "**/*.c"
}
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@
"shared_mutex": "cpp",
"stop_token": "cpp",
"variant": "cpp",
"*.inc": "cpp"
"*.inc": "cpp",
"*.def": "c"
},
"clangd.arguments": [
"--query-driver=${env:PATH_TO_CLANG}"
Expand Down
1 change: 1 addition & 0 deletions demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.wasm
16 changes: 16 additions & 0 deletions demo/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Demo

## PAC Testing

To test the PAC features, which consist of a module pass that inserts custom wasm instructions that sign (`pointer_sign`) and authenticate (`pointer_auth`) a pointer before it is stored to a memory address:
- Disable MTE (in wasmtime or simply don't generate our MTE-based custom instructions in llvm/clang), since PAC can currently not effectively work when MTE is used (no PAC instructions would be inserted due to limits in our LLVM analysis).
- Compile demo C file `test-prevent-real-attack.c` without optimizations (`-O0`), since the code that tests PAC would otherwise be optimized away.

## Building

```shell
Expand Down Expand Up @@ -39,3 +45,13 @@ Wasmtime can be cross-compiled for aarch64 with the provided `Dockerfile` in thi
./wasmtime compile demo-scanf.wasm --cranelift-enable use_mte --wasm-features=memory64,mem-safety
./wasmtime run --allow-precompiled --wasm-features=memory64,mem-safety -- demo-scanf.cwasm
```

## Checking generated code

You can test what code is generated with the following commands, even if you are on a machine that is not aarch64 or doesn't support mte.

```shell
./wasmtime compile --target aarch64-unknown-linux-gnu --cranelift-enable use_mte --wasm-features=memory64,mem-safety demo-<name>.c
llvm-objdump -D demo-<name>.cwasm > demo-<name>.s
```

51 changes: 51 additions & 0 deletions demo/benchmarks-code/memory-tagging/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# CC=/scratch/fritz/src/safe-wasm/llvm-project/build/bin/clang
# WASM_FLAGS=--target=wasm64-unknown-wasi --sysroot /scratch/martin/src/wasm/wasi-libc/sysroot -g -D_WASI_EMULATED_PROCESS_CLOCKS -lwasi-emulated-process-clocks -Wl,--stack-first -Wl,--initial-memory=104857600 -Wl,--max-memory=104857600 -Wl,-z,stack-size=83886080
# SAN_FLAGS=-march=wasm64-wasi+mem-safety -fsanitize=wasm-memsafety
# CFLAGS=-O0 ${WASM_FLAGS}
# # CFLAGS=-O2 ${WASM_FLAGS}
# BUILD_DIR=build

# all: ${BUILD_DIR}/tagging.wasm

# # ${BUILD_DIR}/tagging.wasm: tagging.c
# ${BUILD_DIR}/tagging.wasm: tagging.ll
# ${CC} -o $@ $< ${CFLAGS} ${EXTRA_FLAGS} ${SAN_FLAGS}

# clean:
# @ rm -f ${BUILD_DIR}/tagging.wasm

# ${BUILD_DIR}:
# mkdir -p $@

# # Add the directory as a dependency to ensure it's created before compilation
# ${BUILD_DIR}/%.wasm: | ${BUILD_DIR}


CC=/scratch/fritz/src/safe-wasm/llvm-project/build/bin/clang
WASM_FLAGS=--target=wasm64-unknown-wasi --sysroot /scratch/martin/src/wasm/wasi-libc/sysroot -g -D_WASI_EMULATED_PROCESS_CLOCKS -lwasi-emulated-process-clocks -Wl,--stack-first -Wl,--initial-memory=104857600 -Wl,--max-memory=104857600 -Wl,-z,stack-size=83886080
SAN_FLAGS=-march=wasm64-wasi+mem-safety -fsanitize=wasm-memsafety
CFLAGS=-O0 ${WASM_FLAGS}
# CFLAGS=-O2 ${WASM_FLAGS}
BUILD_DIR=build

FILES=tagging-few-loops-large-segments \
tagging-few-loops-small-segments \
tagging-many-loops-large-segments \
tagging-many-loops-small-segments

TARGETS=$(addprefix ${BUILD_DIR}/, $(addsuffix .wasm, ${FILES}))

all: ${TARGETS}

${BUILD_DIR}/%.wasm: %.ll
${CC} -o $@ $< ${CFLAGS} ${EXTRA_FLAGS} ${SAN_FLAGS}

clean:
@ rm -f ${BUILD_DIR}/*.wasm

${BUILD_DIR}:
mkdir -p $@

# Add the directory as a dependency to ensure it's created before compilation
${BUILD_DIR}/%.wasm: | ${BUILD_DIR}

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
; File: segment_stack_test.ll

declare ptr @llvm.wasm.segment.stack.new(ptr, i64)
declare void @llvm.wasm.segment.stack.free(ptr, ptr, i64)

define i32 @__main_void() {
entry:
%static_size_array = alloca [1000000 x i32], align 16
%iteration_count = alloca i32
store i32 1600, i32* %iteration_count

br label %loop_start

loop_start:
%count = load i32, i32* %iteration_count
%is_done = icmp eq i32 %count, 0
br i1 %is_done, label %loop_end, label %loop_body

loop_body:
%segment_ptr = call ptr @llvm.wasm.segment.stack.new(ptr %static_size_array, i64 4000000)
call void @llvm.wasm.segment.stack.free(ptr %segment_ptr, ptr %static_size_array, i64 4000000)

%new_count = sub i32 %count, 1
store i32 %new_count, i32* %iteration_count
br label %loop_start

loop_end:
ret i32 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
; File: segment_stack_test.ll

declare ptr @llvm.wasm.segment.stack.new(ptr, i64)
declare void @llvm.wasm.segment.stack.free(ptr, ptr, i64)

define i32 @__main_void() {
entry:
%static_size_array = alloca [400 x i32], align 16
%iteration_count = alloca i32
store i32 1600, i32* %iteration_count

br label %loop_start

loop_start:
%count = load i32, i32* %iteration_count
%is_done = icmp eq i32 %count, 0
br i1 %is_done, label %loop_end, label %loop_body

loop_body:
%segment_ptr = call ptr @llvm.wasm.segment.stack.new(ptr %static_size_array, i64 1600)
call void @llvm.wasm.segment.stack.free(ptr %segment_ptr, ptr %static_size_array, i64 1600)

%new_count = sub i32 %count, 1
store i32 %new_count, i32* %iteration_count
br label %loop_start

loop_end:
ret i32 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
; File: segment_stack_test.ll

declare ptr @llvm.wasm.segment.stack.new(ptr, i64)
declare void @llvm.wasm.segment.stack.free(ptr, ptr, i64)

define i32 @__main_void() {
entry:
%static_size_array = alloca [10000 x i32], align 16
%iteration_count = alloca i32
store i32 40000, i32* %iteration_count

br label %loop_start

loop_start:
%count = load i32, i32* %iteration_count
%is_done = icmp eq i32 %count, 0
br i1 %is_done, label %loop_end, label %loop_body

loop_body:
%segment_ptr = call ptr @llvm.wasm.segment.stack.new(ptr %static_size_array, i64 40000)
call void @llvm.wasm.segment.stack.free(ptr %segment_ptr, ptr %static_size_array, i64 40000)

%new_count = sub i32 %count, 1
store i32 %new_count, i32* %iteration_count
br label %loop_start

loop_end:
ret i32 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
; File: segment_stack_test.ll

declare ptr @llvm.wasm.segment.stack.new(ptr, i64)
declare void @llvm.wasm.segment.stack.free(ptr, ptr, i64)

define i32 @__main_void() {
entry:
%static_size_array = alloca [400 x i32], align 16
%iteration_count = alloca i32
store i32 4000000, i32* %iteration_count

br label %loop_start

loop_start:
%count = load i32, i32* %iteration_count
%is_done = icmp eq i32 %count, 0
br i1 %is_done, label %loop_end, label %loop_body

loop_body:
%segment_ptr = call ptr @llvm.wasm.segment.stack.new(ptr %static_size_array, i64 1600)
call void @llvm.wasm.segment.stack.free(ptr %segment_ptr, ptr %static_size_array, i64 1600)

%new_count = sub i32 %count, 1
store i32 %new_count, i32* %iteration_count
br label %loop_start

loop_end:
ret i32 0
}
46 changes: 46 additions & 0 deletions demo/benchmarks-code/memory-tagging/tagging.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// #include <stdio.h>
// #include <stdlib.h>

// int main() {
// size_t n = 1000;
// // volatile int static_size_array[1000];
// volatile int static_size_array[n];

// // for (int i = 0; i < n; i++) {
// // static_size_array[i] = i % 255;
// // }

// for (int i = 0; i < n; i++) {
// static_size_array[i] = i % 255;
// }

// // Pretend to use the data
// use_array(static_size_array, n);

// return 0;
// }


#include <stdio.h>
#include <stdlib.h>

int check = 0; // global variable

int main() {
size_t n = 10000;
size_t alignment = 32;
int static_size_array[n * 32];
// int *static_size_array = malloc(sizeof(int) * (n*32));

for (int i = 0; i < n; i++) {
static_size_array[i] = i % 255;
}

// Unpredictable branch to compiler, will never actually run,
// but compiler doesn't know that for sure
if (check) {
printf("%d", static_size_array[0]);
}

return 0;
}
25 changes: 25 additions & 0 deletions demo/benchmarks-code/pac-store-load-loops/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
CC=/scratch/fritz/src/safe-wasm/llvm-project/build/bin/clang
# WASM_FLAGS=--target=wasm64-unknown-wasi --sysroot /scratch/martin/src/wasm/wasi-libc/sysroot -g -D_WASI_EMULATED_PROCESS_CLOCKS -lwasi-emulated-process-clocks -Wl,--stack-first -Wl,--initial-memory=104857600 -Wl,--max-memory=104857600 -Wl,-z,stack-size=83886080
WASM_FLAGS=--target=wasm64-unknown-wasi --sysroot /scratch/martin/src/wasm/wasi-libc/sysroot -g -D_WASI_EMULATED_PROCESS_CLOCKS -lwasi-emulated-process-clocks -Wl,--stack-first -Wl,--initial-memory=1677721600 -Wl,--max-memory=1677721600 -Wl,-z,stack-size=1342177280

SAN_FLAGS=-march=wasm64-wasi+mem-safety -fsanitize=wasm-memsafety
#CFLAGS=-O0 ${WASM_FLAGS}
CFLAGS=-O2 ${WASM_FLAGS}
BUILD_DIR=build

PAC_SOURCES=$(wildcard pac-*.c)
PAC_WASMS=$(PAC_SOURCES:%.c=${BUILD_DIR}/%.wasm)

all: ${PAC_WASMS}

${BUILD_DIR}/%.wasm: %.c
${CC} -o $@ $< ${CFLAGS} ${EXTRA_FLAGS} ${SAN_FLAGS}

clean:
@ rm -f ${BUILD_DIR}/*.wasm

${BUILD_DIR}:
mkdir -p $@

# Add the directory as a dependency to ensure it's created before compilation
${BUILD_DIR}/%.wasm: | ${BUILD_DIR}
21 changes: 21 additions & 0 deletions demo/benchmarks-code/pac-store-load-loops/pac-1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
size_t n = 10000;

void* ptrArray[n];

// Store n pointers in the array
for (size_t i = 0; i < n; i++) {
ptrArray[i] = (void*) i; // casting the iterating variable to a pointer
}

// Load the n pointers from the array and accumulate their values
size_t sum = 0;
for (size_t i = 0; i < n; i++) {
sum += (size_t) ptrArray[i];
}

return sum % 125; // modulo to make sure it's a valid return code
}
21 changes: 21 additions & 0 deletions demo/benchmarks-code/pac-store-load-loops/pac-2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
size_t n = 100000;

void* ptrArray[n];

// Store n pointers in the array
for (size_t i = 0; i < n; i++) {
ptrArray[i] = (void*) i; // casting the iterating variable to a pointer
}

// Load the n pointers from the array and accumulate their values
size_t sum = 0;
for (size_t i = 0; i < n; i++) {
sum += (size_t) ptrArray[i];
}

return sum % 125; // modulo to make sure it's a valid return code
}
21 changes: 21 additions & 0 deletions demo/benchmarks-code/pac-store-load-loops/pac-3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
size_t n = 1000000;

void* ptrArray[n];

// Store n pointers in the array
for (size_t i = 0; i < n; i++) {
ptrArray[i] = (void*) i; // casting the iterating variable to a pointer
}

// Load the n pointers from the array and accumulate their values
size_t sum = 0;
for (size_t i = 0; i < n; i++) {
sum += (size_t) ptrArray[i];
}

return sum % 125; // modulo to make sure it's a valid return code
}
21 changes: 21 additions & 0 deletions demo/benchmarks-code/pac-store-load-loops/pac-4.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
size_t n = 10000000;

void* ptrArray[n];

// Store n pointers in the array
for (size_t i = 0; i < n; i++) {
ptrArray[i] = (void*) i; // casting the iterating variable to a pointer
}

// Load the n pointers from the array and accumulate their values
size_t sum = 0;
for (size_t i = 0; i < n; i++) {
sum += (size_t) ptrArray[i];
}

return sum % 125; // modulo to make sure it's a valid return code
}
Loading