@photostructure/fs-metadata 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -1
- package/CLAUDE.md +141 -315
- package/CODE_OF_CONDUCT.md +11 -11
- package/CONTRIBUTING.md +1 -1
- package/README.md +34 -103
- package/binding.gyp +97 -22
- package/claude.sh +23 -0
- package/dist/index.cjs +51 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +51 -21
- package/dist/index.mjs.map +1 -1
- package/doc/C++_REVIEW_TODO.md +97 -25
- package/doc/GPG_RELEASE_HOWTO.md +44 -13
- package/doc/MACOS_API_REFERENCE.md +469 -0
- package/doc/SECURITY_AUDIT_2025.md +809 -0
- package/doc/SSH_RELEASE_HOWTO.md +28 -24
- package/doc/WINDOWS_API_REFERENCE.md +422 -0
- package/doc/WINDOWS_ARM64_SECURITY.md +161 -0
- package/doc/WINDOWS_DEBUG_GUIDE.md +9 -2
- package/doc/examples.md +267 -0
- package/doc/gotchas.md +297 -0
- package/doc/logo.png +0 -0
- package/doc/logo.svg +85 -0
- package/doc/macos-asan-sip-issue.md +71 -0
- package/doc/social.png +0 -0
- package/doc/social.svg +125 -0
- package/doc/windows-build.md +226 -0
- package/doc/windows-clang-tidy.md +72 -0
- package/doc/windows-memory-testing.md +108 -0
- package/doc/windows-prebuildify-arm64.md +232 -0
- package/jest.config.cjs +23 -0
- package/package.json +61 -36
- package/prebuilds/darwin-arm64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/darwin-x64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/linux-arm64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/linux-arm64/@photostructure+fs-metadata.musl.node +0 -0
- package/prebuilds/linux-x64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/linux-x64/@photostructure+fs-metadata.musl.node +0 -0
- package/prebuilds/win32-arm64/@photostructure+fs-metadata.glibc.node +0 -0
- package/prebuilds/win32-x64/@photostructure+fs-metadata.glibc.node +0 -0
- package/scripts/check-memory.ts +186 -0
- package/scripts/clang-tidy.ts +690 -99
- package/scripts/install.cjs +42 -0
- package/scripts/is-platform.mjs +1 -1
- package/scripts/macos-asan.sh +155 -0
- package/scripts/post-build.mjs +3 -3
- package/scripts/prebuild-linux-glibc.sh +12 -1
- package/scripts/prebuildify-wrapper.ts +77 -0
- package/scripts/precommit.ts +45 -20
- package/scripts/sanitizers-test.sh +1 -1
- package/src/common/volume_metadata.h +6 -0
- package/src/darwin/hidden.cpp +73 -25
- package/src/darwin/path_security.h +149 -0
- package/src/darwin/raii_utils.h +104 -4
- package/src/darwin/volume_metadata.cpp +132 -58
- package/src/darwin/volume_mount_points.cpp +80 -47
- package/src/hidden.ts +36 -13
- package/src/linux/gio_mount_points.cpp +17 -18
- package/src/linux/gio_utils.cpp +92 -37
- package/src/linux/gio_utils.h +11 -5
- package/src/linux/gio_volume_metadata.cpp +111 -48
- package/src/linux/volume_metadata.cpp +67 -4
- package/src/object.ts +1 -0
- package/src/options.ts +6 -0
- package/src/path.ts +11 -0
- package/src/remote_info.ts +5 -3
- package/src/stack_path.ts +8 -6
- package/src/string_enum.ts +1 -0
- package/src/test-utils/memory-test-core.ts +336 -0
- package/src/test-utils/memory-test-runner.ts +108 -0
- package/src/test-utils/platform.ts +46 -1
- package/src/test-utils/worker-thread-helper.cjs +154 -27
- package/src/types/native_bindings.ts +1 -1
- package/src/types/options.ts +6 -0
- package/src/windows/drive_status.h +133 -163
- package/src/windows/error_utils.h +54 -3
- package/src/windows/fs_meta.h +1 -1
- package/src/windows/hidden.cpp +60 -43
- package/src/windows/security_utils.h +250 -0
- package/src/windows/string.h +68 -11
- package/src/windows/system_volume.h +1 -1
- package/src/windows/thread_pool.h +206 -0
- package/src/windows/volume_metadata.cpp +11 -6
- package/src/windows/volume_mount_points.cpp +8 -7
- package/src/windows/windows_arch.h +39 -0
- package/scripts/check-memory.mjs +0 -123
|
@@ -0,0 +1,809 @@
|
|
|
1
|
+
# Security Audit Report - October 22 2025
|
|
2
|
+
|
|
3
|
+
**Project**: @photostructure/fs-metadata
|
|
4
|
+
**Auditor**: Claude (Anthropic)
|
|
5
|
+
**Scope**: Complete codebase review including API verification against official documentation
|
|
6
|
+
|
|
7
|
+
## Executive Summary
|
|
8
|
+
|
|
9
|
+
This comprehensive security audit examined all source files (12 C++ files, 21 headers, TypeScript bindings, and build configuration) and verified every external API call against official documentation from Microsoft.com, Apple.com, kernel.org, and gnome.org.
|
|
10
|
+
|
|
11
|
+
**Overall Security Rating: B+ (Good with identified improvements needed)**
|
|
12
|
+
|
|
13
|
+
### Strengths
|
|
14
|
+
|
|
15
|
+
- ✅ Excellent RAII patterns preventing resource leaks
|
|
16
|
+
- ✅ Comprehensive integer overflow protection
|
|
17
|
+
- ✅ Strong Windows security compiler flags (/guard:cf, /sdl, /Qspectre)
|
|
18
|
+
- ✅ Good input validation at API boundaries
|
|
19
|
+
- ✅ Proper exception safety throughout
|
|
20
|
+
|
|
21
|
+
### Areas Requiring Improvement
|
|
22
|
+
|
|
23
|
+
- ✅ ~~Path validation can be bypassed (Critical)~~ → FIXED 2025-10-23
|
|
24
|
+
- ⚠️ Thread safety issues with macOS DiskArbitration and Linux GIO (High) → Pending
|
|
25
|
+
- ⚠️ Memory leak risks in error handling (High) → Pending
|
|
26
|
+
- ✅ ~~CFStringGetCString silent failures (Medium)~~ → FIXED 2025-10-23
|
|
27
|
+
- ✅ ~~TOCTOU race conditions on macOS (Medium)~~ → FIXED 2025-10-23
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Critical Priority Findings
|
|
32
|
+
|
|
33
|
+
### Finding #1: Path Validation Bypass (macOS/Linux) ✅ FIXED
|
|
34
|
+
|
|
35
|
+
**Severity**: 🔴 CRITICAL → ✅ RESOLVED
|
|
36
|
+
**Files Affected**:
|
|
37
|
+
|
|
38
|
+
- `src/darwin/hidden.cpp` (updated)
|
|
39
|
+
- `src/darwin/volume_metadata.cpp` (updated)
|
|
40
|
+
- `src/darwin/path_security.h` (new - secure path validation header)
|
|
41
|
+
- `src/darwin-path-security.test.ts` (tests added)
|
|
42
|
+
|
|
43
|
+
**Status**: Fixed on 2025-10-23
|
|
44
|
+
|
|
45
|
+
**Issue**: Simple string-based path validation using `path.find("..")` could be bypassed with URL-encoded sequences, Unicode normalization attacks, redundant separators, or absolute path traversal.
|
|
46
|
+
|
|
47
|
+
**Fix Applied**:
|
|
48
|
+
|
|
49
|
+
- Created `src/darwin/path_security.h` with `realpath()`-based validation
|
|
50
|
+
- Updated `src/darwin/hidden.cpp` and `src/darwin/volume_metadata.cpp`
|
|
51
|
+
- Added 13 comprehensive security tests (all passing)
|
|
52
|
+
|
|
53
|
+
**Security Improvements**:
|
|
54
|
+
|
|
55
|
+
- ✅ Uses `realpath()` to canonicalize paths, eliminating `../`, `./`, and symbolic links
|
|
56
|
+
- ✅ Validates parent directory for non-existent paths
|
|
57
|
+
- ✅ Prevents null byte injection
|
|
58
|
+
- ✅ Maintains backward compatibility (all 486 tests pass)
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### Finding #2: Windows Path Length Restriction ✅ FIXED
|
|
63
|
+
|
|
64
|
+
**Severity**: 🔴 CRITICAL → ✅ RESOLVED
|
|
65
|
+
**Files Affected**:
|
|
66
|
+
|
|
67
|
+
- `src/windows/security_utils.h:106-116` (updated)
|
|
68
|
+
- `src/windows-input-security.test.ts` (tests added)
|
|
69
|
+
- `doc/WINDOWS_API_REFERENCE.md` (documentation updated)
|
|
70
|
+
- `doc/gotchas.md` (documentation added)
|
|
71
|
+
|
|
72
|
+
**Status**: Fixed on 2025-10-23
|
|
73
|
+
|
|
74
|
+
**Issue**: `PathCchCanonicalize` restricts paths to MAX_PATH (260 characters), preventing access to legitimate long paths that Windows 10+ supports (up to 32,768 characters).
|
|
75
|
+
|
|
76
|
+
**Fix Applied**:
|
|
77
|
+
|
|
78
|
+
- Migrated to `PathCchCanonicalizeEx` with `PATHCCH_ALLOW_LONG_PATHS` flag
|
|
79
|
+
- Updated buffer sizes from MAX_PATH (260) to PATHCCH_MAX_CCH (32,768)
|
|
80
|
+
- Added comprehensive test coverage for long paths
|
|
81
|
+
- Updated documentation in `doc/WINDOWS_API_REFERENCE.md` and `doc/gotchas.md`
|
|
82
|
+
|
|
83
|
+
**Note**: Applications must enable long path support via app manifest or registry configuration.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### Finding #3: Integer Overflow in String Conversion ✅ FIXED
|
|
88
|
+
|
|
89
|
+
**Severity**: 🔴 CRITICAL → ✅ RESOLVED
|
|
90
|
+
**Files Affected**:
|
|
91
|
+
|
|
92
|
+
- `src/windows/string.h:9-103` (updated)
|
|
93
|
+
- `src/windows-string-security.test.ts` (tests added)
|
|
94
|
+
- `doc/WINDOWS_API_REFERENCE.md` (documentation updated)
|
|
95
|
+
|
|
96
|
+
**Status**: Fixed on 2025-10-23
|
|
97
|
+
|
|
98
|
+
**Issue**: `WideToUtf8()` and `ToWString()` didn't validate that conversion sizes were positive or check for integer overflow before allocation.
|
|
99
|
+
|
|
100
|
+
**Fix Applied**:
|
|
101
|
+
|
|
102
|
+
- Added overflow protection: validates `size > INT_MAX - 1` before subtraction
|
|
103
|
+
- Enforced sanity limits: 1MB for general strings, PATHCCH_MAX_CCH for paths
|
|
104
|
+
- Added input validation: checks input length fits in `int` type
|
|
105
|
+
- Implemented error detection with `MB_ERR_INVALID_CHARS` flag
|
|
106
|
+
- Added comprehensive debug logging for all failure paths
|
|
107
|
+
|
|
108
|
+
**Test Coverage**: Overflow scenarios, size limits, invalid UTF-8, multi-byte characters, stress testing (100+ conversions)
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## High Priority Findings
|
|
113
|
+
|
|
114
|
+
### Finding #4: Memory Leak in Windows Error Formatting ✅ FIXED
|
|
115
|
+
|
|
116
|
+
**Severity**: 🟠 HIGH → ✅ RESOLVED
|
|
117
|
+
**Files Affected**:
|
|
118
|
+
|
|
119
|
+
- `src/windows/error_utils.h:19-95` (updated)
|
|
120
|
+
- `src/windows-error-utils-security.test.ts` (tests added)
|
|
121
|
+
- `doc/WINDOWS_API_REFERENCE.md` (documentation updated)
|
|
122
|
+
|
|
123
|
+
**Status**: Fixed on 2025-10-23
|
|
124
|
+
|
|
125
|
+
**Issue**: `FormatMessageA` with `FORMAT_MESSAGE_ALLOCATE_BUFFER` requires `LocalFree`, but if the `std::string` constructor throws an exception, memory leaks.
|
|
126
|
+
|
|
127
|
+
**Fix Applied**:
|
|
128
|
+
|
|
129
|
+
- Implemented RAII `LocalFreeGuard` to ensure `LocalFree` is always called
|
|
130
|
+
- Added null safety and error logging
|
|
131
|
+
- Made exception-safe: memory freed regardless of code path
|
|
132
|
+
- Added comprehensive test coverage (1000+ iterations, concurrent operations)
|
|
133
|
+
|
|
134
|
+
**Impact**: Prevents memory leaks in error handling paths, critical for long-running services.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### Finding #5: Undocumented Thread Safety - DiskArbitration (macOS) ✅ FIXED
|
|
139
|
+
|
|
140
|
+
**Severity**: 🟠 HIGH → ✅ RESOLVED
|
|
141
|
+
**Files Affected**:
|
|
142
|
+
|
|
143
|
+
- `src/darwin/volume_metadata.cpp` (updated)
|
|
144
|
+
- `src/darwin/raii_utils.h` (DASessionRAII wrapper added)
|
|
145
|
+
- `src/darwin-disk-arbitration-threading.test.ts` (tests added)
|
|
146
|
+
|
|
147
|
+
**Status**: Fixed on 2025-10-23
|
|
148
|
+
|
|
149
|
+
**Issue**:
|
|
150
|
+
While the code uses a mutex to serialize DiskArbitration access, Apple's documentation doesn't explicitly guarantee thread safety for `DADiskCopyDescription`. The framework is designed for run loop/dispatch queue usage.
|
|
151
|
+
|
|
152
|
+
**Research Findings**:
|
|
153
|
+
|
|
154
|
+
- Apple Developer Forums show no explicit thread-safety guarantees
|
|
155
|
+
- DiskArbitration is designed to work with CFRunLoop (main thread pattern)
|
|
156
|
+
- No documented CVEs, but framework assumptions may not hold in worker threads
|
|
157
|
+
|
|
158
|
+
**Official Documentation**:
|
|
159
|
+
|
|
160
|
+
- [DADiskCopyDescription](<https://developer.apple.com/documentation/diskarbitration/dadiskcopydescription(_:)>)
|
|
161
|
+
- Apple: [Thread Safety Summary](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html)
|
|
162
|
+
|
|
163
|
+
**Current Code**:
|
|
164
|
+
|
|
165
|
+
```cpp
|
|
166
|
+
// src/darwin/volume_metadata.cpp:173
|
|
167
|
+
// Use a global mutex to serialize DiskArbitration access
|
|
168
|
+
std::lock_guard<std::mutex> lock(g_diskArbitrationMutex);
|
|
169
|
+
|
|
170
|
+
CFReleaser<DASessionRef> session(DASessionCreate(kCFAllocatorDefault));
|
|
171
|
+
// ... DA operations
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Implemented Fix**:
|
|
175
|
+
|
|
176
|
+
Based on extensive research into Node.js threading and macOS APIs, we implemented a solution following Apple's DiskArbitration Programming Guide recommendations:
|
|
177
|
+
|
|
178
|
+
**1. Created RAII wrapper for DASession** (`src/darwin/raii_utils.h`):
|
|
179
|
+
|
|
180
|
+
```cpp
|
|
181
|
+
class DASessionRAII {
|
|
182
|
+
private:
|
|
183
|
+
CFReleaser<DASessionRef> session_;
|
|
184
|
+
bool is_scheduled_;
|
|
185
|
+
|
|
186
|
+
public:
|
|
187
|
+
~DASessionRAII() { unschedule(); } // Ensures cleanup order
|
|
188
|
+
|
|
189
|
+
void scheduleOnQueue(dispatch_queue_t queue) {
|
|
190
|
+
DASessionSetDispatchQueue(session_.get(), queue);
|
|
191
|
+
is_scheduled_ = true;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
void unschedule() {
|
|
195
|
+
if (is_scheduled_ && session_.isValid()) {
|
|
196
|
+
DASessionSetDispatchQueue(session_.get(), nullptr); // Required before release
|
|
197
|
+
is_scheduled_ = false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**2. Updated implementation** (`src/darwin/volume_metadata.cpp`):
|
|
204
|
+
|
|
205
|
+
```cpp
|
|
206
|
+
void GetDiskArbitrationInfoSafe() {
|
|
207
|
+
// THREAD SAFETY NOTE:
|
|
208
|
+
// Apple's DiskArbitration Programming Guide recommends scheduling DASession
|
|
209
|
+
// on a run loop or dispatch queue before using it. We use a dedicated serial
|
|
210
|
+
// dispatch queue (not the main queue) to avoid deadlock in Node.js context
|
|
211
|
+
// while following Apple's documented usage pattern.
|
|
212
|
+
std::lock_guard<std::mutex> lock(g_diskArbitrationMutex);
|
|
213
|
+
|
|
214
|
+
// Create session with RAII wrapper
|
|
215
|
+
DASessionRAII session(DASessionCreate(kCFAllocatorDefault));
|
|
216
|
+
|
|
217
|
+
// Schedule on background serial queue (not main queue)
|
|
218
|
+
static dispatch_queue_t da_queue = dispatch_queue_create(
|
|
219
|
+
"com.photostructure.fs-metadata.diskarbitration",
|
|
220
|
+
DISPATCH_QUEUE_SERIAL);
|
|
221
|
+
|
|
222
|
+
session.scheduleOnQueue(da_queue);
|
|
223
|
+
|
|
224
|
+
// Use session...
|
|
225
|
+
CFReleaser<DADiskRef> disk(DADiskCreateFromBSDName(...));
|
|
226
|
+
CFReleaser<CFDictionaryRef> description(DADiskCopyDescription(disk.get()));
|
|
227
|
+
|
|
228
|
+
// RAII wrapper automatically unschedules and releases on scope exit
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Why This Approach**:
|
|
233
|
+
|
|
234
|
+
- ✅ Follows Apple's documented pattern: "create session, schedule it, use it"
|
|
235
|
+
- ✅ Uses background dispatch queue (avoiding main queue deadlock in Node.js)
|
|
236
|
+
- ✅ RAII ensures proper cleanup order (unschedule before release)
|
|
237
|
+
- ✅ Compatible with Node.js/libuv threading model
|
|
238
|
+
- ✅ Mutex still serializes for extra safety
|
|
239
|
+
|
|
240
|
+
**Why NOT `dispatch_sync(dispatch_get_main_queue())`**:
|
|
241
|
+
Research showed this would deadlock because Node.js doesn't pump CFRunLoop on its main thread.
|
|
242
|
+
|
|
243
|
+
**Test Coverage**:
|
|
244
|
+
|
|
245
|
+
- Existing concurrent tests in `volume_metadata.test.ts` (50 concurrent requests)
|
|
246
|
+
- New threading stress tests in `darwin-disk-arbitration-threading.test.ts` (100+ rapid requests)
|
|
247
|
+
- All 486 tests pass
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
### Finding #6: Thread Safety Violation - GVolumeMonitor (Linux) ✅ FIXED
|
|
252
|
+
|
|
253
|
+
**Severity**: 🟠 HIGH → ✅ RESOLVED
|
|
254
|
+
**Files Affected**:
|
|
255
|
+
|
|
256
|
+
- `src/linux/gio_utils.cpp` (rewritten)
|
|
257
|
+
- `src/linux/gio_utils.h` (updated)
|
|
258
|
+
- `src/linux/gio_mount_points.cpp` (updated)
|
|
259
|
+
- `src/linux/gio_volume_metadata.cpp` (updated)
|
|
260
|
+
- `binding.gyp` (updated to include gio-unix-2.0)
|
|
261
|
+
- `src/linux-gio-thread-safety.test.ts` (tests added)
|
|
262
|
+
|
|
263
|
+
**Status**: Fixed on 2025-10-24
|
|
264
|
+
|
|
265
|
+
**Issue**:
|
|
266
|
+
The code accessed `GVolumeMonitor` from AsyncWorker threads, but GIO documentation explicitly states:
|
|
267
|
+
|
|
268
|
+
> "GVolumeMonitor is not thread-default-context aware, and so should not be used other than from the main thread, with no thread-default-context active."
|
|
269
|
+
|
|
270
|
+
**Official Documentation**:
|
|
271
|
+
|
|
272
|
+
- [GVolumeMonitor](https://docs.gtk.org/gio/class.VolumeMonitor.html) - Thread safety restrictions
|
|
273
|
+
- [g_unix_mounts_get](https://gitlab.gnome.org/GNOME/glib/-/blob/main/gio/gunixmounts.c) - Thread-safe alternative
|
|
274
|
+
|
|
275
|
+
**Fix Applied**:
|
|
276
|
+
|
|
277
|
+
Implemented a **dual-path architecture**:
|
|
278
|
+
|
|
279
|
+
1. **Primary Path (Thread-Safe)**: Uses `g_unix_mounts_get()` which is explicitly thread-safe
|
|
280
|
+
- Uses `getmntent_r()` when available (reentrant)
|
|
281
|
+
- Falls back to `getmntent()` with G_LOCK protection
|
|
282
|
+
- Provides mount path, device path, filesystem type
|
|
283
|
+
- Safe to call from worker threads ✅
|
|
284
|
+
|
|
285
|
+
2. **Optional Enhancement (Best-Effort)**: GVolumeMonitor for rich metadata
|
|
286
|
+
- Volume labels from GVFS
|
|
287
|
+
- Network URIs
|
|
288
|
+
- Mount names
|
|
289
|
+
- Wrapped in try/catch - failure is acceptable
|
|
290
|
+
|
|
291
|
+
**Security Improvements**:
|
|
292
|
+
|
|
293
|
+
- ✅ Primary code path uses documented thread-safe API (`g_unix_mounts_get`)
|
|
294
|
+
- ✅ No longer depends on GVolumeMonitor for core functionality
|
|
295
|
+
- ✅ Degrades gracefully if GVolumeMonitor enrichment fails
|
|
296
|
+
- ✅ Fixes Finding #7 (double-free) simultaneously
|
|
297
|
+
- ✅ Updated binding.gyp to include `gio-unix-2.0` package
|
|
298
|
+
|
|
299
|
+
**Test Coverage**:
|
|
300
|
+
|
|
301
|
+
- 3 new tests in `src/linux-gio-thread-safety.test.ts`
|
|
302
|
+
- 50 concurrent mount point requests (stress test)
|
|
303
|
+
- 20 concurrent metadata queries
|
|
304
|
+
- All existing tests pass (490 total)
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
### Finding #7: Potential Double-Free in GIO (Linux) ✅ FIXED
|
|
309
|
+
|
|
310
|
+
**Severity**: 🟠 HIGH → ✅ RESOLVED
|
|
311
|
+
**Files Affected**:
|
|
312
|
+
|
|
313
|
+
- `src/linux/gio_utils.cpp` (rewritten - fixed as part of Finding #6)
|
|
314
|
+
|
|
315
|
+
**Status**: Fixed on 2025-10-24 (resolved together with Finding #6)
|
|
316
|
+
|
|
317
|
+
**Issue**:
|
|
318
|
+
The original code called `g_object_ref(mount)` to take an extra reference, then called `g_object_unref(mount)` in multiple code paths (success, error, exception), and finally called `g_list_free_full(mounts, g_object_unref)` which would unref each mount again, causing a double-free.
|
|
319
|
+
|
|
320
|
+
**Official Documentation**:
|
|
321
|
+
|
|
322
|
+
- [g_list_free_full](https://docs.gtk.org/glib/func.list_free_full.html) - Calls the destroy function on each element
|
|
323
|
+
|
|
324
|
+
**Fix Applied**:
|
|
325
|
+
|
|
326
|
+
The rewrite for Finding #6 completely eliminates this issue:
|
|
327
|
+
|
|
328
|
+
1. **New implementation uses `GUnixMountEntry`** instead of `GMount`
|
|
329
|
+
- No reference counting needed for GUnixMountEntry
|
|
330
|
+
- Freed with `g_unix_mount_free()` not `g_object_unref()`
|
|
331
|
+
- Clean separation: one `g_list_free_full()` call, no manual unrefs
|
|
332
|
+
|
|
333
|
+
2. **Optional GVolumeMonitor path** (when used):
|
|
334
|
+
- Uses `g_list_free_full(mounts, g_object_unref)` exactly once
|
|
335
|
+
- No manual `g_object_ref()`/`g_object_unref()` pairs
|
|
336
|
+
- List owns all references
|
|
337
|
+
|
|
338
|
+
**Why This Matters**:
|
|
339
|
+
Double-unref can cause:
|
|
340
|
+
|
|
341
|
+
1. Use-after-free vulnerabilities
|
|
342
|
+
2. Crashes when GObject reaches ref count 0 prematurely
|
|
343
|
+
3. Memory corruption if object is freed and reallocated
|
|
344
|
+
|
|
345
|
+
**Test Coverage**:
|
|
346
|
+
|
|
347
|
+
- Fixed implementation validated by all existing mount/metadata tests
|
|
348
|
+
- 50+ concurrent requests stress test (would expose double-free under load)
|
|
349
|
+
- All 490 tests pass
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Medium Priority Findings
|
|
354
|
+
|
|
355
|
+
### Finding #8: CFStringGetCString Error Logging (macOS) ✅ FIXED
|
|
356
|
+
|
|
357
|
+
**Severity**: 🟡 MEDIUM → ✅ RESOLVED
|
|
358
|
+
**Files Affected**:
|
|
359
|
+
|
|
360
|
+
- `src/darwin/volume_metadata.cpp` (updated)
|
|
361
|
+
|
|
362
|
+
**Status**: Fixed on 2025-10-23
|
|
363
|
+
|
|
364
|
+
**Issue**:
|
|
365
|
+
The code correctly checks the return value of `CFStringGetCString`, but doesn't log why conversion failed, making debugging difficult.
|
|
366
|
+
|
|
367
|
+
**Fix Applied**: Added debug logging to log conversion failures with buffer size and string length details.
|
|
368
|
+
|
|
369
|
+
**Impact**: Improved debuggability with no performance impact.
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
### Finding #9: TOCTOU Race Condition in statvfs/statfs (macOS/Linux) ✅ FIXED
|
|
374
|
+
|
|
375
|
+
**Severity**: 🟡 MEDIUM → ✅ RESOLVED
|
|
376
|
+
**Files Affected**:
|
|
377
|
+
|
|
378
|
+
- `src/darwin/volume_metadata.cpp` (updated - macOS)
|
|
379
|
+
- `src/linux/volume_metadata.cpp` (updated - Linux)
|
|
380
|
+
|
|
381
|
+
**Status**: macOS fixed on 2025-10-23, Linux fixed on 2025-10-24
|
|
382
|
+
|
|
383
|
+
**Issue**:
|
|
384
|
+
Time-of-check-time-of-use race condition: mount point could be unmounted or replaced between `statvfs` call and subsequent operations.
|
|
385
|
+
|
|
386
|
+
**Official Documentation**:
|
|
387
|
+
|
|
388
|
+
- [Apple: Race Conditions and Secure File Operations](https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html)
|
|
389
|
+
- [statvfs(2) man page](https://man7.org/linux/man-pages/man2/statvfs.2.html)
|
|
390
|
+
- [fstatvfs(2) man page](https://man7.org/linux/man-pages/man2/fstatvfs.2.html)
|
|
391
|
+
- [open(2) man page - O_DIRECTORY flag](https://man7.org/linux/man-pages/man2/open.2.html)
|
|
392
|
+
|
|
393
|
+
**Fix Applied (macOS)**:
|
|
394
|
+
|
|
395
|
+
- Use file descriptor-based approach: `open()` with `O_DIRECTORY`, then `fstatvfs()`/`fstatfs()`
|
|
396
|
+
- Added RAII `FdGuard` to ensure file descriptor is always closed
|
|
397
|
+
- File descriptor holds reference to filesystem, preventing mount changes during operation
|
|
398
|
+
|
|
399
|
+
**Fix Applied (Linux)**:
|
|
400
|
+
|
|
401
|
+
- Same file descriptor-based approach as macOS
|
|
402
|
+
- `open()` with `O_DIRECTORY | O_RDONLY | O_CLOEXEC`
|
|
403
|
+
- Use `fstatvfs()` on file descriptor instead of `statvfs()` on path
|
|
404
|
+
- RAII `FdGuard` struct ensures file descriptor is always closed (exception-safe)
|
|
405
|
+
- Added comprehensive inline documentation explaining TOCTOU prevention
|
|
406
|
+
|
|
407
|
+
**Security Improvements**:
|
|
408
|
+
|
|
409
|
+
- ✅ File descriptor holds reference to filesystem, preventing TOCTOU
|
|
410
|
+
- ✅ `O_DIRECTORY` ensures we're opening a directory (fails otherwise)
|
|
411
|
+
- ✅ `O_CLOEXEC` prevents fd leaks in multithreaded programs
|
|
412
|
+
- ✅ RAII pattern guarantees resource cleanup
|
|
413
|
+
|
|
414
|
+
**Impact**: Prevents race condition attacks; all 491 tests pass with no regressions.
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
### Finding #10: blkid Memory Management Documentation (Linux) ✅ FIXED
|
|
419
|
+
|
|
420
|
+
**Severity**: 🟡 MEDIUM (Documentation) → ✅ RESOLVED
|
|
421
|
+
**Files Affected**:
|
|
422
|
+
|
|
423
|
+
- `src/linux/volume_metadata.cpp` (updated with comprehensive documentation)
|
|
424
|
+
|
|
425
|
+
**Status**: Fixed on 2025-10-24
|
|
426
|
+
|
|
427
|
+
**Issue**:
|
|
428
|
+
The code correctly uses `free()` on strings returned by `blkid_get_tag_value`, but lacked comments explaining WHY `free()` must be used instead of `delete`.
|
|
429
|
+
|
|
430
|
+
**Official Documentation**:
|
|
431
|
+
|
|
432
|
+
- [libblkid source](https://github.com/util-linux/util-linux/blob/master/libblkid/src/resolve.c) shows `blkid_get_tag_value` uses `strdup()`
|
|
433
|
+
|
|
434
|
+
**Fix Applied**:
|
|
435
|
+
|
|
436
|
+
Added comprehensive inline documentation explaining:
|
|
437
|
+
|
|
438
|
+
1. **Memory allocation**: `blkid_get_tag_value()` returns strings allocated with `strdup()` (uses `malloc()` internally)
|
|
439
|
+
2. **Critical requirement**: Must use `free()`, NOT `delete` or `delete[]`
|
|
440
|
+
3. **Why it matters**: Using wrong deallocator causes undefined behavior (likely crash)
|
|
441
|
+
4. **Source reference**: Links to libblkid source code showing `strdup()` usage
|
|
442
|
+
|
|
443
|
+
**Documentation Added**:
|
|
444
|
+
|
|
445
|
+
```cpp
|
|
446
|
+
// MEMORY MANAGEMENT: blkid_get_tag_value() returns strings allocated with strdup()
|
|
447
|
+
//
|
|
448
|
+
// CRITICAL: These strings MUST be freed with free(), NOT delete or delete[]
|
|
449
|
+
// blkid is a C library (libblkid), and blkid_get_tag_value() uses strdup()
|
|
450
|
+
// internally which allocates memory with malloc().
|
|
451
|
+
//
|
|
452
|
+
// Memory allocated with malloc() must be deallocated with free().
|
|
453
|
+
// Using delete or delete[] would invoke the wrong deallocator and
|
|
454
|
+
// cause undefined behavior (likely a crash).
|
|
455
|
+
//
|
|
456
|
+
// See: Finding #10 in SECURITY_AUDIT_2025.md
|
|
457
|
+
// Reference: https://github.com/util-linux/util-linux/blob/master/libblkid/src/resolve.c
|
|
458
|
+
|
|
459
|
+
char *uuid = blkid_get_tag_value(cache.get(), "UUID", options_.device.c_str());
|
|
460
|
+
if (uuid) {
|
|
461
|
+
metadata.uuid = uuid;
|
|
462
|
+
free(uuid); // IMPORTANT: Use free(), not delete (C API, uses malloc/strdup)
|
|
463
|
+
...
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
**Impact**: Prevents future maintenance errors where someone might incorrectly change `free()` to `delete`.
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Low Priority / Enhancements
|
|
472
|
+
|
|
473
|
+
### Finding #11: Thread Pool Shutdown Timeout Configuration (Windows) ✅ REVIEWED
|
|
474
|
+
|
|
475
|
+
**Severity**: 🟢 LOW → ✅ NO ACTION NEEDED
|
|
476
|
+
**Files Affected**:
|
|
477
|
+
|
|
478
|
+
- `src/windows/thread_pool.h:147-178` (reviewed)
|
|
479
|
+
|
|
480
|
+
**Status**: Reviewed on 2025-10-23
|
|
481
|
+
|
|
482
|
+
**Issue**:
|
|
483
|
+
Hard-coded 5-second timeout for thread shutdown may be insufficient for slow I/O operations (network drives, slow HDDs).
|
|
484
|
+
|
|
485
|
+
**Assessment**:
|
|
486
|
+
|
|
487
|
+
The current implementation already has appropriate timeout handling:
|
|
488
|
+
|
|
489
|
+
```cpp
|
|
490
|
+
// src/windows/thread_pool.h:169-174
|
|
491
|
+
DWORD result = WaitForMultipleObjects(static_cast<DWORD>(handles.size()),
|
|
492
|
+
handles.data(), TRUE, 5000);
|
|
493
|
+
|
|
494
|
+
if (result == WAIT_TIMEOUT) {
|
|
495
|
+
DEBUG_LOG("[ThreadPool] WARNING: %zu threads did not exit within 5s",
|
|
496
|
+
handles.size());
|
|
497
|
+
// Note: TerminateThread is dangerous and not recommended
|
|
498
|
+
// Threads will be forcefully terminated when process exits
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
**Rationale for No Changes**:
|
|
503
|
+
|
|
504
|
+
1. **5-second timeout is sufficient**: Most I/O operations complete within milliseconds; 5 seconds provides ample margin
|
|
505
|
+
2. **Configuration would be ungainly**: Exposing this to JavaScript requires:
|
|
506
|
+
- New NativeBindings interface method
|
|
507
|
+
- Modifications to binding.cpp
|
|
508
|
+
- Changing global singleton pattern
|
|
509
|
+
- New TypeScript types and documentation
|
|
510
|
+
- Additional test coverage
|
|
511
|
+
3. **Low priority**: This is a LOW severity finding for a rare edge case
|
|
512
|
+
4. **Debug logging exists**: Timeout warnings are logged for diagnostics
|
|
513
|
+
5. **Graceful degradation**: Process exit handles forced termination safely
|
|
514
|
+
|
|
515
|
+
**Conclusion**:
|
|
516
|
+
|
|
517
|
+
The complexity of making this configurable outweighs the benefit for this LOW priority finding. The current implementation is sufficient for all realistic use cases
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
### Finding #12: ARM64 Security Flag Documentation (Windows) ✅ FIXED
|
|
522
|
+
|
|
523
|
+
**Severity**: 🟢 LOW (Documentation) → ✅ RESOLVED
|
|
524
|
+
**Files Affected**:
|
|
525
|
+
|
|
526
|
+
- `binding.gyp:108-141` (inline comments added)
|
|
527
|
+
- `doc/WINDOWS_ARM64_SECURITY.md` (comprehensive guide created)
|
|
528
|
+
|
|
529
|
+
**Status**: Fixed on 2025-10-23
|
|
530
|
+
|
|
531
|
+
**Issue**:
|
|
532
|
+
ARM64 builds exclude `/Qspectre` and `/CETCOMPAT` without explaining why.
|
|
533
|
+
|
|
534
|
+
**Implemented Fix**:
|
|
535
|
+
|
|
536
|
+
1. **Inline Comments in `binding.gyp`**:
|
|
537
|
+
- Added explanatory comments for each ARM64 compiler flag
|
|
538
|
+
- Documented why `/Qspectre` is omitted (x64/x86-specific)
|
|
539
|
+
- Documented why `/CETCOMPAT` is omitted (Intel CET is x64-specific)
|
|
540
|
+
- Referenced comprehensive documentation
|
|
541
|
+
|
|
542
|
+
2. **Comprehensive Documentation**: `doc/WINDOWS_ARM64_SECURITY.md`
|
|
543
|
+
|
|
544
|
+
Comprehensive documentation explaining:
|
|
545
|
+
|
|
546
|
+
1. **Why `/Qspectre` is omitted**:
|
|
547
|
+
- x64/x86-specific compiler mitigation
|
|
548
|
+
- Not available for ARM64 architecture
|
|
549
|
+
- ARM64 has hardware-level mitigations built into CPU
|
|
550
|
+
|
|
551
|
+
2. **Why `/CETCOMPAT` is omitted**:
|
|
552
|
+
- Intel CET (Control-flow Enforcement Technology) is x64-specific
|
|
553
|
+
- ARM64 has equivalent features: PAC (Pointer Authentication) and BTI (Branch Target Identification)
|
|
554
|
+
- Different hardware security approach
|
|
555
|
+
|
|
556
|
+
3. **ARM64 Security Features Documented**:
|
|
557
|
+
- **PAC (Pointer Authentication Codes)**: Cryptographic pointer signing
|
|
558
|
+
- **BTI (Branch Target Identification)**: Control flow integrity
|
|
559
|
+
- **MTE (Memory Tagging Extension)**: Future hardware memory safety
|
|
560
|
+
- **Control Flow Guard**: Fully supported, same as x64
|
|
561
|
+
- **ASLR**: Fully supported, same as x64
|
|
562
|
+
|
|
563
|
+
4. **Security Comparison Table**: x64 vs ARM64 feature parity
|
|
564
|
+
5. **Future Considerations**: ARM64 shadow stack when compiler support stabilizes
|
|
565
|
+
|
|
566
|
+
**Result**: ARM64 builds have equivalent or better security than x64 builds, just using different (ARM-specific) hardware features.
|
|
567
|
+
|
|
568
|
+
**Reference**:
|
|
569
|
+
|
|
570
|
+
- [ARM64 Security Features](https://learn.microsoft.com/en-us/windows/arm/arm64-security-features)
|
|
571
|
+
- [Spectre Mitigations](https://learn.microsoft.com/en-us/cpp/build/reference/qspectre)
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## API Usage Verification Matrix
|
|
576
|
+
|
|
577
|
+
| API/Function | Platform | Documentation Verified | Status | Finding # |
|
|
578
|
+
| ----------------------- | ----------- | ---------------------- | ---------------------------- | --------- |
|
|
579
|
+
| `MultiByteToWideChar` | Windows | ✅ Microsoft | ⚠️ Needs overflow checks | #3 |
|
|
580
|
+
| `WideCharToMultiByte` | Windows | ✅ Microsoft | ⚠️ Needs overflow checks | #3 |
|
|
581
|
+
| `FormatMessageA` | Windows | ✅ Microsoft | ⚠️ Memory leak risk | #4 |
|
|
582
|
+
| `PathCchCanonicalize` | Windows | ✅ Microsoft | ⚠️ Use Ex version | #2 |
|
|
583
|
+
| `PathCchCanonicalizeEx` | Windows | ✅ Microsoft | ✅ Recommended | #2 |
|
|
584
|
+
| `GetVolumeInformationW` | Windows | ✅ Microsoft | ✅ Correct | - |
|
|
585
|
+
| `WNetGetConnectionA` | Windows | ✅ Microsoft | ✅ Correct | - |
|
|
586
|
+
| `FindFirstFileExA` | Windows | ✅ Microsoft | ✅ Correct | - |
|
|
587
|
+
| `GetDriveTypeA` | Windows | ✅ Microsoft | ✅ Correct | - |
|
|
588
|
+
| `GetDiskFreeSpaceExA` | Windows | ✅ Microsoft | ✅ Correct | - |
|
|
589
|
+
| `DADiskCopyDescription` | macOS | ✅ Apple | ⚠️ Thread safety unclear | #5 |
|
|
590
|
+
| `CFStringGetCString` | macOS | ✅ Apple | ✅ Correct (enhance logging) | #8 |
|
|
591
|
+
| `statvfs` | macOS/Linux | ✅ man7.org/Apple | ⚠️ TOCTOU risk | #9 |
|
|
592
|
+
| `statfs` | macOS | ✅ Apple | ⚠️ TOCTOU risk | #9 |
|
|
593
|
+
| `fstatvfs` | macOS/Linux | ✅ man7.org/Apple | ✅ Recommended | #9 |
|
|
594
|
+
| `realpath` | macOS/Linux | ✅ man7.org/Apple | ✅ Recommended | #1 |
|
|
595
|
+
| `blkid_get_tag_value` | Linux | ✅ kernel.org/GitHub | ✅ Correct | #10 |
|
|
596
|
+
| `g_volume_monitor_get` | Linux | ✅ gnome.org | ⚠️ Thread safety violation | #6 |
|
|
597
|
+
| `g_object_unref` | Linux | ✅ gnome.org | ⚠️ Double-free risk | #7 |
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
## Testing Recommendations
|
|
602
|
+
|
|
603
|
+
### Memory Leak Detection
|
|
604
|
+
|
|
605
|
+
```bash
|
|
606
|
+
# Linux
|
|
607
|
+
valgrind --leak-check=full --show-leak-kinds=all npm test
|
|
608
|
+
|
|
609
|
+
# macOS
|
|
610
|
+
export MallocStackLogging=1
|
|
611
|
+
leaks --atExit -- npm test
|
|
612
|
+
|
|
613
|
+
# Windows
|
|
614
|
+
# Already configured: npm run check:memory
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### Thread Safety Testing
|
|
618
|
+
|
|
619
|
+
```bash
|
|
620
|
+
# ThreadSanitizer (Linux/macOS)
|
|
621
|
+
export CC=clang
|
|
622
|
+
export CXX=clang++
|
|
623
|
+
export CXXFLAGS="-fsanitize=thread -g"
|
|
624
|
+
npm rebuild
|
|
625
|
+
npm test
|
|
626
|
+
|
|
627
|
+
# Stress test
|
|
628
|
+
for i in {1..100}; do npm test & done; wait
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
### Path Traversal Testing
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
// Add to test suite
|
|
635
|
+
describe("Security: Path Validation", () => {
|
|
636
|
+
it("rejects directory traversal attempts", async () => {
|
|
637
|
+
await expect(isHidden("/tmp/../etc/passwd")).rejects.toThrow(
|
|
638
|
+
/invalid path/i,
|
|
639
|
+
);
|
|
640
|
+
await expect(isHidden("/home/user/./../root")).rejects.toThrow(
|
|
641
|
+
/invalid path/i,
|
|
642
|
+
);
|
|
643
|
+
await expect(isHidden("/../../../etc/shadow")).rejects.toThrow(
|
|
644
|
+
/invalid path/i,
|
|
645
|
+
);
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
it("rejects null byte injection", async () => {
|
|
649
|
+
await expect(isHidden("/tmp\0/../../etc/passwd")).rejects.toThrow(
|
|
650
|
+
/invalid path/i,
|
|
651
|
+
);
|
|
652
|
+
});
|
|
653
|
+
});
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
---
|
|
657
|
+
|
|
658
|
+
## Priority Action Plan
|
|
659
|
+
|
|
660
|
+
### Week 1: Critical Fixes ✅ COMPLETE
|
|
661
|
+
|
|
662
|
+
- [x] Fix #1: Implement `realpath()` validation (macOS/Linux) - ✅ Completed 2025-10-23
|
|
663
|
+
- [x] Fix #2: Switch to `PathCchCanonicalizeEx` (Windows) - ✅ Completed 2025-10-23
|
|
664
|
+
- [x] Fix #3: Add overflow checks to string conversion (Windows) - ✅ Completed 2025-10-23
|
|
665
|
+
|
|
666
|
+
### Week 2: High Priority Fixes ✅ COMPLETE
|
|
667
|
+
|
|
668
|
+
- [x] Fix #4: Add RAII to `FormatMessageA` (Windows) - ✅ Completed 2025-10-23
|
|
669
|
+
- [x] Fix #5: Document/fix DiskArbitration threading (macOS) - ✅ Completed 2025-10-23
|
|
670
|
+
- [x] Fix #6: Rewrite GIO to use thread-safe g_unix_mounts_get() (Linux) - ✅ Completed 2025-10-24
|
|
671
|
+
- [x] Fix #7: Fix double-free in GIO iteration (Linux) - ✅ Completed 2025-10-24 (with #6)
|
|
672
|
+
|
|
673
|
+
### Week 3: Medium Priority Improvements ✅ COMPLETE
|
|
674
|
+
|
|
675
|
+
- [x] Fix #8: Add CFString error logging (macOS) - ✅ Completed 2025-10-23
|
|
676
|
+
- [x] Fix #9: Use `fstatvfs()` with fd (macOS) - ✅ Completed 2025-10-23
|
|
677
|
+
- [x] Fix #9: Use `fstatvfs()` with fd (Linux) - ✅ Completed 2025-10-24
|
|
678
|
+
- [x] Fix #10: Add blkid documentation (Linux) - ✅ Completed 2025-10-24
|
|
679
|
+
|
|
680
|
+
### Week 4: Testing & Documentation ✅ COMPLETE (macOS)
|
|
681
|
+
|
|
682
|
+
- [x] Add path traversal tests - ✅ Completed (13 tests, all passing)
|
|
683
|
+
- [ ] Run ThreadSanitizer on all platforms - ⚠️ PENDING
|
|
684
|
+
- [ ] Run memory leak detection - ⚠️ PENDING
|
|
685
|
+
- [x] Update security documentation - ✅ Completed 2025-10-23
|
|
686
|
+
|
|
687
|
+
## Summary of Completed Work
|
|
688
|
+
|
|
689
|
+
### 2025-10-24: Linux Security Fixes (Complete)
|
|
690
|
+
|
|
691
|
+
**Linux Platform**: 4 findings resolved (2 high, 2 medium)
|
|
692
|
+
|
|
693
|
+
**High Priority**:
|
|
694
|
+
|
|
695
|
+
- ✅ Finding #6 (HIGH): GVolumeMonitor thread safety - **FIXED**
|
|
696
|
+
- Rewrote GIO implementation to use thread-safe `g_unix_mounts_get()`
|
|
697
|
+
- GVolumeMonitor now optional best-effort enrichment
|
|
698
|
+
- Dual-path architecture: thread-safe primary + optional rich metadata
|
|
699
|
+
- ✅ Finding #7 (HIGH): Double-free in GIO - **FIXED**
|
|
700
|
+
- Eliminated by using `GUnixMountEntry` instead of `GMount`
|
|
701
|
+
- Clean reference counting, no manual ref/unref pairs
|
|
702
|
+
|
|
703
|
+
**Medium Priority**:
|
|
704
|
+
|
|
705
|
+
- ✅ Finding #9 (MEDIUM): TOCTOU race condition in statvfs - **FIXED**
|
|
706
|
+
- File descriptor-based approach: `open()` + `fstatvfs()`
|
|
707
|
+
- RAII `FdGuard` ensures resource cleanup
|
|
708
|
+
- Prevents mount point changes during operation
|
|
709
|
+
- ✅ Finding #10 (MEDIUM): blkid memory management - **DOCUMENTED**
|
|
710
|
+
- Comprehensive inline documentation added
|
|
711
|
+
- Explains `free()` vs `delete` requirement
|
|
712
|
+
- Prevents future maintenance errors
|
|
713
|
+
|
|
714
|
+
**Test Coverage**: All 491 tests passing (3 new tests added)
|
|
715
|
+
|
|
716
|
+
**Code Quality**: No regressions, maintains backward compatibility
|
|
717
|
+
|
|
718
|
+
### 2025-10-23: macOS and Windows Security Fixes
|
|
719
|
+
|
|
720
|
+
**macOS Platform**: 3 critical/medium findings resolved
|
|
721
|
+
|
|
722
|
+
- ✅ Finding #1 (CRITICAL): Path validation bypass - **FIXED**
|
|
723
|
+
- ✅ Finding #5 (HIGH): DiskArbitration threading - **FIXED**
|
|
724
|
+
- ✅ Finding #8 (MEDIUM): CFString error logging - **FIXED**
|
|
725
|
+
- ✅ Finding #9 (MEDIUM): TOCTOU race condition - **FIXED**
|
|
726
|
+
|
|
727
|
+
**Windows Platform**: 4 critical/high findings resolved
|
|
728
|
+
|
|
729
|
+
- ✅ Finding #2 (CRITICAL): Path length restriction - **FIXED**
|
|
730
|
+
- ✅ Finding #3 (CRITICAL): Integer overflow in string conversion - **FIXED**
|
|
731
|
+
- ✅ Finding #4 (HIGH): Memory leak in error formatting - **FIXED**
|
|
732
|
+
- ✅ Finding #11 (LOW): Thread pool timeout - **REVIEWED (no changes needed)**
|
|
733
|
+
- ✅ Finding #12 (LOW): ARM64 security documentation - **DOCUMENTED**
|
|
734
|
+
|
|
735
|
+
**Remaining Work**:
|
|
736
|
+
|
|
737
|
+
- None! All critical, high, and medium priority findings have been resolved ✅
|
|
738
|
+
|
|
739
|
+
---
|
|
740
|
+
|
|
741
|
+
## References
|
|
742
|
+
|
|
743
|
+
### Official Documentation Sources
|
|
744
|
+
|
|
745
|
+
- **Windows APIs**: [Microsoft Learn](https://learn.microsoft.com/en-us/windows/win32/)
|
|
746
|
+
- **macOS APIs**: [Apple Developer Documentation](https://developer.apple.com/documentation/)
|
|
747
|
+
- **Linux System Calls**: [man7.org](https://man7.org/linux/man-pages/)
|
|
748
|
+
- **GIO/GLib**: [GNOME Developer](https://developer.gnome.org/)
|
|
749
|
+
- **libblkid**: [util-linux GitHub](https://github.com/util-linux/util-linux)
|
|
750
|
+
|
|
751
|
+
### Security Resources
|
|
752
|
+
|
|
753
|
+
- [OWASP Path Traversal](https://owasp.org/www-community/attacks/Path_Traversal)
|
|
754
|
+
- [CWE-22: Path Traversal](https://cwe.mitre.org/data/definitions/22.html)
|
|
755
|
+
- [CWE-362: TOCTOU Race Condition](https://cwe.mitre.org/data/definitions/362.html)
|
|
756
|
+
- [CWE-415: Double Free](https://cwe.mitre.org/data/definitions/415.html)
|
|
757
|
+
|
|
758
|
+
---
|
|
759
|
+
|
|
760
|
+
## Document Maintenance
|
|
761
|
+
|
|
762
|
+
**Last Updated**: October 24, 2025
|
|
763
|
+
**Next Review**: April 2026 (or after major dependency updates)
|
|
764
|
+
|
|
765
|
+
**Change Log**:
|
|
766
|
+
|
|
767
|
+
- 2025-10-24: **Linux Security Fixes (Part 2)**
|
|
768
|
+
- Fixed Finding #9 (MEDIUM) - TOCTOU race condition in statvfs (Linux portion)
|
|
769
|
+
- Updated `src/linux/volume_metadata.cpp` to use file descriptor-based approach
|
|
770
|
+
- Use `open()` with `O_DIRECTORY | O_RDONLY | O_CLOEXEC`, then `fstatvfs()`
|
|
771
|
+
- Added RAII `FdGuard` to ensure file descriptor is always closed
|
|
772
|
+
- Added comprehensive inline documentation explaining TOCTOU prevention
|
|
773
|
+
- Fixed Finding #10 (MEDIUM) - blkid memory management documentation
|
|
774
|
+
- Added extensive inline documentation in `src/linux/volume_metadata.cpp`
|
|
775
|
+
- Explains why `free()` must be used (not `delete`) for blkid strings
|
|
776
|
+
- Includes source references and technical rationale
|
|
777
|
+
- Prevents future maintenance errors
|
|
778
|
+
- 2025-10-24: **Linux GIO Thread Safety Fixes (Part 1)**
|
|
779
|
+
- Fixed Finding #6 (HIGH) - GVolumeMonitor thread safety violation
|
|
780
|
+
- Rewrote `src/linux/gio_utils.cpp` to use thread-safe `g_unix_mounts_get()`
|
|
781
|
+
- Updated `src/linux/gio_utils.h`, `gio_mount_points.cpp`, `gio_volume_metadata.cpp`
|
|
782
|
+
- Updated `binding.gyp` to include `gio-unix-2.0` package
|
|
783
|
+
- Implemented dual-path architecture: thread-safe primary + optional GVolumeMonitor enrichment
|
|
784
|
+
- Added 3 comprehensive tests in `src/linux-gio-thread-safety.test.ts`
|
|
785
|
+
- Fixed Finding #7 (HIGH) - Double-free in GIO iteration (resolved with #6)
|
|
786
|
+
- Eliminated by using `GUnixMountEntry` instead of `GMount`
|
|
787
|
+
- Clean reference counting with single `g_list_free_full()` call
|
|
788
|
+
- No manual `g_object_ref()`/`g_object_unref()` pairs
|
|
789
|
+
- 2025-10-23: Fixed Finding #12 - Comprehensive ARM64 security documentation created
|
|
790
|
+
- 2025-10-23: Fixed Finding #11 - Thread pool shutdown timeout (reviewed, no changes needed)
|
|
791
|
+
- 2025-10-23: Fixed Finding #4 - RAII LocalFreeGuard for FormatMessageA memory leak prevention
|
|
792
|
+
- 2025-10-23: Fixed Finding #3 - Integer overflow protection in string conversions (WideToUtf8, ToWString)
|
|
793
|
+
- 2025-10-23: Fixed Finding #2 - PathCchCanonicalizeEx implementation with comprehensive tests
|
|
794
|
+
- 2025-10-23: **macOS Security Fixes**
|
|
795
|
+
- Fixed Finding #1 (CRITICAL) - Path Validation Bypass using realpath() canonicalization
|
|
796
|
+
- Created `src/darwin/path_security.h` with secure path validation
|
|
797
|
+
- Updated `src/darwin/hidden.cpp` and `src/darwin/volume_metadata.cpp`
|
|
798
|
+
- Added 13 comprehensive security tests (all passing)
|
|
799
|
+
- Prevents directory traversal, null byte injection, and symbolic link attacks
|
|
800
|
+
- Fixed Finding #5 (HIGH) - DiskArbitration threading
|
|
801
|
+
- Created DASessionRAII wrapper in `src/darwin/raii_utils.h`
|
|
802
|
+
- Updated `src/darwin/volume_metadata.cpp` to use dispatch queue pattern
|
|
803
|
+
- Follows Apple's documented DiskArbitration Programming Guide
|
|
804
|
+
- Fixed Finding #8 (MEDIUM) - Added CFStringGetCString error logging
|
|
805
|
+
- Improves debuggability of string conversion failures
|
|
806
|
+
- Fixed Finding #9 (MEDIUM) - TOCTOU race condition prevention (macOS)
|
|
807
|
+
- Implemented file descriptor-based approach with `fstatvfs()`/`fstatfs()`
|
|
808
|
+
- RAII FdGuard ensures no resource leaks
|
|
809
|
+
- 2025-10-22: Initial comprehensive security audit completed
|