Daohub-io/cap9

Procedure#Register Capability (Enforced with Subsets)

Closed this issue · 4 comments

Following from discussion in #108. We are replacing push and delete capabilities (#108,#109) with an enforced register capability (#47) instead.

We need to revert #proc_reg and allow pushing capabilities equal to or subset of the caller's capabilities. This requires the Register capability interface and tests at PR #102, to be reverted, and #47 to be amended.

User Interface:

The user must use #proc_reg:

function proc_reg(uint8 capIndex, bytes32 procId, address procAddr, Capability[] caps) returns (uint32 err)

Where the Capability type is defined as:

struct Capability {
    uint8 targetCapIndex;
    bytes32[] subvalues; // If full capability, must have length 0
}

For Pushing a Full capability X

X must have X.subvalues.length == 0

Test

We need a test that:

  • Creates Procedure A
  • Procedure A is given two procedures: a capability of type capType with values as data, and a procedure register capability (type 0x4) that allows create another procedure with a copy of it's capabilities.
  • Procedure A registers Procedure B at procId with address procAddr and pushes a full copy of it's capType capability iff:
    • capIndex points to a Register Capability within Procedure A's c-list
    • X.targetCapIndex points to the capType capability within Procedure A's c-list
    • X.subvalues.length == 0
    • procId is the id of Procedure B
    • procAddr is a valid procedure address
  • On failure, Procedure A receives:
    • An err value of 1.
  • On success, Procedure A receives:
    • err value of 0,

For Pushing a Subset capability Y

1 < Y.subvalues.length < 5

Y.subvalues is defined as a non-empty list of either: string[] or uint256[]

Test

For Store Caps:

We need a test that:

  • Creates Procedure A

  • Procedure A is given two procedures: a capability of type capType with values as data, and a procedure register capability (type 0x4) that allows create another procedure with a copy of it's capabilities.

  • Procedure A registers Procedure B at procId with address procAddr and pushes a subset of it's capType capability with Y iff:

    • capIndex points to a Push Capability within Procedure A's c-list
    • Y.targetCapIndex points to a capability within Procedure A's c-list
    • procId is the id of Procedure B
    • capType of capIndex is a valid capability type (0x0-0x9) and:
      • Not CAP_NULL or CAP_PROC_CAP_PUSH or CAP_PROC_CAP_DELETE (There's no subset)
      • If CAP_PROC_CALL or CAP_PROC_REGISTER or CAP_PROC_DELETE:
        • Y.subvalues[0..Y.subvalues.length-1] includes a set of procedure keys equal or subset of targetCap
      • Not CAP_PROC_ENTRY (There's no subset)
      • If CAP_STORE_WRITE the Y.subvalues[0..1] storage range is equal to or a subset of the storage available in capIndex
      • If CAP_LOG, either the Y.subvalues[0..4] log range is equal to capIndex or capIndex has less than 4 topics and subvalues appends a topic value.
      • If CAP_GAS_SEND, Y.subvalues[0] is less than or equal to capIndex gas.
  • On failure, Procedure A receives:

    • An err value of 1.
  • On success, Procedure A receives:

    • err value of 0,

I've spec'ed out precise definitions of subsets in the spec. I'm not sure if what parts of that which you've proposed above should be kernel side and what should be user side, but I'll give my thoughts on where that line should lie. Given what is currently implemented I think we should leave minting and definitions to the user space. Here's my thinking:

  1. Less code in the kernel is good.
  2. By only having the code that checks if one capability is the subset of another we simplify not just the amount of code but the complexity of the code paths, it's simply a boolean check.
  3. The steps to check if something is a subset is quite simple.
  4. We already do a heap of marshalling and formatting in user space just to execute the system call, and in fact that's how we currently do it.
  5. If we want the API to use targetCapIndex or the like, we can do that in the BeakerContract base class.

Also, Capability.subvalues.length == 0 does not imply a full cap for WRITE as currently defined. Maybe that should be a conversation on the spec.

@JakeOShannessy: Based on our discussion it would be pertinent to update the proc#reg syscall format to accomodate the CapIndex and CapSize.

Being addressed in #129.

This is complete as of #129.