Skip to content

Conversation

eeckstein
Copy link
Contributor

@eeckstein eeckstein commented Apr 4, 2024

The attribute declares that a struct contains "sensitive" data.
It enforces that the contents of such a struct value is zeroed out at the end of its lifetime.
In other words: the content of such a value is not observable in memory after the value's lifetime.

Also, import __attribute__((swift_attr("sensitive"))) on C structs as @sensitive attributes.

The attribute is mainly implemented in IRGen: IRGen emits a swift_clearSensitive runtime call after destroying or taking "sensitive" struct types.

Also, IRGen supports calling C-functions with "sensitive" parameters or return values. In SIL, sensitive types are address-only and so are sensitive parameters/return values. Though, (small) sensitive C-structs are passed directly to/from C-functions. We need re-abstract such parameter and return values for C-functions.

@eeckstein
Copy link
Contributor Author

@swift-ci test

@CodaFi
Copy link
Contributor

CodaFi commented Apr 5, 2024

Is there a way for this to be tied to a special kind of Cleanup so it can fall out of the compiler’s usual lifetime-related codegen?

EFFECT(NoEffect),
UNKNOWN_MEMEFFECTS)

FUNCTION(MemsetS, memset_s, C_CC, AlwaysAvailable,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this should be a stdlib-defined runtime function so different platforms can bring their own memset_s/memset_explicit/explicit_bzero/SecureZeroMemory

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. This makes sense

@eeckstein
Copy link
Contributor Author

Is there a way for this to be tied to a special kind of Cleanup so it can fall out of the compiler’s usual lifetime-related codegen?

If you are talking about cleanup in SILGen, this is not enough. First, zeroing must also be done for a "take" operation, not only for destroy at cleanup. Second, we need to do it in value witness functions, because a sensitive value can be passed as a generic parameter to a generic function.

if (passIndirectToDirect) {
llvm::Value *ptr = in.claimNext();

if (AI.getKind() == clang::CodeGen::ABIArgInfo::Indirect) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the case where the SIL claimed the C function took it @in_guaranteed (the callee preserves the content of the memory pointed to).

We pass the pointer to a C function that that lowers that argument indirect. It depends on the platform ABI whether the callee may modify that memory or not.

You need to create a temporary copy unless there would be some other guarantee in SIL that the SIL address passed to the C function call is not used after the call.

Comment on lines +2835 to +2841
FUNCTION(MemsetS, memset_s, C_CC, AlwaysAvailable,
RETURNS(Int32Ty),
ARGS(PtrTy, SizeTy, Int32Ty, SizeTy),
ATTRS(NoUnwind),
EFFECT(NoEffect),
UNKNOWN_MEMEFFECTS)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to leave the memset_s declaration here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it's used as a fallback if the swift_clearSensitive runtime function is not available on a deployment target.

@al45tair
Copy link
Contributor

al45tair commented Apr 8, 2024

Neat idea, by the way; this is a really nice feature for a language to have.

@eeckstein
Copy link
Contributor Author

@swift-ci test

@eeckstein
Copy link
Contributor Author

@swift-ci test

Copy link
Contributor

@aschwaighofer aschwaighofer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

The attribute declares that a struct contains "sensitive" data.
It enforces that the contents of such a struct value is zeroed out at the end of its lifetime.
In other words: the content of such a value is not observable in memory after the value's lifetime.

Also add an experimental feature `Sensitive` with which the attribute can be enabled.
Call `swift_clearSensitive` after destroying or taking "sensitive" struct types.

Also, support calling C-functions with "sensitive" parameters or return values. In SIL, sensitive types are address-only and so are sensitive parameters/return values.
Though, (small) sensitive C-structs are passed directly to/from C-functions. We need re-abstract such parameter and return values for C-functions.
@eeckstein
Copy link
Contributor Author

@swift-ci smoke test

@eeckstein eeckstein merged commit 648705e into swiftlang:main Apr 9, 2024
@eeckstein eeckstein deleted the sensitive branch April 9, 2024 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants