Skip to content

Permissions system for comptime #11626

@jfecher

Description

@jfecher

Problem

Related to #11625

One security issue for comptime code that would still be possible if #11625 is implemented would be:

  1. A library helpful is released which encourages users to use its helpful attribute(s) to save on code
  2. 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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions