OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
| 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 "util/mach/child_port_handshake.h" |
| 16 |
| 17 #include "base/mac/scoped_mach_port.h" |
| 18 #include "gtest/gtest.h" |
| 19 #include "util/mach/child_port_types.h" |
| 20 #include "util/mach/mach_extensions.h" |
| 21 #include "util/test/multiprocess.h" |
| 22 |
| 23 namespace crashpad { |
| 24 namespace test { |
| 25 namespace { |
| 26 |
| 27 class ChildPortHandshakeTest : public Multiprocess { |
| 28 public: |
| 29 enum TestType { |
| 30 kTestTypeChildChecksIn = 0, |
| 31 kTestTypeChildDoesNotCheckIn_ReadsPipe, |
| 32 kTestTypeChildDoesNotCheckIn, |
| 33 kTestTypeTokenIncorrect, |
| 34 kTestTypeTokenIncorrectThenCorrect, |
| 35 }; |
| 36 |
| 37 explicit ChildPortHandshakeTest(TestType test_type) |
| 38 : Multiprocess(), child_port_handshake_(), test_type_(test_type) {} |
| 39 ~ChildPortHandshakeTest() {} |
| 40 |
| 41 private: |
| 42 // Multiprocess: |
| 43 |
| 44 void MultiprocessParent() override { |
| 45 base::mac::ScopedMachSendRight child_port( |
| 46 child_port_handshake_.RunServer()); |
| 47 switch (test_type_) { |
| 48 case kTestTypeChildChecksIn: |
| 49 case kTestTypeTokenIncorrectThenCorrect: |
| 50 EXPECT_EQ(bootstrap_port, child_port); |
| 51 break; |
| 52 |
| 53 case kTestTypeChildDoesNotCheckIn_ReadsPipe: |
| 54 case kTestTypeChildDoesNotCheckIn: |
| 55 case kTestTypeTokenIncorrect: |
| 56 EXPECT_EQ(kMachPortNull, child_port); |
| 57 break; |
| 58 } |
| 59 } |
| 60 |
| 61 void MultiprocessChild() override { |
| 62 int read_pipe = child_port_handshake_.ReadPipeFD(); |
| 63 switch (test_type_) { |
| 64 case kTestTypeChildChecksIn: |
| 65 ChildPortHandshake::RunClient( |
| 66 read_pipe, bootstrap_port, MACH_MSG_TYPE_COPY_SEND); |
| 67 break; |
| 68 |
| 69 case kTestTypeChildDoesNotCheckIn_ReadsPipe: { |
| 70 // Don’t run the standard client routine. Instead, drain the pipe, which |
| 71 // will get the parent to the point that it begins waiting for a |
| 72 // check-in message. Then, exit. The pipe is drained using the same |
| 73 // implementation that the real client would use. |
| 74 child_port_token_t token; |
| 75 std::string service_name; |
| 76 ChildPortHandshake::RunClientInternal_ReadPipe( |
| 77 read_pipe, &token, &service_name); |
| 78 break; |
| 79 } |
| 80 |
| 81 case kTestTypeChildDoesNotCheckIn: |
| 82 break; |
| 83 |
| 84 case kTestTypeTokenIncorrect: { |
| 85 // Don’t run the standard client routine. Instead, read the token and |
| 86 // service name, mutate the token, and then check in with the bad token. |
| 87 // The parent should reject the message. |
| 88 child_port_token_t token; |
| 89 std::string service_name; |
| 90 ChildPortHandshake::RunClientInternal_ReadPipe( |
| 91 read_pipe, &token, &service_name); |
| 92 child_port_token_t bad_token = ~token; |
| 93 ChildPortHandshake::RunClientInternal_SendCheckIn( |
| 94 service_name, bad_token, mach_task_self(), MACH_MSG_TYPE_COPY_SEND); |
| 95 break; |
| 96 } |
| 97 |
| 98 case kTestTypeTokenIncorrectThenCorrect: { |
| 99 // Don’t run the standard client routine. Instead, read the token and |
| 100 // service name. Mutate the token, and check in with the bad token, |
| 101 // expecting the parent to reject the message. Then, check in with the |
| 102 // correct token, expecting the parent to accept it. |
| 103 child_port_token_t token; |
| 104 std::string service_name; |
| 105 ChildPortHandshake::RunClientInternal_ReadPipe( |
| 106 read_pipe, &token, &service_name); |
| 107 child_port_token_t bad_token = ~token; |
| 108 ChildPortHandshake::RunClientInternal_SendCheckIn( |
| 109 service_name, bad_token, mach_task_self(), MACH_MSG_TYPE_COPY_SEND); |
| 110 ChildPortHandshake::RunClientInternal_SendCheckIn( |
| 111 service_name, token, bootstrap_port, MACH_MSG_TYPE_COPY_SEND); |
| 112 break; |
| 113 } |
| 114 } |
| 115 } |
| 116 |
| 117 private: |
| 118 ChildPortHandshake child_port_handshake_; |
| 119 TestType test_type_; |
| 120 |
| 121 DISALLOW_COPY_AND_ASSIGN(ChildPortHandshakeTest); |
| 122 }; |
| 123 |
| 124 TEST(ChildPortHandshake, ChildChecksIn) { |
| 125 // In this test, the client checks in with the server normally. It sends a |
| 126 // copy of its bootstrap port to the server, because both parent and child |
| 127 // should have the same bootstrap port, allowing for verification. |
| 128 ChildPortHandshakeTest test(ChildPortHandshakeTest::kTestTypeChildChecksIn); |
| 129 test.Run(); |
| 130 } |
| 131 |
| 132 TEST(ChildPortHandshake, ChildDoesNotCheckIn) { |
| 133 // In this test, the client exits without checking in. This tests that the |
| 134 // server properly detects that it has lost a client. Whether or not the |
| 135 // client closes the pipe before the server writes to it is a race, and the |
| 136 // server needs to be able to detect client loss in both cases, so the |
| 137 // ChildDoesNotCheckIn_ReadsPipe and NoChild tests also exist to test these |
| 138 // individual cases more deterministically. |
| 139 ChildPortHandshakeTest test( |
| 140 ChildPortHandshakeTest::kTestTypeChildDoesNotCheckIn); |
| 141 test.Run(); |
| 142 } |
| 143 |
| 144 TEST(ChildPortHandshake, ChildDoesNotCheckIn_ReadsPipe) { |
| 145 // In this test, the client reads from its pipe, and subsequently exits |
| 146 // without checking in. This tests that the server properly detects that it |
| 147 // has lost its client after sending instructions to it via the pipe, while |
| 148 // waiting for a check-in message. |
| 149 ChildPortHandshakeTest test( |
| 150 ChildPortHandshakeTest::kTestTypeChildDoesNotCheckIn_ReadsPipe); |
| 151 test.Run(); |
| 152 } |
| 153 |
| 154 TEST(ChildPortHandshake, TokenIncorrect) { |
| 155 // In this test, the client checks in with the server with an incorrect token |
| 156 // value and a copy of its own task port. The server should reject the message |
| 157 // because of the invalid token, and return MACH_PORT_NULL to its caller. |
| 158 ChildPortHandshakeTest test(ChildPortHandshakeTest::kTestTypeTokenIncorrect); |
| 159 test.Run(); |
| 160 } |
| 161 |
| 162 TEST(ChildPortHandshake, TokenIncorrectThenCorrect) { |
| 163 // In this test, the client checks in with the server with an incorrect token |
| 164 // value and a copy of its own task port, and subsequently, the correct token |
| 165 // value and a copy of its bootstrap port. The server should reject the first |
| 166 // because of the invalid token, but it should continue waiting for a message |
| 167 // with a valid token as long as the pipe remains open. It should wind wind up |
| 168 // returning the bootstrap port, allowing for verification. |
| 169 ChildPortHandshakeTest test( |
| 170 ChildPortHandshakeTest::kTestTypeTokenIncorrectThenCorrect); |
| 171 test.Run(); |
| 172 } |
| 173 |
| 174 TEST(ChildPortHandshake, NoChild) { |
| 175 // In this test, the client never checks in with the parent because the child |
| 176 // never even runs. This tests that the server properly detects that it has |
| 177 // no client at all, and does not terminate execution with an error such as |
| 178 // “broken pipe” when attempting to send instructions to the client. This test |
| 179 // is similar to ChildDoesNotCheckIn, but because there’s no child at all, the |
| 180 // server is guaranteed to see that its pipe partner is gone. |
| 181 ChildPortHandshake child_port_handshake; |
| 182 base::mac::ScopedMachSendRight child_port(child_port_handshake.RunServer()); |
| 183 EXPECT_EQ(kMachPortNull, child_port); |
| 184 } |
| 185 |
| 186 } // namespace |
| 187 } // namespace test |
| 188 } // namespace crashpad |
OLD | NEW |