Skip to content

Commit 7b3eeea

Browse files
authored
Auto merge of #37677 - jsen-:master, r=alexcrichton
libstd: support creation of anonymous pipe on WinXP/2K3 `PIPE_REJECT_REMOTE_CLIENTS` flag is not supported on Windows < VISTA, and every invocation of `anon_pipe` including attempts to pipe `std::process::Child`'s stdio fails. This PR should work around this issue by performing a runtime check of windows version and conditionally omitting this flag on "XP and friends". Getting the version should be probably moved out of the function `anon_pipe` itself (the OS version does not often change during runtime :) ), but: - I didn't find any precedent for this and assuming there's not much overhead (I hope windows does not perform any heuristics to find out it's own version, just fills couple of fields in the struct). - the code path is not especially performance sensitive anyway.
2 parents 80a95e3 + fc5a361 commit 7b3eeea

File tree

2 files changed

+26
-8
lines changed

2 files changed

+26
-8
lines changed

src/libstd/sys/windows/c.rs

+1
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ pub const ERROR_INVALID_HANDLE: DWORD = 6;
182182
pub const ERROR_NO_MORE_FILES: DWORD = 18;
183183
pub const ERROR_HANDLE_EOF: DWORD = 38;
184184
pub const ERROR_FILE_EXISTS: DWORD = 80;
185+
pub const ERROR_INVALID_PARAMETER: DWORD = 87;
185186
pub const ERROR_BROKEN_PIPE: DWORD = 109;
186187
pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120;
187188
pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122;

src/libstd/sys/windows/pipe.rs

+25-8
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
4343
let reader;
4444
let mut name;
4545
let mut tries = 0;
46+
let mut reject_remote_clients_flag = c::PIPE_REJECT_REMOTE_CLIENTS;
4647
loop {
4748
tries += 1;
4849
let key: u64 = rand::thread_rng().gen();
@@ -56,12 +57,12 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
5657

5758
let handle = c::CreateNamedPipeW(wide_name.as_ptr(),
5859
c::PIPE_ACCESS_INBOUND |
59-
c::FILE_FLAG_FIRST_PIPE_INSTANCE |
60-
c::FILE_FLAG_OVERLAPPED,
60+
c::FILE_FLAG_FIRST_PIPE_INSTANCE |
61+
c::FILE_FLAG_OVERLAPPED,
6162
c::PIPE_TYPE_BYTE |
62-
c::PIPE_READMODE_BYTE |
63-
c::PIPE_WAIT |
64-
c::PIPE_REJECT_REMOTE_CLIENTS,
63+
c::PIPE_READMODE_BYTE |
64+
c::PIPE_WAIT |
65+
reject_remote_clients_flag,
6566
1,
6667
4096,
6768
4096,
@@ -76,11 +77,27 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
7677
//
7778
// Don't try again too much though as this could also perhaps be a
7879
// legit error.
80+
// If ERROR_INVALID_PARAMETER is returned, this probably means we're
81+
// running on pre-Vista version where PIPE_REJECT_REMOTE_CLIENTS is
82+
// not supported, so we continue retrying without it. This implies
83+
// reduced security on Windows versions older than Vista by allowing
84+
// connections to this pipe from remote machines.
85+
// Proper fix would increase the number of FFI imports and introduce
86+
// significant amount of Windows XP specific code with no clean
87+
// testing strategy
88+
// for more info see https://github.com/rust-lang/rust/pull/37677
7989
if handle == c::INVALID_HANDLE_VALUE {
8090
let err = io::Error::last_os_error();
81-
if tries < 10 &&
82-
err.raw_os_error() == Some(c::ERROR_ACCESS_DENIED as i32) {
83-
continue
91+
let raw_os_err = err.raw_os_error();
92+
if tries < 10 {
93+
if raw_os_err == Some(c::ERROR_ACCESS_DENIED as i32) {
94+
continue
95+
} else if reject_remote_clients_flag != 0 &&
96+
raw_os_err == Some(c::ERROR_INVALID_PARAMETER as i32) {
97+
reject_remote_clients_flag = 0;
98+
tries -= 1;
99+
continue
100+
}
84101
}
85102
return Err(err)
86103
}

0 commit comments

Comments
 (0)