OLD | NEW |
1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 #include <errno.h> | 15 #include <errno.h> |
16 #include <limits.h> | 16 #include <limits.h> |
17 #include <stdio.h> | 17 #include <stdio.h> |
18 #include <stdlib.h> | 18 #include <stdlib.h> |
19 #include <sys/types.h> | 19 #include <sys/types.h> |
20 #include <unistd.h> | |
21 | 20 |
22 #include <algorithm> | 21 #include <algorithm> |
23 | 22 |
| 23 #if defined(__APPLE__) || defined(__linux__) |
| 24 #define OS_POSIX 1 |
| 25 #elif defined(_WIN32) |
| 26 #define OS_WIN 1 |
| 27 #endif |
| 28 |
| 29 #if defined(OS_POSIX) |
| 30 #include <unistd.h> |
| 31 #elif defined(OS_WIN) |
| 32 #include <windows.h> |
| 33 #endif |
| 34 |
| 35 #if defined(OS_WIN) |
| 36 |
| 37 namespace { |
| 38 |
| 39 // Various semi-documented NT internals to retrieve open handles. |
| 40 |
| 41 typedef enum _SYSTEM_INFORMATION_CLASS { |
| 42 SystemHandleInformation = 16 |
| 43 } SYSTEM_INFORMATION_CLASS; |
| 44 |
| 45 typedef struct _SYSTEM_HANDLE_INFORMATION { |
| 46 USHORT ProcessId; |
| 47 USHORT CreatorBackTraceIndex; |
| 48 UCHAR ObjectTypeNumber; |
| 49 UCHAR Flags; |
| 50 USHORT Handle; |
| 51 PVOID Object; |
| 52 ACCESS_MASK GrantedAccess; |
| 53 } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; |
| 54 |
| 55 typedef struct _SYSTEM_HANDLE_INFORMATION_EX { |
| 56 ULONG NumberOfHandles; |
| 57 SYSTEM_HANDLE_INFORMATION Information[1]; |
| 58 } SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; |
| 59 |
| 60 typedef NTSTATUS(WINAPI* NTQUERYSYSTEMINFORMATION)( |
| 61 SYSTEM_INFORMATION_CLASS SystemInformationClass, |
| 62 PVOID SystemInformation, |
| 63 ULONG SystemInformationLength, |
| 64 PULONG ReturnLength); |
| 65 |
| 66 void EnsureOnlyStdioHandlesOpen() { |
| 67 // Initialize the NTAPI functions we need. |
| 68 HMODULE ntdll_handle = GetModuleHandle(L"ntdll.dll"); |
| 69 if (!ntdll_handle) { |
| 70 fprintf(stderr, "GetModuleHandle ntdll.dll failed.\n"); |
| 71 abort(); |
| 72 } |
| 73 |
| 74 NTQUERYSYSTEMINFORMATION NtQuerySystemInformation; |
| 75 NtQuerySystemInformation = reinterpret_cast<NTQUERYSYSTEMINFORMATION>( |
| 76 GetProcAddress(ntdll_handle, "NtQuerySystemInformation")); |
| 77 if (!NtQuerySystemInformation) { |
| 78 fprintf(stderr, "GetProcAddress NtQuerySystemInformation failed.\n"); |
| 79 abort(); |
| 80 } |
| 81 |
| 82 // Get the number of handles on the system. |
| 83 DWORD buffer_size = 0; |
| 84 SYSTEM_HANDLE_INFORMATION_EX temp_info; |
| 85 NTSTATUS status = NtQuerySystemInformation( |
| 86 SystemHandleInformation, &temp_info, sizeof(temp_info), &buffer_size); |
| 87 if (!buffer_size) { |
| 88 fprintf(stderr, |
| 89 "NtQuerySystemInformation for number of handles failed: 0x%lX\n", |
| 90 status); |
| 91 abort(); |
| 92 } |
| 93 |
| 94 SYSTEM_HANDLE_INFORMATION_EX *system_handles = |
| 95 reinterpret_cast<SYSTEM_HANDLE_INFORMATION_EX*>(new BYTE[buffer_size]); |
| 96 |
| 97 // This is likely flaky as we're racing with other handles being created on |
| 98 // the system between the size query above, and the actual retrieval here. |
| 99 status = NtQuerySystemInformation(SystemHandleInformation, system_handles, |
| 100 buffer_size, &buffer_size); |
| 101 if (status != 0) { |
| 102 fprintf(stderr, "Failed to get the handle list: 0x%lX\n", status); |
| 103 delete[] system_handles; |
| 104 abort(); |
| 105 } |
| 106 |
| 107 for (ULONG i = 0; i < system_handles->NumberOfHandles; ++i) { |
| 108 USHORT h = system_handles->Information[i].Handle; |
| 109 if (system_handles->Information[i].ProcessId != GetCurrentProcessId()) |
| 110 continue; |
| 111 |
| 112 // TODO(scottmg): This is probably insufficient, we'll need to allow having |
| 113 // a few other standard handles open (for example, to the window station), |
| 114 // or only check for handles of certain types. |
| 115 HANDLE handle = reinterpret_cast<HANDLE>(h); |
| 116 if (handle != GetStdHandle(STD_INPUT_HANDLE) && |
| 117 handle != GetStdHandle(STD_OUTPUT_HANDLE) && |
| 118 handle != GetStdHandle(STD_ERROR_HANDLE)) { |
| 119 fprintf(stderr, "Handle 0x%lX is not stdio handle\n", handle); |
| 120 abort(); |
| 121 } |
| 122 } |
| 123 |
| 124 delete [] system_handles; |
| 125 } |
| 126 |
| 127 } // namespace |
| 128 |
| 129 #endif // OS_WIN |
| 130 |
24 int main(int argc, char* argv[]) { | 131 int main(int argc, char* argv[]) { |
| 132 #if defined(OS_POSIX) |
25 // Make sure that there’s nothing open at any FD higher than 3. All FDs other | 133 // Make sure that there’s nothing open at any FD higher than 3. All FDs other |
26 // than stdin, stdout, and stderr should have been closed prior to or at | 134 // than stdin, stdout, and stderr should have been closed prior to or at |
27 // exec(). | 135 // exec(). |
28 int max_fd = std::max(static_cast<int>(sysconf(_SC_OPEN_MAX)), OPEN_MAX); | 136 int max_fd = std::max(static_cast<int>(sysconf(_SC_OPEN_MAX)), OPEN_MAX); |
29 max_fd = std::max(max_fd, getdtablesize()); | 137 max_fd = std::max(max_fd, getdtablesize()); |
30 for (int fd = STDERR_FILENO + 1; fd < max_fd; ++fd) { | 138 for (int fd = STDERR_FILENO + 1; fd < max_fd; ++fd) { |
31 if (close(fd) == 0 || errno != EBADF) { | 139 if (close(fd) == 0 || errno != EBADF) { |
32 abort(); | 140 abort(); |
33 } | 141 } |
34 } | 142 } |
35 | 143 |
36 // Read a byte from stdin, expecting it to be a specific value. | 144 // Read a byte from stdin, expecting it to be a specific value. |
37 char c; | 145 char c; |
38 ssize_t rv = read(STDIN_FILENO, &c, 1); | 146 ssize_t rv = read(STDIN_FILENO, &c, 1); |
39 if (rv != 1 || c != 'z') { | 147 if (rv != 1 || c != 'z') { |
40 abort(); | 148 abort(); |
41 } | 149 } |
42 | 150 |
43 // Write a byte to stdout. | 151 // Write a byte to stdout. |
44 c = 'Z'; | 152 c = 'Z'; |
45 rv = write(STDOUT_FILENO, &c, 1); | 153 rv = write(STDOUT_FILENO, &c, 1); |
46 if (rv != 1) { | 154 if (rv != 1) { |
47 abort(); | 155 abort(); |
48 } | 156 } |
| 157 #elif defined(OS_WIN) |
| 158 // Make sure there's nothing open other than stdin, stdout, and stderr. |
| 159 EnsureOnlyStdioHandlesOpen(); |
| 160 |
| 161 // Read a byte from stdin, expecting it to be a specific value. |
| 162 char c; |
| 163 DWORD bytes_read; |
| 164 if (!ReadFile(GetStdHandle(STD_INPUT_HANDLE), &c, 1, &bytes_read, nullptr) || |
| 165 bytes_read != 1 || c != 'z') { |
| 166 abort(); |
| 167 } |
| 168 |
| 169 // Write a byte to stdout. |
| 170 c = 'Z'; |
| 171 DWORD bytes_written; |
| 172 if (!WriteFile( |
| 173 GetStdHandle(STD_OUTPUT_HANDLE), &c, 1, &bytes_written, nullptr) || |
| 174 bytes_written != 1) { |
| 175 abort(); |
| 176 } |
| 177 #endif // OS_POSIX |
49 | 178 |
50 return 0; | 179 return 0; |
51 } | 180 } |
OLD | NEW |