]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/seccomp.c
lxc-start: remove unnecessary checks
[mirror_lxc.git] / src / lxc / seccomp.c
index 108faa0a8d1382dd42b4f80d7c07e1fc9a66668d..deacd12173cb5e3ccfe58d4de042fa90d7118856 100644 (file)
  */
 
 #define _GNU_SOURCE
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <seccomp.h>
-#include <errno.h>
-#include <seccomp.h>
-#include <sys/utsname.h>
 #include <sys/mount.h>
+#include <sys/utsname.h>
 
 #include "config.h"
-#include "lxcseccomp.h"
 #include "log.h"
+#include "lxcseccomp.h"
 
 lxc_log_define(lxc_seccomp, lxc);
 
@@ -48,11 +47,11 @@ static int parse_config_v1(FILE *f, struct lxc_conf *conf)
                        return -1;
                ret = seccomp_rule_add(
 #if HAVE_SCMP_FILTER_CTX
-                       conf->seccomp_ctx,
+                   conf->seccomp_ctx,
 #endif
-                       SCMP_ACT_ALLOW, nr, 0);
+                   SCMP_ACT_ALLOW, nr, 0);
                if (ret < 0) {
-                       ERROR("failed loading allow rule for %d", nr);
+                       ERROR("Failed loading allow rule for %d.", nr);
                        return ret;
                }
        }
@@ -74,14 +73,15 @@ static uint32_t get_v2_default_action(char *line)
 {
        uint32_t ret_action = -1;
 
-       while (*line == ' ') line++;
-       // after 'whitelist' or 'blacklist' comes default behavior
+       while (*line == ' ')
+               line++;
+       /* After 'whitelist' or 'blacklist' comes default behavior. */
        if (strncmp(line, "kill", 4) == 0)
                ret_action = SCMP_ACT_KILL;
        else if (strncmp(line, "errno", 5) == 0) {
                int e;
-               if (sscanf(line+5, "%d", &e) != 1) {
-                       ERROR("Bad errno value in %s", line);
+               if (sscanf(line + 5, "%d", &e) != 1) {
+                       ERROR("Bad errno value in %s.", line);
                        return -2;
                }
                ret_action = SCMP_ACT_ERRNO(e);
@@ -92,6 +92,23 @@ static uint32_t get_v2_default_action(char *line)
        return ret_action;
 }
 
+static const char *get_action_name(uint32_t action)
+{
+       /* The upper 16 bits indicate the type of the seccomp action. */
+       switch(action & 0xffff0000){
+       case SCMP_ACT_KILL:
+               return "kill";
+       case SCMP_ACT_ALLOW:
+               return "allow";
+       case SCMP_ACT_TRAP:
+               return "trap";
+       case SCMP_ACT_ERRNO(0):
+               return "errno";
+       default:
+               return "invalid action";
+       }
+}
+
 static uint32_t get_and_clear_v2_action(char *line, uint32_t def_action)
 {
        char *p = strchr(line, ' ');
@@ -119,33 +136,59 @@ enum lxc_hostarch_t {
        lxc_seccomp_arch_all = 0,
        lxc_seccomp_arch_native,
        lxc_seccomp_arch_i386,
+       lxc_seccomp_arch_x32,
        lxc_seccomp_arch_amd64,
        lxc_seccomp_arch_arm,
+       lxc_seccomp_arch_arm64,
        lxc_seccomp_arch_ppc64,
        lxc_seccomp_arch_ppc64le,
        lxc_seccomp_arch_ppc,
+       lxc_seccomp_arch_mips,
+       lxc_seccomp_arch_mips64,
+       lxc_seccomp_arch_mips64n32,
+       lxc_seccomp_arch_mipsel,
+       lxc_seccomp_arch_mipsel64,
+       lxc_seccomp_arch_mipsel64n32,
+       lxc_seccomp_arch_s390x,
        lxc_seccomp_arch_unknown = 999,
 };
 
+#ifdef __MIPSEL__
+# define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
+# define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
+#else
+# define MIPS_ARCH_O32 lxc_seccomp_arch_mips
+# define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
+#endif
+
 int get_hostarch(void)
 {
        struct utsname uts;
        if (uname(&uts) < 0) {
-               SYSERROR("Failed to read host arch");
+               SYSERROR("Failed to read host arch.");
                return -1;
        }
        if (strcmp(uts.machine, "i686") == 0)
                return lxc_seccomp_arch_i386;
+       /* no x32 kernels */
        else if (strcmp(uts.machine, "x86_64") == 0)
                return lxc_seccomp_arch_amd64;
        else if (strncmp(uts.machine, "armv7", 5) == 0)
                return lxc_seccomp_arch_arm;
+       else if (strncmp(uts.machine, "aarch64", 7) == 0)
+               return lxc_seccomp_arch_arm64;
        else if (strncmp(uts.machine, "ppc64le", 7) == 0)
                return lxc_seccomp_arch_ppc64le;
        else if (strncmp(uts.machine, "ppc64", 5) == 0)
                return lxc_seccomp_arch_ppc64;
        else if (strncmp(uts.machine, "ppc", 3) == 0)
                return lxc_seccomp_arch_ppc;
+       else if (strncmp(uts.machine, "mips64", 6) == 0)
+               return MIPS_ARCH_N64;
+       else if (strncmp(uts.machine, "mips", 4) == 0)
+               return MIPS_ARCH_O32;
+       else if (strncmp(uts.machine, "s390x", 5) == 0)
+               return lxc_seccomp_arch_s390x;
        return lxc_seccomp_arch_unknown;
 }
 
@@ -157,8 +200,12 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_
 
        switch(n_arch) {
        case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
+       case lxc_seccomp_arch_x32: arch = SCMP_ARCH_X32; break;
        case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
        case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
+#ifdef SCMP_ARCH_AARCH64
+       case lxc_seccomp_arch_arm64: arch = SCMP_ARCH_AARCH64; break;
+#endif
 #ifdef SCMP_ARCH_PPC64LE
        case lxc_seccomp_arch_ppc64le: arch = SCMP_ARCH_PPC64LE; break;
 #endif
@@ -167,23 +214,39 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_
 #endif
 #ifdef SCMP_ARCH_PPC
        case lxc_seccomp_arch_ppc: arch = SCMP_ARCH_PPC; break;
+#endif
+#ifdef SCMP_ARCH_MIPS
+       case lxc_seccomp_arch_mips: arch = SCMP_ARCH_MIPS; break;
+       case lxc_seccomp_arch_mips64: arch = SCMP_ARCH_MIPS64; break;
+       case lxc_seccomp_arch_mips64n32: arch = SCMP_ARCH_MIPS64N32; break;
+       case lxc_seccomp_arch_mipsel: arch = SCMP_ARCH_MIPSEL; break;
+       case lxc_seccomp_arch_mipsel64: arch = SCMP_ARCH_MIPSEL64; break;
+       case lxc_seccomp_arch_mipsel64n32: arch = SCMP_ARCH_MIPSEL64N32; break;
+#endif
+#ifdef SCMP_ARCH_S390X
+       case lxc_seccomp_arch_s390x: arch = SCMP_ARCH_S390X; break;
 #endif
        default: return NULL;
        }
 
        if ((ctx = seccomp_init(default_policy_action)) == NULL) {
-               ERROR("Error initializing seccomp context");
+               ERROR("Error initializing seccomp context.");
                return NULL;
        }
        if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
-               ERROR("failed to turn off n-new-privs");
+               ERROR("Failed to turn off no-new-privs.");
                seccomp_release(ctx);
                return NULL;
        }
+#ifdef SCMP_FLTATR_ATL_TSKIP
+       if (seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
+               WARN("Failed to turn on seccomp nop-skip, continuing");
+       }
+#endif
        ret = seccomp_arch_add(ctx, arch);
        if (ret != 0) {
                ERROR("Seccomp error %d (%s) adding arch: %d", ret,
-                               strerror(ret), (int)n_arch);
+                     strerror(-ret), (int)n_arch);
                seccomp_release(ctx);
                return NULL;
        }
@@ -201,17 +264,22 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
 {
        int nr, ret;
 
-       if (arch && seccomp_arch_exist(ctx, arch) != 0) {
-               ERROR("BUG: seccomp: rule and context arch do not match (arch %d)", arch);
+       ret = seccomp_arch_exist(ctx, arch);
+       if (arch && ret != 0) {
+               ERROR("BUG: Seccomp: rule and context arch do not match (arch "
+                     "%d): %s.",
+                     arch, strerror(-ret));
                return false;
        }
 
        if (strncmp(line, "reject_force_umount", 19) == 0) {
-               INFO("Setting seccomp rule to reject force umounts\n");
+               INFO("Setting Seccomp rule to reject force umounts.");
                ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2),
                                1, SCMP_A1(SCMP_CMP_MASKED_EQ , MNT_FORCE , MNT_FORCE ));
                if (ret < 0) {
-                       ERROR("failed (%d) loading rule to reject force umount", ret);
+                       ERROR("Failed (%d) loading rule to reject force "
+                             "umount: %s.",
+                             ret, strerror(-ret));
                        return false;
                }
                return true;
@@ -219,18 +287,19 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
 
        nr = seccomp_syscall_resolve_name(line);
        if (nr == __NR_SCMP_ERROR) {
-               WARN("Seccomp: failed to resolve syscall: %s", line);
-               WARN("This syscall will NOT be blacklisted");
+               WARN("Seccomp: failed to resolve syscall: %s.", line);
+               WARN("This syscall will NOT be blacklisted.");
                return true;
        }
        if (nr < 0) {
-               WARN("Seccomp: got negative # for syscall: %s", line);
-               WARN("This syscall will NOT be blacklisted");
+               WARN("Seccomp: got negative for syscall: %d: %s.", nr, line);
+               WARN("This syscall will NOT be blacklisted.");
                return true;
        }
        ret = seccomp_rule_add_exact(ctx, action, nr, 0);
        if (ret < 0) {
-               ERROR("failed (%d) loading rule for %s (nr %d action %d)", ret, line, nr, action);
+               ERROR("Failed (%d) loading rule for %s (nr %d action %d(%s)): %s.",
+                     ret, line, nr, action, get_action_name(action), strerror(-ret));
                return false;
        }
        return true;
@@ -254,21 +323,22 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
 {
        char *p;
        int ret;
-       scmp_filter_ctx compat_ctx = NULL;
+       scmp_filter_ctx compat_ctx[2] = {NULL, NULL};
        bool blacklist = false;
        uint32_t default_policy_action = -1, default_rule_action = -1, action;
        enum lxc_hostarch_t native_arch = get_hostarch(),
                            cur_rule_arch = native_arch;
+       uint32_t compat_arch[2] = {SCMP_ARCH_NATIVE, SCMP_ARCH_NATIVE};
 
        if (strncmp(line, "blacklist", 9) == 0)
                blacklist = true;
        else if (strncmp(line, "whitelist", 9) != 0) {
-               ERROR("Bad seccomp policy style: %s", line);
+               ERROR("Bad seccomp policy style: %s.", line);
                return -1;
        }
 
        if ((p = strchr(line, ' '))) {
-               default_policy_action = get_v2_default_action(p+1);
+               default_policy_action = get_v2_default_action(p + 1);
                if (default_policy_action == -2)
                        return -1;
        }
@@ -288,22 +358,71 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
 
        if (native_arch == lxc_seccomp_arch_amd64) {
                cur_rule_arch = lxc_seccomp_arch_all;
-               compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
+               compat_arch[0] = SCMP_ARCH_X86;
+               compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_i386,
+                               default_policy_action);
+               compat_arch[1] = SCMP_ARCH_X32;
+               compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_x32,
                                default_policy_action);
-               if (!compat_ctx)
+               if (!compat_ctx[0] || !compat_ctx[1])
                        goto bad;
+#ifdef SCMP_ARCH_PPC
+       } else if (native_arch == lxc_seccomp_arch_ppc64) {
+               cur_rule_arch = lxc_seccomp_arch_all;
+               compat_arch[0] = SCMP_ARCH_PPC;
+               compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_ppc,
+                               default_policy_action);
+               if (!compat_ctx[0])
+                       goto bad;
+#endif
+#ifdef SCMP_ARCH_ARM
+       } else if (native_arch == lxc_seccomp_arch_arm64) {
+               cur_rule_arch = lxc_seccomp_arch_all;
+               compat_arch[0] = SCMP_ARCH_ARM;
+               compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_arm,
+                               default_policy_action);
+               if (!compat_ctx[0])
+                       goto bad;
+#endif
+#ifdef SCMP_ARCH_MIPS
+       } else if (native_arch == lxc_seccomp_arch_mips64) {
+               cur_rule_arch = lxc_seccomp_arch_all;
+               compat_arch[0] = SCMP_ARCH_MIPS;
+               compat_arch[1] = SCMP_ARCH_MIPS64N32;
+               compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mips,
+                               default_policy_action);
+               compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
+                               default_policy_action);
+               if (!compat_ctx[0] || !compat_ctx[1])
+                       goto bad;
+       } else if (native_arch == lxc_seccomp_arch_mipsel64) {
+               cur_rule_arch = lxc_seccomp_arch_all;
+               compat_arch[0] = SCMP_ARCH_MIPSEL;
+               compat_arch[1] = SCMP_ARCH_MIPSEL64N32;
+               compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
+                               default_policy_action);
+               compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
+                               default_policy_action);
+               if (!compat_ctx[0] || !compat_ctx[1])
+                       goto bad;
+#endif
        }
 
        if (default_policy_action != SCMP_ACT_KILL) {
                ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
                if (ret != 0) {
-                       ERROR("Error re-initializing seccomp");
+                       ERROR("Error re-initializing Seccomp.");
                        return -1;
                }
                if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
-                       ERROR("failed to turn off n-new-privs");
+                       ERROR("Failed to turn off no-new-privs.");
                        return -1;
                }
+#ifdef SCMP_FLTATR_ATL_TSKIP
+               if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
+                       WARN("Failed to turn on seccomp nop-skip, continuing");
+               }
+#endif
        }
 
        while (fgets(line, 1024, f)) {
@@ -315,55 +434,57 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
                remove_trailing_newlines(line);
                INFO("processing: .%s.", line);
                if (line[0] == '[') {
-                       // read the architecture for next set of rules
+                       /* Read the architecture for next set of rules. */
                        if (strcmp(line, "[x86]") == 0 ||
-                                       strcmp(line, "[X86]") == 0) {
+                           strcmp(line, "[X86]") == 0) {
                                if (native_arch != lxc_seccomp_arch_i386 &&
-                                       native_arch != lxc_seccomp_arch_amd64) {
+                                               native_arch != lxc_seccomp_arch_amd64) {
                                        cur_rule_arch = lxc_seccomp_arch_unknown;
                                        continue;
                                }
                                cur_rule_arch = lxc_seccomp_arch_i386;
-                               if (native_arch == lxc_seccomp_arch_amd64) {
-                                       if (compat_ctx)
-                                               continue;
-                                       compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
-                                                       default_policy_action);
-                                       if (!compat_ctx)
-                                               goto bad;
+                       } else if (strcmp(line, "[x32]") == 0 ||
+                                  strcmp(line, "[X32]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_amd64) {
+                                       cur_rule_arch = lxc_seccomp_arch_unknown;
+                                       continue;
                                }
+                               cur_rule_arch = lxc_seccomp_arch_x32;
                        } else if (strcmp(line, "[X86_64]") == 0 ||
-                                       strcmp(line, "[x86_64]") == 0) {
+                                  strcmp(line, "[x86_64]") == 0) {
                                if (native_arch != lxc_seccomp_arch_amd64) {
                                        cur_rule_arch = lxc_seccomp_arch_unknown;
                                        continue;
                                }
                                cur_rule_arch = lxc_seccomp_arch_amd64;
                        } else if (strcmp(line, "[all]") == 0 ||
-                                       strcmp(line, "[ALL]") == 0) {
+                                  strcmp(line, "[ALL]") == 0) {
                                cur_rule_arch = lxc_seccomp_arch_all;
-                               if (native_arch == lxc_seccomp_arch_amd64 && !compat_ctx) {
-                                       if (compat_ctx)
-                                               continue;
-                                       compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
-                                                       default_policy_action);
-                                       if (!compat_ctx)
-                                               goto bad;
-                               }
                        }
 #ifdef SCMP_ARCH_ARM
                        else if (strcmp(line, "[arm]") == 0 ||
-                                       strcmp(line, "[ARM]") == 0) {
-                               if (native_arch != lxc_seccomp_arch_arm) {
+                                strcmp(line, "[ARM]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_arm &&
+                                               native_arch != lxc_seccomp_arch_arm64) {
                                        cur_rule_arch = lxc_seccomp_arch_unknown;
                                        continue;
                                }
                                cur_rule_arch = lxc_seccomp_arch_arm;
                        }
 #endif
+#ifdef SCMP_ARCH_AARCH64
+                       else if (strcmp(line, "[arm64]") == 0 ||
+                                strcmp(line, "[ARM64]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_arm64) {
+                                       cur_rule_arch = lxc_seccomp_arch_unknown;
+                                       continue;
+                               }
+                               cur_rule_arch = lxc_seccomp_arch_arm64;
+                       }
+#endif
 #ifdef SCMP_ARCH_PPC64LE
                        else if (strcmp(line, "[ppc64le]") == 0 ||
-                                       strcmp(line, "[PPC64LE]") == 0) {
+                                strcmp(line, "[PPC64LE]") == 0) {
                                if (native_arch != lxc_seccomp_arch_ppc64le) {
                                        cur_rule_arch = lxc_seccomp_arch_unknown;
                                        continue;
@@ -373,7 +494,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
 #endif
 #ifdef SCMP_ARCH_PPC64
                        else if (strcmp(line, "[ppc64]") == 0 ||
-                                       strcmp(line, "[PPC64]") == 0) {
+                                strcmp(line, "[PPC64]") == 0) {
                                if (native_arch != lxc_seccomp_arch_ppc64) {
                                        cur_rule_arch = lxc_seccomp_arch_unknown;
                                        continue;
@@ -383,13 +504,71 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
 #endif
 #ifdef SCMP_ARCH_PPC
                        else if (strcmp(line, "[ppc]") == 0 ||
-                                       strcmp(line, "[PPC]") == 0) {
-                               if (native_arch != lxc_seccomp_arch_ppc) {
+                                strcmp(line, "[PPC]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_ppc &&
+                                               native_arch != lxc_seccomp_arch_ppc64) {
                                        cur_rule_arch = lxc_seccomp_arch_unknown;
                                        continue;
                                }
                                cur_rule_arch = lxc_seccomp_arch_ppc;
                        }
+#endif
+#ifdef SCMP_ARCH_MIPS
+                       else if (strcmp(line, "[mips64]") == 0 ||
+                                strcmp(line, "[MIPS64]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_mips64) {
+                                       cur_rule_arch = lxc_seccomp_arch_unknown;
+                                       continue;
+                               }
+                               cur_rule_arch = lxc_seccomp_arch_mips64;
+                       } else if (strcmp(line, "[mips64n32]") == 0 ||
+                                  strcmp(line, "[MIPS64N32]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_mips64) {
+                                       cur_rule_arch = lxc_seccomp_arch_unknown;
+                                       continue;
+                               }
+                               cur_rule_arch = lxc_seccomp_arch_mips64n32;
+                       } else if (strcmp(line, "[mips]") == 0 ||
+                                  strcmp(line, "[MIPS]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_mips &&
+                                               native_arch != lxc_seccomp_arch_mips64) {
+                                       cur_rule_arch = lxc_seccomp_arch_unknown;
+                                       continue;
+                               }
+                               cur_rule_arch = lxc_seccomp_arch_mips;
+                       } else if (strcmp(line, "[mipsel64]") == 0 ||
+                                  strcmp(line, "[MIPSEL64]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_mipsel64) {
+                                       cur_rule_arch = lxc_seccomp_arch_unknown;
+                                       continue;
+                               }
+                               cur_rule_arch = lxc_seccomp_arch_mipsel64;
+                       } else if (strcmp(line, "[mipsel64n32]") == 0 ||
+                                  strcmp(line, "[MIPSEL64N32]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_mipsel64) {
+                                       cur_rule_arch = lxc_seccomp_arch_unknown;
+                                       continue;
+                               }
+                               cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
+                       } else if (strcmp(line, "[mipsel]") == 0 ||
+                                  strcmp(line, "[MIPSEL]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_mipsel &&
+                                               native_arch != lxc_seccomp_arch_mipsel64) {
+                                       cur_rule_arch = lxc_seccomp_arch_unknown;
+                                       continue;
+                               }
+                               cur_rule_arch = lxc_seccomp_arch_mipsel;
+                       }
+#endif
+#ifdef SCMP_ARCH_S390X
+                       else if (strcmp(line, "[s390x]") == 0 ||
+                                strcmp(line, "[S390X]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_s390x) {
+                                       cur_rule_arch = lxc_seccomp_arch_unknown;
+                                       continue;
+                               }
+                               cur_rule_arch = lxc_seccomp_arch_s390x;
+                       }
 #endif
                        else
                                goto bad_arch;
@@ -404,53 +583,48 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
                /* read optional action which follows the syscall */
                action = get_and_clear_v2_action(line, default_rule_action);
                if (action == -1) {
-                       ERROR("Failed to interpret action");
+                       ERROR("Failed to interpret action.");
                        goto bad_rule;
                }
 
-               /*
-                * TODO generalize - if !is_compat_only(native_arch, cur_rule_arch)
-                *
-                * in other words, the rule is 32-bit only, on 64-bit host;  don't run
-                * the rule against the native arch.
-                */
-               if (!(cur_rule_arch == lxc_seccomp_arch_i386 &&
-                       native_arch == lxc_seccomp_arch_amd64)) {
-                       INFO("Adding non-compat rule for %s action %d", line, action);
+               if (cur_rule_arch == native_arch ||
+                   cur_rule_arch == lxc_seccomp_arch_native ||
+                   compat_arch[0] == SCMP_ARCH_NATIVE) {
+                       INFO("Adding native rule for %s action %d(%s).", line, action,
+                            get_action_name(action));
                        if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
                                goto bad_rule;
                }
-
-               /*
-                * TODO generalize - if need_compat(native_arch, cur_rule_arch)
-                */
-               if (native_arch == lxc_seccomp_arch_amd64 &&
-                       cur_rule_arch != lxc_seccomp_arch_amd64) {
-                       int nr1, nr2;
-                       INFO("Adding compat rule for %s action %d", line, action);
-                       nr1 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_X86, line);
-                       nr2 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE, line);
-                       if (nr1 == nr2) {
-                               /* If the syscall # is the same for 32- and 64-bit, then we cannot
-                                * apply it to the compat_ctx.  So apply it to the noncompat ctx.
-                                * We may already have done so, but that's ok
-                                */
-                               INFO("Adding non-compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2);
-                               if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
-                                       goto bad_rule;
-                               continue;
-                       }
-                       INFO("Really adding compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2);
-                       if (!do_resolve_add_rule(SCMP_ARCH_X86, line,
-                                               compat_ctx, action))
+               else if (cur_rule_arch != lxc_seccomp_arch_all) {
+                       int arch_index =
+                               cur_rule_arch == lxc_seccomp_arch_mips64n32 ||
+                               cur_rule_arch == lxc_seccomp_arch_mipsel64n32 ? 1 : 0;
+
+                       INFO("Adding compat-only rule for %s action %d(%s).", line, action,
+                            get_action_name(action));
+                       if (!do_resolve_add_rule(compat_arch[arch_index], line, compat_ctx[arch_index], action))
+                               goto bad_rule;
+               }
+               else {
+                       INFO("Adding native rule for %s action %d(%s).", line, action,
+                            get_action_name(action));
+                       if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
+                               goto bad_rule;
+                       INFO("Adding compat rule for %s action %d(%s).", line, action,
+                            get_action_name(action));
+                       if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], action))
+                               goto bad_rule;
+                       if (compat_arch[1] != SCMP_ARCH_NATIVE &&
+                               !do_resolve_add_rule(compat_arch[1], line, compat_ctx[1], action))
                                goto bad_rule;
                }
        }
 
-       if (compat_ctx) {
-               INFO("Merging in the compat seccomp ctx into the main one");
-               if (seccomp_merge(conf->seccomp_ctx, compat_ctx) != 0) {
-                       ERROR("Error merging i386 seccomp contexts");
+       if (compat_ctx[0]) {
+               INFO("Merging in the compat Seccomp ctx into the main one.");
+               if (seccomp_merge(conf->seccomp_ctx, compat_ctx[0]) != 0 ||
+                       (compat_ctx[1] != NULL && seccomp_merge(conf->seccomp_ctx, compat_ctx[1]) != 0)) {
+                       ERROR("Error merging compat Seccomp contexts.");
                        goto bad;
                }
        }
@@ -458,11 +632,13 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
        return 0;
 
 bad_arch:
-       ERROR("Unsupported arch: %s", line);
+       ERROR("Unsupported arch: %s.", line);
 bad_rule:
 bad:
-       if (compat_ctx)
-               seccomp_release(compat_ctx);
+       if (compat_ctx[0])
+               seccomp_release(compat_ctx[0]);
+       if (compat_ctx[1])
+               seccomp_release(compat_ctx[1]);
        return -1;
 }
 #else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
@@ -476,9 +652,9 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
  * The first line of the config file has a policy language version
  * the second line has some directives
  * then comes policy subject to the directives
- * right now version must be '1'
- * the directives must include 'whitelist' (only type of policy currently
- * supported) and can include 'debug' (though debug is not yet supported).
+ * right now version must be '1' or '2'
+ * the directives must include 'whitelist'(version == 1 or 2) or 'blacklist'
+ * (version == 2) and can include 'debug' (though debug is not yet supported).
  */
 static int parse_config(FILE *f, struct lxc_conf *conf)
 {
@@ -487,20 +663,20 @@ static int parse_config(FILE *f, struct lxc_conf *conf)
 
        ret = fscanf(f, "%d\n", &version);
        if (ret != 1 || (version != 1 && version != 2)) {
-               ERROR("invalid version");
+               ERROR("Invalid version.");
                return -1;
        }
        if (!fgets(line, 1024, f)) {
-               ERROR("invalid config file");
+               ERROR("Invalid config file.");
                return -1;
        }
        if (version == 1 && !strstr(line, "whitelist")) {
-               ERROR("only whitelist policy is supported");
+               ERROR("Only whitelist policy is supported.");
                return -1;
        }
 
        if (strstr(line, "debug")) {
-               ERROR("debug not yet implemented");
+               ERROR("Debug not yet implemented.");
                return -1;
        }
 
@@ -530,7 +706,7 @@ static bool use_seccomp(void)
        while (fgets(line, 1024, f)) {
                if (strncmp(line, "Seccomp:", 8) == 0) {
                        found = true;
-                       ret = sscanf(line+8, "%d", &v);
+                       ret = sscanf(line + 8, "%d", &v);
                        if (ret == 1 && v != 0)
                                already_enabled = true;
                        break;
@@ -538,12 +714,12 @@ static bool use_seccomp(void)
        }
 
        fclose(f);
-       if (!found) {  /* no Seccomp line, no seccomp in kernel */
-               INFO("Seccomp is not enabled in the kernel");
+       if (!found) { /* no Seccomp line, no seccomp in kernel */
+               INFO("Seccomp is not enabled in the kernel.");
                return false;
        }
-       if (already_enabled) {  /* already seccomp-confined */
-               INFO("Already seccomp-confined, not loading new policy");
+       if (already_enabled) { /* already seccomp-confined */
+               INFO("Already seccomp-confined, not loading new policy.");
                return false;
        }
        return true;
@@ -553,6 +729,7 @@ int lxc_read_seccomp_config(struct lxc_conf *conf)
 {
        FILE *f;
        int ret;
+       int check_seccomp_attr_set;
 
        if (!conf->seccomp)
                return 0;
@@ -567,24 +744,30 @@ int lxc_read_seccomp_config(struct lxc_conf *conf)
        ret = seccomp_init(SCMP_ACT_KILL) < 0;
 #endif
        if (ret) {
-               ERROR("failed initializing seccomp");
+               ERROR("Failed initializing seccomp.");
                return -1;
        }
 
-       /* turn of no-new-privs.  We don't want it in lxc, and it breaks
-        * with apparmor */
-       if (seccomp_attr_set(
+/* turn off no-new-privs.  We don't want it in lxc, and it breaks
+ * with apparmor */
 #if HAVE_SCMP_FILTER_CTX
-                       conf->seccomp_ctx,
+       check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
+#else
+       check_seccomp_attr_set = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
 #endif
-                       SCMP_FLTATR_CTL_NNP, 0)) {
-               ERROR("failed to turn off n-new-privs");
+       if (check_seccomp_attr_set) {
+               ERROR("Failed to turn off no-new-privs.");
                return -1;
        }
+#ifdef SCMP_FLTATR_ATL_TSKIP
+       if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
+               WARN("Failed to turn on seccomp nop-skip, continuing");
+       }
+#endif
 
        f = fopen(conf->seccomp, "r");
        if (!f) {
-               SYSERROR("failed to open seccomp policy file %s", conf->seccomp);
+               SYSERROR("Failed to open seccomp policy file %s.", conf->seccomp);
                return -1;
        }
        ret = parse_config(f, conf);
@@ -601,17 +784,30 @@ int lxc_seccomp_load(struct lxc_conf *conf)
                return 0;
        ret = seccomp_load(
 #if HAVE_SCMP_FILTER_CTX
-                       conf->seccomp_ctx
+           conf->seccomp_ctx
 #endif
-       );
+           );
        if (ret < 0) {
-               ERROR("Error loading the seccomp policy");
+               ERROR("Error loading the seccomp policy: %s.", strerror(-ret));
                return -1;
        }
+
+/* After load seccomp filter into the kernel successfully, export the current seccomp
+ * filter to log file */
+#if HAVE_SCMP_FILTER_CTX
+       if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE || conf->loglevel <= LXC_LOG_LEVEL_TRACE) &&
+           lxc_log_fd >= 0) {
+               ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd);
+               /* Just give an warning when export error */
+               if (ret < 0)
+                       WARN("Failed to export seccomp filter to log file: %s.", strerror(-ret));
+       }
+#endif
        return 0;
 }
 
-void lxc_seccomp_free(struct lxc_conf *conf) {
+void lxc_seccomp_free(struct lxc_conf *conf)
+{
        free(conf->seccomp);
        conf->seccomp = NULL;
 #if HAVE_SCMP_FILTER_CTX