pyln-client: don't leak dirfd after connecting Unix socket
What changed, and why it matters
This commit fixes a file descriptor leak in the Python client library used to talk to Core Lightning. When connecting to a Unix socket whose path was too long, the code opened a temporary directory file descriptor but never closed it. Over time this could exhaust the process's allowance of open files, causing test failures or potentially disrupting normal operation. The fix wraps the socket connection in a try/finally block so the temporary descriptor is always closed.
Upgrade pyln-client to a version containing this commit. If upgrading is not possible, avoid using RPC socket paths longer than the platform's AF_UNIX limit, or monitor and restart client processes before file descriptor limits are exhausted.
Security signals we found
Resource exhaustion via unclosed file descriptor
Condition triggered only by long Unix socket paths
Fix uses try/finally to guarantee descriptor cleanup
Evidence from the diff
In contrib/pyln-client/pyln/client/lightning.py, the UnixSocket class handles AF_UNIX paths exceeding sockaddr_un limits by opening a directory FD and referencing the socket via /proc/self/fd/
Changed components
contrib/pyln-client/pyln/client/lightning.pypyln-client UnixSocket connection helperInspect captured patch +6 / −3
diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py
index 1706a472..440e36bb 100644
--- a/contrib/pyln-client/pyln/client/lightning.py
+++ b/contrib/pyln-client/pyln/client/lightning.py
@@ -254,9 +254,12 @@ class UnixSocket(object):
# Open an fd to our home directory, that we can then find
# through `/proc/self/fd` and access the contents.
dirfd = os.open(dirname, os.O_DIRECTORY | os.O_RDONLY)
- short_path = "/proc/self/fd/%d/%s" % (dirfd, basename)
- self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- self.sock.connect(short_path)
+ try:
+ short_path = "/proc/self/fd/%d/%s" % (dirfd, basename)
+ self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ self.sock.connect(short_path)
+ finally:
+ os.close(dirfd)
elif (e.args[0] == "AF_UNIX path too long" and os.uname()[0] == "Darwin"):
temp_dir = tempfile.mkdtemp()
temp_link = os.path.join(temp_dir, "socket_link")
Why this scored 28/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.