What changed, and why it matters
This commit fixes a bug where Bitcoin Core would fail to start if the operating system allowed an unusually high number of open files (file descriptors). The limit was being treated as a negative number due to a conversion overflow, causing the program to incorrectly report that no file descriptors were available. The fix caps the value at the maximum a normal integer can hold, preventing the startup failure.
Apply the patch. It is a low-risk defensive fix that prevents a startup failure on systems with very high or misconfigured RLIMIT_NOFILE values. No immediate incident response is required.
Security signals we found
Integer overflow / signedness conversion in resource-limit handling
Denial-of-service vector: malformed/incompatible system ulimit can prevent node startup
Startup failure due to negative available file descriptor count
Evidence from the diff
RaiseFileDescriptorLimit() in src/util/fs_helpers.cpp now clamps rlim_cur values greater than or equal to INT_MAX to std::numeric_limits
Changed components
src/util/fs_helpers.cpp::RaiseFileDescriptorLimit()test/functional/feature_init.pyInspect captured patch +15 / −3
diff --git a/src/util/fs_helpers.cpp b/src/util/fs_helpers.cpp
index 3efc9fda..e2b4c899 100644
--- a/src/util/fs_helpers.cpp
+++ b/src/util/fs_helpers.cpp
@@ -179,11 +179,13 @@ int RaiseFileDescriptorLimit(int min_fd)
// Check the (possibly raised) current soft limit against the special
// value of RLIM_INFINITY. Some platforms implement this as the maximum
// uint64, others as int64 (-1). Avoid casting even if the return type
- // is changed to uint64_t.
- if (limitFD.rlim_cur == RLIM_INFINITY) {
+ // is changed to uint64_t. We also cap unlikely but possible values
+ // that would overflow int.
+ if (limitFD.rlim_cur == RLIM_INFINITY ||
+ std::cmp_greater_equal(limitFD.rlim_cur, std::numeric_limits<int>::max())) {
return std::numeric_limits<int>::max();
}
- return limitFD.rlim_cur;
+ return static_cast<int>(limitFD.rlim_cur);
}
return min_fd; // getrlimit failed, assume it's fine
#endif
diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py
index ee28a287..e7c226b2 100755
--- a/test/functional/feature_init.py
+++ b/test/functional/feature_init.py
@@ -348,6 +348,15 @@ class InitTest(BitcoinTestFramework):
self.log.info("Testing node startup with RLIM_INFINITY fd limit")
self.restart_node_with_fd_limit(self.RLIM_INFINITY)
+ def init_rlimit_large_test(self):
+ """Test that bitcoind starts correctly when the soft RLIMIT_NOFILE limit is above INT_MAX."""
+ if self.RLIM_INFINITY is None:
+ self.log.info("Skipping: resource module not available")
+ return
+
+ self.log.info("Testing node startup with fd limit above INT_MAX")
+ self.restart_node_with_fd_limit(1 << 31)
+
def run_test(self):
self.init_pid_test()
self.init_stress_test_interrupt()
@@ -355,6 +364,7 @@ class InitTest(BitcoinTestFramework):
self.break_wait_test()
self.init_empty_test()
self.init_rlimit_test()
+ self.init_rlimit_large_test()
if __name__ == '__main__':
Why this scored 33/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.