diff --git a/core/endorser/endorser.go b/core/endorser/endorser.go index 7f8d2ace2a4..b61fee5b0d2 100644 --- a/core/endorser/endorser.go +++ b/core/endorser/endorser.go @@ -313,6 +313,14 @@ func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedPro return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err } + // block invocations to security-sensitive system chaincodes + if syscc.IsSysCCAndNotInvokable(hdrExt.ChaincodeId.Name) { + endorserLogger.Errorf("ProcessProposal error: an attempt was made by %#v to invoke system chaincode %s", + shdr.Creator, hdrExt.ChaincodeId.Name) + err = fmt.Errorf("Chaincode %s cannot be invoked through a proposal", hdrExt.ChaincodeId.Name) + return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err + } + chainID := chdr.ChannelId // Check for uniqueness of prop.TxID with ledger diff --git a/core/endorser/endorser_test.go b/core/endorser/endorser_test.go index 17f261d54a4..0372caaa3b3 100644 --- a/core/endorser/endorser_test.go +++ b/core/endorser/endorser_test.go @@ -623,6 +623,21 @@ func TestAdminACLFail(t *testing.T) { chaincode.GetChain().Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: chaincodeID}}) } +// TestInvokeSccFail makes sure that invoking a system chaincode fails +func TestInvokeSccFail(t *testing.T) { + chainID := util.GetTestChainID() + + chaincodeID := &pb.ChaincodeID{Name: "escc"} + args := util.ToChaincodeArgs("someFunc", "someArg") + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeId: chaincodeID, Input: &pb.ChaincodeInput{Args: args}} + _, _, _, _, err := invoke(chainID, spec) + if err == nil { + t.Logf("Invoking escc should have failed!") + t.Fail() + return + } +} + func newTempDir() string { tempDir, err := ioutil.TempDir("", "fabric-") if err != nil { diff --git a/core/scc/importsysccs.go b/core/scc/importsysccs.go index a080ee8223d..50e0c9a4a85 100644 --- a/core/scc/importsysccs.go +++ b/core/scc/importsysccs.go @@ -28,18 +28,20 @@ import ( //see systemchaincode_test.go for an example using "sample_syscc" var systemChaincodes = []*SystemChaincode{ { - Enabled: true, - Name: "cscc", - Path: "github.com/hyperledger/fabric/core/scc/cscc", - InitArgs: [][]byte{[]byte("")}, - Chaincode: &cscc.PeerConfiger{}, + Enabled: true, + Name: "cscc", + Path: "github.com/hyperledger/fabric/core/scc/cscc", + InitArgs: [][]byte{[]byte("")}, + Chaincode: &cscc.PeerConfiger{}, + InvokableExternal: true, // cscc is invoked to join a channel }, { - Enabled: true, - Name: "lscc", - Path: "github.com/hyperledger/fabric/core/scc/lscc", - InitArgs: [][]byte{[]byte("")}, - Chaincode: &lscc.LifeCycleSysCC{}, + Enabled: true, + Name: "lscc", + Path: "github.com/hyperledger/fabric/core/scc/lscc", + InitArgs: [][]byte{[]byte("")}, + Chaincode: &lscc.LifeCycleSysCC{}, + InvokableExternal: true, // lccc is invoked to deploy new chaincodes }, { Enabled: true, @@ -56,11 +58,13 @@ var systemChaincodes = []*SystemChaincode{ Chaincode: &vscc.ValidatorOneValidSignature{}, }, { - Enabled: true, - Name: "qscc", - Path: "github.com/hyperledger/fabric/core/chaincode/qscc", - InitArgs: [][]byte{[]byte("")}, - Chaincode: &qscc.LedgerQuerier{}, + Enabled: true, + Name: "qscc", + Path: "github.com/hyperledger/fabric/core/chaincode/qscc", + InitArgs: [][]byte{[]byte("")}, + Chaincode: &qscc.LedgerQuerier{}, + InvokableExternal: true, // qscc can be invoked to retrieve blocks + InvokableCC2CC: true, // qscc can be invoked to retrieve blocks also by a cc }, } @@ -100,6 +104,18 @@ func IsSysCC(name string) bool { return false } +// IsSysCCAndNotInvokable returns true if the chaincode +// is a system chaincode and *CANNOT* be invoked through +// a proposal to this peer +func IsSysCCAndNotInvokable(name string) bool { + for _, sysCC := range systemChaincodes { + if sysCC.Name == name { + return !sysCC.InvokableExternal + } + } + return false +} + // MockRegisterSysCCs is used only for testing // This is needed to break import cycle func MockRegisterSysCCs(mockSysCCs []*SystemChaincode) []*SystemChaincode { diff --git a/core/scc/sysccapi.go b/core/scc/sysccapi.go index 3ad32e6f770..e541265f144 100644 --- a/core/scc/sysccapi.go +++ b/core/scc/sysccapi.go @@ -54,6 +54,17 @@ type SystemChaincode struct { // Chaincode is the actual chaincode object Chaincode shim.Chaincode + + // InvokableExternal keeps track of whether + // this system chaincode can be invoked + // through a proposal sent to this peer + InvokableExternal bool + + // InvokableCC2CC keeps track of whether + // this system chaincode can be invoked + // by way of a chaincode-to-chaincode + // invocation + InvokableCC2CC bool } // RegisterSysCC registers the given system chaincode with the peer