Skip to content

Commit f028836

Browse files
committed
Create example
0 parents  commit f028836

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+481
-0
lines changed

.github/workflows/microwalk.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Build & Analyze with Microwalk
2+
3+
on:
4+
push:
5+
pull_request:
6+
workflow_dispatch:
7+
8+
env:
9+
script_directory: microwalk
10+
11+
jobs:
12+
build-analyze:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v2
16+
17+
- name: Run Microwalk analysis
18+
id: run_microwalk
19+
uses: microwalk-project/microwalk-pin-action@v1
20+
with:
21+
script-directory: ${{ env.script_directory }}
22+
23+
- name: Upload analysis result
24+
uses: github/codeql-action/upload-sarif@v2
25+
with:
26+
sarif_file: ${{ github.workspace }}/${{ env.script_directory }}/results/report.sarif
27+
checkout_path: ${{ github.workspace }}
28+
29+
- name: Archive analysis artifacts
30+
uses: actions/upload-artifact@v3
31+
with:
32+
name: leakage-analysis-results
33+
path: ${{ github.workspace }}/${{ env.script_directory }}/results

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) Institute for IT Security, University of Lübeck
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.PHONY : clean
2+
3+
CFLAGS=-O2 -fPIC -g
4+
LDFLAGS=-shared
5+
6+
SOURCES=$(shell echo src/*.c)
7+
OBJECTS=$(SOURCES:.c=.o)
8+
9+
TARGET=libexample.so
10+
11+
all: $(TARGET)
12+
13+
clean:
14+
rm -f $(OBJECTS) $(TARGET)
15+
16+
$(TARGET) : $(OBJECTS)
17+
$(CC) $(CFLAGS) $(OBJECTS) -o $@ $(LDFLAGS)

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Microwalk Pin GitHub Workflow Example
2+
3+
This repository features a simple example for running the Microwalk GitHub analysis workflow with C code.
4+
5+
It makes use of [microwalk-pin-action](https://github.com/microwalk-project/microwalk-pin-action) to analyze the targets `microwalk/target-*.c` and generate a leakage report.
6+
7+
The target code calls functions from our `libexample` library, as defined in the [src](src) folder. In the `master` branch, those are empty and thus constant-time. In the example pull request ["#1 Add leakage"](https://github.com/microwalk-project/example-c/pull/1) (for branch `add-leakage`), the functions are filled with leaking code, that is subsequently detected by the Microwalk analysis.
8+
9+
The SARIF-formatted leakage report is sent back to GitHub and displayed both in the pull request UI (for everyone) and in the repository's "Security" tab (for users with write access only).

microwalk/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.dwarf
2+
*.map

microwalk/analyze.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
thisDir=$(pwd)
6+
repoRootDir=$(realpath $thisDir/..)
7+
resultsDir=$thisDir/results
8+
9+
mkdir -p $resultsDir
10+
11+
reports=""
12+
13+
for target in $(find . -name "target-*.c" -print)
14+
do
15+
targetName=$(basename -- ${target%.*})
16+
17+
echo "Running target ${targetName}..."
18+
19+
export TESTCASE_DIRECTORY=$thisDir/testcases/$targetName
20+
export TARGET_NAME=$targetName
21+
22+
mkdir -p $WORK_DIR/$targetName/work
23+
mkdir -p $WORK_DIR/$targetName/persist
24+
25+
cd $MICROWALK_PATH
26+
time dotnet Microwalk.dll $thisDir/config.yml
27+
28+
cd $CQR_GENERATOR_PATH
29+
reportFile=$resultsDir/report-$targetName.sarif
30+
dotnet CiReportGenerator.dll $WORK_DIR/$targetName/persist/results/call-stacks.json $targetName $reportFile sarif dwarf $thisDir $repoRootDir
31+
32+
cd $thisDir
33+
cp $WORK_DIR/$targetName/persist/results/call-stacks.txt $resultsDir/call-stacks-$targetName.txt
34+
35+
reports="${reports} ${reportFile}"
36+
37+
echo "Running target ${targetName} successful, generated report ${reportFile}"
38+
done
39+
40+
echo "Merging report files..."
41+
cat $reports | jq -s '.[0].runs[0].results=([.[].runs[0].results]|flatten)|.[0]' > $resultsDir/report.sarif

microwalk/build.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/bash
2+
3+
thisDir=$(pwd)
4+
mainDir=$(realpath $thisDir/..)
5+
6+
# Build library
7+
pushd $mainDir
8+
make -j all
9+
dwarfdump -l libexample.so >microwalk/libexample.so.dwarf
10+
popd
11+
12+
# Generate MAP file for library
13+
pushd $MAP_GENERATOR_PATH
14+
dotnet MapFileGenerator.dll $mainDir/libexample.so $thisDir/libexample.map
15+
popd
16+
17+
# Build targets
18+
for target in $(find . -name "target-*.c" -print)
19+
do
20+
targetName=$(basename -- ${target%.*})
21+
22+
gcc main.c $targetName.c -g -fno-inline -fno-split-stack -L "$mainDir" -lexample -I "$mainDir/src" -o $targetName
23+
24+
pushd $MAP_GENERATOR_PATH
25+
dotnet MapFileGenerator.dll $thisDir/$targetName $thisDir/$targetName.map
26+
popd
27+
28+
dwarfdump -l $targetName >$targetName.dwarf
29+
done

microwalk/config.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
constants:
2+
TARGET_PATH: $$CONFIG_PATH$$/$$$TARGET_NAME$$$
3+
LIBRARY_PATH: $$CONFIG_PATH$$/../
4+
WORK_DIR: $$$WORK_DIR$$$/$$$TARGET_NAME$$$
5+
---
6+
7+
general:
8+
logger:
9+
log-level: warning
10+
file: $$WORK_DIR$$/work/log.txt
11+
monitor:
12+
enable: true
13+
sample-rate: 50
14+
15+
testcase:
16+
module: load
17+
module-options:
18+
input-directory: $$$TESTCASE_DIRECTORY$$$
19+
20+
trace:
21+
module: pin
22+
module-options:
23+
output-directory: $$WORK_DIR$$/work/traces
24+
pin-tool-path: $$$PINTOOL$$$
25+
pin-path: $$$PIN_PATH$$$/pin
26+
wrapper-path: $$TARGET_PATH$$
27+
environment:
28+
LD_LIBRARY_PATH: $$LIBRARY_PATH$$
29+
images:
30+
- $$TARGET_NAME$$
31+
- libexample.so
32+
options:
33+
input-buffer-size: 4
34+
35+
preprocess:
36+
module: pin
37+
module-options:
38+
output-directory: $$WORK_DIR$$/work/traces
39+
store-traces: true
40+
keep-raw-traces: false
41+
options:
42+
input-buffer-size: 2
43+
max-parallel-threads: 4
44+
45+
analysis:
46+
modules:
47+
- module: control-flow-leakage
48+
module-options:
49+
output-directory: $$WORK_DIR$$/persist/results
50+
map-files:
51+
- $$TARGET_PATH$$.map
52+
- libexample.map
53+
dump-call-tree: false
54+
include-testcases-in-call-stacks: false
55+
56+
options:
57+
input-buffer-size: 1
58+
max-parallel-threads: 1

microwalk/main.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#ifdef _GNU_SOURCE
2+
#undef _GNU_SOURCE
3+
#endif
4+
5+
#include <sys/resource.h>
6+
7+
#include <stdio.h>
8+
#include <stdint.h>
9+
#include <string.h>
10+
#include <errno.h>
11+
12+
13+
// Performs target initialization steps.
14+
// This function is called once in the very beginning for the first testcase file, to make sure that the target is entirely loaded.
15+
// The call is included in the trace prefix.
16+
extern void InitTarget(FILE* input);
17+
18+
// Executes the target function.
19+
// Do not use global variables, since the trace generator will reuse the instrumented version of this executable for several different inputs.
20+
extern void RunTarget(FILE* input);
21+
22+
23+
// Pin notification functions.
24+
// These functions (and their names) must not be optimized away by the compiler, so Pin can find and instrument them.
25+
// The return values reduce the probability that the compiler uses these function in other places as no-ops (Visual C++ did do this in some experiments).
26+
#pragma optimize("", off)
27+
int PinNotifyTestcaseStart(int t) { return t + 42; }
28+
int PinNotifyTestcaseEnd() { return 42; }
29+
int PinNotifyStackPointer(uint64_t spMin, uint64_t spMax) { return (int)(spMin + spMax + 42); }
30+
int PinNotifyAllocation(uint64_t address, uint64_t size) { return (int)(address + 23 * size); }
31+
#pragma optimize("", on)
32+
33+
// Reads the stack pointer base value and transmits it to Pin.
34+
void ReadAndSendStackPointer()
35+
{
36+
// There does not seem to be a reliable way to get the stack size, so we use an estimation
37+
// Compiling with -fno-split-stack may be desired, to avoid surprises during analysis
38+
39+
// Take the current stack pointer as base value
40+
uintptr_t stackBase;
41+
asm("mov %%rsp, %0" : "=r"(stackBase));
42+
43+
// Get full stack size
44+
struct rlimit stackLimit;
45+
if(getrlimit(RLIMIT_STACK, &stackLimit) != 0)
46+
{
47+
char errBuffer[128];
48+
strerror_r(errno, errBuffer, sizeof(errBuffer));
49+
fprintf(stderr, "Error reading stack limit: [%d] %s\n", errno, errBuffer);
50+
}
51+
52+
uint64_t stackMin = (uint64_t)stackBase - (uint64_t)stackLimit.rlim_cur;
53+
uint64_t stackMax = ((uint64_t)stackBase + 0x10000) & ~0xFFFFull; // Round to next higher multiple of 64 kB (should be safe on x86 systems)
54+
PinNotifyStackPointer(stackMin, stackMax);
55+
}
56+
57+
// Main trace target function. The following actions are performed:
58+
// The current action is read from stdin.
59+
// A line with "t" followed by a numeric ID, and another line with a file path determining a new testcase, that is subsequently loaded and fed into the target function, while calling PinNotifyNextFile() beforehand.
60+
// A line with "e 0" terminates the program.
61+
void TraceFunc()
62+
{
63+
// First transmit stack pointer information
64+
ReadAndSendStackPointer();
65+
66+
PinNotifyAllocation((uint64_t)&errno, 8);
67+
68+
// Run until exit is requested
69+
char inputBuffer[512];
70+
char errBuffer[128];
71+
int targetInitialized = 0;
72+
while(1)
73+
{
74+
// Read command and testcase ID (0 for exit command)
75+
char command;
76+
int testcaseId;
77+
fgets(inputBuffer, sizeof(inputBuffer), stdin);
78+
sscanf(inputBuffer, "%c %d", &command, &testcaseId);
79+
80+
// Exit or process given testcase
81+
if(command == 'e')
82+
break;
83+
if(command == 't')
84+
{
85+
// Read testcase file name
86+
fgets(inputBuffer, sizeof(inputBuffer), stdin);
87+
int inputFileNameLength = strlen(inputBuffer);
88+
if(inputFileNameLength > 0 && inputBuffer[inputFileNameLength - 1] == '\n')
89+
inputBuffer[inputFileNameLength - 1] = '\0';
90+
91+
// Load testcase file and run target function
92+
FILE* inputFile = fopen(inputBuffer, "rb");
93+
if(!inputFile)
94+
{
95+
strerror_r(errno, errBuffer, sizeof(errBuffer));
96+
fprintf(stderr, "Error opening input file '%s': [%d] %s\n", inputBuffer, errno, errBuffer);
97+
continue;
98+
}
99+
100+
// If the target was not yet initialized, call the init function for the first test case
101+
if(!targetInitialized)
102+
{
103+
InitTarget(inputFile);
104+
fseek(inputFile, 0, SEEK_SET);
105+
targetInitialized = 1;
106+
}
107+
108+
PinNotifyTestcaseStart(testcaseId);
109+
RunTarget(inputFile);
110+
PinNotifyTestcaseEnd();
111+
112+
fclose(inputFile);
113+
}
114+
}
115+
}
116+
117+
// Wrapper entry point.
118+
int main(int argc, const char** argv)
119+
{
120+
// Run target function
121+
TraceFunc();
122+
return 0;
123+
}

microwalk/target-branch-leakage.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <stdint.h>
2+
#include <stdio.h>
3+
4+
#include <my_lib.h>
5+
6+
extern void RunTarget(FILE* input)
7+
{
8+
uint8_t plain[16];
9+
if(fread(plain, 1, 16, input) != 16)
10+
return;
11+
12+
branch_leakage(plain, 16);
13+
}
14+
15+
extern void InitTarget(FILE* input)
16+
{
17+
init();
18+
RunTarget(input);
19+
}

0 commit comments

Comments
 (0)