add compatibility architectures for supported architectures (LP: #1592022) #181

Merged
merged 5 commits into from Nov 18, 2016
@@ -0,0 +1,13 @@
+summary: Check that basic install works
+# This is blacklisted on debian because we first have to get the dpkg-vendor patches
+systems: [-debian-8]
+prepare: |
+ snap install --edge test-seccomp-compat
+execute: |
+ cd /
+ echo Run the 64 bit binary
+ test-seccomp-compat.true64
+ echo Run the 32 bit binary
+ test-seccomp-compat.true32
+restore: |
+ snap remove test-seccomp-compat
View
@@ -25,6 +25,7 @@
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
+#include <sys/utsname.h>
// needed for search mappings
#include <linux/can.h>
@@ -500,6 +501,71 @@ static void preprocess_filter(FILE * f, struct preprocess *p)
return;
}
+uint32_t get_hostarch(void)
@zyga

zyga Nov 18, 2016

Collaborator

This should be static IMHO, I'll add a quick patch that corrects this.

@jdstrand

jdstrand Nov 18, 2016

Contributor

That's fine.

+{
+ struct utsname uts;
+ if (uname(&uts) < 0)
+ die("uname() failed");
+
+ if (strcmp(uts.machine, "i686") == 0)
@zyga

zyga Nov 18, 2016

Collaborator

This block can be a small dedicated function that could be unit tested for sanity. I can gladly patch this.

@jdstrand

jdstrand Nov 18, 2016

Contributor

If you are keen on doing this, you have my blessing. If you want me to do it, I can look at it next week (I'm working on something else atm).

+ return SCMP_ARCH_X86;
+ else if (strcmp(uts.machine, "x86_64") == 0)
+ return SCMP_ARCH_X86_64;
+ else if (strncmp(uts.machine, "armv7", 5) == 0)
+ return SCMP_ARCH_ARM;
+ else if (strncmp(uts.machine, "aarch64", 7) == 0)
+ return SCMP_ARCH_AARCH64;
+ else if (strncmp(uts.machine, "ppc64le", 7) == 0)
+ return SCMP_ARCH_PPC64LE;
+ else if (strncmp(uts.machine, "ppc64", 5) == 0)
+ return SCMP_ARCH_PPC64;
+ else if (strncmp(uts.machine, "ppc", 3) == 0)
+ return SCMP_ARCH_PPC;
+ else if (strncmp(uts.machine, "s390x", 5) == 0)
+ return SCMP_ARCH_S390X;
+
+ // Just return the seccomp userspace native arch if we can't detect the
+ // kernel host arch.
+ return seccomp_arch_native();
+}
+
+void sc_add_seccomp_archs(scmp_filter_ctx * ctx)
+{
+ uint32_t native_arch = seccomp_arch_native(); // seccomp userspace
+ uint32_t host_arch = get_hostarch(); // kernel
+ uint32_t compat_arch = 0;
+
+ debug("host arch (kernel) is '%d'", host_arch);
+ debug("native arch (userspace) is '%d'", native_arch);
+
+ // For architectures that support a compat architecure, when the
+ // kernel and userspace match, add the compat arch, otherwise add
+ // the kernel arch to support the kernel's arch (eg, 64bit kernels with
+ // 32bit userspace).
+ if (host_arch == native_arch) {
+ switch (host_arch) {
+ case SCMP_ARCH_X86_64:
+ compat_arch = SCMP_ARCH_X86;
+ break;
+ case SCMP_ARCH_AARCH64:
+ compat_arch = SCMP_ARCH_ARM;
+ break;
+ case SCMP_ARCH_PPC64:
+ compat_arch = SCMP_ARCH_PPC;
+ break;
+ default:
+ break;
+ }
+ } else
+ compat_arch = host_arch;
+
+ if (compat_arch > 0 && seccomp_arch_exist(ctx, compat_arch) == -EEXIST) {
@zyga

zyga Nov 18, 2016

Collaborator

Are all of the SCMP_ARCH_ constants > 0?

@jdstrand

jdstrand Nov 18, 2016

Contributor

Yes

@jdstrand

jdstrand Nov 18, 2016

Contributor

To expand on that, SCMP_ARCH_NATIVE is 0 and the others are >0. We don't ever set compat_arch to SCMP_ARCH_NATIVE because the SCMP_ARCH_NATIVE is there by default.

+ debug("adding compat arch '%d'", compat_arch);
+ if (seccomp_arch_add(ctx, compat_arch) < 0)
+ die("seccomp_arch_add(..., compat_arch) failed");
+ }
+}
+
scmp_filter_ctx sc_prepare_seccomp_context(const char *filter_profile)
{
int rc = 0;
@@ -521,6 +587,9 @@ scmp_filter_ctx sc_prepare_seccomp_context(const char *filter_profile)
errno = ENOMEM;
die("seccomp_init() failed");
}
+ // Setup native arch and any compatibility archs
+ sc_add_seccomp_archs(ctx);
+
// Disable NO_NEW_PRIVS because it interferes with exec transitions in
// AppArmor. Unfortunately this means that security policies must be
// very careful to not allow the following otherwise apps can escape