fix POLLNVAL in pipeTraffic

This commit is contained in:
Wiktor Garbacz 2020-02-17 15:55:08 +01:00
parent 5c61521295
commit a47123b8a7
2 changed files with 67 additions and 39 deletions

View File

@ -119,18 +119,23 @@ static bool setTimer(nsjconf_t* nsjconf) {
static bool pipeTraffic(nsjconf_t* nsjconf, int listenfd) { static bool pipeTraffic(nsjconf_t* nsjconf, int listenfd) {
std::vector<struct pollfd> fds; std::vector<struct pollfd> fds;
fds.reserve(nsjconf->pipes.size() * 2 + 1); fds.reserve(nsjconf->pipes.size() * 3 + 1);
for (const auto& p : nsjconf->pipes) { for (const auto& p : nsjconf->pipes) {
fds.push_back({ fds.push_back({
.fd = p.first, .fd = p.sock_fd,
.events = POLLIN, .events = POLLIN | POLLOUT,
.revents = 0, .revents = 0,
}); });
fds.push_back({ fds.push_back({
.fd = p.second, .fd = p.pipe_in,
.events = POLLOUT, .events = POLLOUT,
.revents = 0, .revents = 0,
}); });
fds.push_back({
.fd = p.pipe_out,
.events = POLLIN,
.revents = 0,
});
} }
fds.push_back({ fds.push_back({
.fd = listenfd, .fd = listenfd,
@ -147,46 +152,60 @@ static bool pipeTraffic(nsjconf_t* nsjconf, int listenfd) {
return true; return true;
} }
bool cleanup = false; bool cleanup = false;
for (size_t i = 0; i < fds.size() - 1; i += 2) { for (size_t i = 0; i < fds.size() - 1; ++i) {
bool read_ready = fds[i].events == 0 || (fds[i].revents & POLLIN) == POLLIN; if (fds[i].revents & POLLIN) {
bool write_ready = fds[i].events &= ~POLLIN;
fds[i + 1].events == 0 || (fds[i + 1].revents & POLLOUT) == POLLOUT; }
bool pair_closed = (fds[i].revents & (POLLHUP | POLLERR)) != 0 || if (fds[i].revents & POLLOUT) {
(fds[i + 1].revents & (POLLHUP | POLLERR)) != 0; fds[i].events &= ~POLLOUT;
if (read_ready && write_ready) { }
LOG_D("Read+write ready on %ld", i / 2); }
ssize_t rv = splice(fds[i].fd, nullptr, fds[i + 1].fd, nullptr, for (size_t i = 0; i < fds.size() - 3; i += 3) {
4096, SPLICE_F_NONBLOCK); const size_t pipe_no = i / 3;
int in, out;
const char* direction;
bool closed = false;
std::tuple<int, int, const char*> direction_map[] = {
{i, i + 1, "in"}, {i + 2, i, "out"}};
for (const auto& entry : direction_map) {
std::tie(in, out, direction) = entry;
bool in_ready = (fds[in].events & POLLIN) == 0 ||
(fds[in].revents & POLLIN) == POLLIN;
bool out_ready = (fds[out].events & POLLOUT) == 0 ||
(fds[out].revents & POLLOUT) == POLLOUT;
if (in_ready && out_ready) {
LOG_D("#%ld piping data %s", pipe_no, direction);
ssize_t rv = splice(fds[in].fd, nullptr, fds[out].fd,
nullptr, 4096, SPLICE_F_NONBLOCK);
if (rv == -1 && errno != EAGAIN) { if (rv == -1 && errno != EAGAIN) {
PLOG_E("splice fd pair #%ld {%d, %d}\n", i / 2, fds[i].fd, PLOG_E("splice fd pair #%ld {%d, %d}\n", pipe_no,
fds[i + 1].fd); fds[in].fd, fds[out].fd);
} }
if (rv == 0) { if (rv == 0) {
pair_closed = true; closed = true;
} }
fds[i].events = POLLIN; fds[in].events |= POLLIN;
fds[i + 1].events = POLLOUT; fds[out].events |= POLLOUT;
} else if (read_ready) {
LOG_D("Read ready on %ld", i / 2);
fds[i].events = 0;
} else if (write_ready) {
LOG_D("Write ready on %ld", i / 2);
fds[i + 1].events = 0;
} }
if (pair_closed) { if ((fds[in].revents & (POLLERR | POLLHUP)) != 0 ||
LOG_D("Hangup on %ld", i / 2); (fds[out].revents & (POLLERR | POLLHUP)) != 0) {
closed = true;
}
}
if (closed) {
LOG_D("#%ld connection closed", pipe_no);
cleanup = true; cleanup = true;
close(fds[i].fd); close(nsjconf->pipes[pipe_no].sock_fd);
close(fds[i + 1].fd); close(nsjconf->pipes[pipe_no].pipe_in);
nsjconf->pipes[i / 2] = {0, 0}; close(nsjconf->pipes[pipe_no].pipe_out);
nsjconf->pipes[pipe_no] = {};
} }
} }
if (cleanup) { if (cleanup) {
break; break;
} }
} }
nsjconf->pipes.erase( nsjconf->pipes.erase(std::remove(nsjconf->pipes.begin(), nsjconf->pipes.end(), pipemap_t{}),
std::remove(nsjconf->pipes.begin(), nsjconf->pipes.end(), std::pair<int, int>(0, 0)),
nsjconf->pipes.end()); nsjconf->pipes.end());
return false; return false;
} }
@ -216,8 +235,8 @@ static int listenMode(nsjconf_t* nsjconf) {
PLOG_E("pipe"); PLOG_E("pipe");
continue; continue;
} }
nsjconf->pipes.emplace_back(connfd, in[1]); nsjconf->pipes.push_back(
nsjconf->pipes.emplace_back(out[0], connfd); {.sock_fd = connfd, .pipe_in = in[1], .pipe_out = out[0]});
subproc::runChild(nsjconf, connfd, in[0], out[1], out[1]); subproc::runChild(nsjconf, connfd, in[0], out[1], out[1]);
close(in[0]); close(in[0]);
close(out[1]); close(out[1]);

View File

@ -82,6 +82,15 @@ enum ns_mode_t {
MODE_STANDALONE_RERUN MODE_STANDALONE_RERUN
}; };
struct pipemap_t {
int sock_fd;
int pipe_in;
int pipe_out;
bool operator==(const pipemap_t& o) {
return sock_fd == o.sock_fd && pipe_in == o.pipe_in && pipe_out == o.pipe_out;
}
};
struct nsjconf_t { struct nsjconf_t {
std::string exec_file; std::string exec_file;
bool use_execveat; bool use_execveat;
@ -158,7 +167,7 @@ struct nsjconf_t {
std::vector<int> openfds; std::vector<int> openfds;
std::vector<int> caps; std::vector<int> caps;
std::vector<std::string> ifaces; std::vector<std::string> ifaces;
std::vector<std::pair<int, int>> pipes; std::vector<pipemap_t> pipes;
}; };
#endif /* _NSJAIL_H */ #endif /* _NSJAIL_H */