gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/exec.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 "test/syscalls/linux/exec.h"
    16  
    17  #include <errno.h>
    18  #include <fcntl.h>
    19  #include <sys/eventfd.h>
    20  #include <sys/resource.h>
    21  #include <sys/time.h>
    22  #include <unistd.h>
    23  
    24  #include <iostream>
    25  #include <memory>
    26  #include <string>
    27  #include <vector>
    28  
    29  #include "gtest/gtest.h"
    30  #include "absl/strings/match.h"
    31  #include "absl/strings/numbers.h"
    32  #include "absl/strings/str_cat.h"
    33  #include "absl/strings/str_split.h"
    34  #include "absl/strings/string_view.h"
    35  #include "absl/synchronization/mutex.h"
    36  #include "absl/types/optional.h"
    37  #include "test/util/file_descriptor.h"
    38  #include "test/util/fs_util.h"
    39  #include "test/util/multiprocess_util.h"
    40  #include "test/util/posix_error.h"
    41  #include "test/util/temp_path.h"
    42  #include "test/util/test_util.h"
    43  #include "test/util/thread_util.h"
    44  
    45  namespace gvisor {
    46  namespace testing {
    47  
    48  namespace {
    49  
    50  constexpr char kBasicWorkload[] = "test/syscalls/linux/exec_basic_workload";
    51  constexpr char kExitScript[] = "test/syscalls/linux/exit_script";
    52  constexpr char kStateWorkload[] = "test/syscalls/linux/exec_state_workload";
    53  constexpr char kProcExeWorkload[] =
    54      "test/syscalls/linux/exec_proc_exe_workload";
    55  constexpr char kAssertClosedWorkload[] =
    56      "test/syscalls/linux/exec_assert_closed_workload";
    57  constexpr char kPriorityWorkload[] = "test/syscalls/linux/priority_execve";
    58  
    59  constexpr char kExit42[] = "--exec_exit_42";
    60  constexpr char kExecWithThread[] = "--exec_exec_with_thread";
    61  constexpr char kExecFromThread[] = "--exec_exec_from_thread";
    62  
    63  // Runs file specified by dirfd and pathname with argv and checks that the exit
    64  // status is expect_status and that stderr contains expect_stderr.
    65  void CheckExecHelper(const absl::optional<int32_t> dirfd,
    66                       const std::string& pathname, const ExecveArray& argv,
    67                       const ExecveArray& envv, const int flags,
    68                       int expect_status, const std::string& expect_stderr) {
    69    int pipe_fds[2];
    70    ASSERT_THAT(pipe2(pipe_fds, O_CLOEXEC), SyscallSucceeds());
    71  
    72    FileDescriptor read_fd(pipe_fds[0]);
    73    FileDescriptor write_fd(pipe_fds[1]);
    74  
    75    pid_t child;
    76    int execve_errno;
    77  
    78    const auto remap_stderr = [pipe_fds] {
    79      // Remap stdin and stdout to /dev/null.
    80      int fd = open("/dev/null", O_RDWR | O_CLOEXEC);
    81      if (fd < 0) {
    82        _exit(errno);
    83      }
    84  
    85      int ret = dup2(fd, 0);
    86      if (ret < 0) {
    87        _exit(errno);
    88      }
    89  
    90      ret = dup2(fd, 1);
    91      if (ret < 0) {
    92        _exit(errno);
    93      }
    94  
    95      // And stderr to the pipe.
    96      ret = dup2(pipe_fds[1], 2);
    97      if (ret < 0) {
    98        _exit(errno);
    99      }
   100  
   101      // Here, we'd ideally close all other FDs inherited from the parent.
   102      // However, that's not worth the effort and CloexecNormalFile and
   103      // CloexecEventfd depend on that not happening.
   104    };
   105  
   106    Cleanup kill;
   107    if (dirfd.has_value()) {
   108      kill = ASSERT_NO_ERRNO_AND_VALUE(ForkAndExecveat(*dirfd, pathname, argv,
   109                                                       envv, flags, remap_stderr,
   110                                                       &child, &execve_errno));
   111    } else {
   112      kill = ASSERT_NO_ERRNO_AND_VALUE(
   113          ForkAndExec(pathname, argv, envv, remap_stderr, &child, &execve_errno));
   114    }
   115  
   116    ASSERT_EQ(0, execve_errno);
   117  
   118    // Not needed anymore.
   119    write_fd.reset();
   120  
   121    // Read stderr until the child exits.
   122    std::string output;
   123    constexpr int kSize = 128;
   124    char buf[kSize];
   125    int n;
   126    do {
   127      ASSERT_THAT(n = ReadFd(read_fd.get(), buf, kSize), SyscallSucceeds());
   128      if (n > 0) {
   129        output.append(buf, n);
   130      }
   131    } while (n > 0);
   132  
   133    int status;
   134    ASSERT_THAT(RetryEINTR(waitpid)(child, &status, 0), SyscallSucceeds());
   135    EXPECT_EQ(status, expect_status);
   136  
   137    // Process cleanup no longer needed.
   138    kill.Release();
   139  
   140    EXPECT_TRUE(absl::StrContains(output, expect_stderr)) << output;
   141  }
   142  
   143  void CheckExec(const std::string& filename, const ExecveArray& argv,
   144                 const ExecveArray& envv, int expect_status,
   145                 const std::string& expect_stderr) {
   146    CheckExecHelper(/*dirfd=*/absl::optional<int32_t>(), filename, argv, envv,
   147                    /*flags=*/0, expect_status, expect_stderr);
   148  }
   149  
   150  void CheckExecveat(const int32_t dirfd, const std::string& pathname,
   151                     const ExecveArray& argv, const ExecveArray& envv,
   152                     const int flags, int expect_status,
   153                     const std::string& expect_stderr) {
   154    CheckExecHelper(absl::optional<int32_t>(dirfd), pathname, argv, envv, flags,
   155                    expect_status, expect_stderr);
   156  }
   157  
   158  TEST(ExecTest, EmptyPath) {
   159    int execve_errno;
   160    ASSERT_NO_ERRNO_AND_VALUE(ForkAndExec("", {}, {}, nullptr, &execve_errno));
   161    EXPECT_EQ(execve_errno, ENOENT);
   162  }
   163  
   164  TEST(ExecTest, Basic) {
   165    CheckExec(RunfilePath(kBasicWorkload), {RunfilePath(kBasicWorkload)}, {},
   166              ArgEnvExitStatus(0, 0),
   167              absl::StrCat(RunfilePath(kBasicWorkload), "\n"));
   168  }
   169  
   170  TEST(ExecTest, OneArg) {
   171    CheckExec(RunfilePath(kBasicWorkload), {RunfilePath(kBasicWorkload), "1"}, {},
   172              ArgEnvExitStatus(1, 0),
   173              absl::StrCat(RunfilePath(kBasicWorkload), "\n1\n"));
   174  }
   175  
   176  TEST(ExecTest, FiveArg) {
   177    CheckExec(RunfilePath(kBasicWorkload),
   178              {RunfilePath(kBasicWorkload), "1", "2", "3", "4", "5"}, {},
   179              ArgEnvExitStatus(5, 0),
   180              absl::StrCat(RunfilePath(kBasicWorkload), "\n1\n2\n3\n4\n5\n"));
   181  }
   182  
   183  TEST(ExecTest, OneEnv) {
   184    CheckExec(RunfilePath(kBasicWorkload), {RunfilePath(kBasicWorkload)}, {"1"},
   185              ArgEnvExitStatus(0, 1),
   186              absl::StrCat(RunfilePath(kBasicWorkload), "\n1\n"));
   187  }
   188  
   189  TEST(ExecTest, FiveEnv) {
   190    CheckExec(RunfilePath(kBasicWorkload), {RunfilePath(kBasicWorkload)},
   191              {"1", "2", "3", "4", "5"}, ArgEnvExitStatus(0, 5),
   192              absl::StrCat(RunfilePath(kBasicWorkload), "\n1\n2\n3\n4\n5\n"));
   193  }
   194  
   195  TEST(ExecTest, OneArgOneEnv) {
   196    CheckExec(RunfilePath(kBasicWorkload), {RunfilePath(kBasicWorkload), "arg"},
   197              {"env"}, ArgEnvExitStatus(1, 1),
   198              absl::StrCat(RunfilePath(kBasicWorkload), "\narg\nenv\n"));
   199  }
   200  
   201  TEST(ExecTest, InterpreterScript) {
   202    CheckExec(RunfilePath(kExitScript), {RunfilePath(kExitScript), "25"}, {},
   203              ArgEnvExitStatus(25, 0), "");
   204  }
   205  
   206  std::string GetShortTestTmpdir() {
   207  #ifdef ANDROID
   208    // Using GetAbsoluteTestTmpdir() can cause the tmp directory path to exceed
   209    // the max length of the interpreter script path (127).
   210    //
   211    // However, existing systems that are built with the ANDROID configuration
   212    // have their temp directory in a different location, and must respect the
   213    // TEST_TMPDIR.
   214    return GetAbsoluteTestTmpdir();
   215  #else
   216    return "/tmp";
   217  #endif  // ANDROID
   218  }
   219  
   220  // Everything after the path in the interpreter script is a single argument.
   221  TEST(ExecTest, InterpreterScriptArgSplit) {
   222    // Symlink through /tmp to ensure the path is short enough.
   223    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateSymlinkTo(
   224        GetShortTestTmpdir(), RunfilePath(kBasicWorkload)));
   225  
   226    TempPath script = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   227        GetShortTestTmpdir(), absl::StrCat("#!", link.path(), " foo bar"), 0755));
   228  
   229    CheckExec(script.path(), {script.path()}, {}, ArgEnvExitStatus(2, 0),
   230              absl::StrCat(link.path(), "\nfoo bar\n", script.path(), "\n"));
   231  }
   232  
   233  // Original argv[0] is replaced with the script path.
   234  TEST(ExecTest, InterpreterScriptArgvZero) {
   235    // Symlink through /tmp to ensure the path is short enough.
   236    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateSymlinkTo(
   237        GetShortTestTmpdir(), RunfilePath(kBasicWorkload)));
   238  
   239    TempPath script = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   240        GetShortTestTmpdir(), absl::StrCat("#!", link.path()), 0755));
   241  
   242    CheckExec(script.path(), {"REPLACED"}, {}, ArgEnvExitStatus(1, 0),
   243              absl::StrCat(link.path(), "\n", script.path(), "\n"));
   244  }
   245  
   246  // Original argv[0] is replaced with the script path, exactly as passed to
   247  // execve.
   248  TEST(ExecTest, InterpreterScriptArgvZeroRelative) {
   249    // Symlink through /tmp to ensure the path is short enough.
   250    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateSymlinkTo(
   251        GetShortTestTmpdir(), RunfilePath(kBasicWorkload)));
   252  
   253    TempPath script = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   254        GetShortTestTmpdir(), absl::StrCat("#!", link.path()), 0755));
   255  
   256    auto cwd = ASSERT_NO_ERRNO_AND_VALUE(GetCWD());
   257    auto script_relative =
   258        ASSERT_NO_ERRNO_AND_VALUE(GetRelativePath(cwd, script.path()));
   259  
   260    CheckExec(script_relative, {"REPLACED"}, {}, ArgEnvExitStatus(1, 0),
   261              absl::StrCat(link.path(), "\n", script_relative, "\n"));
   262  }
   263  
   264  // argv[0] is added as the script path, even if there was none.
   265  TEST(ExecTest, InterpreterScriptArgvZeroAdded) {
   266    // Symlink through /tmp to ensure the path is short enough.
   267    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateSymlinkTo(
   268        GetShortTestTmpdir(), RunfilePath(kBasicWorkload)));
   269  
   270    TempPath script = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   271        GetShortTestTmpdir(), absl::StrCat("#!", link.path()), 0755));
   272  
   273    CheckExec(script.path(), {}, {}, ArgEnvExitStatus(1, 0),
   274              absl::StrCat(link.path(), "\n", script.path(), "\n"));
   275  }
   276  
   277  // A NUL byte in the script line ends parsing.
   278  TEST(ExecTest, InterpreterScriptArgNUL) {
   279    // Symlink through /tmp to ensure the path is short enough.
   280    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateSymlinkTo(
   281        GetShortTestTmpdir(), RunfilePath(kBasicWorkload)));
   282  
   283    TempPath script = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   284        GetShortTestTmpdir(),
   285        absl::StrCat("#!", link.path(), " foo", std::string(1, '\0'), "bar"),
   286        0755));
   287  
   288    CheckExec(script.path(), {script.path()}, {}, ArgEnvExitStatus(2, 0),
   289              absl::StrCat(link.path(), "\nfoo\n", script.path(), "\n"));
   290  }
   291  
   292  // Trailing whitespace following interpreter path is ignored.
   293  TEST(ExecTest, InterpreterScriptTrailingWhitespace) {
   294    // Symlink through /tmp to ensure the path is short enough.
   295    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateSymlinkTo(
   296        GetShortTestTmpdir(), RunfilePath(kBasicWorkload)));
   297  
   298    TempPath script = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   299        GetShortTestTmpdir(), absl::StrCat("#!", link.path(), "  \n"), 0755));
   300  
   301    CheckExec(script.path(), {script.path()}, {}, ArgEnvExitStatus(1, 0),
   302              absl::StrCat(link.path(), "\n", script.path(), "\n"));
   303  }
   304  
   305  // Multiple whitespace characters between interpreter and arg allowed.
   306  TEST(ExecTest, InterpreterScriptArgWhitespace) {
   307    // Symlink through /tmp to ensure the path is short enough.
   308    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateSymlinkTo(
   309        GetShortTestTmpdir(), RunfilePath(kBasicWorkload)));
   310  
   311    TempPath script = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   312        GetShortTestTmpdir(), absl::StrCat("#!", link.path(), "  foo"), 0755));
   313  
   314    CheckExec(script.path(), {script.path()}, {}, ArgEnvExitStatus(2, 0),
   315              absl::StrCat(link.path(), "\nfoo\n", script.path(), "\n"));
   316  }
   317  
   318  TEST(ExecTest, InterpreterScriptNoPath) {
   319    TempPath script = ASSERT_NO_ERRNO_AND_VALUE(
   320        TempPath::CreateFileWith(GetShortTestTmpdir(), "#!\n\n", 0755));
   321  
   322    int execve_errno;
   323    ASSERT_NO_ERRNO_AND_VALUE(
   324        ForkAndExec(script.path(), {script.path()}, {}, nullptr, &execve_errno));
   325    EXPECT_EQ(execve_errno, ENOEXEC);
   326  }
   327  
   328  // AT_EXECFN is the path passed to execve.
   329  TEST(ExecTest, ExecFn) {
   330    // Symlink through /tmp to ensure the path is short enough.
   331    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateSymlinkTo(
   332        GetShortTestTmpdir(), RunfilePath(kStateWorkload)));
   333  
   334    TempPath script = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   335        GetShortTestTmpdir(), absl::StrCat("#!", link.path(), " PrintExecFn"),
   336        0755));
   337  
   338    // Pass the script as a relative path and assert that is what appears in
   339    // AT_EXECFN.
   340    auto cwd = ASSERT_NO_ERRNO_AND_VALUE(GetCWD());
   341    auto script_relative =
   342        ASSERT_NO_ERRNO_AND_VALUE(GetRelativePath(cwd, script.path()));
   343  
   344    CheckExec(script_relative, {script_relative}, {}, ArgEnvExitStatus(0, 0),
   345              absl::StrCat(script_relative, "\n"));
   346  }
   347  
   348  TEST(ExecTest, ExecName) {
   349    std::string path = RunfilePath(kStateWorkload);
   350  
   351    CheckExec(path, {path, "PrintExecName"}, {}, ArgEnvExitStatus(0, 0),
   352              absl::StrCat(Basename(path).substr(0, 15), "\n"));
   353  }
   354  
   355  TEST(ExecTest, ExecNameScript) {
   356    // Symlink through /tmp to ensure the path is short enough.
   357    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateSymlinkTo(
   358        GetShortTestTmpdir(), RunfilePath(kStateWorkload)));
   359  
   360    TempPath script = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   361        GetShortTestTmpdir(), absl::StrCat("#!", link.path(), " PrintExecName"),
   362        0755));
   363  
   364    std::string script_path = script.path();
   365  
   366    CheckExec(script_path, {script_path}, {}, ArgEnvExitStatus(0, 0),
   367              absl::StrCat(Basename(script_path).substr(0, 15), "\n"));
   368  }
   369  
   370  // execve may be called by a multithreaded process.
   371  TEST(ExecTest, WithSiblingThread) {
   372    CheckExec("/proc/self/exe", {"/proc/self/exe", kExecWithThread}, {},
   373              W_EXITCODE(42, 0), "");
   374  }
   375  
   376  // execve may be called from a thread other than the leader of a multithreaded
   377  // process.
   378  TEST(ExecTest, FromSiblingThread) {
   379    CheckExec("/proc/self/exe", {"/proc/self/exe", kExecFromThread}, {},
   380              W_EXITCODE(42, 0), "");
   381  }
   382  
   383  TEST(ExecTest, NotFound) {
   384    char* const argv[] = {nullptr};
   385    char* const envp[] = {nullptr};
   386    EXPECT_THAT(execve("/file/does/not/exist", argv, envp),
   387                SyscallFailsWithErrno(ENOENT));
   388  }
   389  
   390  TEST(ExecTest, NoExecPerm) {
   391    char* const argv[] = {nullptr};
   392    char* const envp[] = {nullptr};
   393    auto f = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
   394    EXPECT_THAT(execve(f.path().c_str(), argv, envp),
   395                SyscallFailsWithErrno(EACCES));
   396  }
   397  
   398  // A signal handler we never expect to be called.
   399  void SignalHandler(int signo) {
   400    std::cerr << "Signal " << signo << " raised." << std::endl;
   401    exit(1);
   402  }
   403  
   404  // Signal handlers are reset on execve(2), unless they have default or ignored
   405  // disposition.
   406  TEST(ExecStateTest, HandlerReset) {
   407    struct sigaction sa;
   408    sa.sa_handler = SignalHandler;
   409    ASSERT_THAT(sigaction(SIGUSR1, &sa, nullptr), SyscallSucceeds());
   410  
   411    ExecveArray args = {
   412        RunfilePath(kStateWorkload),
   413        "CheckSigHandler",
   414        absl::StrCat(SIGUSR1),
   415        absl::StrCat(absl::Hex(reinterpret_cast<uintptr_t>(SIG_DFL))),
   416    };
   417  
   418    CheckExec(RunfilePath(kStateWorkload), args, {}, W_EXITCODE(0, 0), "");
   419  }
   420  
   421  // Ignored signal dispositions are not reset.
   422  TEST(ExecStateTest, IgnorePreserved) {
   423    struct sigaction sa;
   424    sa.sa_handler = SIG_IGN;
   425    ASSERT_THAT(sigaction(SIGUSR1, &sa, nullptr), SyscallSucceeds());
   426  
   427    ExecveArray args = {
   428        RunfilePath(kStateWorkload),
   429        "CheckSigHandler",
   430        absl::StrCat(SIGUSR1),
   431        absl::StrCat(absl::Hex(reinterpret_cast<uintptr_t>(SIG_IGN))),
   432    };
   433  
   434    CheckExec(RunfilePath(kStateWorkload), args, {}, W_EXITCODE(0, 0), "");
   435  }
   436  
   437  // Signal masks are not reset on exec
   438  TEST(ExecStateTest, SignalMask) {
   439    sigset_t s;
   440    sigemptyset(&s);
   441    sigaddset(&s, SIGUSR1);
   442    ASSERT_THAT(sigprocmask(SIG_BLOCK, &s, nullptr), SyscallSucceeds());
   443  
   444    ExecveArray args = {
   445        RunfilePath(kStateWorkload),
   446        "CheckSigBlocked",
   447        absl::StrCat(SIGUSR1),
   448    };
   449  
   450    CheckExec(RunfilePath(kStateWorkload), args, {}, W_EXITCODE(0, 0), "");
   451  }
   452  
   453  // itimers persist across execve.
   454  // N.B. Timers created with timer_create(2) should not be preserved!
   455  TEST(ExecStateTest, ItimerPreserved) {
   456    // The fork in ForkAndExec clears itimers, so only set them up after fork.
   457    auto setup_itimer = [] {
   458      // Ignore SIGALRM, as we don't actually care about timer
   459      // expirations.
   460      struct sigaction sa;
   461      sa.sa_handler = SIG_IGN;
   462      int ret = sigaction(SIGALRM, &sa, nullptr);
   463      if (ret < 0) {
   464        _exit(errno);
   465      }
   466  
   467      struct itimerval itv;
   468      itv.it_interval.tv_sec = 1;
   469      itv.it_interval.tv_usec = 0;
   470      itv.it_value.tv_sec = 1;
   471      itv.it_value.tv_usec = 0;
   472      ret = setitimer(ITIMER_REAL, &itv, nullptr);
   473      if (ret < 0) {
   474        _exit(errno);
   475      }
   476    };
   477  
   478    std::string filename = RunfilePath(kStateWorkload);
   479    ExecveArray argv = {
   480        filename,
   481        "CheckItimerEnabled",
   482        absl::StrCat(ITIMER_REAL),
   483    };
   484  
   485    pid_t child;
   486    int execve_errno;
   487    auto kill = ASSERT_NO_ERRNO_AND_VALUE(
   488        ForkAndExec(filename, argv, {}, setup_itimer, &child, &execve_errno));
   489    ASSERT_EQ(0, execve_errno);
   490  
   491    int status;
   492    ASSERT_THAT(RetryEINTR(waitpid)(child, &status, 0), SyscallSucceeds());
   493    EXPECT_EQ(0, status);
   494  
   495    // Process cleanup no longer needed.
   496    kill.Release();
   497  }
   498  
   499  TEST(ProcSelfExe, ChangesAcrossExecve) {
   500    // See exec_proc_exe_workload for more details. We simply
   501    // assert that the /proc/self/exe link changes across execve.
   502    CheckExec(RunfilePath(kProcExeWorkload),
   503              {RunfilePath(kProcExeWorkload),
   504               ASSERT_NO_ERRNO_AND_VALUE(ProcessExePath(getpid()))},
   505              {}, W_EXITCODE(0, 0), "");
   506  }
   507  
   508  TEST(ExecTest, CloexecNormalFile) {
   509    TempPath tempFile = ASSERT_NO_ERRNO_AND_VALUE(
   510        TempPath::CreateFileWith(GetAbsoluteTestTmpdir(), "bar", 0755));
   511    const FileDescriptor fd_closed_on_exec =
   512        ASSERT_NO_ERRNO_AND_VALUE(Open(tempFile.path(), O_RDONLY | O_CLOEXEC));
   513  
   514    CheckExec(RunfilePath(kAssertClosedWorkload),
   515              {RunfilePath(kAssertClosedWorkload),
   516               absl::StrCat(fd_closed_on_exec.get())},
   517              {}, W_EXITCODE(0, 0), "");
   518  
   519    // The assert closed workload exits with code 2 if the file still exists.  We
   520    // can use this to do a negative test.
   521    const FileDescriptor fd_open_on_exec =
   522        ASSERT_NO_ERRNO_AND_VALUE(Open(tempFile.path(), O_RDONLY));
   523  
   524    CheckExec(
   525        RunfilePath(kAssertClosedWorkload),
   526        {RunfilePath(kAssertClosedWorkload), absl::StrCat(fd_open_on_exec.get())},
   527        {}, W_EXITCODE(2, 0), "");
   528  }
   529  
   530  TEST(ExecTest, CloexecEventfd) {
   531    int efd;
   532    ASSERT_THAT(efd = eventfd(0, EFD_CLOEXEC), SyscallSucceeds());
   533    FileDescriptor fd(efd);
   534  
   535    CheckExec(RunfilePath(kAssertClosedWorkload),
   536              {RunfilePath(kAssertClosedWorkload), absl::StrCat(fd.get())}, {},
   537              W_EXITCODE(0, 0), "");
   538  }
   539  
   540  constexpr int kLinuxMaxSymlinks = 40;
   541  
   542  TEST(ExecTest, SymlinkLimitExceeded) {
   543    std::string path = RunfilePath(kBasicWorkload);
   544  
   545    // Hold onto TempPath objects so they are not destructed prematurely.
   546    std::vector<TempPath> symlinks;
   547    for (int i = 0; i < kLinuxMaxSymlinks + 1; i++) {
   548      symlinks.push_back(ASSERT_NO_ERRNO_AND_VALUE(
   549          TempPath::CreateSymlinkTo(GetAbsoluteTestTmpdir(), path)));
   550      path = symlinks[i].path();
   551    }
   552  
   553    int execve_errno;
   554    ASSERT_NO_ERRNO_AND_VALUE(
   555        ForkAndExec(path, {path}, {}, /*child=*/nullptr, &execve_errno));
   556    EXPECT_EQ(execve_errno, ELOOP);
   557  }
   558  
   559  TEST(ExecTest, SymlinkLimitRefreshedForInterpreter) {
   560    std::string tmp_dir = GetAbsoluteTestTmpdir();
   561    std::string interpreter_path = "/bin/echo";
   562    TempPath script = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFileWith(
   563        tmp_dir, absl::StrCat("#!", interpreter_path), 0755));
   564    std::string script_path = script.path();
   565  
   566    // Hold onto TempPath objects so they are not destructed prematurely.
   567    std::vector<TempPath> interpreter_symlinks;
   568    std::vector<TempPath> script_symlinks;
   569    // Replace both the interpreter and script paths with symlink chains of just
   570    // over half the symlink limit each; this is the minimum required to test that
   571    // the symlink limit applies separately to each traversal, while tolerating
   572    // some symlinks in the resolution of (the original) interpreter_path and
   573    // script_path.
   574    for (int i = 0; i < (kLinuxMaxSymlinks / 2) + 1; i++) {
   575      interpreter_symlinks.push_back(ASSERT_NO_ERRNO_AND_VALUE(
   576          TempPath::CreateSymlinkTo(tmp_dir, interpreter_path)));
   577      interpreter_path = interpreter_symlinks[i].path();
   578      script_symlinks.push_back(ASSERT_NO_ERRNO_AND_VALUE(
   579          TempPath::CreateSymlinkTo(tmp_dir, script_path)));
   580      script_path = script_symlinks[i].path();
   581    }
   582  
   583    CheckExec(script_path, {script_path}, {}, ArgEnvExitStatus(0, 0), "");
   584  }
   585  
   586  TEST(ExecveatTest, BasicWithFDCWD) {
   587    std::string path = RunfilePath(kBasicWorkload);
   588    CheckExecveat(AT_FDCWD, path, {path}, {}, /*flags=*/0, ArgEnvExitStatus(0, 0),
   589                  absl::StrCat(path, "\n"));
   590  }
   591  
   592  TEST(ExecveatTest, Basic) {
   593    std::string absolute_path = RunfilePath(kBasicWorkload);
   594    std::string parent_dir = std::string(Dirname(absolute_path));
   595    std::string base = std::string(Basename(absolute_path));
   596    const FileDescriptor dirfd =
   597        ASSERT_NO_ERRNO_AND_VALUE(Open(parent_dir, O_DIRECTORY));
   598  
   599    CheckExecveat(dirfd.get(), base, {absolute_path}, {}, /*flags=*/0,
   600                  ArgEnvExitStatus(0, 0), absl::StrCat(absolute_path, "\n"));
   601  }
   602  
   603  TEST(ExecveatTest, FDNotADirectory) {
   604    std::string absolute_path = RunfilePath(kBasicWorkload);
   605    std::string base = std::string(Basename(absolute_path));
   606    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(absolute_path, 0));
   607  
   608    int execve_errno;
   609    ASSERT_NO_ERRNO_AND_VALUE(ForkAndExecveat(fd.get(), base, {absolute_path}, {},
   610                                              /*flags=*/0, /*child=*/nullptr,
   611                                              &execve_errno));
   612    EXPECT_EQ(execve_errno, ENOTDIR);
   613  }
   614  
   615  TEST(ExecveatTest, AbsolutePathWithFDCWD) {
   616    std::string path = RunfilePath(kBasicWorkload);
   617    CheckExecveat(AT_FDCWD, path, {path}, {}, ArgEnvExitStatus(0, 0), 0,
   618                  absl::StrCat(path, "\n"));
   619  }
   620  
   621  TEST(ExecveatTest, AbsolutePath) {
   622    std::string path = RunfilePath(kBasicWorkload);
   623    // File descriptor should be ignored when an absolute path is given.
   624    const int32_t badFD = -1;
   625    CheckExecveat(badFD, path, {path}, {}, ArgEnvExitStatus(0, 0), 0,
   626                  absl::StrCat(path, "\n"));
   627  }
   628  
   629  TEST(ExecveatTest, EmptyPathBasic) {
   630    std::string path = RunfilePath(kBasicWorkload);
   631    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(path, O_PATH));
   632  
   633    CheckExecveat(fd.get(), "", {path}, {}, AT_EMPTY_PATH, ArgEnvExitStatus(0, 0),
   634                  absl::StrCat(path, "\n"));
   635  }
   636  
   637  TEST(ExecveatTest, EmptyPathWithDirFD) {
   638    std::string path = RunfilePath(kBasicWorkload);
   639    std::string parent_dir = std::string(Dirname(path));
   640    const FileDescriptor dirfd =
   641        ASSERT_NO_ERRNO_AND_VALUE(Open(parent_dir, O_DIRECTORY));
   642  
   643    int execve_errno;
   644    ASSERT_NO_ERRNO_AND_VALUE(ForkAndExecveat(dirfd.get(), "", {path}, {},
   645                                              AT_EMPTY_PATH,
   646                                              /*child=*/nullptr, &execve_errno));
   647    EXPECT_EQ(execve_errno, EACCES);
   648  }
   649  
   650  TEST(ExecveatTest, EmptyPathWithoutEmptyPathFlag) {
   651    std::string path = RunfilePath(kBasicWorkload);
   652    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(path, O_PATH));
   653  
   654    int execve_errno;
   655    ASSERT_NO_ERRNO_AND_VALUE(ForkAndExecveat(
   656        fd.get(), "", {path}, {}, /*flags=*/0, /*child=*/nullptr, &execve_errno));
   657    EXPECT_EQ(execve_errno, ENOENT);
   658  }
   659  
   660  TEST(ExecveatTest, AbsolutePathWithEmptyPathFlag) {
   661    std::string path = RunfilePath(kBasicWorkload);
   662    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(path, O_PATH));
   663  
   664    CheckExecveat(fd.get(), path, {path}, {}, AT_EMPTY_PATH,
   665                  ArgEnvExitStatus(0, 0), absl::StrCat(path, "\n"));
   666  }
   667  
   668  TEST(ExecveatTest, RelativePathWithEmptyPathFlag) {
   669    std::string absolute_path = RunfilePath(kBasicWorkload);
   670    std::string parent_dir = std::string(Dirname(absolute_path));
   671    std::string base = std::string(Basename(absolute_path));
   672    const FileDescriptor dirfd =
   673        ASSERT_NO_ERRNO_AND_VALUE(Open(parent_dir, O_DIRECTORY));
   674  
   675    CheckExecveat(dirfd.get(), base, {absolute_path}, {}, AT_EMPTY_PATH,
   676                  ArgEnvExitStatus(0, 0), absl::StrCat(absolute_path, "\n"));
   677  }
   678  
   679  TEST(ExecveatTest, SymlinkNoFollowWithRelativePath) {
   680    std::string parent_dir = GetAbsoluteTestTmpdir();
   681    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(
   682        TempPath::CreateSymlinkTo(parent_dir, RunfilePath(kBasicWorkload)));
   683    const FileDescriptor dirfd =
   684        ASSERT_NO_ERRNO_AND_VALUE(Open(parent_dir, O_DIRECTORY));
   685    std::string base = std::string(Basename(link.path()));
   686  
   687    int execve_errno;
   688    ASSERT_NO_ERRNO_AND_VALUE(ForkAndExecveat(dirfd.get(), base, {base}, {},
   689                                              AT_SYMLINK_NOFOLLOW,
   690                                              /*child=*/nullptr, &execve_errno));
   691    EXPECT_EQ(execve_errno, ELOOP);
   692  }
   693  
   694  TEST(ExecveatTest, UnshareFiles) {
   695    TempPath tempFile = ASSERT_NO_ERRNO_AND_VALUE(
   696        TempPath::CreateFileWith(GetAbsoluteTestTmpdir(), "bar", 0755));
   697    const FileDescriptor fd_closed_on_exec =
   698        ASSERT_NO_ERRNO_AND_VALUE(Open(tempFile.path(), O_RDONLY | O_CLOEXEC));
   699  
   700    ExecveArray argv = {"test"};
   701    ExecveArray envp;
   702    std::string child_path = RunfilePath(kBasicWorkload);
   703    pid_t child =
   704        syscall(__NR_clone, SIGCHLD | CLONE_VFORK | CLONE_FILES, 0, 0, 0, 0);
   705    if (child == 0) {
   706      execve(child_path.c_str(), argv.get(), envp.get());
   707      _exit(1);
   708    }
   709    ASSERT_THAT(child, SyscallSucceeds());
   710  
   711    int status;
   712    ASSERT_THAT(RetryEINTR(waitpid)(child, &status, 0), SyscallSucceeds());
   713    EXPECT_EQ(status, 0);
   714  
   715    struct stat st;
   716    EXPECT_THAT(fstat(fd_closed_on_exec.get(), &st), SyscallSucceeds());
   717  }
   718  
   719  TEST(ExecveatTest, SymlinkNoFollowWithAbsolutePath) {
   720    std::string parent_dir = GetAbsoluteTestTmpdir();
   721    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(
   722        TempPath::CreateSymlinkTo(parent_dir, RunfilePath(kBasicWorkload)));
   723    std::string path = link.path();
   724  
   725    int execve_errno;
   726    ASSERT_NO_ERRNO_AND_VALUE(ForkAndExecveat(AT_FDCWD, path, {path}, {},
   727                                              AT_SYMLINK_NOFOLLOW,
   728                                              /*child=*/nullptr, &execve_errno));
   729    EXPECT_EQ(execve_errno, ELOOP);
   730  }
   731  
   732  TEST(ExecveatTest, SymlinkNoFollowAndEmptyPath) {
   733    TempPath link = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateSymlinkTo(
   734        GetAbsoluteTestTmpdir(), RunfilePath(kBasicWorkload)));
   735    std::string path = link.path();
   736    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(path, 0));
   737  
   738    CheckExecveat(fd.get(), "", {path}, {}, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW,
   739                  ArgEnvExitStatus(0, 0), absl::StrCat(path, "\n"));
   740  }
   741  
   742  TEST(ExecveatTest, SymlinkNoFollowIgnoreSymlinkAncestor) {
   743    TempPath parent_link = ASSERT_NO_ERRNO_AND_VALUE(
   744        TempPath::CreateSymlinkTo(GetAbsoluteTestTmpdir(), "/bin"));
   745    std::string path_with_symlink = JoinPath(parent_link.path(), "echo");
   746  
   747    CheckExecveat(AT_FDCWD, path_with_symlink, {path_with_symlink}, {},
   748                  AT_SYMLINK_NOFOLLOW, ArgEnvExitStatus(0, 0), "");
   749  }
   750  
   751  TEST(ExecveatTest, SymlinkNoFollowWithNormalFile) {
   752    const FileDescriptor dirfd =
   753        ASSERT_NO_ERRNO_AND_VALUE(Open("/bin", O_DIRECTORY));
   754  
   755    CheckExecveat(dirfd.get(), "echo", {"echo"}, {}, AT_SYMLINK_NOFOLLOW,
   756                  ArgEnvExitStatus(0, 0), "");
   757  }
   758  
   759  TEST(ExecveatTest, BasicWithCloexecFD) {
   760    std::string path = RunfilePath(kBasicWorkload);
   761    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(path, O_CLOEXEC));
   762  
   763    CheckExecveat(fd.get(), "", {path}, {}, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH,
   764                  ArgEnvExitStatus(0, 0), absl::StrCat(path, "\n"));
   765  }
   766  
   767  TEST(ExecveatTest, InterpreterScriptWithCloexecFD) {
   768    std::string path = RunfilePath(kExitScript);
   769    const FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(path, O_CLOEXEC));
   770  
   771    int execve_errno;
   772    ASSERT_NO_ERRNO_AND_VALUE(ForkAndExecveat(fd.get(), "", {path}, {},
   773                                              AT_EMPTY_PATH, /*child=*/nullptr,
   774                                              &execve_errno));
   775    EXPECT_EQ(execve_errno, ENOENT);
   776  }
   777  
   778  TEST(ExecveatTest, InterpreterScriptWithCloexecDirFD) {
   779    std::string absolute_path = RunfilePath(kExitScript);
   780    std::string parent_dir = std::string(Dirname(absolute_path));
   781    std::string base = std::string(Basename(absolute_path));
   782    const FileDescriptor dirfd =
   783        ASSERT_NO_ERRNO_AND_VALUE(Open(parent_dir, O_CLOEXEC | O_DIRECTORY));
   784  
   785    int execve_errno;
   786    ASSERT_NO_ERRNO_AND_VALUE(ForkAndExecveat(dirfd.get(), base, {base}, {},
   787                                              /*flags=*/0, /*child=*/nullptr,
   788                                              &execve_errno));
   789    EXPECT_EQ(execve_errno, ENOENT);
   790  }
   791  
   792  TEST(ExecveatTest, InvalidFlags) {
   793    int execve_errno;
   794    ASSERT_NO_ERRNO_AND_VALUE(ForkAndExecveat(
   795        /*dirfd=*/-1, "", {}, {}, /*flags=*/0xFFFF, /*child=*/nullptr,
   796        &execve_errno));
   797    EXPECT_EQ(execve_errno, EINVAL);
   798  }
   799  
   800  // Priority consistent across calls to execve()
   801  TEST(GetpriorityTest, ExecveMaintainsPriority) {
   802    int prio = 16;
   803    ASSERT_THAT(setpriority(PRIO_PROCESS, getpid(), prio), SyscallSucceeds());
   804  
   805    // To avoid trying to use negative exit values, check for
   806    // 20 - prio. Since prio should always be in the range [-20, 19],
   807    // this leave expected_exit_code in the range [1, 40].
   808    int expected_exit_code = 20 - prio;
   809  
   810    // Program run (priority_execve) will exit(X) where
   811    // X=getpriority(PRIO_PROCESS,0). Check that this exit value is prio.
   812    CheckExec(RunfilePath(kPriorityWorkload), {RunfilePath(kPriorityWorkload)},
   813              {}, W_EXITCODE(expected_exit_code, 0), "");
   814  }
   815  
   816  void ExecWithThread() {
   817    // Used to ensure that the thread has actually started.
   818    absl::Mutex mu;
   819    bool started = false;
   820  
   821    ScopedThread t([&] {
   822      mu.Lock();
   823      started = true;
   824      mu.Unlock();
   825  
   826      while (true) {
   827        pause();
   828      }
   829    });
   830  
   831    mu.LockWhen(absl::Condition(&started));
   832    mu.Unlock();
   833  
   834    const ExecveArray argv = {"/proc/self/exe", kExit42};
   835    const ExecveArray envv;
   836  
   837    execve("/proc/self/exe", argv.get(), envv.get());
   838    exit(errno);
   839  }
   840  
   841  void ExecFromThread() {
   842    ScopedThread t([] {
   843      const ExecveArray argv = {"/proc/self/exe", kExit42};
   844      const ExecveArray envv;
   845  
   846      execve("/proc/self/exe", argv.get(), envv.get());
   847      exit(errno);
   848    });
   849  
   850    while (true) {
   851      pause();
   852    }
   853  }
   854  
   855  bool ValidateProcCmdlineVsArgv(const int argc, const char* const* argv) {
   856    auto contents_or = GetContents("/proc/self/cmdline");
   857    if (!contents_or.ok()) {
   858      std::cerr << "Unable to get /proc/self/cmdline: " << contents_or.error()
   859                << std::endl;
   860      return false;
   861    }
   862    auto contents = contents_or.ValueOrDie();
   863    if (contents.back() != '\0') {
   864      std::cerr << "Non-null terminated /proc/self/cmdline!" << std::endl;
   865      return false;
   866    }
   867    contents.pop_back();
   868    std::vector<std::string> procfs_cmdline = absl::StrSplit(contents, '\0');
   869  
   870    if (static_cast<int>(procfs_cmdline.size()) != argc) {
   871      std::cerr << "argc = " << argc << " != " << procfs_cmdline.size()
   872                << std::endl;
   873      return false;
   874    }
   875  
   876    for (int i = 0; i < argc; ++i) {
   877      if (procfs_cmdline[i] != argv[i]) {
   878        std::cerr << "Procfs command line argument " << i << " mismatch "
   879                  << procfs_cmdline[i] << " != " << argv[i] << std::endl;
   880        return false;
   881      }
   882    }
   883    return true;
   884  }
   885  
   886  }  // namespace
   887  
   888  }  // namespace testing
   889  }  // namespace gvisor
   890  
   891  int main(int argc, char** argv) {
   892    // Start by validating that the stack argv is consistent with procfs.
   893    if (!gvisor::testing::ValidateProcCmdlineVsArgv(argc, argv)) {
   894      return 1;
   895    }
   896  
   897    // Some of these tests require no background threads, so check for them before
   898    // TestInit.
   899    for (int i = 0; i < argc; i++) {
   900      absl::string_view arg(argv[i]);
   901  
   902      if (arg == gvisor::testing::kExit42) {
   903        return 42;
   904      }
   905      if (arg == gvisor::testing::kExecWithThread) {
   906        gvisor::testing::ExecWithThread();
   907        return 1;
   908      }
   909      if (arg == gvisor::testing::kExecFromThread) {
   910        gvisor::testing::ExecFromThread();
   911        return 1;
   912      }
   913    }
   914  
   915    gvisor::testing::TestInit(&argc, &argv);
   916    return gvisor::testing::RunAllTests();
   917  }