Skip to content
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

Introduce label lattice definition in Oak ABI #657

Merged
merged 1 commit into from
Mar 5, 2020

Conversation

tiziano88
Copy link
Collaborator

@tiziano88 tiziano88 commented Feb 28, 2020

Not used yet, but as a starting point for future functionality.

It is in the ABI because it will be used by both the runtime and the
SDK.

Ref #630

Checklist

  • Pull request affects core Oak functionality (e.g. runtime, SDK, ABI)
    • I have written tests that cover the code changes.
    • I have checked that these tests are run by Cloudbuild
    • I have updated documentation accordingly.
    • I have raised an issue to
      cover any TODOs and/or unfinished work.
  • Pull request includes prototype/experimental work that is under
    construction.

@tiziano88
Copy link
Collaborator Author

FTR @aferr is locked out of his own GitHub account but he sent me the following review via email, pasting here for reference:

High level comments:

Maybe it is useful to also add functions for meet and join in the label trait?
You might already know these, but for convenience:

  • join is (self.secrecy set_union other.secrecy, self.integrity set_intersect other.integrity)
  • join is (self.secrecy set_intersect other.secrecy, self.integrity set_union other.integrity)

One possibly annoying thing about using sets for the definition of tags is that while you have an easy way of writing "public to everyone" and "trusted by everyone" (both are the empty set), I can't think of an easy way to write "secret to everyone" or "untrusted by everyone" which should both be the sets of all tags. Is there actually an easy way to get those in Rust? Both secret and untrusted seem useful to me. Untrusted is useful for values that come from outside the system.

Another annoying thing about using sets of tags as labels is that you can't easily have a tag that represents the secrecy of "A or B" if A is a tag and B is a tag.
You could have:
L1 = ({A}, {})
L2 = ({B}, {})

and L1 join L2 is ( {A,B}, {} ) which is a label you could apply to a node that

  • can store secrets from either L1 or L2
  • cannot be read by either L1 or L2
  • this is kind of like FLAM's A /\ B

you might like the opposite which should have:

  • can be read by either L1 or L2
  • cannot store secrets from either L1 or L2 (though using the rules of robustness, either A or B do have the authority to declassify to this label)
  • sadly L1 meet L2 is just ({}, {}) which is public and can also be read by C

You can kind of workaround this issue by instead giving Alice and Bob labels like ({Alice, AliceNBob}, {}), ({Bob, AliceNBob}. {}) because now when you compute the meet of these labels you are left with conf label {AliceNBob} that can't be read by C.

Another solution would be to implement something more FLAM-like, but this would be a bunch of work and would also require a SAT solver. If it turns out that not having "totally secret" or "A or B" is annoying, I could possibly help with FLAM-like labels. Maybe this isn't too useful anyway, though. In any case, at a high level this would require:

  • Have a lattice over atomic principals (where atomic principals are things like "Alice" and not things like "Alice /\ Bob"). The "covers" relation is an input to an application, and can be given as a list of pairs like (Alice, Bob) representing principals that trust each other completely. (The covers relation is the members of the relation not due to transitivity.) Another way of describing this implementation would be that the Hasse diagram of the lattice is also a graph, and that this is the adjacency list representation of the graph.
  • You'd want a way to write principals that are ANDs and ORs of other principals.
  • Lattice operators (flowsTo, meet, join) over labels (which either are just principals themselves or are pairs of principals) are functions in term the lattice operators over principals (trusts, or, and)

More specific comments:

label.rs Line 143: maybe call this public_trusted ? really this is a nitpick and not a big deal.

policy.rs Line Line 54, Line 56. Are these set and clear tag functions exposed to applications? I am guessing they are not, but thought it was worth checking just in case.

@tiziano88
Copy link
Collaborator Author

Maybe it is useful to also add functions for meet and join in the label trait?

I am planning to add them in a future PR, as it's not super clear how / when they would be used yet. I guess their use will be motivated by some of the upcoming examples too (e.g. the Chat app).

I can't think of an easy way to write "secret to everyone" or "untrusted by everyone" which should both be the sets of all tags. Is there actually an easy way to get those in Rust? Both secret and untrusted seem useful to me.

What would be the use case of a Node or Channel having a label "secret to everyone" in practice? It seems useful from a theoretical point of view, but I'm not sure whether it can ever show up at runtime.

Another annoying thing about using sets of tags as labels is that you can't easily have a tag that represents the secrecy of "A or B" if A is a tag and B is a tag.

This is true, and I think it's a reasonable compromise for now, which we should revisit in the future.

Copy link
Contributor

@blaxill blaxill left a comment

Choose a reason for hiding this comment

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

Just a few general comments:

  • Are the labels only to be used by the runtime? Perhaps they should be in the ABI if exposed to other things?
  • I'm trying to remove protobuf dependencies right now from the runtime. Perhaps we could feature gate the labels? This would allow no_std for a certain feature set.

@aferr
Copy link

aferr commented Mar 2, 2020

Maybe it is useful to also add functions for meet and join in the label trait?

I am planning to add them in a future PR, as it's not super clear how / when they would be used yet. I guess their use will be motivated by some of the upcoming examples too (e.g. the Chat app).

OK, that makes sense to me.

I can't think of an easy way to write "secret to everyone" or "untrusted by everyone" which should both be the sets of all tags. Is there actually an easy way to get those in Rust? Both secret and untrusted seem useful to me.

What would be the use case of a Node or Channel having a label "secret to everyone" in practice? It seems useful from a theoretical point of view, but I'm not sure whether it can ever show up at runtime.

Right, you might not actually need it. A clear use-case for totally untrusted is values that come from the outside world. You have said that you do not care about integrity at the moment, but if you would like to eventually prove something like robustness, integrity will become important.

Maybe for a client-server application, if you have a part of the server code that needs to store some global secret it is useful to label it as "totally secret". A totally secret node can't directly send messages anywhere, but it could declassify some safe value that is derived from a secret. For example, the server code could encrypt a message meant for a client node with a private key and declassify the ciphertext.

It seems fine to not have a solution until you are sure you need it though.

Another annoying thing about using sets of tags as labels is that you can't easily have a tag that represents the secrecy of "A or B" if A is a tag and B is a tag.

This is true, and I think it's a reasonable compromise for now, which we should revisit in the future.

SGTM

@tiziano88
Copy link
Collaborator Author

  • Are the labels only to be used by the runtime? Perhaps they should be in the ABI if exposed to other things?

Good point, they are kind of part of the ABI in the sense that both the runtime and the SDK will eventually depend on these definitions. I will try to move these definitions there and see if it works out, and then re-request your review.

  • I'm trying to remove protobuf dependencies right now from the runtime. Perhaps we could feature gate the labels? This would allow no_std for a certain feature set.

Uhmm this may be problematic. We could gate it for the time being, but what is the ultimate solution to this problem? Should I start looking at alternatives? I mean, those labels don't need to be protobuf, they could be serialized in any other way (e.g. bincode, JSON, FIDL), but it would be nice to have a single canonical serialization format across runtime and SDK. @blaxill do you think the issues with protobuf and no_std will be resolved somehow, or should we start looking elsewhere?

@blaxill
Copy link
Contributor

blaxill commented Mar 2, 2020

For e.g. the protobuf application configuration, I have std feature gated the protobuf configuration. The runtime still has a rust representation of configuration, with the idea being that it can be configured natively or by having a protobuf configuration serialized to the native rust struct in the untrusted area and sent in. This way protobuf configuration is still supported.

Fixing no_std protobuf is possible but not something I wanted to open as it blocks my critical path of finishing runtime parity and may require a nontrivial amount of work.

Feature gating behind std for the short term allows labels to be used in tests. Then we could either fix protobuf for no_std, or allow Labels to exist in the runtime without the runtime (de)serializing them from protobuf. This last choice depends on exactly where the lables are being serialized- if it's in initial configuration this isn't a problem as they can be deserialized from protobuf at application configuration time. If they need to be continually deserialized by the runtime during execution then this approach might not be viable.

@blaxill
Copy link
Contributor

blaxill commented Mar 2, 2020

Thinking about it a little more, I'm guessing you intend for the labels to be (de)serialized by the runtime as they can contain tags with runtime values (e.g. your bearer tokens). Let me think a little bit if there is a third option.

@blaxill
Copy link
Contributor

blaxill commented Mar 2, 2020

Prost no_std support is tantalisingly close https://github.com/danburkert/prost/pull/215

My vote would be to feature gate it for std at the moment, I'll finish the runtime for no_std support, delaying the protobuf issue. Hopefully it will then be resolved upstream (for prost, I don't think the work has been done for rust-protobuf) or we could add support ourselves.

@tiziano88 tiziano88 added the blocked This pull request is blocked by another pull request or issue label Mar 4, 2020
@tiziano88
Copy link
Collaborator Author

Blocked by #666, so that I can just start using the new proto generation.

@tiziano88 tiziano88 force-pushed the tzn_label_runtime branch 2 times, most recently from e563bfa to 975822e Compare March 4, 2020 11:57
@tiziano88
Copy link
Collaborator Author

label.rs Line 143: maybe call this public_trusted ? really this is a nitpick and not a big deal.

Done

policy.rs Line Line 54, Line 56. Are these set and clear tag functions exposed to applications? I am guessing they are not, but thought it was worth checking just in case.

Yes they are exposed, these are automatically generated by protobuf. It should not matter anyways, once labels are sent over to the runtime, then it does not matter whether the application can keep mutating its local copy, right?

@tiziano88 tiziano88 changed the title Introduce label lattice definition in Oak Runtime Introduce label lattice definition in Oak ABI Mar 4, 2020
// See the License for the specific language governing permissions and
// limitations under the License.
//

Copy link
Contributor

Choose a reason for hiding this comment

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

This didn't immediately look like it belonged here, because it doesn't give constant values or host function signatures for things that flow across the Wasm ABI boundary.

However, I'm guessing that serialized Label protos will flow over the ABI boundary at some point in future, and then any Rust code on either side of the ABI boundary will have a use for these Rust helpers.

So maybe add a module doc comment explaining that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

@tiziano88 tiziano88 force-pushed the tzn_label_runtime branch from 975822e to 94e57d0 Compare March 4, 2020 19:19
@tiziano88
Copy link
Collaborator Author

@blaxill let me know if you'd rather submit #666 before this, or you are happy to rebase that on top of this.

@blaxill
Copy link
Contributor

blaxill commented Mar 5, 2020

@tiziano88 happy to do it either way round, #666 and #656 need approval (or change requests :) )

Not used yet, but as a starting point for future functionality.

It is in the ABI because it will be used by both the runtime and the
SDK.

Ref project-oak#630
@tiziano88 tiziano88 force-pushed the tzn_label_runtime branch from 94e57d0 to b97a38c Compare March 5, 2020 14:59
@tiziano88 tiziano88 removed the blocked This pull request is blocked by another pull request or issue label Mar 5, 2020
@tiziano88
Copy link
Collaborator Author

@tiziano88 happy to do it either way round, #666 and #656 need approval (or change requests :) )

Rebased on those PRs, the result looks good so I'll go ahead now!

@tiziano88 tiziano88 merged commit 302cec1 into project-oak:master Mar 5, 2020
@tiziano88 tiziano88 deleted the tzn_label_runtime branch March 5, 2020 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants