Skip to content

Commit

Permalink
[FAB-2997] don't invoke some scc thru proposals
Browse files Browse the repository at this point in the history
This is the first of three fixes required for FAB-2997 (described in the
discussion for that jira item). In this change set we prevent
security-sensitive system chaincodes (such as escc or vscc) from being
invoked from the outside through proposals sent to the peer. A flag has
been added to the system chaincode struct to keep track of whether a system
chaincode can be invoked this way or not. A second flag was added to keep
track of whether the system chaincode can be invoked using a cc2cc
invocation. This flag will be used in the second change set related to this
jira item.

Change-Id: Iaf05217fcf7247f61fddb4a16afb0908c9735efc
Signed-off-by: Alessandro Sorniotti <ale.linux@sopit.net>
  • Loading branch information
ale-linux committed Apr 18, 2017
1 parent 7f336b9 commit a3efa2c
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 15 deletions.
8 changes: 8 additions & 0 deletions core/endorser/endorser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 15 additions & 0 deletions core/endorser/endorser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
46 changes: 31 additions & 15 deletions core/scc/importsysccs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
},
}

Expand Down Expand Up @@ -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 {
Expand Down
11 changes: 11 additions & 0 deletions core/scc/sysccapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit a3efa2c

Please sign in to comment.