-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Enforce read-only-ness of package directory even when it's inside writable directories #3996
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
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 |
---|---|---|
|
@@ -895,10 +895,6 @@ extension SwiftPackageTool { | |
help: "Allow the plugin to write to an additional directory") | ||
var additionalAllowedWritableDirectories: [String] = [] | ||
|
||
@Flag(name: .customLong("block-writing-to-temporary-directory"), | ||
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. This flag was just added, so nobody is depending on it yet, and it was mostly for unit tests — it seems much clearer to always make the package directory read-only, even for packages checked out to |
||
help: "Block the plugin from writing to the package directory (by default this is allowed)") | ||
var blockWritingToTemporaryDirectory: Bool = false | ||
|
||
@Argument(parsing: .unconditionalRemaining, | ||
help: "Name and arguments of the command plugin to invoke") | ||
var pluginCommand: [String] = [] | ||
|
@@ -979,13 +975,6 @@ extension SwiftPackageTool { | |
if allowWritingToPackageDirectory { | ||
writableDirectories.append(package.path) | ||
} | ||
if !blockWritingToTemporaryDirectory { | ||
writableDirectories.append(AbsolutePath("/tmp")) | ||
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 temporary directories are now again handled by the strictness. |
||
writableDirectories.append(AbsolutePath(NSTemporaryDirectory())) | ||
} | ||
if allowWritingToPackageDirectory { | ||
writableDirectories.append(package.path) | ||
} | ||
Comment on lines
-986
to
-988
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. This was actually redundant with lines 975-977 above. |
||
else { | ||
// If the plugin requires write permission but it wasn't provided, we ask the user for approval. | ||
if case .command(_, let permissions) = plugin.capability { | ||
|
@@ -999,6 +988,9 @@ extension SwiftPackageTool { | |
writableDirectories.append(AbsolutePath(pathString, relativeTo: swiftTool.originalWorkingDirectory)) | ||
} | ||
|
||
// Make sure that the package path is read-only unless it's covered by any of the explicitly writable directories. | ||
let readOnlyDirectories = writableDirectories.contains{ package.path.isDescendantOfOrEqual(to: $0) } ? [] : [package.path] | ||
|
||
Comment on lines
+991
to
+993
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. This one is subject to debate. It avoids marking the package path as readonly if it's covered by any of the directories marked as explicitly writable. Maybe what should be done here in the long term is to have a single list of directory-specific permissions, each of which could be either 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. starting simple makes sense to me. having the sandbox API accepts a list of allow/deny and having the call site define that make sense. 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. 👍 |
||
// Use the directory containing the compiler as an additional search directory, and add the $PATH. | ||
let toolSearchDirs = [try swiftTool.getToolchain().swiftCompilerPath.parentDirectory] | ||
+ getEnvSearchPaths(pathString: ProcessEnv.path, currentWorkingDirectory: .none) | ||
|
@@ -1051,6 +1043,7 @@ extension SwiftPackageTool { | |
toolSearchDirectories: toolSearchDirs, | ||
toolNamesToPaths: toolNamesToPaths, | ||
writableDirectories: writableDirectories, | ||
readOnlyDirectories: readOnlyDirectories, | ||
fileSystem: localFileSystem, | ||
observabilityScope: swiftTool.observabilityScope, | ||
callbackQueue: delegateQueue, | ||
|
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.
would it better to have the call site pass the temp dirs as writable locations instead of defining a new strictness option for that? alternatively, should this be an argument on "default" strictness instead of it's own case?
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.
I had that (passing in the temporary directories from the client) initially actually, but that pushes the platform-specific nature of these paths onto the client. In addition to the paths, there could actually be a varying number of them on different platforms. But I agree that this shouldn't really be part of the strictness, but rather an option on the default strictness as you suggest. I think there are more of those in the future, such as whether or not to allow network, etc.
So yes, in retrospect I think it was a mistake to add the temporary directory handling as a separate strictness level, and it's something to be unwound in the future.
Really what I'd like to do is to change the
Sandbox
struct to aSandboxProfile
or some other name that suggests that it's a set of options, and then that profile could be configured once and passed around so it can be applied to multiple calls later without having to thread through all the individual parameters (and perhaps also cached using operating system calls based on the contents of that profile). Then as we add more parameters, none of the intermediate code has to change. The code that calls the subprocess could just apply the same profile to one command after another. I'm hoping to get to that improvement soonish, in particular since I'm hopeful that it could allow compilation of the profile on macOS just once and the reuse of the compiled profile, saving time when starting sandboxed subprocesses.At that point it would make sense to get rid of strictness, I think, and just have a set of individually controllable options, and then a convenience initializer to create a
SandboxProfile
that matches the SwiftPM 5.3 semantics. That special case could then exist outside of theSandboxProfile
code itself as an extension, which seems more correct than leaking it into the sandbox API.All of course for a future PR, but hopefully not too long in the future.