| Index: sandbox/linux/services/unix_domain_socket_unittest.cc
|
| diff --git a/sandbox/linux/services/unix_domain_socket_unittest.cc b/sandbox/linux/services/unix_domain_socket_unittest.cc
|
| deleted file mode 100644
|
| index dafa91d44fd3b544035391c06ed85f0781948b9f..0000000000000000000000000000000000000000
|
| --- a/sandbox/linux/services/unix_domain_socket_unittest.cc
|
| +++ /dev/null
|
| @@ -1,267 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include <sched.h>
|
| -#include <stdio.h>
|
| -#include <string.h>
|
| -#include <sys/socket.h>
|
| -#include <sys/syscall.h>
|
| -#include <sys/wait.h>
|
| -#include <unistd.h>
|
| -
|
| -#include <vector>
|
| -
|
| -#include "base/files/scoped_file.h"
|
| -#include "base/logging.h"
|
| -#include "base/memory/scoped_vector.h"
|
| -#include "base/posix/eintr_wrapper.h"
|
| -#include "base/posix/unix_domain_socket_linux.h"
|
| -#include "base/process/process.h"
|
| -#include "sandbox/linux/services/syscall_wrappers.h"
|
| -#include "sandbox/linux/tests/unit_tests.h"
|
| -
|
| -// Additional tests for base's UnixDomainSocket to make sure it behaves
|
| -// correctly in the presence of sandboxing functionality (e.g., receiving
|
| -// PIDs across namespaces).
|
| -
|
| -namespace sandbox {
|
| -
|
| -namespace {
|
| -
|
| -const char kHello[] = "hello";
|
| -
|
| -// If the calling process isn't root, then try using unshare(CLONE_NEWUSER)
|
| -// to fake it.
|
| -void FakeRoot() {
|
| - // If we're already root, then allow test to proceed.
|
| - if (geteuid() == 0)
|
| - return;
|
| -
|
| - // Otherwise hope the kernel supports unprivileged namespaces.
|
| - if (unshare(CLONE_NEWUSER) == 0)
|
| - return;
|
| -
|
| - printf("Permission to use CLONE_NEWPID missing; skipping test.\n");
|
| - UnitTests::IgnoreThisTest();
|
| -}
|
| -
|
| -void WaitForExit(pid_t pid) {
|
| - int status;
|
| - CHECK_EQ(pid, HANDLE_EINTR(waitpid(pid, &status, 0)));
|
| - CHECK(WIFEXITED(status));
|
| - CHECK_EQ(0, WEXITSTATUS(status));
|
| -}
|
| -
|
| -base::ProcessId GetParentProcessId(base::ProcessId pid) {
|
| - // base::GetParentProcessId() is defined as taking a ProcessHandle instead of
|
| - // a ProcessId, even though it's a POSIX-only function and IDs and Handles
|
| - // are both simply pid_t on POSIX... :/
|
| - base::Process process = base::Process::Open(pid);
|
| - CHECK(process.IsValid());
|
| - base::ProcessId ret = base::GetParentProcessId(process.Handle());
|
| - return ret;
|
| -}
|
| -
|
| -// SendHello sends a "hello" to socket fd, and then blocks until the recipient
|
| -// acknowledges it by calling RecvHello.
|
| -void SendHello(int fd) {
|
| - int pipe_fds[2];
|
| - CHECK_EQ(0, pipe(pipe_fds));
|
| - base::ScopedFD read_pipe(pipe_fds[0]);
|
| - base::ScopedFD write_pipe(pipe_fds[1]);
|
| -
|
| - std::vector<int> send_fds;
|
| - send_fds.push_back(write_pipe.get());
|
| - CHECK(UnixDomainSocket::SendMsg(fd, kHello, sizeof(kHello), send_fds));
|
| -
|
| - write_pipe.reset();
|
| -
|
| - // Block until receiver closes their end of the pipe.
|
| - char ch;
|
| - CHECK_EQ(0, HANDLE_EINTR(read(read_pipe.get(), &ch, 1)));
|
| -}
|
| -
|
| -// RecvHello receives and acknowledges a "hello" on socket fd, and returns the
|
| -// process ID of the sender in sender_pid. Optionally, write_pipe can be used
|
| -// to return a file descriptor, and the acknowledgement will be delayed until
|
| -// the descriptor is closed.
|
| -// (Implementation details: SendHello allocates a new pipe, sends us the writing
|
| -// end alongside the "hello" message, and then blocks until we close the writing
|
| -// end of the pipe.)
|
| -void RecvHello(int fd,
|
| - base::ProcessId* sender_pid,
|
| - base::ScopedFD* write_pipe = NULL) {
|
| - // Extra receiving buffer space to make sure we really received only
|
| - // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
|
| - char buf[sizeof(kHello) + 1];
|
| - ScopedVector<base::ScopedFD> message_fds;
|
| - ssize_t n = UnixDomainSocket::RecvMsgWithPid(
|
| - fd, buf, sizeof(buf), &message_fds, sender_pid);
|
| - CHECK_EQ(sizeof(kHello), static_cast<size_t>(n));
|
| - CHECK_EQ(0, memcmp(buf, kHello, sizeof(kHello)));
|
| - CHECK_EQ(1U, message_fds.size());
|
| - if (write_pipe)
|
| - write_pipe->swap(*message_fds[0]);
|
| -}
|
| -
|
| -// Check that receiving PIDs works across a fork().
|
| -SANDBOX_TEST(UnixDomainSocketTest, Fork) {
|
| - int fds[2];
|
| - CHECK_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
|
| - base::ScopedFD recv_sock(fds[0]);
|
| - base::ScopedFD send_sock(fds[1]);
|
| -
|
| - CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
|
| -
|
| - const pid_t pid = fork();
|
| - CHECK_NE(-1, pid);
|
| - if (pid == 0) {
|
| - // Child process.
|
| - recv_sock.reset();
|
| - SendHello(send_sock.get());
|
| - _exit(0);
|
| - }
|
| -
|
| - // Parent process.
|
| - send_sock.reset();
|
| -
|
| - base::ProcessId sender_pid;
|
| - RecvHello(recv_sock.get(), &sender_pid);
|
| - CHECK_EQ(pid, sender_pid);
|
| -
|
| - WaitForExit(pid);
|
| -}
|
| -
|
| -// Similar to Fork above, but forking the child into a new pid namespace.
|
| -SANDBOX_TEST(UnixDomainSocketTest, Namespace) {
|
| - FakeRoot();
|
| -
|
| - int fds[2];
|
| - CHECK_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
|
| - base::ScopedFD recv_sock(fds[0]);
|
| - base::ScopedFD send_sock(fds[1]);
|
| -
|
| - CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
|
| -
|
| - const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0);
|
| - CHECK_NE(-1, pid);
|
| - if (pid == 0) {
|
| - // Child process.
|
| - recv_sock.reset();
|
| -
|
| - // Check that we think we're pid 1 in our new namespace.
|
| - CHECK_EQ(1, sys_getpid());
|
| -
|
| - SendHello(send_sock.get());
|
| - _exit(0);
|
| - }
|
| -
|
| - // Parent process.
|
| - send_sock.reset();
|
| -
|
| - base::ProcessId sender_pid;
|
| - RecvHello(recv_sock.get(), &sender_pid);
|
| - CHECK_EQ(pid, sender_pid);
|
| -
|
| - WaitForExit(pid);
|
| -}
|
| -
|
| -// Again similar to Fork, but now with nested PID namespaces.
|
| -SANDBOX_TEST(UnixDomainSocketTest, DoubleNamespace) {
|
| - FakeRoot();
|
| -
|
| - int fds[2];
|
| - CHECK_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
|
| - base::ScopedFD recv_sock(fds[0]);
|
| - base::ScopedFD send_sock(fds[1]);
|
| -
|
| - CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
|
| -
|
| - const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0);
|
| - CHECK_NE(-1, pid);
|
| - if (pid == 0) {
|
| - // Child process.
|
| - recv_sock.reset();
|
| -
|
| - const pid_t pid2 = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0);
|
| - CHECK_NE(-1, pid2);
|
| -
|
| - if (pid2 != 0) {
|
| - // Wait for grandchild to run to completion; see comments below.
|
| - WaitForExit(pid2);
|
| -
|
| - // Fallthrough once grandchild has sent its hello and exited.
|
| - }
|
| -
|
| - // Check that we think we're pid 1.
|
| - CHECK_EQ(1, sys_getpid());
|
| -
|
| - SendHello(send_sock.get());
|
| - _exit(0);
|
| - }
|
| -
|
| - // Parent process.
|
| - send_sock.reset();
|
| -
|
| - // We have two messages to receive: first from the grand-child,
|
| - // then from the child.
|
| - for (unsigned iteration = 0; iteration < 2; ++iteration) {
|
| - base::ProcessId sender_pid;
|
| - base::ScopedFD pipe_fd;
|
| - RecvHello(recv_sock.get(), &sender_pid, &pipe_fd);
|
| -
|
| - // We need our child and grandchild processes to both be alive for
|
| - // GetParentProcessId() to return a valid pid, hence the pipe trickery.
|
| - // (On the first iteration, grandchild is blocked reading from the pipe
|
| - // until we close it, and child is blocked waiting for grandchild to exit.)
|
| - switch (iteration) {
|
| - case 0: // Grandchild's message
|
| - // Check that sender_pid refers to our grandchild by checking that pid
|
| - // (our child) is its parent.
|
| - CHECK_EQ(pid, GetParentProcessId(sender_pid));
|
| - break;
|
| - case 1: // Child's message
|
| - CHECK_EQ(pid, sender_pid);
|
| - break;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| - }
|
| -
|
| - WaitForExit(pid);
|
| -}
|
| -
|
| -// Tests that GetPeerPid() returns 0 if the peer does not exist in caller's
|
| -// namespace.
|
| -SANDBOX_TEST(UnixDomainSocketTest, ImpossiblePid) {
|
| - FakeRoot();
|
| -
|
| - int fds[2];
|
| - CHECK_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
|
| - base::ScopedFD send_sock(fds[0]);
|
| - base::ScopedFD recv_sock(fds[1]);
|
| -
|
| - CHECK(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
|
| -
|
| - const pid_t pid = sys_clone(CLONE_NEWPID | SIGCHLD, 0, 0, 0, 0);
|
| - CHECK_NE(-1, pid);
|
| - if (pid == 0) {
|
| - // Child process.
|
| - send_sock.reset();
|
| -
|
| - base::ProcessId sender_pid;
|
| - RecvHello(recv_sock.get(), &sender_pid);
|
| - CHECK_EQ(0, sender_pid);
|
| - _exit(0);
|
| - }
|
| -
|
| - // Parent process.
|
| - recv_sock.reset();
|
| - SendHello(send_sock.get());
|
| - WaitForExit(pid);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -} // namespace sandbox
|
|
|