-
Notifications
You must be signed in to change notification settings - Fork 0
π‘οΈ Sentinel: [CRITICAL] Fix TOCTOU vulnerability in file permissions #286
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -307,14 +307,22 @@ public final class SysctlJournal { | |
| do { | ||
| let data = try PropertyListEncoder().encode(state) | ||
|
|
||
| // Write to temp file (non-atomic β we control the rename ourselves). | ||
| try data.write(to: tmpURL) | ||
|
|
||
| // Set permissions to 0600 (root-only) on temp file before rename. | ||
| try FileManager.default.setAttributes( | ||
| [.posixPermissions: 0o600], | ||
| ofItemAtPath: tmpURL.path | ||
| ) | ||
| // Write to temp file securely using open(2) with O_CREAT and 0600 permissions | ||
| // to avoid TOCTOU vulnerability where file is briefly accessible before chmod. | ||
| let success = tmpURL.withUnsafeFileSystemRepresentation { pathPtr -> Bool in | ||
| guard let ptr = pathPtr else { return false } | ||
| let fd = open(ptr, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRUSR | S_IWUSR) | ||
| guard fd >= 0 else { return false } | ||
| let bytesWritten = data.withUnsafeBytes { buffer in | ||
| write(fd, buffer.baseAddress, buffer.count) | ||
| } | ||
|
Comment on lines
+316
to
+318
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The new persistence path performs a single Useful? React with πΒ / π. |
||
| close(fd) | ||
| return bytesWritten == data.count | ||
| } | ||
| guard success else { | ||
| try? FileManager.default.removeItem(at: tmpURL) | ||
| throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil) | ||
| } | ||
|
|
||
| // Atomic rename(2) β atomicity on APFS/HFS+. | ||
| if rename(tmpURL.path, url.path) != 0 { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opening the temp file with
O_CREAT | O_TRUNCdoes not reset permissions on an existing file, so a pre-existing.tmpwith broader mode (for example from a prior run or custom writable directory) will keep those broader bits and then be atomically renamed into the live journal. This is a regression from the previoussetAttributes(...0600...)step and can expose journal contents to unintended users unless youfchmodafter open or use safer exclusive creation logic.Useful? React with πΒ / π.