-
Notifications
You must be signed in to change notification settings - Fork 416
251 lines (217 loc) · 8.07 KB
/
kernelctf-submission-verification.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
name: kernelCTF PR check
on:
pull_request_target:
types: [opened, synchronize, reopened, labeled]
paths: [pocs/linux/kernelctf/**]
workflow_dispatch:
inputs:
prNumber:
description: 'PR number'
type: number
shaHash:
description: 'SHA hash'
permissions: {}
env:
PR_REF: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.shaHash || format('refs/pull/{0}/merge', github.event.inputs.prNumber)) || github.event.pull_request.head.sha }}
jobs:
structure_check:
# if labeling triggered the job then only run in case of the "recheck" label
if: github.event.action != 'labeled' || github.event.label.name == 'recheck'
runs-on: ubuntu-latest
permissions: {}
outputs:
targets: ${{ steps.check_submission.outputs.targets }}
submission_dir: ${{ steps.check_submission.outputs.submission_dir }}
exploits_info: ${{ steps.check_submission.outputs.exploits_info }}
artifact_backup_dir: ${{ steps.check_submission.outputs.artifact_backup_dir }}
steps:
- run: pip install -U jsonschema
- name: Checkout repo content
uses: actions/checkout@v4
with:
ref: master
- name: Checkout PR content
uses: actions/checkout@v4
with:
path: pr
ref: ${{ env.PR_REF }}
fetch-depth: 0
- id: check_submission
name: Check submission
working-directory: pr
run: |
echo "::stop-commands::$(uuidgen)"
../kernelctf/check-submission.py ${{ github.event.pull_request.base.sha }}
exploit_build:
runs-on: ubuntu-latest
needs: structure_check
permissions: {}
strategy:
matrix:
target: ${{ fromJSON(needs.structure_check.outputs.targets) }}
fail-fast: false # do not cancel other targets
env:
RELEASE_ID: ${{ matrix.target }}
EXPLOIT_DIR: pr/pocs/linux/kernelctf/${{ needs.structure_check.outputs.submission_dir }}/exploit/${{ matrix.target }}
steps:
- name: Checkout PR content
uses: actions/checkout@v4
with:
path: pr
ref: ${{ env.PR_REF }}
fetch-depth: 0
- name: List files
run: find .
- name: Backup original exploit
run: mv $EXPLOIT_DIR/exploit ./
- name: Build exploit
id: build_exploit
working-directory: ${{ env.EXPLOIT_DIR }}
run: |
if make -n prerequisites; then
make prerequisites
fi
make exploit
- name: Upload exploit (newly compiled)
if: success()
uses: actions/upload-artifact@v4
with:
name: exploit_${{ env.RELEASE_ID }}
path: ${{ env.EXPLOIT_DIR }}/exploit
if-no-files-found: error
- name: Upload exploit (original, build failed)
if: failure() && steps.build_exploit.outcome == 'failure'
uses: actions/upload-artifact@v4
with:
name: exploit_${{ env.RELEASE_ID }}
path: ./exploit
if-no-files-found: error
- name: Summarize result (success)
if: success()
run: printf '✅ Exploit was built successfully.\n\nIt can be found under the artifacts (`exploit_${{ env.RELEASE_ID }}`).\n' >> $GITHUB_STEP_SUMMARY
- name: Summarize result (failure)
if: failure() && steps.build_exploit.outcome == 'failure'
run: printf '❌ The exploit compilation failed.\n\nPlease fix it.\n\nYou can see the build logs by clicking on `...` here and then on "View job logs". Or by selecting `exploit_build (${{ env.RELEASE_ID }})` under Jobs in the left menubar.\n' >> $GITHUB_STEP_SUMMARY
exploit_repro:
runs-on: ubuntu-22.04-4core
timeout-minutes: 300
permissions: {}
needs: [structure_check, exploit_build]
strategy:
matrix:
target: ${{ fromJSON(needs.structure_check.outputs.targets) }}
fail-fast: false
if: always() && needs.structure_check.result == 'success'
env:
RELEASE_ID: ${{ matrix.target }}
SUBMISSION_DIR: ${{ needs.structure_check.outputs.submission_dir }}
EXPLOIT_INFO: ${{ toJSON(fromJSON(needs.structure_check.outputs.exploits_info)[matrix.target]) }}
defaults:
run:
shell: bash
working-directory: ./kernelctf/repro/
steps:
- name: Checkout repo content
uses: actions/checkout@v4
with:
ref: master
- name: Install tools (QEMU, inotify, expect)
run: sudo apt-get update && sudo apt-get install -y qemu-system-x86 inotify-tools expect
- name: Enable KVM group perms
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Download exploit
uses: actions/download-artifact@v4
with:
name: exploit_${{ env.RELEASE_ID }}
path: ./kernelctf/repro/exp/
- name: Fetch rootfs
run: |
wget -O rootfs.img.gz https://storage.googleapis.com/kernelctf-build/files/rootfs_repro_v2.img.gz
gzip -d rootfs.img.gz
- name: Download bzImage
run: |
if [ "$RELEASE_ID" == "mitigation-6.1" ]; then RELEASE_ID="mitigation-6.1-v2"; fi
wget https://storage.googleapis.com/kernelctf-build/releases/$RELEASE_ID/bzImage
- name: List repro folder contents
run: ls -alR ./
# ugly hack to make Github Actions UI to show repro logs separately in somewhat readable fashion
- id: repro1
name: Reproduction (1 / 10)
continue-on-error: true
run: ./repro.sh 1
- id: repro2
name: Reproduction (2 / 10)
continue-on-error: true
run: ./repro.sh 2
- id: repro3
name: Reproduction (3 / 10)
continue-on-error: true
run: ./repro.sh 3
- id: repro4
name: Reproduction (4 / 10)
continue-on-error: true
run: ./repro.sh 4
- id: repro5
name: Reproduction (5 / 10)
continue-on-error: true
run: ./repro.sh 5
- id: repro6
name: Reproduction (6 / 10)
continue-on-error: true
run: ./repro.sh 6
- id: repro7
name: Reproduction (7 / 10)
continue-on-error: true
run: ./repro.sh 7
- id: repro8
name: Reproduction (8 / 10)
continue-on-error: true
run: ./repro.sh 8
- id: repro9
name: Reproduction (9 / 10)
continue-on-error: true
run: ./repro.sh 9
- id: repro10
name: Reproduction (10 / 10)
continue-on-error: true
run: ./repro.sh 10
- name: Upload repro QEMU logs as an artifact
uses: actions/upload-artifact@v4
with:
name: repro_logs_${{ env.RELEASE_ID }}
path: ./kernelctf/repro/repro_log_*.txt
- name: Reproduction // Summary
env:
STEPS: ${{ toJSON(steps) }}
run: |
echo $STEPS >> steps.json
../repro_summary.py ${{ github.run_id }}
- name: Upload repro summary as an artifact
uses: actions/upload-artifact@v4
with:
name: repro_summary_${{ env.RELEASE_ID }}
path: ./kernelctf/repro/repro_summary.md
backup_artifacts:
runs-on: ubuntu-latest
needs: [structure_check, exploit_build, exploit_repro]
if: always() && needs.structure_check.result == 'success'
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
credentials_json: '${{secrets.KERNELCTF_GCS_SA_KEY}}'
- name: Upload artifacts to GCS
uses: 'google-github-actions/upload-cloud-storage@v2'
with:
path: ./artifacts
destination: kernelctf-build/artifacts/${{ needs.structure_check.outputs.artifact_backup_dir }}_${{ github.run_id }}
parent: false
predefinedAcl: publicRead
process_gcloudignore: false # removes warnings that .gcloudignore file does not exist