gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/seccomp.cc (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <errno.h>
    16  #include <linux/audit.h>
    17  #include <linux/filter.h>
    18  #include <linux/seccomp.h>
    19  #include <pthread.h>
    20  #include <sched.h>
    21  #include <signal.h>
    22  #include <string.h>
    23  #include <sys/prctl.h>
    24  #include <sys/syscall.h>
    25  #include <time.h>
    26  #include <ucontext.h>
    27  #include <unistd.h>
    28  
    29  #include <atomic>
    30  
    31  #include "gmock/gmock.h"
    32  #include "gtest/gtest.h"
    33  #include "absl/base/macros.h"
    34  #include "test/util/logging.h"
    35  #include "test/util/memory_util.h"
    36  #include "test/util/multiprocess_util.h"
    37  #include "test/util/platform_util.h"
    38  #include "test/util/posix_error.h"
    39  #include "test/util/proc_util.h"
    40  #include "test/util/test_util.h"
    41  #include "test/util/thread_util.h"
    42  
    43  #ifndef SYS_SECCOMP
    44  #define SYS_SECCOMP 1
    45  #endif
    46  
    47  namespace gvisor {
    48  namespace testing {
    49  
    50  namespace {
    51  
    52  // A syscall not implemented by Linux that we don't expect to be called.
    53  #ifdef __x86_64__
    54  constexpr uint32_t kFilteredSyscall = SYS_vserver;
    55  #elif __aarch64__
    56  // Use the last of arch_specific_syscalls which are not implemented on arm64.
    57  constexpr uint32_t kFilteredSyscall = __NR_arch_specific_syscall + 15;
    58  #endif
    59  
    60  // Applies a seccomp-bpf filter that returns `filtered_result` for
    61  // `sysno` and allows all other syscalls. Async-signal-safe.
    62  void ApplySeccompFilter(uint32_t sysno, uint32_t filtered_result,
    63                          uint32_t flags = 0) {
    64    // "Prior to [PR_SET_SECCOMP], the task must call prctl(PR_SET_NO_NEW_PRIVS,
    65    // 1) or run with CAP_SYS_ADMIN privileges in its namespace." -
    66    // Documentation/prctl/seccomp_filter.txt
    67    //
    68    // prctl(PR_SET_NO_NEW_PRIVS, 1) may be called repeatedly; calls after the
    69    // first are no-ops.
    70    TEST_PCHECK(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == 0);
    71    MaybeSave();
    72  
    73    struct sock_filter filter[] = {
    74        // A = seccomp_data.arch
    75        BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 4),
    76  #if defined(__x86_64__)
    77        // if (A != AUDIT_ARCH_X86_64) goto kill
    78        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 0, 4),
    79  #elif defined(__aarch64__)
    80        // if (A != AUDIT_ARCH_AARCH64) goto kill
    81        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_AARCH64, 0, 4),
    82  #else
    83  #error "Unknown architecture"
    84  #endif
    85        // A = seccomp_data.nr
    86        BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 0),
    87        // if (A != sysno) goto allow
    88        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, sysno, 0, 1),
    89        // return filtered_result
    90        BPF_STMT(BPF_RET | BPF_K, filtered_result),
    91        // allow: return SECCOMP_RET_ALLOW
    92        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
    93        // kill: return SECCOMP_RET_KILL
    94        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
    95    };
    96    struct sock_fprog prog;
    97    prog.len = ABSL_ARRAYSIZE(filter);
    98    prog.filter = filter;
    99    if (flags) {
   100      TEST_CHECK(syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, flags, &prog) ==
   101                 0);
   102    } else {
   103      TEST_PCHECK(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0) == 0);
   104    }
   105    MaybeSave();
   106  }
   107  
   108  // ApplyUncacheableFilter adds a no-op filter which reads one of the
   109  // syscall arguments when queried about `sysno`, and returns ALLOW.
   110  // This purposefully breaks the Linux seccomp cache.
   111  void ApplyUncacheableFilter(uint32_t sysno) {
   112    // "Prior to [PR_SET_SECCOMP], the task must call prctl(PR_SET_NO_NEW_PRIVS,
   113    // 1) or run with CAP_SYS_ADMIN privileges in its namespace." -
   114    // Documentation/prctl/seccomp_filter.txt
   115    //
   116    // prctl(PR_SET_NO_NEW_PRIVS, 1) may be called repeatedly; calls after the
   117    // first are no-ops.
   118    TEST_PCHECK(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == 0);
   119    MaybeSave();
   120  
   121    struct sock_filter filter[] = {
   122        // A = seccomp_data.arch
   123        BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 4),
   124  #if defined(__x86_64__)
   125        // if (A != AUDIT_ARCH_X86_64) goto kill
   126        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 0, 4),
   127  #elif defined(__aarch64__)
   128        // if (A != AUDIT_ARCH_AARCH64) goto kill
   129        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_AARCH64, 0, 4),
   130  #else
   131  #error "Unknown architecture"
   132  #endif
   133        // A = seccomp_data.nr
   134        BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 0),
   135        // if (A != sysno) goto end
   136        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, sysno, 0, 1),
   137        // A = seccomp_data.args[0]
   138        BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 16),
   139        // end: return SECCOMP_RET_ALLOW
   140        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
   141        // kill: return SECCOMP_RET_KILL
   142        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
   143    };
   144    struct sock_fprog prog;
   145    prog.len = ABSL_ARRAYSIZE(filter);
   146    prog.filter = filter;
   147    TEST_PCHECK(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0) == 0);
   148    MaybeSave();
   149  }
   150  
   151  // Wrapper for sigaction. Async-signal-safe.
   152  void RegisterSignalHandler(int signum,
   153                             void (*handler)(int, siginfo_t*, void*)) {
   154    struct sigaction sa = {};
   155    sa.sa_sigaction = handler;
   156    sigemptyset(&sa.sa_mask);
   157    sa.sa_flags = SA_SIGINFO;
   158    TEST_PCHECK(sigaction(signum, &sa, nullptr) == 0);
   159    MaybeSave();
   160  }
   161  
   162  // All of the following tests execute in a subprocess to ensure that each test
   163  // is run in a separate process. This avoids cross-contamination of seccomp
   164  // state between tests, and is necessary to ensure that test processes killed
   165  // by SECCOMP_RET_KILL are single-threaded (since SECCOMP_RET_KILL only kills
   166  // the offending thread, not the whole thread group).
   167  
   168  TEST(SeccompTest, RetKillCausesDeathBySIGSYS) {
   169    pid_t const pid = fork();
   170    if (pid == 0) {
   171      // Register a signal handler for SIGSYS that we don't expect to be invoked.
   172      RegisterSignalHandler(SIGSYS, +[](int, siginfo_t*, void*) { _exit(1); });
   173      ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_KILL);
   174      syscall(kFilteredSyscall);
   175      TEST_CHECK_MSG(false, "Survived invocation of test syscall");
   176    }
   177    ASSERT_THAT(pid, SyscallSucceeds());
   178    int status;
   179    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   180    EXPECT_TRUE(WIFSIGNALED(status) && WTERMSIG(status) == SIGSYS)
   181        << "status " << status;
   182  }
   183  
   184  TEST(SeccompTest, RetKillOnlyKillsOneThread) {
   185    Mapping stack = ASSERT_NO_ERRNO_AND_VALUE(
   186        MmapAnon(2 * kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE));
   187  
   188    pid_t const pid = fork();
   189    if (pid == 0) {
   190      // Register a signal handler for SIGSYS that we don't expect to be invoked.
   191      RegisterSignalHandler(SIGSYS, +[](int, siginfo_t*, void*) { _exit(1); });
   192      ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_KILL);
   193      // Pass CLONE_VFORK to block the original thread in the child process until
   194      // the clone thread exits with SIGSYS.
   195      //
   196      // N.B. clone(2) is not officially async-signal-safe, but at minimum glibc's
   197      // x86_64 implementation is safe. See glibc
   198      // sysdeps/unix/sysv/linux/x86_64/clone.S.
   199      clone(
   200          +[](void* arg) {
   201            syscall(kFilteredSyscall);  // should kill the thread
   202            _exit(1);                   // should be unreachable
   203            return 2;  // should be very unreachable, shut up the compiler
   204          },
   205          stack.endptr(),
   206          CLONE_FILES | CLONE_FS | CLONE_SIGHAND | CLONE_THREAD | CLONE_VM |
   207              CLONE_VFORK,
   208          nullptr);
   209      _exit(0);
   210    }
   211    ASSERT_THAT(pid, SyscallSucceeds());
   212    int status;
   213    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   214    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0)
   215        << "status " << status;
   216  }
   217  
   218  TEST(SeccompTest, RetTrapCausesSIGSYS) {
   219    pid_t const pid = fork();
   220    if (pid == 0) {
   221      constexpr uint16_t kTrapValue = 0xdead;
   222      RegisterSignalHandler(
   223          SIGSYS, +[](int signo, siginfo_t* info, void* ucv) {
   224            ucontext_t* uc = static_cast<ucontext_t*>(ucv);
   225            // This is a signal handler, so we must stay async-signal-safe.
   226            TEST_CHECK(info->si_signo == SIGSYS);
   227            TEST_CHECK(info->si_code == SYS_SECCOMP);
   228            TEST_CHECK(info->si_errno == kTrapValue);
   229            TEST_CHECK(info->si_call_addr != nullptr);
   230            TEST_CHECK(info->si_syscall == kFilteredSyscall);
   231  #if defined(__x86_64__)
   232            TEST_CHECK(info->si_arch == AUDIT_ARCH_X86_64);
   233            TEST_CHECK(uc->uc_mcontext.gregs[REG_RAX] == kFilteredSyscall);
   234  #elif defined(__aarch64__)
   235            TEST_CHECK(info->si_arch == AUDIT_ARCH_AARCH64);
   236            TEST_CHECK(uc->uc_mcontext.regs[8] == kFilteredSyscall);
   237  #endif  // defined(__x86_64__)
   238            _exit(0);
   239          });
   240      ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_TRAP | kTrapValue);
   241      syscall(kFilteredSyscall);
   242      TEST_CHECK_MSG(false, "Survived invocation of test syscall");
   243    }
   244    ASSERT_THAT(pid, SyscallSucceeds());
   245    int status;
   246    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   247    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0)
   248        << "status " << status;
   249  }
   250  
   251  #ifdef __x86_64__
   252  
   253  constexpr uint64_t kVsyscallTimeEntry = 0xffffffffff600400;
   254  
   255  time_t vsyscall_time(time_t* t) {
   256    return reinterpret_cast<time_t (*)(time_t*)>(kVsyscallTimeEntry)(t);
   257  }
   258  
   259  TEST(SeccompTest, SeccompAppliesToVsyscall) {
   260    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsVsyscallEnabled()));
   261    SKIP_IF(PlatformSupportVsyscall() == PlatformSupport::NotSupported);
   262  
   263    pid_t const pid = fork();
   264    if (pid == 0) {
   265      constexpr uint16_t kTrapValue = 0xdead;
   266      RegisterSignalHandler(
   267          SIGSYS, +[](int signo, siginfo_t* info, void* ucv) {
   268            ucontext_t* uc = static_cast<ucontext_t*>(ucv);
   269            // This is a signal handler, so we must stay async-signal-safe.
   270            TEST_CHECK(info->si_signo == SIGSYS);
   271            TEST_CHECK(info->si_code == SYS_SECCOMP);
   272            TEST_CHECK(info->si_errno == kTrapValue);
   273            TEST_CHECK(info->si_call_addr != nullptr);
   274            TEST_CHECK(info->si_syscall == SYS_time);
   275            TEST_CHECK(info->si_arch == AUDIT_ARCH_X86_64);
   276            TEST_CHECK(uc->uc_mcontext.gregs[REG_RAX] == SYS_time);
   277            _exit(0);
   278          });
   279      ApplySeccompFilter(SYS_time, SECCOMP_RET_TRAP | kTrapValue);
   280      vsyscall_time(nullptr);  // Should result in death.
   281      TEST_CHECK_MSG(false, "Survived invocation of test syscall");
   282    }
   283    ASSERT_THAT(pid, SyscallSucceeds());
   284    int status;
   285    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   286    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0)
   287        << "status " << status;
   288  }
   289  
   290  TEST(SeccompTest, RetKillVsyscallCausesDeathBySIGSYS) {
   291    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsVsyscallEnabled()));
   292    SKIP_IF(PlatformSupportVsyscall() == PlatformSupport::NotSupported);
   293  
   294    pid_t const pid = fork();
   295    if (pid == 0) {
   296      // Register a signal handler for SIGSYS that we don't expect to be invoked.
   297      RegisterSignalHandler(SIGSYS, +[](int, siginfo_t*, void*) { _exit(1); });
   298      ApplySeccompFilter(SYS_time, SECCOMP_RET_KILL);
   299      vsyscall_time(nullptr);  // Should result in death.
   300      TEST_CHECK_MSG(false, "Survived invocation of test syscall");
   301    }
   302    ASSERT_THAT(pid, SyscallSucceeds());
   303    int status;
   304    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   305    EXPECT_TRUE(WIFSIGNALED(status) && WTERMSIG(status) == SIGSYS)
   306        << "status " << status;
   307  }
   308  
   309  #endif  // defined(__x86_64__)
   310  
   311  TEST(SeccompTest, RetTraceWithoutPtracerReturnsENOSYS) {
   312    pid_t const pid = fork();
   313    if (pid == 0) {
   314      ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_TRACE);
   315      TEST_CHECK(syscall(kFilteredSyscall) == -1 && errno == ENOSYS);
   316      _exit(0);
   317    }
   318    ASSERT_THAT(pid, SyscallSucceeds());
   319    int status;
   320    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   321    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0)
   322        << "status " << status;
   323  }
   324  
   325  TEST(SeccompTest, RetErrnoReturnsErrno) {
   326    pid_t const pid = fork();
   327    if (pid == 0) {
   328      // ENOTNAM: "Not a XENIX named type file"
   329      ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_ERRNO | ENOTNAM);
   330      TEST_CHECK(syscall(kFilteredSyscall) == -1 && errno == ENOTNAM);
   331      _exit(0);
   332    }
   333    ASSERT_THAT(pid, SyscallSucceeds());
   334    int status;
   335    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   336    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0)
   337        << "status " << status;
   338  }
   339  
   340  TEST(SeccompTest, RetAllowAllowsSyscall) {
   341    pid_t const pid = fork();
   342    if (pid == 0) {
   343      ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_ALLOW);
   344      TEST_CHECK(syscall(kFilteredSyscall) == -1 && errno == ENOSYS);
   345      _exit(0);
   346    }
   347    ASSERT_THAT(pid, SyscallSucceeds());
   348    int status;
   349    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   350    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0)
   351        << "status " << status;
   352  }
   353  
   354  TEST(SeccompTest, RetAllowAllowsNonCachableSyscall) {
   355    pid_t const pid = fork();
   356    if (pid == 0) {
   357      ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_ALLOW);
   358      ApplyUncacheableFilter(kFilteredSyscall);
   359      TEST_CHECK(syscall(kFilteredSyscall) == -1 && errno == ENOSYS);
   360      _exit(0);
   361    }
   362    ASSERT_THAT(pid, SyscallSucceeds());
   363    int status;
   364    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   365    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0)
   366        << "status " << status;
   367  }
   368  
   369  // This test will validate that TSYNC will apply to all threads.
   370  TEST(SeccompTest, TsyncAppliesToAllThreads) {
   371    Mapping stack = ASSERT_NO_ERRNO_AND_VALUE(
   372        MmapAnon(2 * kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE));
   373  
   374    // We don't want to apply this policy to other test runner threads, so fork.
   375    const pid_t pid = fork();
   376  
   377    if (pid == 0) {
   378      // First check that we receive a ENOSYS before the policy is applied.
   379      TEST_CHECK(syscall(kFilteredSyscall) == -1 && errno == ENOSYS);
   380  
   381      // N.B. clone(2) is not officially async-signal-safe, but at minimum glibc's
   382      // x86_64 implementation is safe. See glibc
   383      // sysdeps/unix/sysv/linux/x86_64/clone.S.
   384      clone(
   385          +[](void* arg) {
   386            ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_ERRNO | ENOTNAM,
   387                               SECCOMP_FILTER_FLAG_TSYNC);
   388            return 0;
   389          },
   390          stack.endptr(),
   391          CLONE_FILES | CLONE_FS | CLONE_SIGHAND | CLONE_THREAD | CLONE_VM |
   392              CLONE_VFORK,
   393          nullptr);
   394  
   395      // Because we're using CLONE_VFORK this thread will be blocked until
   396      // the second thread has released resources to our virtual memory, since
   397      // we're not execing that will happen on _exit.
   398  
   399      // Now verify that the policy applied to this thread too.
   400      TEST_CHECK(syscall(kFilteredSyscall) == -1 && errno == ENOTNAM);
   401      _exit(0);
   402    }
   403  
   404    ASSERT_THAT(pid, SyscallSucceeds());
   405    int status = 0;
   406    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   407    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0)
   408        << "status " << status;
   409  }
   410  
   411  // This test will validate that seccomp(2) rejects unsupported flags.
   412  TEST(SeccompTest, SeccompRejectsUnknownFlags) {
   413    constexpr uint32_t kInvalidFlag = 123;
   414    ASSERT_THAT(
   415        syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, kInvalidFlag, nullptr),
   416        SyscallFailsWithErrno(EINVAL));
   417  }
   418  
   419  TEST(SeccompTest, LeastPermissiveFilterReturnValueApplies) {
   420    // This is RetKillCausesDeathBySIGSYS, plus extra filters before and after the
   421    // one that causes the kill that should be ignored.
   422    pid_t const pid = fork();
   423    if (pid == 0) {
   424      RegisterSignalHandler(SIGSYS, +[](int, siginfo_t*, void*) { _exit(1); });
   425      ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_TRACE);
   426      ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_KILL);
   427      ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_ERRNO | ENOTNAM);
   428      syscall(kFilteredSyscall);
   429      TEST_CHECK_MSG(false, "Survived invocation of test syscall");
   430    }
   431    ASSERT_THAT(pid, SyscallSucceeds());
   432    int status;
   433    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   434    EXPECT_TRUE(WIFSIGNALED(status) && WTERMSIG(status) == SIGSYS)
   435        << "status " << status;
   436  }
   437  
   438  // Passed as argv[1] to cause the test binary to invoke kFilteredSyscall and
   439  // exit. Not a real flag since flag parsing happens during initialization,
   440  // which may create threads.
   441  constexpr char kInvokeFilteredSyscallFlag[] = "--seccomp_test_child";
   442  
   443  TEST(SeccompTest, FiltersPreservedAcrossForkAndExecve) {
   444    ExecveArray const grandchild_argv(
   445        {"/proc/self/exe", kInvokeFilteredSyscallFlag});
   446  
   447    pid_t const pid = fork();
   448    if (pid == 0) {
   449      ApplySeccompFilter(kFilteredSyscall, SECCOMP_RET_KILL);
   450      pid_t const grandchild_pid = fork();
   451      if (grandchild_pid == 0) {
   452        execve(grandchild_argv.get()[0], grandchild_argv.get(),
   453               /* envp = */ nullptr);
   454        TEST_PCHECK_MSG(false, "execve failed");
   455      }
   456      int status;
   457      TEST_PCHECK(waitpid(grandchild_pid, &status, 0) == grandchild_pid);
   458      TEST_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGSYS);
   459      _exit(0);
   460    }
   461    ASSERT_THAT(pid, SyscallSucceeds());
   462    int status;
   463    ASSERT_THAT(waitpid(pid, &status, 0), SyscallSucceedsWithValue(pid));
   464    EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0)
   465        << "status " << status;
   466  }
   467  
   468  TEST(SeccompTest, EmptyProgramIsRejected) {
   469    struct sock_fprog prog;
   470    prog.len = 0;
   471    prog.filter = nullptr;
   472    ASSERT_THAT(syscall(__NR_seccomp, SECCOMP_MODE_FILTER, &prog),
   473                SyscallFailsWithErrno(EINVAL));
   474    MaybeSave();
   475    ASSERT_THAT(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0),
   476                SyscallFailsWithErrno(EINVAL));
   477  }
   478  
   479  TEST(SeccompTest, ProgramTooLargeIsRejected) {
   480    constexpr int kTooLargeFilterSize = 4097;  // BPF_MAXINSNS + 1
   481    TEST_PCHECK(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == 0);
   482    MaybeSave();
   483    struct sock_filter filter[kTooLargeFilterSize];
   484    for (int i = 0; i < kTooLargeFilterSize; ++i) {
   485      filter[i] = BPF_STMT(BPF_LD | BPF_ABS | BPF_W, 0);  // A = seccomp_data.nr
   486    }
   487    filter[kTooLargeFilterSize - 1] =
   488        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW);  // Return allow
   489    struct sock_fprog prog;
   490    prog.len = ABSL_ARRAYSIZE(filter);
   491    prog.filter = filter;
   492    ASSERT_THAT(syscall(__NR_seccomp, SECCOMP_MODE_FILTER, &prog),
   493                SyscallFailsWithErrno(EINVAL));
   494    MaybeSave();
   495    ASSERT_THAT(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0),
   496                SyscallFailsWithErrno(EINVAL));
   497  }
   498  
   499  }  // namespace
   500  
   501  }  // namespace testing
   502  }  // namespace gvisor
   503  
   504  int main(int argc, char** argv) {
   505    if (argc >= 2 &&
   506        strcmp(argv[1], gvisor::testing::kInvokeFilteredSyscallFlag) == 0) {
   507      syscall(gvisor::testing::kFilteredSyscall);
   508      exit(0);
   509    }
   510  
   511    gvisor::testing::TestInit(&argc, &argv);
   512    return gvisor::testing::RunAllTests();
   513  }