diff options
author | Bhasker Hariharan <bhaskerh@google.com> | 2021-07-01 14:39:20 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-07-01 14:42:00 -0700 |
commit | 570ca571805d6939c4c24b6a88660eefaf558ae7 (patch) | |
tree | 50b36e53b2b692a72dc135d3ec1aa3db58fb5b05 /test/syscalls/linux/socket_test_util.cc | |
parent | 3d4a8824f8e7aafdf6c1d18822b7593fa2e3e6bb (diff) |
Fix bug with TCP bind w/ SO_REUSEADDR.
In gVisor today its possible that when trying to bind a TCP socket
w/ SO_REUSEADDR specified and requesting the kernel pick a port by
setting port to zero can result in a previously bound port being
returned. This behaviour is incorrect as the user is clearly requesting
a free port. The behaviour is fine when the user explicity specifies
a port.
This change now checks if the user specified a port when making a port
reservation for a TCP port and only returns unbound ports even if
SO_REUSEADDR was specified.
Fixes #6209
PiperOrigin-RevId: 382607638
Diffstat (limited to 'test/syscalls/linux/socket_test_util.cc')
-rw-r--r-- | test/syscalls/linux/socket_test_util.cc | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/test/syscalls/linux/socket_test_util.cc b/test/syscalls/linux/socket_test_util.cc index 5e36472b4..1afb1ab50 100644 --- a/test/syscalls/linux/socket_test_util.cc +++ b/test/syscalls/linux/socket_test_util.cc @@ -24,6 +24,7 @@ #include "gtest/gtest.h" #include "absl/memory/memory.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_split.h" #include "absl/time/clock.h" #include "absl/types/optional.h" #include "test/util/file_descriptor.h" @@ -1067,5 +1068,43 @@ void SetupTimeWaitClose(const TestAddress* listener, absl::SleepFor(absl::Seconds(1)); } +constexpr char kRangeFile[] = "/proc/sys/net/ipv4/ip_local_port_range"; + +PosixErrorOr<int> MaybeLimitEphemeralPorts() { + int min = 0; + int max = 1 << 16; + + // Read the ephemeral range from /proc. + ASSIGN_OR_RETURN_ERRNO(std::string rangefile, GetContents(kRangeFile)); + const std::string err_msg = + absl::StrFormat("%s has invalid content: %s", kRangeFile, rangefile); + if (rangefile.back() != '\n') { + return PosixError(EINVAL, err_msg); + } + rangefile.pop_back(); + std::vector<std::string> range = + absl::StrSplit(rangefile, absl::ByAnyChar("\t ")); + if (range.size() < 2 || !absl::SimpleAtoi(range.front(), &min) || + !absl::SimpleAtoi(range.back(), &max)) { + return PosixError(EINVAL, err_msg); + } + + // If we can open as writable, limit the range. + if (!access(kRangeFile, W_OK)) { + ASSIGN_OR_RETURN_ERRNO(FileDescriptor fd, + Open(kRangeFile, O_WRONLY | O_TRUNC, 0)); + max = min + 50; + const std::string small_range = absl::StrFormat("%d %d", min, max); + int n = write(fd.get(), small_range.c_str(), small_range.size()); + if (n < 0) { + return PosixError( + errno, + absl::StrFormat("write(%d [%s], \"%s\", %d)", fd.get(), kRangeFile, + small_range.c_str(), small_range.size())); + } + } + return max - min; +} + } // namespace testing } // namespace gvisor |