Skip to content
Bitcoin Roots

v31.1-roots.1 · Commit 6: [PATCH 06/17] feat(wallet): preserve Roots signing and spend controls on v31

src/util/subprocess.cpp

Before: /dev/null · After: src/util/subprocess.cpp

File metadata
new file mode 100644
index 0000000000000000000000000000000000000000..2e6e5d80b9415cb33e2562c699a7697ca222f200

Download original patch · Release notes

Diff rows 1–116 of 116. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.

src/util/subprocess.cpp ADDED
@@ -0,0 +1,116 @@
1
+ // Copyright (c) 2025-present The Bitcoin Roots developers
2
+ // Distributed under the MIT software license, see the accompanying
3
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
+
5
+ #include <bitcoin-build-config.h> // IWYU pragma: keep
6
+
7
+ #ifndef WIN32
8
+
9
+ #if HAVE_CLOSE_RANGE_LINUX
10
+ #ifndef _GNU_SOURCE
11
+ #define _GNU_SOURCE
12
+ #endif
13
+ #include <linux/close_range.h>
14
+ #endif
15
+
16
+ #include <cerrno>
17
+ #include <cstddef>
18
+ #include <cstdint>
19
+ #include <cstring>
20
+ #include <fcntl.h>
21
+ #include <limits.h>
22
+ #include <unistd.h>
23
+
24
+ #ifdef __linux__
25
+ #include <sys/syscall.h>
26
+ #endif
27
+
28
+ namespace subprocess::detail {
29
+
30
+ #ifdef __linux__
31
+ // The kernel ABI for getdents64. No libc directory iterator or heap storage is
32
+ // used after fork: /proc enumerates the actual descriptors, including ones above
33
+ // a subsequently lowered RLIMIT_NOFILE.
34
+ struct LinuxDirent64 {
35
+ uint64_t inode;
36
+ int64_t offset;
37
+ unsigned short record_length;
38
+ unsigned char type;
39
+ char name[1];
40
+ };
41
+
42
+ static bool CloseProcDescriptors() noexcept
43
+ {
44
+ const int directory = open("/proc/self/fd", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
45
+ if (directory < 0) return false;
46
+ alignas(LinuxDirent64) char buffer[4096];
47
+ bool success{true};
48
+ for (;;) {
49
+ const long count = syscall(SYS_getdents64, directory, buffer, sizeof(buffer));
50
+ if (count == 0) break;
51
+ if (count < 0) {
52
+ if (errno == EINTR) continue;
53
+ success = false;
54
+ break;
55
+ }
56
+ for (long position{0}; position < count;) {
57
+ constexpr size_t name_offset{offsetof(LinuxDirent64, name)};
58
+ if (count - position <= static_cast<long>(name_offset)) {
59
+ success = false;
60
+ break;
61
+ }
62
+ unsigned short record_length;
63
+ std::memcpy(&record_length, buffer + position + offsetof(LinuxDirent64, record_length), sizeof(record_length));
64
+ const char* name{buffer + position + name_offset};
65
+ if (record_length <= name_offset || record_length > count - position) {
66
+ success = false;
67
+ break;
68
+ }
69
+ int fd{0};
70
+ size_t digit{0};
71
+ for (; digit < record_length - name_offset; ++digit) {
72
+ const char ch{name[digit]};
73
+ if (ch < '0' || ch > '9' || fd > (INT_MAX - (ch - '0')) / 10) break;
74
+ fd = fd * 10 + ch - '0';
75
+ }
76
+ if (digit > 0 && digit < record_length - name_offset && name[digit] == '\0' && fd > 3 && fd != directory) close(fd);
77
+ position += record_length;
78
+ }
79
+ if (!success) break;
80
+ }
81
+ close(directory);
82
+ return success;
83
+ }
84
+ #endif
85
+
86
+ bool subprocess_close_all_fds(int& except_fd, [[maybe_unused]] bool force_fallback) noexcept
87
+ {
88
+ if (except_fd < 3) return false;
89
+ // Keep the exec-error pipe at a fixed descriptor so native close-from APIs
90
+ // need no exception list or scan of a potentially enormous numeric range.
91
+ if (except_fd != 3) {
92
+ if (dup2(except_fd, 3) < 0) return false;
93
+ close(except_fd);
94
+ except_fd = 3;
95
+ }
96
+ if (fcntl(3, F_SETFD, FD_CLOEXEC) < 0) return false;
97
+ #if HAVE_CLOSE_RANGE_GENERIC || HAVE_CLOSE_RANGE_LINUX
98
+ if (!force_fallback && close_range(4, UINT_MAX, 0) == 0) return true;
99
+ #endif
100
+ #ifdef __linux__
101
+ return CloseProcDescriptors();
102
+ #elif HAVE_CLOSEFROM_RETURN_INT
103
+ return closefrom(4) == 0;
104
+ #elif HAVE_CLOSEFROM
105
+ closefrom(4);
106
+ return true;
107
+ #else
108
+ // An unsupported or unavailable safe closure mechanism must not allow the
109
+ // signer to execute with unrelated inherited descriptors.
110
+ return false;
111
+ #endif
112
+ }
113
+
114
+ } // namespace subprocess::detail
115
+
116
+ #endif // !WIN32