1717#include < errno.h>
1818#include < fcntl.h>
1919#include < sys/eventfd.h>
20+ #include < sys/mman.h>
2021#include < sys/ptrace.h>
2122#include < sys/resource.h>
2223#include < sys/time.h>
3334#include " gmock/gmock.h"
3435#include " gtest/gtest.h"
3536#include " absl/strings/match.h"
37+ #include " absl/strings/numbers.h"
3638#include " absl/strings/str_cat.h"
39+ #include " absl/strings/str_format.h"
3740#include " absl/strings/str_split.h"
3841#include " absl/strings/string_view.h"
3942#include " absl/synchronization/mutex.h"
4043#include " absl/types/optional.h"
4144#include " test/util/file_descriptor.h"
4245#include " test/util/fs_util.h"
46+ #include " test/util/logging.h"
47+ #include " test/util/memory_util.h"
4348#include " test/util/multiprocess_util.h"
4449#include " test/util/posix_error.h"
50+ #include " test/util/save_util.h"
4551#include " test/util/temp_path.h"
4652#include " test/util/test_util.h"
4753#include " test/util/thread_util.h"
@@ -63,6 +69,9 @@ constexpr char kPriorityWorkload[] = "test/syscalls/linux/priority_execve";
6369constexpr char kExit42 [] = " --exec_exit_42" ;
6470constexpr char kExecWithThread [] = " --exec_exec_with_thread" ;
6571constexpr char kExecFromThread [] = " --exec_exec_from_thread" ;
72+ constexpr char kExecInParent [] = " --exec_exec_in_parent" ;
73+ constexpr char kWriteAndWaitForPid [] = " --exec_write_and_wait_for_pid" ;
74+ const unsigned int mmapAddr = 0xD0000000 ;
6675
6776// Runs file specified by dirfd and pathname with argv and checks that the exit
6877// status is expect_status and that stderr contains expect_stderr.
@@ -851,6 +860,75 @@ TEST(ExecTest, Setpgid) {
851860 EXPECT_THAT (setpgid (getpid (), pid), SyscallSucceeds ());
852861}
853862
863+ TEST (ExecTest, ReadProcMemAfterExecFromChild) {
864+ // Fork and exec in the parent process.
865+ CheckExec (" /proc/self/exe" , {" /proc/self/exe" , kExecInParent }, {},
866+ W_EXITCODE (42 , 0 ), " " );
867+ }
868+
869+ void execInParent () {
870+ auto memfd = ASSERT_NO_ERRNO_AND_VALUE (Open (" /proc/self/mem" , O_RDONLY));
871+ int pipe_fd[2 ] = {};
872+ ASSERT_THAT (pipe (pipe_fd), SyscallSucceeds ());
873+
874+ const auto readSecret = [&] {
875+ // Close writing end of the pipe.
876+ close (pipe_fd[1 ]);
877+ // Await parent OK to read the secret.
878+ char ok = 0 ;
879+ TEST_CHECK (ReadFd (pipe_fd[0 ], &ok, sizeof (ok)) == sizeof (ok));
880+ // Close the reading end of the pipe.
881+ TEST_PCHECK (close (pipe_fd[0 ]) == 0 );
882+ // Parent sent the signal. Read the secret.
883+ // Use /proc/mem fd from parent to try to read the secret.
884+ char secret[] = " secret" ;
885+ char output[sizeof (secret)];
886+ TEST_PCHECK_MSG (
887+ pread (memfd.get (), output, sizeof (output), mmapAddr) != sizeof (secret),
888+ " pread succeeded. It should have failed." );
889+ };
890+ pid_t pid = fork ();
891+ // In child process.
892+ if (pid == 0 ) {
893+ readSecret ();
894+ TEST_CHECK_MSG (!::testing::Test::HasFailure (),
895+ " EXPECT*/ASSERT* failed. These are not async-signal-safe "
896+ " and must not be called from fn." );
897+ _exit (0 );
898+ }
899+ // In parent process.
900+ MaybeSave ();
901+ ASSERT_THAT (pid, SyscallSucceeds ());
902+
903+ // Execve with args{function name, child_pid, pipe_fd[1]}
904+ const ExecveArray argv = {" /proc/self/exe" , kWriteAndWaitForPid ,
905+ absl::StrCat (pid) /* child_pid*/ ,
906+ absl::StrCat (pipe_fd[1 ])};
907+ const ExecveArray envv;
908+ execve (" /proc/self/exe" , argv.get (), envv.get ());
909+ }
910+
911+ void writeAndWaitForPid (int child_pid, int pipe_fd) {
912+ // mmap the same address that the child process will try to read.
913+ const Mapping m = ASSERT_NO_ERRNO_AND_VALUE (
914+ Mmap (reinterpret_cast <void *>(mmapAddr), kPageSize , PROT_READ | PROT_WRITE,
915+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1 , 0 ));
916+ const char secret[] = " secret" ;
917+ absl::SNPrintF ((char *)m.addr (), sizeof (secret), " %s" , secret);
918+
919+ // Tell the child process to read the secret.
920+ char ok = 1 ;
921+ EXPECT_THAT (WriteFd (pipe_fd, &ok, sizeof (ok)),
922+ SyscallSucceedsWithValue (sizeof (ok)));
923+ EXPECT_THAT (close (pipe_fd), SyscallSucceeds ());
924+
925+ // Wait for child process to read the exit.
926+ int status;
927+ ASSERT_THAT (waitpid (child_pid, &status, 0 ), SyscallSucceeds ());
928+ ASSERT_TRUE (WIFEXITED (status) && WEXITSTATUS (status) == 0 );
929+ exit (42 );
930+ }
931+
854932void ExecWithThread () {
855933 // Used to ensure that the thread has actually started.
856934 absl::Mutex mu;
@@ -948,6 +1026,22 @@ int main(int argc, char** argv) {
9481026 gvisor::testing::ExecFromThread ();
9491027 return 1 ;
9501028 }
1029+ if (arg == gvisor::testing::kExecInParent ) {
1030+ gvisor::testing::execInParent ();
1031+ return 1 ;
1032+ }
1033+ if (arg == gvisor::testing::kWriteAndWaitForPid ) {
1034+ int pid;
1035+ if (!absl::SimpleAtoi (argv[i + 1 ], &pid)) {
1036+ return 1 ;
1037+ }
1038+ int fd;
1039+ if (!absl::SimpleAtoi (argv[i + 2 ], &fd)) {
1040+ return 1 ;
1041+ }
1042+ gvisor::testing::writeAndWaitForPid (pid, fd);
1043+ return 1 ;
1044+ }
9511045 }
9521046
9531047 gvisor::testing::TestInit (&argc, &argv);
0 commit comments