diff --git a/util/posix/close_stdio.cc b/util/posix/close_stdio.cc new file mode 100644 index 00000000..8ff59d0a --- /dev/null +++ b/util/posix/close_stdio.cc @@ -0,0 +1,52 @@ +// Copyright 2014 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/posix/close_stdio.h" + +#include +#include +#include + +#include "base/basictypes.h" +#include "base/files/scoped_file.h" +#include "base/logging.h" +#include "base/posix/eintr_wrapper.h" + +namespace crashpad { + +namespace { + +void CloseStdioStream(int desired_fd, int oflag) { + base::ScopedFD fd(HANDLE_EINTR(open(_PATH_DEVNULL, oflag))); + if (fd == desired_fd) { + // Weird, but play along. + ignore_result(fd.release()); + } else { + PCHECK(fd.get() >= 0) << "open"; + PCHECK(HANDLE_EINTR(dup2(fd.get(), desired_fd)) != -1) << "dup2"; + fd.reset(); + } +} + +} // namespace + +void CloseStdinAndStdout() { + // Open /dev/null for stdin and stdout separately, so that it can be opened + // with the correct mode each time. This ensures that attempts to write to + // stdin or read from stdout fail with EBADF. + CloseStdioStream(STDIN_FILENO, O_RDONLY); + CloseStdioStream(STDOUT_FILENO, O_WRONLY); +} + +} // namespace crashpad diff --git a/util/posix/close_stdio.h b/util/posix/close_stdio.h new file mode 100644 index 00000000..9515923b --- /dev/null +++ b/util/posix/close_stdio.h @@ -0,0 +1,42 @@ +// Copyright 2014 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CRASHPAD_UTIL_POSIX_CLOSE_STDIO_H_ +#define CRASHPAD_UTIL_POSIX_CLOSE_STDIO_H_ + +namespace crashpad { + +//! \brief Closes `stdin` and `stdout` by opening `/dev/null` over them. +//! +//! It is normally inadvisable to `close()` the three standard input/output +//! streams, because they occupy special file descriptors. Closing them outright +//! could result in their file descriptors being reused. This causes problems +//! for library code (including the standard library) that expects these file +//! descriptors to have special meaning. +//! +//! This function discards the standard input and standard output streams by +//! opening `/dev/null` and assigning it to their file descriptors, closing +//! whatever had been at those file descriptors previously. +//! +//! `stderr`, the standard error stream, is not closed. It is often useful to +//! retain the ability to send diagnostic messages to the standard error stream. +//! +//! \note This function can only maintain its guarantees in a single-threaded +//! process, or in situations where the caller has control of all threads in +//! the process. +void CloseStdinAndStdout(); + +} // namespace crashpad + +#endif // CRASHPAD_UTIL_POSIX_CLOSE_STDIO_H_ diff --git a/util/util.gyp b/util/util.gyp index b3bdf0ff..b950c5db 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -99,6 +99,8 @@ 'numeric/in_range_cast.h', 'numeric/int128.h', 'numeric/safe_assignment.h', + 'posix/close_stdio.cc', + 'posix/close_stdio.h', 'posix/drop_privileges.cc', 'posix/drop_privileges.h', 'posix/process_info.h',