-
Notifications
You must be signed in to change notification settings - Fork 373
Description
Problem
Related to #11625
One security issue for comptime code that would still be possible if #11625 is implemented would be:
- A library
helpfulis released which encourages users to use its helpful attribute(s) to save on code - The library is later updated so that its previously helpful attribute(s) now maliciously edit functions
Happy Case
It is difficult to prevent this in general but one way which may make it more difficult is if users had to enable permissions for attributes they call. Attributes without the permission to, e.g. edit a function, would not be able to do so. This makes it more difficult for a attribute which only reads data to be updated to modify a function without the end-user knowing.
The first hurdle to this approach is the question of how granular these permissions should be. Most user-written attributes edit the item they're placed on to some degree so a simple read_only vs allow_mutation distinction may not be effective in practice.
One option would be to allow each comptime API builtin to be called individually. This would require users explicitly opt-into allow(set_body, set_parameters), etc. with possible aliases like allow(everything) for convenience but trading off on precision and thus security. Following is a list of each comptime builtin (at the time of writing) which may mutate a source code item:
"function_def_add_attribute"
"function_def_set_body"
"function_def_set_parameters"
"function_def_set_return_type"
"function_def_set_return_public"
"function_def_set_return_data"
"function_def_set_unconstrained"
"module_add_item"
"type_def_add_attribute"
"type_def_add_generic"
"type_def_set_fields"
The list of functions which may read from an item is much larger. It isn't clear if there's any security concerns from only reading source code without being able to modify it or have access to IO. Following is an abbreviated list of methods which read from an item but do not modify it:
Read-only comptime builtin methods
"function_def_as_typed_expr"
"function_def_body"
"function_def_eq"
"function_def_has_named_attribute"
"function_def_hash"
"function_def_is_unconstrained"
"function_def_module"
"function_def_name"
"function_def_parameters"
"function_def_return_type"
"function_def_visibility"
"module_child_modules"
"module_eq"
"module_functions"
"module_has_named_attribute"
"module_hash"
"module_is_contract"
"module_name"
"module_parent"
"module_structs"
"quoted_as_module"
"quoted_as_trait_constraint"
"quoted_as_type"
"quoted_hash"
"quoted_tokens"
"trait_constraint_eq"
"trait_constraint_hash"
"trait_def_eq"
"trait_def_hash"
"trait_impl_methods"
"trait_impl_trait_generic_args"
"type_def_eq"
"type_def_fields"
"type_def_fields_as_written"
"type_def_generics"
"type_def_has_named_attribute"
"type_def_hash"
"type_def_module"
"type_def_name"
"type_eq"
"type_get_trait_impl"
"type_hash"
"type_implements"
"type_of"
"typed_expr_as_function_definition"
"typed_expr_get_type"
One possibility with explicitly allowing each modification may look like:
// The aforementioned "helpful" attribute which is later updated to a malicious one
use helpful::helpful_attr;
#[allow(function_def_set_parameters)]
#[helpful_attr]
fn foo() {}Above, helpful_attr would be allowed to modify the parameters but we'd get an error if it were updated to mutate the function body as well.
From the list of mutating functions function_def_set_body seems the main target for potential insertion of malicious code. The other candidate would be module_add_item as well as simply returning a Quoted value from the attribute to insert new code into the module. This could be used to insert a malicious trait implementation which gets called automatically for example. Given how common these three operations are in attributes, it is unclear how much value adding a fine-grained permissions simple would add. Permissions may end up devolving into "this may mutate" versus "this may not mutate" anyway:
#mut[helpful_attr] // This may mutate foo, the current module, or submodules
fn foo() {}
#[helpful_attr] // This may not mutate anything
fn bar() {}
With how commonly mutation may be allowed, nargo expand may still be the simplest tool to check for malicious code. Opting into such changes as in #11625 would at least help mark them, although users would still be vulnerable to malicious library updates.
Workaround
None
Workaround Description
No response
Additional Context
No response
Project Impact
None
Blocker Context
No response
Would you like to submit a PR for this Issue?
None
Support Needs
No response