-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Support for stack protectors. #60933
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
Conversation
@swift-ci test |
@swift-ci benchmark |
Now that Swift decides whether or not we need stack protection we should force LLVM to emit stack protection when we request it:
|
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.
The stdlib parts look good! 👍
(Will stack protection also trigger on functions that use withUnsafeTemporaryAllocation
?)
Good point! It should, but I need to add handling of the "stackAlloc" builtin to make it work. |
eaf3dcd
to
1fd6554
Compare
@lorentey I added support for withUnsafeTemporaryAllocation. |
@swift-ci test |
stdlib/public/core/KeyPath.swift
Outdated
@@ -1951,7 +1951,8 @@ func _modifyAtWritableKeyPath_impl<Root, Value>( | |||
keyPath: _unsafeUncheckedDowncast(keyPath, | |||
to: ReferenceWritableKeyPath<Root, Value>.self)) | |||
} | |||
return keyPath._projectMutableAddress(from: &root) | |||
let ptr = UnsafePointer<Root>(Builtin.unprotectedAddressOf(&root)) |
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.
Can this use the scoped _withUnprotectedUnsafePointer
function rather than using the Builtin to get an unscoped pointer?
Same comment for Random
and StringSwitch
. Is there a reason not to use the scoped versions?
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.
yeah, that's a good idea
It doesn't make sense to let getAccessPathWithScope return an `EnclosingScope` as the second tuple element, because in case it's a `base`, it duplicates the `AccessBase` (which is returned in the first tuple element). Instead just return an optional `BeginAccessInst` which is not nil if such an "scope" is found.
Indicates that stack protectors are inserted into this function to detect stack related buffer overflows.
…ndex_addr` instructions. Also add new "unprotected" variants of the `addressof` builtins: * `Builtin.unprotectedAddressOf` * `Builtin.unprotectedAddressOfBorrow`
…LOptions. ... because we need it in the SIL pass pipeline, too. Also, add Swift bridging for that option.
Those functions work the same way as their "unprotected" counterparts, except that they don't trigger stack protection for the pointers. * `_withUnprotectedUnsafeMutablePointer` * `_withUnprotectedUnsafePointer` * `_withUnprotectedUnsafeBytes` (two times)
…ffer overflows. We trust the internal implementation of the stdlib to not cause any unintentional buffer overflows. In such cases we can use the "unprotected" address-to-pointer conversions. This avoids inserting stack protections where it's not needed.
And make all the case identifiers lowercase.
It decides which functions need stack protection. It sets the `needStackProtection` flags on all function which contain stack-allocated values for which an buffer overflow could occur. Within safe swift code there shouldn't be any buffer overflows. But if the address of a stack variable is converted to an unsafe pointer, it's not in the control of the compiler anymore. This means, if there is any `address_to_pointer` instruction for an `alloc_stack`, such a function is marked for stack protection. Another case is `index_addr` for non-tail allocated memory. This pattern appears if pointer arithmetic is done with unsafe pointers in swift code. If the origin of an unsafe pointer can only be tracked to a function argument, the pass tries to find the root stack allocation for such an argument by doing an inter-procedural analysis. If this is not possible, the fallback is to move the argument into a temporary `alloc_stack` and do the unsafe pointer operations on the temporary. rdar://93677524
…tack protection. Now that Swift decides whether or not we need stack protection we should force LLVM to emit stack protection when we request it.
…tectedAddressOf`
1fd6554
to
5eff906
Compare
@swift-ci test |
@swift-ci benchmark |
The pass to decide which functions should get stack protection was added in swiftlang#60933, but was disabled by default. This PR enables stack protection by default, but not the possibility to move arguments into temporaries - to keep the risk low. Moving to temporaries can be enabled with the new frontend option `-enable-move-inout-stack-protector`. rdar://93677524
The main part of this PR is a new
StackProtection
optimization and changes in the stdlibThe optimization decides which functions need stack protection. It sets the
needStackProtection
flags on all function which contain stack-allocated values for which an buffer overflow could occur.In the stdlib there are new underscored
_withUnprotected..Pointer
functions. These functions work the same way as their "unprotected" counterparts, except that they don't trigger stack protection for the pointers. They can be used to opt out of stack protection.Also, in the stdlib, opt out of stack protection in places where there can't be buffer overflows.
We trust the internal implementation of the stdlib to not cause any unintentional buffer overflows. In such cases we can use the "unprotected" address-to-pointer conversions. This avoids inserting stack protections where it's not needed.
For details see the commit messages.
Note: this PR does not enable stack protection by default, yet. It still needs to be enabled with the
-Xfrontend -enable-stack-protector
option.rdar://93677524