- Add upstream patch <https://github.com/opencontainers/runc/pull/4219> to properly fix -ENOSYS stub on ppc64le. bsc#1192051 bsc#1221050 + 0001-bsc1221050-libct-seccomp-patchbpf-rm-duplicated-code.patch + 0002-bsc1221050-seccomp-patchbpf-rename-nativeArch-linuxA.patch + 0003-bsc1221050-seccomp-patchbpf-always-include-native-ar.patch OBS-URL: https://build.opensuse.org/request/show/1159948 OBS-URL: https://build.opensuse.org/package/show/Virtualization:containers/runc?expand=0&rev=156
290 lines
12 KiB
Diff
290 lines
12 KiB
Diff
From de510c0c092bae47cdc1b54da25544c3e101e6ec Mon Sep 17 00:00:00 2001
|
|
From: Aleksa Sarai <cyphar@cyphar.com>
|
|
Date: Wed, 13 Mar 2024 13:40:16 +1100
|
|
Subject: [PATCH 2/3] bsc1221050: seccomp: patchbpf: rename nativeArch ->
|
|
linuxAuditArch
|
|
|
|
(This is a backport of 6167f5ffc3e3fd53e6a41a2effa592a4873ad046.)
|
|
|
|
Calling the Linux AUDIT_* architecture constants "native" leads to
|
|
confusing code when we are getting the actual native architecture of the
|
|
running system.
|
|
|
|
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
|
|
---
|
|
libcontainer/seccomp/patchbpf/enosys_linux.go | 81 ++++++++++---------
|
|
.../seccomp/patchbpf/enosys_linux_test.go | 16 ++--
|
|
2 files changed, 49 insertions(+), 48 deletions(-)
|
|
|
|
diff --git a/libcontainer/seccomp/patchbpf/enosys_linux.go b/libcontainer/seccomp/patchbpf/enosys_linux.go
|
|
index c9c1d4ccb685..1b67fda85c64 100644
|
|
--- a/libcontainer/seccomp/patchbpf/enosys_linux.go
|
|
+++ b/libcontainer/seccomp/patchbpf/enosys_linux.go
|
|
@@ -164,11 +164,11 @@ func disassembleFilter(filter *libseccomp.ScmpFilter) ([]bpf.Instruction, error)
|
|
return program, nil
|
|
}
|
|
|
|
-type nativeArch uint32
|
|
+type linuxAuditArch uint32
|
|
|
|
-const invalidArch nativeArch = 0
|
|
+const invalidArch linuxAuditArch = 0
|
|
|
|
-func archToNative(arch libseccomp.ScmpArch) (nativeArch, error) {
|
|
+func scmpArchToAuditArch(arch libseccomp.ScmpArch) (linuxAuditArch, error) {
|
|
switch arch {
|
|
case libseccomp.ArchNative:
|
|
// Convert to actual native architecture.
|
|
@@ -176,48 +176,48 @@ func archToNative(arch libseccomp.ScmpArch) (nativeArch, error) {
|
|
if err != nil {
|
|
return invalidArch, fmt.Errorf("unable to get native arch: %w", err)
|
|
}
|
|
- return archToNative(arch)
|
|
+ return scmpArchToAuditArch(arch)
|
|
case libseccomp.ArchX86:
|
|
- return nativeArch(C.C_AUDIT_ARCH_I386), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_I386), nil
|
|
case libseccomp.ArchAMD64, libseccomp.ArchX32:
|
|
// NOTE: x32 is treated like x86_64 except all x32 syscalls have the
|
|
// 30th bit of the syscall number set to indicate that it's not a
|
|
// normal x86_64 syscall.
|
|
- return nativeArch(C.C_AUDIT_ARCH_X86_64), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_X86_64), nil
|
|
case libseccomp.ArchARM:
|
|
- return nativeArch(C.C_AUDIT_ARCH_ARM), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_ARM), nil
|
|
case libseccomp.ArchARM64:
|
|
- return nativeArch(C.C_AUDIT_ARCH_AARCH64), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_AARCH64), nil
|
|
case libseccomp.ArchMIPS:
|
|
- return nativeArch(C.C_AUDIT_ARCH_MIPS), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPS), nil
|
|
case libseccomp.ArchMIPS64:
|
|
- return nativeArch(C.C_AUDIT_ARCH_MIPS64), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPS64), nil
|
|
case libseccomp.ArchMIPS64N32:
|
|
- return nativeArch(C.C_AUDIT_ARCH_MIPS64N32), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPS64N32), nil
|
|
case libseccomp.ArchMIPSEL:
|
|
- return nativeArch(C.C_AUDIT_ARCH_MIPSEL), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPSEL), nil
|
|
case libseccomp.ArchMIPSEL64:
|
|
- return nativeArch(C.C_AUDIT_ARCH_MIPSEL64), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPSEL64), nil
|
|
case libseccomp.ArchMIPSEL64N32:
|
|
- return nativeArch(C.C_AUDIT_ARCH_MIPSEL64N32), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_MIPSEL64N32), nil
|
|
case libseccomp.ArchPPC:
|
|
- return nativeArch(C.C_AUDIT_ARCH_PPC), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_PPC), nil
|
|
case libseccomp.ArchPPC64:
|
|
- return nativeArch(C.C_AUDIT_ARCH_PPC64), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_PPC64), nil
|
|
case libseccomp.ArchPPC64LE:
|
|
- return nativeArch(C.C_AUDIT_ARCH_PPC64LE), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_PPC64LE), nil
|
|
case libseccomp.ArchS390:
|
|
- return nativeArch(C.C_AUDIT_ARCH_S390), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_S390), nil
|
|
case libseccomp.ArchS390X:
|
|
- return nativeArch(C.C_AUDIT_ARCH_S390X), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_S390X), nil
|
|
case libseccomp.ArchRISCV64:
|
|
- return nativeArch(C.C_AUDIT_ARCH_RISCV64), nil
|
|
+ return linuxAuditArch(C.C_AUDIT_ARCH_RISCV64), nil
|
|
default:
|
|
return invalidArch, fmt.Errorf("unknown architecture: %v", arch)
|
|
}
|
|
}
|
|
|
|
-type lastSyscallMap map[nativeArch]map[libseccomp.ScmpArch]libseccomp.ScmpSyscall
|
|
+type lastSyscallMap map[linuxAuditArch]map[libseccomp.ScmpArch]libseccomp.ScmpSyscall
|
|
|
|
// Figure out largest syscall number referenced in the filter for each
|
|
// architecture. We will be generating code based on the native architecture
|
|
@@ -234,17 +234,17 @@ func findLastSyscalls(config *configs.Seccomp) (lastSyscallMap, error) {
|
|
}
|
|
|
|
// Figure out native architecture representation of the architecture.
|
|
- nativeArch, err := archToNative(arch)
|
|
+ auditArch, err := scmpArchToAuditArch(arch)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot map architecture %v to AUDIT_ARCH_ constant: %w", arch, err)
|
|
}
|
|
|
|
- if _, ok := lastSyscalls[nativeArch]; !ok {
|
|
- lastSyscalls[nativeArch] = map[libseccomp.ScmpArch]libseccomp.ScmpSyscall{}
|
|
+ if _, ok := lastSyscalls[auditArch]; !ok {
|
|
+ lastSyscalls[auditArch] = map[libseccomp.ScmpArch]libseccomp.ScmpSyscall{}
|
|
}
|
|
- if _, ok := lastSyscalls[nativeArch][arch]; ok {
|
|
+ if _, ok := lastSyscalls[auditArch][arch]; ok {
|
|
// Because of ArchNative we may hit the same entry multiple times.
|
|
- // Just skip it if we've seen this (nativeArch, ScmpArch)
|
|
+ // Just skip it if we've seen this (linuxAuditArch, ScmpArch)
|
|
// combination before.
|
|
continue
|
|
}
|
|
@@ -262,10 +262,11 @@ func findLastSyscalls(config *configs.Seccomp) (lastSyscallMap, error) {
|
|
}
|
|
}
|
|
if largestSyscall != 0 {
|
|
- lastSyscalls[nativeArch][arch] = largestSyscall
|
|
+ logrus.Debugf("seccomp: largest syscall number for arch %v is %v", arch, largestSyscall)
|
|
+ lastSyscalls[auditArch][arch] = largestSyscall
|
|
} else {
|
|
- logrus.Warnf("could not find any syscalls for arch %s", ociArch)
|
|
- delete(lastSyscalls[nativeArch], arch)
|
|
+ logrus.Warnf("could not find any syscalls for arch %v", arch)
|
|
+ delete(lastSyscalls[auditArch], arch)
|
|
}
|
|
}
|
|
return lastSyscalls, nil
|
|
@@ -283,10 +284,10 @@ func findLastSyscalls(config *configs.Seccomp) (lastSyscallMap, error) {
|
|
// close_range(2) which were added out-of-order in the syscall table between
|
|
// kernel releases.
|
|
func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error) {
|
|
- // A jump-table for each nativeArch used to generate the initial
|
|
+ // A jump-table for each linuxAuditArch used to generate the initial
|
|
// conditional jumps -- measured from the *END* of the program so they
|
|
// remain valid after prepending to the tail.
|
|
- archJumpTable := map[nativeArch]uint32{}
|
|
+ archJumpTable := map[linuxAuditArch]uint32{}
|
|
|
|
// Generate our own -ENOSYS rules for each architecture. They have to be
|
|
// generated in reverse (prepended to the tail of the program) because the
|
|
@@ -299,7 +300,7 @@ func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error)
|
|
}
|
|
|
|
// Generate the syscall -ENOSYS rules.
|
|
- for nativeArch, maxSyscalls := range lastSyscalls {
|
|
+ for auditArch, maxSyscalls := range lastSyscalls {
|
|
// The number of instructions from the tail of this section which need
|
|
// to be jumped in order to reach the -ENOSYS return. If the section
|
|
// does not jump, it will fall through to the actual filter.
|
|
@@ -380,7 +381,7 @@ func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error)
|
|
|
|
// If we're on x86 we need to add a check for x32 and if we're in
|
|
// the wrong mode we jump over the section.
|
|
- if uint32(nativeArch) == uint32(C.C_AUDIT_ARCH_X86_64) {
|
|
+ if uint32(auditArch) == uint32(C.C_AUDIT_ARCH_X86_64) {
|
|
// Generate a prefix to check the mode.
|
|
switch scmpArch {
|
|
case libseccomp.ArchAMD64:
|
|
@@ -409,8 +410,8 @@ func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error)
|
|
section = append(section, sectionTail...)
|
|
case 2:
|
|
// x32 and x86_64 are a unique case, we can't handle any others.
|
|
- if uint32(nativeArch) != uint32(C.C_AUDIT_ARCH_X86_64) {
|
|
- return nil, fmt.Errorf("unknown architecture overlap on native arch %#x", nativeArch)
|
|
+ if uint32(auditArch) != uint32(C.C_AUDIT_ARCH_X86_64) {
|
|
+ return nil, fmt.Errorf("unknown architecture overlap on native arch %#x", auditArch)
|
|
}
|
|
|
|
x32sysno, ok := maxSyscalls[libseccomp.ArchX32]
|
|
@@ -487,7 +488,7 @@ func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error)
|
|
programTail = append(section, programTail...)
|
|
|
|
// Update jump table.
|
|
- archJumpTable[nativeArch] = uint32(len(programTail))
|
|
+ archJumpTable[auditArch] = uint32(len(programTail))
|
|
}
|
|
|
|
// Add a dummy "jump to filter" for any architecture we might miss below.
|
|
@@ -507,9 +508,9 @@ func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error)
|
|
// architectures based on how large the jumps are going to be, or
|
|
// re-sort the candidate architectures each time to make sure that we
|
|
// pick the largest jump which is going to be smaller than 255.
|
|
- for nativeArch := range lastSyscalls {
|
|
+ for auditArch := range lastSyscalls {
|
|
// We jump forwards but the jump table is calculated from the *END*.
|
|
- jump := uint32(len(programTail)) - archJumpTable[nativeArch]
|
|
+ jump := uint32(len(programTail)) - archJumpTable[auditArch]
|
|
|
|
// Same routine as above -- this is a basic jeq check, complicated
|
|
// slightly if it turns out that we need to do a long jump.
|
|
@@ -518,7 +519,7 @@ func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error)
|
|
// jeq [arch],[jump]
|
|
bpf.JumpIf{
|
|
Cond: bpf.JumpEqual,
|
|
- Val: uint32(nativeArch),
|
|
+ Val: uint32(auditArch),
|
|
SkipTrue: uint8(jump),
|
|
},
|
|
}, programTail...)
|
|
@@ -527,7 +528,7 @@ func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error)
|
|
// jne [arch],1
|
|
bpf.JumpIf{
|
|
Cond: bpf.JumpNotEqual,
|
|
- Val: uint32(nativeArch),
|
|
+ Val: uint32(auditArch),
|
|
SkipTrue: 1,
|
|
},
|
|
// ja [jump]
|
|
diff --git a/libcontainer/seccomp/patchbpf/enosys_linux_test.go b/libcontainer/seccomp/patchbpf/enosys_linux_test.go
|
|
index e2d363a43bd3..bdfeff68adb3 100644
|
|
--- a/libcontainer/seccomp/patchbpf/enosys_linux_test.go
|
|
+++ b/libcontainer/seccomp/patchbpf/enosys_linux_test.go
|
|
@@ -23,7 +23,7 @@ type seccompData struct {
|
|
}
|
|
|
|
// mockSyscallPayload creates a fake seccomp_data struct with the given data.
|
|
-func mockSyscallPayload(t *testing.T, sysno libseccomp.ScmpSyscall, arch nativeArch, args ...uint64) []byte {
|
|
+func mockSyscallPayload(t *testing.T, sysno libseccomp.ScmpSyscall, arch linuxAuditArch, args ...uint64) []byte {
|
|
var buf bytes.Buffer
|
|
|
|
data := seccompData{
|
|
@@ -150,8 +150,8 @@ func testEnosysStub(t *testing.T, defaultAction configs.Action, arches []string)
|
|
|
|
for _, arch := range testArches {
|
|
type syscallTest struct {
|
|
- syscall string
|
|
sysno libseccomp.ScmpSyscall
|
|
+ syscall string
|
|
expected uint32
|
|
}
|
|
|
|
@@ -160,7 +160,7 @@ func testEnosysStub(t *testing.T, defaultAction configs.Action, arches []string)
|
|
t.Fatalf("unknown libseccomp architecture %q: %v", arch, err)
|
|
}
|
|
|
|
- nativeArch, err := archToNative(scmpArch)
|
|
+ auditArch, err := scmpArchToAuditArch(scmpArch)
|
|
if err != nil {
|
|
t.Fatalf("unknown audit architecture %q: %v", arch, err)
|
|
}
|
|
@@ -179,9 +179,9 @@ func testEnosysStub(t *testing.T, defaultAction configs.Action, arches []string)
|
|
t.Fatalf("unknown syscall %q on arch %q: %v", syscall, arch, err)
|
|
}
|
|
syscallTests = append(syscallTests, syscallTest{
|
|
- syscall,
|
|
- sysno,
|
|
- expected,
|
|
+ sysno: sysno,
|
|
+ syscall: syscall,
|
|
+ expected: expected,
|
|
})
|
|
}
|
|
|
|
@@ -233,7 +233,7 @@ func testEnosysStub(t *testing.T, defaultAction configs.Action, arches []string)
|
|
test.expected = retFallthrough
|
|
}
|
|
|
|
- payload := mockSyscallPayload(t, test.sysno, nativeArch, 0x1337, 0xF00BA5)
|
|
+ payload := mockSyscallPayload(t, test.sysno, auditArch, 0x1337, 0xF00BA5)
|
|
// NOTE: golang.org/x/net/bpf returns int here rather
|
|
// than uint32.
|
|
rawRet, err := filter.Run(payload)
|
|
@@ -247,7 +247,7 @@ func testEnosysStub(t *testing.T, defaultAction configs.Action, arches []string)
|
|
t.Logf(" [%4.1d] %s", idx, insn)
|
|
}
|
|
t.Logf("payload: %#v", payload)
|
|
- t.Errorf("filter %s(%d) %q(%d): got %#x, want %#x", arch, nativeArch, test.syscall, test.sysno, ret, test.expected)
|
|
+ t.Errorf("filter %s(%d) %q(%d): got %#x, want %#x", arch, auditArch, test.syscall, test.sysno, ret, test.expected)
|
|
}
|
|
}
|
|
}
|
|
--
|
|
2.44.0
|
|
|