Запретить дочернему процессу наследовать открытые TCP-порты родительского процесса с помощью библиотеки boost процесса
У меня есть приложение C++, прослушивающее определенный порт TCP. Приложение также запускает дочерний процесс, используя дочерний класс Boost из библиотеки процессов Boost. Как только дочерний процесс запущен, вывод команды netstat показывает, что порт TCP также связывается с созданным дочерним процессом. Есть ли способ, с помощью которого я могу запретить дочернему элементу наследовать порты родителя при использовании библиотеки процессов наддува? Ребенок создан как:
bp::child* proc = new bp::child("a.out", bp::std_out > stdout, bp::std_err > stderr);
Я использую платформу Linux. Благодарю.
1 ответ
Там в настоящее время нет способа сделать это.
Я играл с патчем, чтобы добавить его, но у меня были некоторые проблемы, и у меня не хватило времени на тестирование. Я могу поделиться патчем, но вы будете самостоятельно его тестировать.
Не все, что ниже, предполагает POSIX-системы.
Простой дубль № 1
Казалось бы, самое простое - закрыть все нестандартные fd без исключения:
struct close_fds : bp::extend::handler {
template <typename Executor>
void on_exec_setup(Executor& /*ex*/) {
// TODO implemented smarter - below meddles with the library internals
int maxfd=sysconf(_SC_OPEN_MAX);
for(int fd=3; fd<maxfd; fd++) {
::close(fd);
}
}
};
Теперь вы просто передадите это ключевое слово в API создания вашего процесса:
bp::child x(..., close_fds{});
ЭТО НЕ БУДЕТ РАБОТАТЬ
Во-первых, есть обязательный канал "родитель-потомок", используемый для внутренней коммуникации внутри внутренних процессов Boost (например, обработка ошибок / создание отчетов). Мы не учитывали это, и это не было бы предсказуемо. fd
значение имеет значение, так что давайте перейдем к более сложным идеям:
Более сложные настройки
Более интеллектуальные настройки будут учитывать любые fds, которые задействованы в Boost Process. Это включает в себя канал (упомянутый выше) и любые другие fds, которые могут быть результатом перенаправлений, указанных в других аргументах запуска процесса.
Вот патч, как я его подготовил
Опять же, это не проверено. Патч изначально был выпущен для Boost 1.63, который еще не имел официального релиза Boost Process, но я "недавно" (апрель) портировал его на Boost 1.66.
Использование будет выглядеть примерно так:
bp::child x(..., bp::posix::fd.restrict_inherit()); };
Обратите внимание, что он позволяет координировать действия с другими (пользовательскими) расширениями для сбора FD, которые должны наследоваться.
From 45c46a3d9ed42278af97e6ca11474bfbddf3ffb4 Mon Sep 17 00:00:00 2001
From: Seth Heeren <heeren@tracksinspector.com>
Date: Tue, 10 Apr 2018 02:48:27 +0200
Subject: [PATCH] fd_restrict prototype
---
boost/process/detail/posix/executor.hpp | 16 ++-
boost/process/detail/posix/fd.hpp | 8 ++
boost/process/detail/posix/fd_restrict.hpp | 154 +++++++++++++++++++++++++
boost/process/detail/posix/file_descriptor.hpp | 7 ++
4 files changed, 181 insertions(+), 4 deletions(-)
create mode 100644 boost/process/detail/posix/fd_restrict.hpp
diff --git a/boost/process/detail/posix/executor.hpp b/boost/process/detail/posix/executor.hpp
index b3781f2..0a7c446 100644
--- a/boost/process/detail/posix/executor.hpp
+++ b/boost/process/detail/posix/executor.hpp
@@ -15,6 +15,7 @@
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/basic_pipe.hpp>
#include <boost/process/detail/posix/use_vfork.hpp>
+#include <boost/process/detail/posix/file_descriptor.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <cstdlib>
#include <sys/types.h>
@@ -45,7 +46,7 @@ inline int execvpe(const char* filename, char * const arg_list[], char* env[])
if (e != nullptr)
{
- std::vector<std::string> path;
+ std::vector<std::string> path;
boost::split(path, *e, boost::is_any_of(":"));
for (const std::string & pp : path)
@@ -157,13 +158,13 @@ struct on_fork_success_t
};
template<typename Executor> on_setup_t <Executor> call_on_setup (Executor & exec) {return exec;}
-template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
+template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
{
return on_error_t<Executor> (exec, ec);
}
template<typename Executor> on_success_t<Executor> call_on_success(Executor & exec) {return exec;}
-template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
+template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
{
return on_fork_error_t<Executor> (exec, ec);
}
@@ -330,6 +331,12 @@ public:
}
void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());};
+ // customization point for fd_restrict
+ template <typename OutputIterator>
+ friend void collect_filedescriptors(executor const& me, OutputIterator& outit) {
+ // always protect the write end of the parent/child pipe
+ *outit++ = me._pipe_sink;
+ }
};
template<typename Sequence>
@@ -380,6 +387,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
return child();
}
_ec.clear();
+ _pipe_sink = p[1];
boost::fusion::for_each(seq, call_on_setup(*this));
if (_ec)
@@ -391,6 +399,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
this->pid = ::fork();
if (pid == -1)
{
+ _pipe_sink = -1;
_ec = boost::process::detail::get_last_error();
_msg = "fork() failed";
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
@@ -400,7 +409,6 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
}
else if (pid == 0)
{
- _pipe_sink = p[1];
::close(p[0]);
boost::fusion::for_each(seq, call_on_exec_setup(*this));
diff --git a/boost/process/detail/posix/fd.hpp b/boost/process/detail/posix/fd.hpp
index 51790c3..f759d9e 100644
--- a/boost/process/detail/posix/fd.hpp
+++ b/boost/process/detail/posix/fd.hpp
@@ -11,6 +11,7 @@
#define BOOST_PROCESS_DETAIL_POSIX_FD_HPP
#include <boost/process/detail/posix/handler.hpp>
+#include <boost/process/detail/posix/fd_restrict.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -68,6 +69,12 @@ public:
}
private:
+ // customization point for fd_restrict
+ template <typename OutputIterator>
+ friend void collect_filedescriptors(bind_fd_ const& bind_fd, OutputIterator& outit) {
+ *outit++ = bind_fd.id_;
+ }
+
int id_;
FileDescriptor fd_;
};
@@ -84,6 +91,7 @@ struct fd_
template <class FileDescriptor>
bind_fd_<FileDescriptor> bind(int id, const FileDescriptor & fd) const {return {id, fd};}
+ fd_restrict::property_<> restrict_inherit(size_t capacity = 128) const {return {capacity};}
};
diff --git a/boost/process/detail/posix/fd_restrict.hpp b/boost/process/detail/posix/fd_restrict.hpp
new file mode 100644
index 0000000..71c6c7d
--- /dev/null
+++ b/boost/process/detail/posix/fd_restrict.hpp
@@ -0,0 +1,154 @@
+// Copyright (c) 2017 Seth Heeren
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_PROCESS_DETAIL_POSIX_FD_RESTRICT_HPP
+#define BOOST_PROCESS_DETAIL_POSIX_FD_RESTRICT_HPP
+
+#include <boost/process/detail/posix/handler.hpp>
+#include <unistd.h>
+
+namespace boost { namespace process { namespace detail { namespace posix { namespace fd_restrict {
+ // customization point for (custom) properties that need to protect fds
+ template <typename Property, typename OutputIterator>
+ void collect_filedescriptors(Property const& /*property*/, OutputIterator& /*outit*/) {
+ // primary template
+ }
+
+ // polymorphic function object for ADL dispatch
+ template <typename OutputIterator>
+ struct collect_fd_f {
+ OutputIterator mutable _outit;
+
+ template <typename Property>
+ void operator()(Property const& property) const {
+ using boost::process::detail::posix::fd_restrict::collect_filedescriptors; // ADL desired
+ collect_filedescriptors(property, _outit);
+ }
+ };
+
+ // launch property
+ template <typename=void>
+ struct property_ : handler_base_ext
+ {
+ public:
+ property_(size_t capacity) {
+ // reserve to avoid allocations between fork/exec which may
+ // deadlock with threads
+ _protected_fds.reserve(capacity);
+ }
+
+ template <class PosixExecutor>
+ void on_exec_setup(PosixExecutor& exec) const
+ {
+ _protected_fds.resize(0);
+ auto outit = back_inserter(_protected_fds);
+ collect_fd_f<decltype(outit)> visit{outit};
+
+ visit(exec);
+ boost::fusion::for_each(exec.seq, visit);
+
+ auto begin = _protected_fds.begin(), end = _protected_fds.end();
+ std::sort(begin, end);
+
+ for(int fd=0, maxfd=sysconf(_SC_OPEN_MAX); fd<maxfd; ++fd) {
+ if (!std::binary_search(begin, end, fd))
+ ::close(fd);
+ }
+ }
+
+ private:
+ std::vector<int> mutable _protected_fds;
+ };
+
+}}}}}
+
+/*
+ * Non-intrusive instrumentation of existing POSIX properties that require filedescriptors
+ *
+ * All of these could be done with an inline `friend` definition, like above.
+ *
+ * For now I prefer to keep them separate so that
+ *
+ * - upstream changes merge cleanly
+ * - interface changes in fd_restrict can more easily be applied consistently in 1 file
+ *
+ * Only bind_fd_ and filedescriptor need friend access, so cannot usefully be kept separate.
+ */
+
+#include <boost/process/detail/posix/async_in.hpp>
+#include <boost/process/detail/posix/async_out.hpp>
+#include <boost/process/detail/posix/null_in.hpp>
+#include <boost/process/detail/posix/null_out.hpp>
+#include <boost/process/detail/posix/file_in.hpp>
+#include <boost/process/detail/posix/file_out.hpp>
+#include <boost/process/detail/posix/pipe_in.hpp>
+#include <boost/process/detail/posix/pipe_out.hpp>
+
+namespace boost { namespace process { namespace detail { namespace posix {
+
+template<typename... Ts, typename OutputIterator>
+void collect_filedescriptors(async_in_buffer<Ts...> const&, OutputIterator& outit) {
+ *outit++ = STDIN_FILENO;
+}
+
+template<int p1, int p2, typename... Ts, typename OutputIterator>
+void collect_filedescriptors(async_out_buffer<p1, p2, Ts...> const&, OutputIterator& outit) {
+ if (p1==1||p2==1) *outit++ = STDOUT_FILENO;
+ if (p1==2||p2==2) *outit++ = STDERR_FILENO;
+}
+
+template<int p1, int p2, typename... Ts, typename OutputIterator>
+void collect_filedescriptors(async_out_future<p1, p2, Ts...> const&, OutputIterator& outit) {
+ if (p1==1||p2==1) *outit++ = STDOUT_FILENO;
+ if (p1==2||p2==2) *outit++ = STDERR_FILENO;
+}
+
+template<typename OutputIterator>
+void collect_filedescriptors(file_in const&, OutputIterator& outit) {
+ *outit++ = STDIN_FILENO;
+}
+
+template<int p1, int p2, typename OutputIterator>
+void collect_filedescriptors(file_out<p1, p2> const&, OutputIterator& outit) {
+ if (p1==1||p2==1) *outit++ = STDOUT_FILENO;
+ if (p1==2||p2==2) *outit++ = STDERR_FILENO;
+}
+
+template<typename OutputIterator>
+void collect_filedescriptors(null_in const&, OutputIterator& outit) {
+ *outit++ = STDIN_FILENO;
+}
+
+template<int p1, int p2, typename OutputIterator>
+void collect_filedescriptors(null_out<p1, p2> const&, OutputIterator& outit) {
+ if (p1==1||p2==1) *outit++ = STDOUT_FILENO;
+ if (p1==2||p2==2) *outit++ = STDERR_FILENO;
+}
+
+template<typename OutputIterator>
+void collect_filedescriptors(pipe_in const&, OutputIterator& outit) {
+ *outit++ = STDIN_FILENO;
+}
+
+template<typename OutputIterator>
+void collect_filedescriptors(async_pipe_in const&, OutputIterator& outit) {
+ *outit++ = STDIN_FILENO;
+}
+
+template<int p1, int p2, typename OutputIterator>
+void collect_filedescriptors(pipe_out<p1, p2> const&, OutputIterator& outit) {
+ if (p1==1||p2==1) *outit++ = STDOUT_FILENO;
+ if (p1==2||p2==2) *outit++ = STDERR_FILENO;
+}
+
+template<int p1, int p2, typename OutputIterator>
+void collect_filedescriptors(async_pipe_out<p1, p2> const&, OutputIterator& outit) {
+ if (p1==1||p2==1) *outit++ = STDOUT_FILENO;
+ if (p1==2||p2==2) *outit++ = STDERR_FILENO;
+}
+
+}}}}
+
+#endif
diff --git a/boost/process/detail/posix/file_descriptor.hpp b/boost/process/detail/posix/file_descriptor.hpp
index 0dcb99c..0cfcfd1 100644
--- a/boost/process/detail/posix/file_descriptor.hpp
+++ b/boost/process/detail/posix/file_descriptor.hpp
@@ -53,6 +53,13 @@ struct file_descriptor
int handle() const { return _handle;}
private:
+ // customization point for fd_restrict
+ template <typename OutputIterator>
+ friend void collect_filedescriptors(file_descriptor const& property_, OutputIterator& outit) {
+ if (-1 != property_._handle)
+ *outit++ = property_._handle;
+ }
+
static int create_file(const char* name, mode_t mode )
{
switch(mode)
--
2.16.2
Я позволю комментариям в исходном коде быть вашим руководством, чтобы понять идею.