Beispiel #1
0
 internal static void WipeActiveFlags(SVX_MSG msg)
 {
     if (msg != null)
     {
         msg.active = false;
         // FIXME: What if a field contains an object whose dynamic type
         // contains more nested messages than the static type of the
         // field?  We should fix this for all FieldFinder callers at
         // once. ~ REDACTED 2016-08-16
         foreach (var acc in FieldFinder <SVX_MSG> .FindFields(msg.GetType(),
                                                               // We do our own recursion in matches since it's cleaner.
                                                               false))
         {
             WipeActiveFlags(acc.nullConditionalGetter(msg));
         }
     }
 }
Beispiel #2
0
        private static SymT GatherUsefulSymTs(SVX_MSG msg)
        {
            // Want to warn if the msg is inactive but has a symT set, at least
            // for the root message (possible developer mistake)?
            SymT rootSymT = msg.active ? (SymT)msg.SVX_symT : null;

            var nestedSymTs = (
                // NOTE: This will traverse into PayloadSecrets that contain
                // messages, which is what we want.
                from acc in FieldFinder <SVX_MSG> .FindFields(msg.GetType(),
                                                              // We do our own recursion in matches.
                                                              false)
                let nestedMsg = acc.nullConditionalGetter(msg)
                                where nestedMsg != null
                                let nestedSymT = GatherUsefulSymTs(nestedMsg)
                                                 where nestedSymT != null
                                                 select new NestedSymTEntry {
                fieldPath = acc.path, symT = nestedSymT
            }
                ).ToArray();

            // As a simplification, don't unnecessarily create composites
            // (though it shouldn't break anything).  And if we have no
            // information, return null so an outer message doesn't
            // unnecessarily create a composite.

            if (nestedSymTs.Length == 0)
            {
                return(rootSymT);  // may be null
            }
            if (rootSymT == null)
            {
                rootSymT = new SymTNondet {
                    messageTypeFullName = msg.GetType().FullName
                }
            }
            ;

            return(new SymTComposite {
                RootSymTWithMessageId = rootSymT,
                nestedSymTs = nestedSymTs
            });
        }
Beispiel #3
0
        string EmitMessage(SymT symT, MessageReuseScope scope)
        {
            // First look in the scope.  This mechanism currently handles cases
            // where a later argument to a method call is derived from an
            // earlier one; that's enough for the authorization code flow example.
            string reuseVarName;

            for (var checkScope = scope; checkScope != null; checkScope = checkScope.outer)
            {
                if (checkScope.availableMessages.TryGetValue(symT.messageId, out reuseVarName))
                {
                    return(reuseVarName);
                }
            }
            // Otherwise not found; proceed.

            // XXX: Currently we cannot deal with non-public participant classes
            // and methods.  It's an open question if we should be able to and
            // how it should be implemented.  I guess one way is for developers
            // to write [InternalsVisibleTo("VProgram")].  There shouldn't be
            // much risk of abuse because for the vProgram to access a program
            // element, someone authorized had to pass it to an SVX API.

            SymTNondet    symTNondet;
            SymTMethod    symTMethod;
            SymTComposite symTComposite;
            SymTTransfer  symTTransfer;
            string        outputVarName;

            // Consider using a visitor.  It's not worth it yet. :/
            if ((symTNondet = symT as SymTNondet) != null)
            {
                outputVarName = nextVar("msg");
                // FIXME: Nondetting arbitrary data structures will cause
                // aliasing nightmares.  We need to emit a specialized Nondet
                // for each message type.
                AppendFormattedLine("{0} {1} = SVX.VProgram_API.Nondet<{0}>();",
                                    FormatTypeFullName(symTNondet.messageTypeFullName), outputVarName);
            }
            else if ((symTMethod = symT as SymTMethod) != null)
            {
                var newScope = new MessageReuseScope {
                    outer = scope
                };
                var argVarNames = new List <string>();
                for (int i = 0; i < symTMethod.methodArgTypeFullNames.Length; i++)
                {
                    SymT   inputSymT = symTMethod.inputSymTs[i];
                    string inputVarName;
                    if (inputSymT != null)
                    {
                        inputVarName = EmitMessage(inputSymT, newScope);
                        newScope.availableMessages[inputSymT.messageId] = inputVarName;
                    }
                    else
                    {
                        // Nondet non-message argument.  One could argue for using a SymTNondet
                        // even for non-message types.
                        inputVarName = nextVar("arg");
                        AppendFormattedLine("{0} {1} = SVX.VProgram_API.Nondet<{0}>();",
                                            FormatTypeFullName(symTMethod.methodArgTypeFullNames[i]), inputVarName);
                    }
                    argVarNames.Add(inputVarName);
                }
                outputVarName = nextVar("msg");
                AppendFormattedLine("{0} {1} = {2}.{3}({4});",
                                    FormatTypeFullName(symTMethod.methodReturnTypeFullName), outputVarName,
                                    EmitParticipant(symTMethod.participantId),
                                    symTMethod.methodName, string.Join(", ", argVarNames));
            }
            else if ((symTComposite = symT as SymTComposite) != null)
            {
                SymTTransfer rootTransfer;
                if (symTComposite.rootSymT is SymTNondet)
                {
                    // Nondet the root message and then overwrite the nested
                    // messages that we have information about.
                    outputVarName = EmitMessage(symTComposite.rootSymT, scope);
                    foreach (var entry in symTComposite.nestedSymTs)
                    {
                        string nestedVarName = EmitMessage(entry.symT, scope);
                        // Make sure we have a non-null parent to store the nested message in.
                        var lastDot = entry.fieldPath.LastIndexOf('.');
                        if (lastDot != -1)
                        {
                            AppendFormattedLine("System.Diagnostics.Contracts.Contract.Assume({0} != null);",
                                                MakeFieldPathNullConditional(outputVarName, entry.fieldPath.Substring(0, lastDot),
                                                                             symTComposite.MessageTypeFullName));
                        }
                        AppendFormattedLine("{0}.{1} = {2};",
                                            outputVarName, entry.fieldPath, nestedVarName);
                    }
                }
                else if (symTComposite.rootSymT is SymTMethod)
                {
                    // In this case, we assume the information in the rootSymT
                    // subsumes the information in the nested SymTs and emit
                    // code only for the rootSymT.  If we had Equals for
                    // messages, we could assume the nested messages equal, but
                    // this is extra work which I don't believe is needed for
                    // our examples so far.
                    outputVarName = EmitMessage(symTComposite.rootSymT, scope);
                }
                else if ((rootTransfer = symTComposite.rootSymT as SymTTransfer) != null)
                {
                    // The emitted code for the SymTTransfer will determine
                    // whether the transfer is trusted.  If so, just use the
                    // transfer and ignore the nested messages, as in the
                    // SymTMethod case.  If not, it will use the fallback we
                    // specify.
                    outputVarName = EmitMessage(new SymTTransfer(rootTransfer)
                    {
                        fallback = new SymTComposite
                        {
                            RootSymTWithMessageId = new SymTNondet {
                                messageTypeFullName = symTComposite.MessageTypeFullName
                            },
                            nestedSymTs = symTComposite.nestedSymTs
                        }
                    }, scope);
                }
                else
                {
                    // We should never have double composites.
                    throw new NotImplementedException("Unhandled root SymT in composite");
                }
            }
            else if ((symTTransfer = symT as SymTTransfer) != null)
            {
                string producerVarName = nextVar("producer");
                AppendFormattedLine("SVX.Principal {0} = {1};", producerVarName, EmitPrincipalHandleOrNondet(symTTransfer.producer));
                outputVarName = nextVar("msg");
                AppendFormattedLine("{0} {1};", FormatTypeFullName(symTTransfer.MessageTypeFullName), outputVarName);
                AppendFormattedLine("if (SVX.VProgram_API.IsTrusted({0})) {{", producerVarName);
                {
                    IncreaseIndent();
                    string inputVarName = EmitMessage(symTTransfer.originalSymT, scope);
                    AppendFormattedLine("{0} = {1};", outputVarName, inputVarName);
                    // To maintain soundness of the model, update the metadata
                    // of nested messages the same way TransferNested would in
                    // production, even though we don't use their SymTs.
                    // XXX: symTTransfer.payloadSecretsVerifiedOnImport could
                    // contain non-message payload secrets once we support them,
                    // and we'd need to skip them here.
                    foreach (var entry in symTTransfer.payloadSecretsVerifiedOnImport)
                    {
                        string paramsPath = entry.fieldPath + ".theParams";
                        AppendFormattedLine("System.Diagnostics.Contracts.Contract.Assume({0} != null);",
                                            MakeFieldPathNullConditional(outputVarName, paramsPath, symTTransfer.MessageTypeFullName));
                        AppendFormattedLine("SVX.SVX_Ops.TransferNested({0}.{1}, new {2}().Signer);",
                                            outputVarName, paramsPath, FormatTypeFullName(entry.secretGeneratorTypeFullName));
                    }
                    DecreaseIndent();
                }
                AppendFormattedLine("}} else {{");
                {
                    IncreaseIndent();
                    string inputVarName = EmitMessage(symTTransfer.fallback ??
                                                      new SymTNondet {
                        messageTypeFullName = symTTransfer.MessageTypeFullName
                    }, scope);
                    AppendFormattedLine("{0} = {1};", outputVarName, inputVarName);
                    DecreaseIndent();
                }
                AppendFormattedLine("}}");

                // Should we introduce a "transfer info" object that we can both
                // use as an arg to Transfer and store in the SymTTransfer, to
                // avoid shuttling individual arguments back and forth?  The
                // following is not too bad.
                if (symTTransfer.hasSender)
                {
                    // Note: Transfer does not use the realRequestProducer arg in the vProgram.
                    AppendFormattedLine("SVX.SVX_Ops.Transfer({0}, {1}, {2}, null, {3});",
                                        outputVarName, producerVarName, EmitPrincipalHandleOrNondet(symTTransfer.sender),
                                        // http://stackoverflow.com/a/491367 :/
                                        symTTransfer.browserOnly.ToString().ToLower());
                }
                else
                {
                    AppendFormattedLine("SVX.SVX_Ops.TransferNested({0}, {1});",
                                        outputVarName, producerVarName);
                }

                // If we verified secrets on import, they are valid regardless
                // of whether the transfer was trusted.
                foreach (var entry in symTTransfer.payloadSecretsVerifiedOnImport)
                {
                    // I'm unsure of BCT handling of null dereferences in
                    // general, but here we can definitely assume non-null.
                    AppendFormattedLine("System.Diagnostics.Contracts.Contract.Assume({0} != null);",
                                        MakeFieldPathNullConditional(outputVarName, entry.fieldPath, symTTransfer.MessageTypeFullName));
                    // Follow the commented-out lines in
                    // MessagePayloadSecretGenerator.VerifyAndExtract.  I'd like
                    // to define a helper method for this, but until I merge
                    // SVX_Common and SVX_Ops, I'm between a rock and a hard
                    // place because the method needs to be BCT translated but
                    // needs to reference MessagePayloadSecretGenerator.
                    AppendFormattedLine("System.Diagnostics.Contracts.Contract.Assume({0}.{1}.secretValue != null);",
                                        outputVarName, entry.fieldPath);
                    AppendFormattedLine("System.Diagnostics.Contracts.Contract.Assume({0}.{1}.theParams != null);",
                                        outputVarName, entry.fieldPath);
                    // XXX We're assuming the generator has a no-arg public
                    // constructor and doesn't need any configuration parameters.
                    AppendFormattedLine("SVX.VProgram_API.AssumeValidSecret({0}.{1}.secretValue, " +
                                        "{0}.{1}.theParams, new {2}().GetReaders({0}.{1}.theParams));",
                                        outputVarName, entry.fieldPath, FormatTypeFullName(entry.secretGeneratorTypeFullName));
                }

                if (symTTransfer.hasSender)
                {
                    Type messageType = GetTypeByFullName(symTTransfer.MessageTypeFullName);
                    foreach (var acc in FieldFinder <Secret> .FindFields(messageType, true))
                    {
                        AppendFormattedLine("SVX.VProgram_API.AssumeBorne({0}.SVX_producer, {1});",
                                            outputVarName, MakeFieldPathNullConditional(outputVarName, acc.path + ".secretValue",
                                                                                        symTTransfer.MessageTypeFullName));
                        AppendFormattedLine("SVX.VProgram_API.AssumeBorne({0}.SVX_sender, {1});",
                                            outputVarName, MakeFieldPathNullConditional(outputVarName, acc.path + ".secretValue",
                                                                                        symTTransfer.MessageTypeFullName));
                    }
                }
            }
            else
            {
                throw new NotImplementedException("Unhandled SymT");
            }
            return(outputVarName);
        }