File 0002-bsc1221050-seccomp-patchbpf-rename-nativeArch-linuxA.patch of Package runc
290
1
From ac6f405fa10a078170e91d0d911c4903930cc5d1 Mon Sep 17 00:00:00 2001
2
From: Aleksa Sarai <cyphar@cyphar.com>
3
Date: Wed, 13 Mar 2024 13:40:16 +1100
4
Subject: [PATCH 2/4] bsc1221050: seccomp: patchbpf: rename nativeArch ->
5
linuxAuditArch
6
7
(This is a backport of 6167f5ffc3e3fd53e6a41a2effa592a4873ad046.)
8
9
Calling the Linux AUDIT_* architecture constants "native" leads to
10
confusing code when we are getting the actual native architecture of the
11
running system.
12
13
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
14
---
15
libcontainer/seccomp/patchbpf/enosys_linux.go | 81 ++++++++++---------
16
.../seccomp/patchbpf/enosys_linux_test.go | 16 ++--
17
2 files changed, 49 insertions(+), 48 deletions(-)
18
19
diff --git a/libcontainer/seccomp/patchbpf/enosys_linux.go b/libcontainer/seccomp/patchbpf/enosys_linux.go
20
index c9c1d4ccb685..1b67fda85c64 100644
21
--- a/libcontainer/seccomp/patchbpf/enosys_linux.go
22
+++ b/libcontainer/seccomp/patchbpf/enosys_linux.go
23
24
return program, nil
25
}
26
27
-type nativeArch uint32
28
+type linuxAuditArch uint32
29
30
-const invalidArch nativeArch = 0
31
+const invalidArch linuxAuditArch = 0
32
33
-func archToNative(arch libseccomp.ScmpArch) (nativeArch, error) {
34
+func scmpArchToAuditArch(arch libseccomp.ScmpArch) (linuxAuditArch, error) {
35
switch arch {
36
case libseccomp.ArchNative:
37
// Convert to actual native architecture.
38
39
if err != nil {
40
return invalidArch, fmt.Errorf("unable to get native arch: %w", err)
41
}
42
- return archToNative(arch)
43
+ return scmpArchToAuditArch(arch)
44
case libseccomp.ArchX86:
45
- return nativeArch(C.C_AUDIT_ARCH_I386), nil
46
+ return linuxAuditArch(C.C_AUDIT_ARCH_I386), nil
47
case libseccomp.ArchAMD64, libseccomp.ArchX32:
48
// NOTE: x32 is treated like x86_64 except all x32 syscalls have the
49
// 30th bit of the syscall number set to indicate that it's not a
50
// normal x86_64 syscall.
51
- return nativeArch(C.C_AUDIT_ARCH_X86_64), nil
52
+ return linuxAuditArch(C.C_AUDIT_ARCH_X86_64), nil
53
case libseccomp.ArchARM:
54
- return nativeArch(C.C_AUDIT_ARCH_ARM), nil
55
+ return linuxAuditArch(C.C_AUDIT_ARCH_ARM), nil
56
case libseccomp.ArchARM64:
57
- return nativeArch(C.C_AUDIT_ARCH_AARCH64), nil
58
+ return linuxAuditArch(C.C_AUDIT_ARCH_AARCH64), nil
59
case libseccomp.ArchMIPS:
60
- return nativeArch(C.C_AUDIT_ARCH_MIPS), nil
61
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPS), nil
62
case libseccomp.ArchMIPS64:
63
- return nativeArch(C.C_AUDIT_ARCH_MIPS64), nil
64
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPS64), nil
65
case libseccomp.ArchMIPS64N32:
66
- return nativeArch(C.C_AUDIT_ARCH_MIPS64N32), nil
67
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPS64N32), nil
68
case libseccomp.ArchMIPSEL:
69
- return nativeArch(C.C_AUDIT_ARCH_MIPSEL), nil
70
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPSEL), nil
71
case libseccomp.ArchMIPSEL64:
72
- return nativeArch(C.C_AUDIT_ARCH_MIPSEL64), nil
73
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPSEL64), nil
74
case libseccomp.ArchMIPSEL64N32:
75
- return nativeArch(C.C_AUDIT_ARCH_MIPSEL64N32), nil
76
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPSEL64N32), nil
77
case libseccomp.ArchPPC:
78
- return nativeArch(C.C_AUDIT_ARCH_PPC), nil
79
+ return linuxAuditArch(C.C_AUDIT_ARCH_PPC), nil
80
case libseccomp.ArchPPC64:
81
- return nativeArch(C.C_AUDIT_ARCH_PPC64), nil
82
+ return linuxAuditArch(C.C_AUDIT_ARCH_PPC64), nil
83
case libseccomp.ArchPPC64LE:
84
- return nativeArch(C.C_AUDIT_ARCH_PPC64LE), nil
85
+ return linuxAuditArch(C.C_AUDIT_ARCH_PPC64LE), nil
86
case libseccomp.ArchS390:
87
- return nativeArch(C.C_AUDIT_ARCH_S390), nil
88
+ return linuxAuditArch(C.C_AUDIT_ARCH_S390), nil
89
case libseccomp.ArchS390X:
90
- return nativeArch(C.C_AUDIT_ARCH_S390X), nil
91
+ return linuxAuditArch(C.C_AUDIT_ARCH_S390X), nil
92
case libseccomp.ArchRISCV64:
93
- return nativeArch(C.C_AUDIT_ARCH_RISCV64), nil
94
+ return linuxAuditArch(C.C_AUDIT_ARCH_RISCV64), nil
95
default:
96
return invalidArch, fmt.Errorf("unknown architecture: %v", arch)
97
}
98
}
99
100
-type lastSyscallMap map[nativeArch]map[libseccomp.ScmpArch]libseccomp.ScmpSyscall
101
+type lastSyscallMap map[linuxAuditArch]map[libseccomp.ScmpArch]libseccomp.ScmpSyscall
102
103
// Figure out largest syscall number referenced in the filter for each
104
// architecture. We will be generating code based on the native architecture
105
106
}
107
108
// Figure out native architecture representation of the architecture.
109
- nativeArch, err := archToNative(arch)
110
+ auditArch, err := scmpArchToAuditArch(arch)
111
if err != nil {
112
return nil, fmt.Errorf("cannot map architecture %v to AUDIT_ARCH_ constant: %w", arch, err)
113
}
114
115
- if _, ok := lastSyscalls[nativeArch]; !ok {
116
- lastSyscalls[nativeArch] = map[libseccomp.ScmpArch]libseccomp.ScmpSyscall{}
117
+ if _, ok := lastSyscalls[auditArch]; !ok {
118
+ lastSyscalls[auditArch] = map[libseccomp.ScmpArch]libseccomp.ScmpSyscall{}
119
}
120
- if _, ok := lastSyscalls[nativeArch][arch]; ok {
121
+ if _, ok := lastSyscalls[auditArch][arch]; ok {
122
// Because of ArchNative we may hit the same entry multiple times.
123
- // Just skip it if we've seen this (nativeArch, ScmpArch)
124
+ // Just skip it if we've seen this (linuxAuditArch, ScmpArch)
125
// combination before.
126
continue
127
}
128
129
}
130
}
131
if largestSyscall != 0 {
132
- lastSyscalls[nativeArch][arch] = largestSyscall
133
+ logrus.Debugf("seccomp: largest syscall number for arch %v is %v", arch, largestSyscall)
134
+ lastSyscalls[auditArch][arch] = largestSyscall
135
} else {
136
- logrus.Warnf("could not find any syscalls for arch %s", ociArch)
137
- delete(lastSyscalls[nativeArch], arch)
138
+ logrus.Warnf("could not find any syscalls for arch %v", arch)
139
+ delete(lastSyscalls[auditArch], arch)
140
}
141
}
142
return lastSyscalls, nil
143
144
// close_range(2) which were added out-of-order in the syscall table between
145
// kernel releases.
146
func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error) {
147
- // A jump-table for each nativeArch used to generate the initial
148
+ // A jump-table for each linuxAuditArch used to generate the initial
149
// conditional jumps -- measured from the *END* of the program so they
150
// remain valid after prepending to the tail.
151
- archJumpTable := map[nativeArch]uint32{}
152
+ archJumpTable := map[linuxAuditArch]uint32{}
153
154
// Generate our own -ENOSYS rules for each architecture. They have to be
155
// generated in reverse (prepended to the tail of the program) because the
156
157
}
158
159
// Generate the syscall -ENOSYS rules.
160
- for nativeArch, maxSyscalls := range lastSyscalls {
161
+ for auditArch, maxSyscalls := range lastSyscalls {
162
// The number of instructions from the tail of this section which need
163
// to be jumped in order to reach the -ENOSYS return. If the section
164
// does not jump, it will fall through to the actual filter.
165
166
167
// If we're on x86 we need to add a check for x32 and if we're in
168
// the wrong mode we jump over the section.
169
- if uint32(nativeArch) == uint32(C.C_AUDIT_ARCH_X86_64) {
170
+ if uint32(auditArch) == uint32(C.C_AUDIT_ARCH_X86_64) {
171
// Generate a prefix to check the mode.
172
switch scmpArch {
173
case libseccomp.ArchAMD64:
174
175
section = append(section, sectionTail...)
176
case 2:
177
// x32 and x86_64 are a unique case, we can't handle any others.
178
- if uint32(nativeArch) != uint32(C.C_AUDIT_ARCH_X86_64) {
179
- return nil, fmt.Errorf("unknown architecture overlap on native arch %#x", nativeArch)
180
+ if uint32(auditArch) != uint32(C.C_AUDIT_ARCH_X86_64) {
181
+ return nil, fmt.Errorf("unknown architecture overlap on native arch %#x", auditArch)
182
}
183
184
x32sysno, ok := maxSyscalls[libseccomp.ArchX32]
185
186
programTail = append(section, programTail...)
187
188
// Update jump table.
189
- archJumpTable[nativeArch] = uint32(len(programTail))
190
+ archJumpTable[auditArch] = uint32(len(programTail))
191
}
192
193
// Add a dummy "jump to filter" for any architecture we might miss below.
194
195
// architectures based on how large the jumps are going to be, or
196
// re-sort the candidate architectures each time to make sure that we
197
// pick the largest jump which is going to be smaller than 255.
198
- for nativeArch := range lastSyscalls {
199
+ for auditArch := range lastSyscalls {
200
// We jump forwards but the jump table is calculated from the *END*.
201
- jump := uint32(len(programTail)) - archJumpTable[nativeArch]
202
+ jump := uint32(len(programTail)) - archJumpTable[auditArch]
203
204
// Same routine as above -- this is a basic jeq check, complicated
205
// slightly if it turns out that we need to do a long jump.
206
207
// jeq [arch],[jump]
208
bpf.JumpIf{
209
Cond: bpf.JumpEqual,
210
- Val: uint32(nativeArch),
211
+ Val: uint32(auditArch),
212
SkipTrue: uint8(jump),
213
},
214
}, programTail...)
215
216
// jne [arch],1
217
bpf.JumpIf{
218
Cond: bpf.JumpNotEqual,
219
- Val: uint32(nativeArch),
220
+ Val: uint32(auditArch),
221
SkipTrue: 1,
222
},
223
// ja [jump]
224
diff --git a/libcontainer/seccomp/patchbpf/enosys_linux_test.go b/libcontainer/seccomp/patchbpf/enosys_linux_test.go
225
index e2d363a43bd3..bdfeff68adb3 100644
226
--- a/libcontainer/seccomp/patchbpf/enosys_linux_test.go
227
+++ b/libcontainer/seccomp/patchbpf/enosys_linux_test.go
228
229
}
230
231
// mockSyscallPayload creates a fake seccomp_data struct with the given data.
232
-func mockSyscallPayload(t *testing.T, sysno libseccomp.ScmpSyscall, arch nativeArch, args ...uint64) []byte {
233
+func mockSyscallPayload(t *testing.T, sysno libseccomp.ScmpSyscall, arch linuxAuditArch, args ...uint64) []byte {
234
var buf bytes.Buffer
235
236
data := seccompData{
237
238
239
for _, arch := range testArches {
240
type syscallTest struct {
241
- syscall string
242
sysno libseccomp.ScmpSyscall
243
+ syscall string
244
expected uint32
245
}
246
247
248
t.Fatalf("unknown libseccomp architecture %q: %v", arch, err)
249
}
250
251
- nativeArch, err := archToNative(scmpArch)
252
+ auditArch, err := scmpArchToAuditArch(scmpArch)
253
if err != nil {
254
t.Fatalf("unknown audit architecture %q: %v", arch, err)
255
}
256
257
t.Fatalf("unknown syscall %q on arch %q: %v", syscall, arch, err)
258
}
259
syscallTests = append(syscallTests, syscallTest{
260
- syscall,
261
- sysno,
262
- expected,
263
+ sysno: sysno,
264
+ syscall: syscall,
265
+ expected: expected,
266
})
267
}
268
269
270
test.expected = retFallthrough
271
}
272
273
- payload := mockSyscallPayload(t, test.sysno, nativeArch, 0x1337, 0xF00BA5)
274
+ payload := mockSyscallPayload(t, test.sysno, auditArch, 0x1337, 0xF00BA5)
275
// NOTE: golang.org/x/net/bpf returns int here rather
276
// than uint32.
277
rawRet, err := filter.Run(payload)
278
279
t.Logf(" [%4.1d] %s", idx, insn)
280
}
281
t.Logf("payload: %#v", payload)
282
- t.Errorf("filter %s(%d) %q(%d): got %#x, want %#x", arch, nativeArch, test.syscall, test.sysno, ret, test.expected)
283
+ t.Errorf("filter %s(%d) %q(%d): got %#x, want %#x", arch, auditArch, test.syscall, test.sysno, ret, test.expected)
284
}
285
}
286
}
287
--
288
2.45.2
289
290