summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls/linux/socket_test_util.cc
diff options
context:
space:
mode:
authorBhasker Hariharan <bhaskerh@google.com>2021-07-01 14:39:20 -0700
committergVisor bot <gvisor-bot@google.com>2021-07-01 14:42:00 -0700
commit570ca571805d6939c4c24b6a88660eefaf558ae7 (patch)
tree50b36e53b2b692a72dc135d3ec1aa3db58fb5b05 /test/syscalls/linux/socket_test_util.cc
parent3d4a8824f8e7aafdf6c1d18822b7593fa2e3e6bb (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.cc39
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